saa7146_core.c

来自「trident tm5600的linux驱动」· C语言 代码 · 共 602 行 · 第 1/2 页

C
602
字号
	u32 ack_isr;	/* read out the interrupt status register */	ack_isr = isr = saa7146_read(dev, ISR);	/* is this our interrupt? */	if ( 0 == isr ) {		/* nope, some other device */		return IRQ_NONE;	}	if (dev->ext) {		if (dev->ext->irq_mask & isr) {			if (dev->ext->irq_func)				dev->ext->irq_func(dev, &isr);			isr &= ~dev->ext->irq_mask;		}	}	if (0 != (isr & (MASK_27))) {		DEB_INT(("irq: RPS0 (0x%08x).\n",isr));		if (dev->vv_data && dev->vv_callback)			dev->vv_callback(dev,isr);		isr &= ~MASK_27;	}	if (0 != (isr & (MASK_28))) {		if (dev->vv_data && dev->vv_callback)			dev->vv_callback(dev,isr);		isr &= ~MASK_28;	}	if (0 != (isr & (MASK_16|MASK_17))) {		SAA7146_IER_DISABLE(dev, MASK_16|MASK_17);		/* only wake up if we expect something */		if (0 != dev->i2c_op) {			dev->i2c_op = 0;			wake_up(&dev->i2c_wq);		} else {			u32 psr = saa7146_read(dev, PSR);			u32 ssr = saa7146_read(dev, SSR);			printk(KERN_WARNING "%s: unexpected i2c irq: isr %08x psr %08x ssr %08x\n",			       dev->name, isr, psr, ssr);		}		isr &= ~(MASK_16|MASK_17);	}	if( 0 != isr ) {		ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr));		ERR(("disabling interrupt source(s)!\n"));		SAA7146_IER_DISABLE(dev,isr);	}	saa7146_write(dev, ISR, ack_isr);	return IRQ_HANDLED;}/*********************************************************************************//* configuration-functions                                                       */static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent){	struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data;	struct saa7146_extension *ext = pci_ext->ext;	struct saa7146_dev *dev;	int err = -ENOMEM;	/* clear out mem for sure */	dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL);	if (!dev) {		ERR(("out of memory.\n"));		goto out;	}	DEB_EE(("pci:%p\n",pci));	err = pci_enable_device(pci);	if (err < 0) {		ERR(("pci_enable_device() failed.\n"));		goto err_free;	}	/* enable bus-mastering */	pci_set_master(pci);	dev->pci = pci;	/* get chip-revision; this is needed to enable bug-fixes */	err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision);	if (err < 0) {		ERR(("pci_read_config_dword() failed.\n"));		goto err_disable;	}	dev->revision &= 0xf;	/* remap the memory from virtual to physical address */	err = pci_request_region(pci, 0, "saa7146");	if (err < 0)		goto err_disable;	dev->mem = ioremap(pci_resource_start(pci, 0),			   pci_resource_len(pci, 0));	if (!dev->mem) {		ERR(("ioremap() failed.\n"));		err = -ENODEV;		goto err_release;	}	/* we don't do a master reset here anymore, it screws up	   some boards that don't have an i2c-eeprom for configuration	   values *//*	saa7146_write(dev, MC1, MASK_31);*/	/* disable all irqs */	saa7146_write(dev, IER, 0);	/* shut down all dma transfers and rps tasks */	saa7146_write(dev, MC1, 0x30ff0000);	/* clear out any rps-signals pending */	saa7146_write(dev, MC2, 0xf8000000);	/* request an interrupt for the saa7146 */	err = request_irq(pci->irq, interrupt_hw, IRQF_SHARED | IRQF_DISABLED,			  dev->name, dev);	if (err < 0) {		ERR(("request_irq() failed.\n"));		goto err_unmap;	}	err = -ENOMEM;	/* get memory for various stuff */	dev->d_rps0.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,						    &dev->d_rps0.dma_handle);	if (!dev->d_rps0.cpu_addr)		goto err_free_irq;	memset(dev->d_rps0.cpu_addr, 0x0, SAA7146_RPS_MEM);	dev->d_rps1.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,						    &dev->d_rps1.dma_handle);	if (!dev->d_rps1.cpu_addr)		goto err_free_rps0;	memset(dev->d_rps1.cpu_addr, 0x0, SAA7146_RPS_MEM);	dev->d_i2c.cpu_addr = pci_alloc_consistent(pci, SAA7146_RPS_MEM,						   &dev->d_i2c.dma_handle);	if (!dev->d_i2c.cpu_addr)		goto err_free_rps1;	memset(dev->d_i2c.cpu_addr, 0x0, SAA7146_RPS_MEM);	/* the rest + print status message */	/* create a nice device name */	sprintf(dev->name, "saa7146 (%d)", saa7146_num);	INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));	dev->ext = ext;	pci_set_drvdata(pci, dev);	mutex_init(&dev->lock);	spin_lock_init(&dev->int_slock);	spin_lock_init(&dev->slock);	mutex_init(&dev->i2c_lock);	dev->module = THIS_MODULE;	init_waitqueue_head(&dev->i2c_wq);	/* set some sane pci arbitrition values */	saa7146_write(dev, PCI_BT_V1, 0x1c00101f);	/* TODO: use the status code of the callback */	err = -ENODEV;	if (ext->probe && ext->probe(dev)) {		DEB_D(("ext->probe() failed for %p. skipping device.\n",dev));		goto err_free_i2c;	}	if (ext->attach(dev, pci_ext)) {		DEB_D(("ext->attach() failed for %p. skipping device.\n",dev));		goto err_unprobe;	}	INIT_LIST_HEAD(&dev->item);	list_add_tail(&dev->item,&saa7146_devices);	saa7146_num++;	err = 0;out:	return err;err_unprobe:	pci_set_drvdata(pci, NULL);err_free_i2c:	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr,			    dev->d_i2c.dma_handle);err_free_rps1:	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr,			    dev->d_rps1.dma_handle);err_free_rps0:	pci_free_consistent(pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr,			    dev->d_rps0.dma_handle);err_free_irq:	free_irq(pci->irq, (void *)dev);err_unmap:	iounmap(dev->mem);err_release:	pci_release_region(pci, 0);err_disable:	pci_disable_device(pci);err_free:	kfree(dev);	goto out;}static void saa7146_remove_one(struct pci_dev *pdev){	struct saa7146_dev* dev = pci_get_drvdata(pdev);	struct {		void *addr;		dma_addr_t dma;	} dev_map[] = {		{ dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle },		{ dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle },		{ dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle },		{ NULL, 0 }	}, *p;	DEB_EE(("dev:%p\n",dev));	dev->ext->detach(dev);	/* shut down all video dma transfers */	saa7146_write(dev, MC1, 0x00ff0000);	/* disable all irqs, release irq-routine */	saa7146_write(dev, IER, 0);	free_irq(pdev->irq, dev);	for (p = dev_map; p->addr; p++)		pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma);	iounmap(dev->mem);	pci_release_region(pdev, 0);	list_del(&dev->item);	pci_disable_device(pdev);	kfree(dev);	saa7146_num--;}/*********************************************************************************//* extension handling functions                                                  */int saa7146_register_extension(struct saa7146_extension* ext){	DEB_EE(("ext:%p\n",ext));	ext->driver.name = ext->name;	ext->driver.id_table = ext->pci_tbl;	ext->driver.probe = saa7146_init_one;	ext->driver.remove = saa7146_remove_one;	printk("saa7146: register extension '%s'.\n",ext->name);	return pci_register_driver(&ext->driver);}int saa7146_unregister_extension(struct saa7146_extension* ext){	DEB_EE(("ext:%p\n",ext));	printk("saa7146: unregister extension '%s'.\n",ext->name);	pci_unregister_driver(&ext->driver);	return 0;}EXPORT_SYMBOL_GPL(saa7146_register_extension);EXPORT_SYMBOL_GPL(saa7146_unregister_extension);/* misc functions used by extension modules */EXPORT_SYMBOL_GPL(saa7146_pgtable_alloc);EXPORT_SYMBOL_GPL(saa7146_pgtable_free);EXPORT_SYMBOL_GPL(saa7146_pgtable_build_single);EXPORT_SYMBOL_GPL(saa7146_vmalloc_build_pgtable);EXPORT_SYMBOL_GPL(saa7146_vfree_destroy_pgtable);EXPORT_SYMBOL_GPL(saa7146_wait_for_debi_done);EXPORT_SYMBOL_GPL(saa7146_setgpio);EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare);EXPORT_SYMBOL_GPL(saa7146_debug);EXPORT_SYMBOL_GPL(saa7146_devices);EXPORT_SYMBOL_GPL(saa7146_devices_lock);MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");MODULE_DESCRIPTION("driver for generic saa7146-based hardware");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?