X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fcommon%2Fsaa7146_core.c;h=8cdd4d265ffa235bb69a57f7a57679b6e0827e72;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=369d949fded45d8e1e60f1288cb00f3e8f433a79;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 369d949fd..8cdd4d265 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -20,16 +20,14 @@ #include -/* global variables */ -struct list_head saa7146_devices; -struct semaphore saa7146_devices_lock; +LIST_HEAD(saa7146_devices); +DEFINE_MUTEX(saa7146_devices_lock); -static int initialized = 0; -int saa7146_num = 0; +static int saa7146_num; -unsigned int saa7146_debug = 0; +unsigned int saa7146_debug; -MODULE_PARM(saa7146_debug,"i"); +module_param(saa7146_debug, int, 0644); MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); #if 0 @@ -48,50 +46,51 @@ static void dump_registers(struct saa7146_dev* dev) * gpio and debi helper functions ****************************************************************************/ -/* write "data" to the gpio-pin "pin" */ -void saa7146_set_gpio(struct saa7146_dev *dev, u8 pin, u8 data) +void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) { u32 value = 0; - /* sanity check */ - if(pin > 3) - return; - - /* read old register contents */ - value = saa7146_read(dev, GPIO_CTRL ); - - value &= ~(0xff << (8*pin)); - value |= (data << (8*pin)); + BUG_ON(port > 3); + value = saa7146_read(dev, GPIO_CTRL); + value &= ~(0xff << (8*port)); + value |= (data << (8*port)); saa7146_write(dev, GPIO_CTRL, value); } /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ -int saa7146_wait_for_debi_done(struct saa7146_dev *dev) +int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) { unsigned long start; + int err; /* wait for registers to be programmed */ start = jiffies; while (1) { - if (saa7146_read(dev, MC2) & 2) - break; - if (time_after(jiffies, start + HZ/20)) { + err = time_after(jiffies, start + HZ/20); + if (saa7146_read(dev, MC2) & 2) + break; + if (err) { DEB_S(("timed out while waiting for registers getting programmed\n")); return -ETIMEDOUT; } + if (nobusyloop) + msleep(1); } /* wait for transfer to complete */ start = jiffies; while (1) { + err = time_after(jiffies, start + HZ/4); if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) break; saa7146_read(dev, MC2); - if (time_after(jiffies, start + HZ/4)) { + if (err) { DEB_S(("timed out while waiting for transfer completion\n")); return -ETIMEDOUT; } + if (nobusyloop) + msleep(1); } return 0; @@ -101,7 +100,7 @@ int saa7146_wait_for_debi_done(struct saa7146_dev *dev) * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from video-buf.c make sure virt has been allocated with vmalloc_32(), otherwise the BUG() may be triggered on highmem machines */ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) @@ -110,21 +109,19 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) struct page *pg; int i; - sglist = kmalloc(sizeof(struct scatterlist)*nr_pages, GFP_KERNEL); + sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); if (NULL == sglist) return NULL; - memset(sglist,0,sizeof(struct scatterlist)*nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); if (NULL == pg) goto err; - if (PageHighMem(pg)) - BUG(); + BUG_ON(PageHighMem(pg)); sglist[i].page = pg; sglist[i].length = PAGE_SIZE; } return sglist; - + err: kfree(sglist); return NULL; @@ -133,8 +130,6 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) /********************************************************************************/ /* common page table functions */ -#define SAA7146_PGTABLE_SIZE 4096 - char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) { int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; @@ -156,7 +151,7 @@ char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa vfree(mem); return NULL; } - + slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE); if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) { return NULL; @@ -171,22 +166,20 @@ void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) return; pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); pt->cpu = NULL; - if (NULL != pt->slist) { - kfree(pt->slist); - pt->slist = NULL; - } + kfree(pt->slist); + pt->slist = NULL; } int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) { - u32 *cpu; - dma_addr_t dma_addr; + u32 *cpu; + dma_addr_t dma_addr; - cpu = pci_alloc_consistent(pci, SAA7146_PGTABLE_SIZE, &dma_addr); + cpu = pci_alloc_consistent(pci, PAGE_SIZE, &dma_addr); if (NULL == cpu) { return -ENOMEM; } - pt->size = SAA7146_PGTABLE_SIZE; + pt->size = PAGE_SIZE; pt->cpu = cpu; pt->dma = dma_addr; @@ -196,17 +189,13 @@ int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt, struct scatterlist *list, int sglen ) { - u32 *ptr, fill; + u32 *ptr, fill; int nr_pages = 0; - int i,p; + int i,p; - BUG_ON( 0 == sglen); + BUG_ON(0 == sglen); + BUG_ON(list->offset > PAGE_SIZE); - if (list->offset > PAGE_SIZE) { - DEB_D(("offset > PAGE_SIZE. this should not happen.")); - return -EINVAL; - } - /* if we have a user buffer, the first page may not be aligned to a page boundary. */ pt->offset = list->offset; @@ -217,7 +206,7 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt printk("i:%d, adr:0x%08x, len:%d, offset:%d\n", i,sg_dma_address(list), sg_dma_len(list), list->offset); */ for (p = 0; p * 4096 < list->length; p++, ptr++) { - *ptr = sg_dma_address(list) + p * 4096; + *ptr = cpu_to_le32(sg_dma_address(list) + p * 4096); nr_pages++; } } @@ -239,25 +228,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt return 0; } -/********************************************************************************/ -/* gpio functions */ - -void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) -{ - u32 val = 0; - - val=saa7146_read(dev,GPIO_CTRL); - val&=~(0xff << (8*(port))); - val|=(data)<<(8*(port)); - saa7146_write(dev, GPIO_CTRL, val); -} - /********************************************************************************/ /* interrupt handler */ - static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) { - struct saa7146_dev *dev = (struct saa7146_dev*)dev_id; + struct saa7146_dev *dev = dev_id; u32 isr = 0; /* read out the interrupt status register */ @@ -295,7 +270,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) if (0 != (isr & (MASK_16|MASK_17))) { u32 status = saa7146_read(dev, I2C_STATUS); if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { - IER_DISABLE(dev, MASK_16|MASK_17); + SAA7146_IER_DISABLE(dev, MASK_16|MASK_17); /* only wake up if we expect something */ if( 0 != dev->i2c_op ) { u32 psr = (saa7146_read(dev, PSR) >> 16) & 0x2; @@ -314,7 +289,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) if( 0 != isr ) { ERR(("warning: interrupt enabled, but not handled properly.(0x%08x)\n",isr)); ERR(("disabling interrupt source(s)!\n")); - IER_DISABLE(dev,isr); + SAA7146_IER_DISABLE(dev,isr); } return IRQ_HANDLED; } @@ -324,55 +299,51 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id, struct pt_regs *regs) static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent) { - unsigned long adr = 0, len = 0; - struct saa7146_dev* dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL); - struct saa7146_pci_extension_data *pci_ext = (struct saa7146_pci_extension_data *)ent->driver_data; - struct saa7146_extension* ext = pci_ext->ext; - int err = 0; - - if (!(dev = kmalloc (sizeof(struct saa7146_dev),GFP_KERNEL))) { - ERR(("out of memory.\n")); - return -ENOMEM; - } + struct saa7146_extension *ext = pci_ext->ext; + struct saa7146_dev *dev; + int err = -ENOMEM; /* clear out mem for sure */ - memset(dev, 0x0, sizeof(struct saa7146_dev)); + dev = kzalloc(sizeof(struct saa7146_dev), GFP_KERNEL); + if (!dev) { + ERR(("out of memory.\n")); + goto out; + } DEB_EE(("pci:%p\n",pci)); - if (pci_enable_device(pci)) { + err = pci_enable_device(pci); + if (err < 0) { ERR(("pci_enable_device() failed.\n")); - err = -EIO; - goto pci_error; + goto err_free; } /* enable bus-mastering */ pci_set_master(pci); dev->pci = pci; + /* get chip-revision; this is needed to enable bug-fixes */ - if( 0 > pci_read_config_dword(dev->pci, PCI_CLASS_REVISION, &dev->revision)) { + err = pci_read_config_dword(pci, PCI_CLASS_REVISION, &dev->revision); + if (err < 0) { ERR(("pci_read_config_dword() failed.\n")); - err = -ENODEV; - goto pci_error; + goto err_disable; } dev->revision &= 0xf; /* remap the memory from virtual to physical adress */ - adr = pci_resource_start(pci,0); - len = pci_resource_len(pci,0); - if (!request_mem_region(pci_resource_start(pci,0), pci_resource_len(pci,0), "saa7146")) { - ERR(("request_mem_region() failed.\n")); - err = -ENODEV; - goto pci_error; - } + err = pci_request_region(pci, 0, "saa7146"); + if (err < 0) + goto err_disable; - if (!(dev->mem = ioremap(adr,len))) { + dev->mem = ioremap(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + if (!dev->mem) { ERR(("ioremap() failed.\n")); err = -ENODEV; - goto ioremap_error; + goto err_release; } /* we don't do a master reset here anymore, it screws up @@ -385,77 +356,75 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent /* disable all irqs */ saa7146_write(dev, IER, 0); - /* shut down all dma transfers */ - saa7146_write(dev, MC1, 0x00ff0000); + /* 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 */ - if (request_irq(dev->pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT, - dev->name, dev)) - { + err = request_irq(pci->irq, interrupt_hw, SA_SHIRQ | SA_INTERRUPT, + dev->name, dev); + if (err < 0) { ERR(("request_irq() failed.\n")); - err = -ENODEV; - goto irq_error; + goto err_unmap; } + err = -ENOMEM; + /* get memory for various stuff */ - dev->d_rps0.cpu_addr = pci_alloc_consistent(dev->pci, SAA7146_RPS_MEM, &dev->d_rps0.dma_handle); - if( NULL == dev->d_rps0.cpu_addr ) { - err = -ENOMEM; - goto kmalloc_error_1; - } + 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(dev->pci, SAA7146_RPS_MEM, &dev->d_rps1.dma_handle); - if( NULL == dev->d_rps1.cpu_addr ) { - err = -ENOMEM; - goto kmalloc_error_2; - } + 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(dev->pci, SAA7146_RPS_MEM, &dev->d_i2c.dma_handle); - if( NULL == dev->d_i2c.cpu_addr ) { - err = -ENOMEM; - goto kmalloc_error_3; - } + 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[0], "saa7146 (%d)",saa7146_num); + 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,dev->pci->irq,dev->pci->subsystem_vendor,dev->pci->subsystem_device)); + 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); + pci_set_drvdata(pci, dev); - init_MUTEX(&dev->lock); - dev->int_slock = SPIN_LOCK_UNLOCKED; - dev->slock = SPIN_LOCK_UNLOCKED; + mutex_init(&dev->lock); + spin_lock_init(&dev->int_slock); + spin_lock_init(&dev->slock); - init_MUTEX(&dev->i2c_lock); + 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); + saa7146_write(dev, PCI_BT_V1, 0x1c00101f); - if( 0 != ext->probe) { - if( 0 != ext->probe(dev) ) { - DEB_D(("ext->probe() failed for %p. skipping device.\n",dev)); - err = -ENODEV; - goto probe_error; - } + /* 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( 0 != ext->attach(dev,pci_ext) ) { + if (ext->attach(dev, pci_ext)) { DEB_D(("ext->attach() failed for %p. skipping device.\n",dev)); - err = -ENODEV; - goto attach_error; + goto err_unprobe; } INIT_LIST_HEAD(&dev->item); @@ -463,30 +432,46 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent saa7146_num++; err = 0; - goto out; -attach_error: -probe_error: - pci_set_drvdata(pci,NULL); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle); -kmalloc_error_3: - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle); -kmalloc_error_2: - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle); -kmalloc_error_1: - free_irq(dev->pci->irq, (void *)dev); -irq_error: - iounmap(dev->mem); -ioremap_error: - release_mem_region(adr,len); -pci_error: - kfree(dev); 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 = (struct saa7146_dev*) pci_get_drvdata(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); @@ -497,17 +482,15 @@ static void saa7146_remove_one(struct pci_dev *pdev) /* disable all irqs, release irq-routine */ saa7146_write(dev, IER, 0); - free_irq(dev->pci->irq, (void *)dev); + free_irq(pdev->irq, dev); - /* free kernel memory */ - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_i2c.cpu_addr, dev->d_i2c.dma_handle); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps1.cpu_addr, dev->d_rps1.dma_handle); - pci_free_consistent(dev->pci, SAA7146_RPS_MEM, dev->d_rps0.cpu_addr, dev->d_rps0.dma_handle); + for (p = dev_map; p->addr; p++) + pci_free_consistent(pdev, SAA7146_RPS_MEM, p->addr, p->dma); iounmap(dev->mem); - release_mem_region(pci_resource_start(dev->pci,0), pci_resource_len(dev->pci,0)); - + pci_release_region(pdev, 0); list_del(&dev->item); + pci_disable_device(pdev); kfree(dev); saa7146_num--; @@ -520,19 +503,13 @@ int saa7146_register_extension(struct saa7146_extension* ext) { DEB_EE(("ext:%p\n",ext)); - if( 0 == initialized ) { - INIT_LIST_HEAD(&saa7146_devices); - init_MUTEX(&saa7146_devices_lock); - initialized = 1; - } - 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_module_init(&ext->driver); + return pci_register_driver(&ext->driver); } int saa7146_unregister_extension(struct saa7146_extension* ext) @@ -543,23 +520,6 @@ int saa7146_unregister_extension(struct saa7146_extension* ext) return 0; } -static int __init saa7146_init_module(void) -{ - if( 0 == initialized ) { - INIT_LIST_HEAD(&saa7146_devices); - init_MUTEX(&saa7146_devices_lock); - initialized = 1; - } - return 0; -} - -static void __exit saa7146_cleanup_module(void) -{ -} - -module_init(saa7146_init_module); -module_exit(saa7146_cleanup_module); - EXPORT_SYMBOL_GPL(saa7146_register_extension); EXPORT_SYMBOL_GPL(saa7146_unregister_extension);