X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fmedia%2Fcommon%2Fsaa7146_core.c;h=7707b8c7394b17308c067b2813f6809e105c5072;hb=e9b62693ae0a1e13ccc97a6792d9a7770c8d1b5b;hp=86cbdbcf9d7db1f005e9cfa37a44b76088c59c61;hpb=7d12e780e003f93433d49ce78cfedf4b4c52adc5;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c index 86cbdbc..7707b8c 100644 --- a/drivers/media/common/saa7146_core.c +++ b/drivers/media/common/saa7146_core.c @@ -27,7 +27,7 @@ static int saa7146_num; unsigned int saa7146_debug; -module_param(saa7146_debug, int, 0644); +module_param(saa7146_debug, uint, 0644); MODULE_PARM_DESC(saa7146_debug, "debug level (default: 0)"); #if 0 @@ -59,48 +59,94 @@ void saa7146_setgpio(struct saa7146_dev *dev, int port, u32 data) } /* This DEBI code is based on the saa7146 Stradis driver by Nathan Laredo */ -int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) +static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev, + unsigned long us1, unsigned long us2) { - unsigned long start; + unsigned long timeout; int err; /* wait for registers to be programmed */ - start = jiffies; + timeout = jiffies + usecs_to_jiffies(us1); while (1) { - err = time_after(jiffies, start + HZ/20); + err = time_after(jiffies, timeout); if (saa7146_read(dev, MC2) & 2) break; if (err) { - DEB_S(("timed out while waiting for registers getting programmed\n")); + printk(KERN_ERR "%s: %s timed out while waiting for " + "registers getting programmed\n", + dev->name, __FUNCTION__); return -ETIMEDOUT; } - if (nobusyloop) - msleep(1); + msleep(1); } /* wait for transfer to complete */ - start = jiffies; + timeout = jiffies + usecs_to_jiffies(us2); while (1) { - err = time_after(jiffies, start + HZ/4); + err = time_after(jiffies, timeout); if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) break; saa7146_read(dev, MC2); if (err) { - DEB_S(("timed out while waiting for transfer completion\n")); + DEB_S(("%s: %s timed out while waiting for transfer " + "completion\n", dev->name, __FUNCTION__)); return -ETIMEDOUT; } - if (nobusyloop) - msleep(1); + msleep(1); } return 0; } +static inline int saa7146_wait_for_debi_done_busyloop(struct saa7146_dev *dev, + unsigned long us1, unsigned long us2) +{ + unsigned long loops; + + /* wait for registers to be programmed */ + loops = us1; + while (1) { + if (saa7146_read(dev, MC2) & 2) + break; + if (!loops--) { + printk(KERN_ERR "%s: %s timed out while waiting for " + "registers getting programmed\n", + dev->name, __FUNCTION__); + return -ETIMEDOUT; + } + udelay(1); + } + + /* wait for transfer to complete */ + loops = us2 / 5; + while (1) { + if (!(saa7146_read(dev, PSR) & SPCI_DEBI_S)) + break; + saa7146_read(dev, MC2); + if (!loops--) { + DEB_S(("%s: %s timed out while waiting for transfer " + "completion\n", dev->name, __FUNCTION__)); + return -ETIMEDOUT; + } + udelay(5); + } + + return 0; +} + +int saa7146_wait_for_debi_done(struct saa7146_dev *dev, int nobusyloop) +{ + if (nobusyloop) + return saa7146_wait_for_debi_done_sleep(dev, 50000, 250000); + else + return saa7146_wait_for_debi_done_busyloop(dev, 50000, 250000); +} + /**************************************************************************** * general helper functions ****************************************************************************/ -/* this is videobuf_vmalloc_to_sg() from video-buf.c +/* this is videobuf_vmalloc_to_sg() from videobuf-dma-sg.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) @@ -112,13 +158,13 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL); if (NULL == sglist) return NULL; + sg_init_table(sglist, nr_pages); for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) { pg = vmalloc_to_page(virt); if (NULL == pg) goto err; BUG_ON(PageHighMem(pg)); - sglist[i].page = pg; - sglist[i].length = PAGE_SIZE; + sg_set_page(&sglist[i], pg, PAGE_SIZE, 0); } return sglist; @@ -130,34 +176,51 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages) /********************************************************************************/ /* common page table functions */ -char *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) +void *saa7146_vmalloc_build_pgtable(struct pci_dev *pci, long length, struct saa7146_pgtable *pt) { int pages = (length+PAGE_SIZE-1)/PAGE_SIZE; - char *mem = vmalloc_32(length); + void *mem = vmalloc_32(length); int slen = 0; - if (NULL == mem) { - return NULL; - } + if (NULL == mem) + goto err_null; - if (!(pt->slist = vmalloc_to_sg(mem, pages))) { - vfree(mem); - return NULL; - } + if (!(pt->slist = vmalloc_to_sg(mem, pages))) + goto err_free_mem; - if (saa7146_pgtable_alloc(pci, pt)) { - kfree(pt->slist); - pt->slist = NULL; - vfree(mem); - return NULL; - } + if (saa7146_pgtable_alloc(pci, pt)) + goto err_free_slist; - slen = pci_map_sg(pci,pt->slist,pages,PCI_DMA_FROMDEVICE); - if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) { - return NULL; - } + pt->nents = pages; + slen = pci_map_sg(pci,pt->slist,pt->nents,PCI_DMA_FROMDEVICE); + if (0 == slen) + goto err_free_pgtable; + + if (0 != saa7146_pgtable_build_single(pci, pt, pt->slist, slen)) + goto err_unmap_sg; return mem; + +err_unmap_sg: + pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); +err_free_pgtable: + saa7146_pgtable_free(pci, pt); +err_free_slist: + kfree(pt->slist); + pt->slist = NULL; +err_free_mem: + vfree(mem); +err_null: + return NULL; +} + +void saa7146_vfree_destroy_pgtable(struct pci_dev *pci, void *mem, struct saa7146_pgtable *pt) +{ + pci_unmap_sg(pci, pt->slist, pt->nents, PCI_DMA_FROMDEVICE); + saa7146_pgtable_free(pci, pt); + kfree(pt->slist); + pt->slist = NULL; + vfree(mem); } void saa7146_pgtable_free(struct pci_dev *pci, struct saa7146_pgtable *pt) @@ -166,8 +229,6 @@ 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; - kfree(pt->slist); - pt->slist = NULL; } int saa7146_pgtable_alloc(struct pci_dev *pci, struct saa7146_pgtable *pt) @@ -233,10 +294,11 @@ int saa7146_pgtable_build_single(struct pci_dev *pci, struct saa7146_pgtable *pt static irqreturn_t interrupt_hw(int irq, void *dev_id) { struct saa7146_dev *dev = dev_id; - u32 isr = 0; + u32 isr; + u32 ack_isr; /* read out the interrupt status register */ - isr = saa7146_read(dev, ISR); + ack_isr = isr = saa7146_read(dev, ISR); /* is this our interrupt? */ if ( 0 == isr ) { @@ -244,45 +306,35 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) return IRQ_NONE; } - saa7146_write(dev, ISR, isr); - - if( 0 != (dev->ext)) { - if( 0 != (dev->ext->irq_mask & isr )) { - if( 0 != dev->ext->irq_func ) { + 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( 0 != dev->vv_data && 0 != dev->vv_callback) { + if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); - } isr &= ~MASK_27; } if (0 != (isr & (MASK_28))) { - if( 0 != dev->vv_data && 0 != dev->vv_callback) { + if (dev->vv_data && dev->vv_callback) dev->vv_callback(dev,isr); - } isr &= ~MASK_28; } if (0 != (isr & (MASK_16|MASK_17))) { - u32 status = saa7146_read(dev, I2C_STATUS); - if( (0x3 == (status & 0x3)) || (0 == (status & 0x1)) ) { - 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; - u32 ssr = (saa7146_read(dev, SSR) >> 17) & 0x1f; - DEB_I2C(("irq: i2c, status: 0x%08x, psr:0x%02x, ssr:0x%02x).\n",status,psr,ssr)); - dev->i2c_op = 0; - wake_up(&dev->i2c_wq); - } else { - DEB_I2C(("unexpected irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); - } + 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 { - DEB_I2C(("unhandled irq: i2c, status: 0x%08x, isr %#x\n",status, isr)); + 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); } @@ -291,6 +343,7 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id) ERR(("disabling interrupt source(s)!\n")); SAA7146_IER_DISABLE(dev,isr); } + saa7146_write(dev, ISR, ack_isr); return IRQ_HANDLED; } @@ -332,7 +385,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent } dev->revision &= 0xf; - /* remap the memory from virtual to physical adress */ + /* remap the memory from virtual to physical address */ err = pci_request_region(pci, 0, "saa7146"); if (err < 0) @@ -528,11 +581,11 @@ 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_transfer); EXPORT_SYMBOL_GPL(saa7146_i2c_adapter_prepare); EXPORT_SYMBOL_GPL(saa7146_debug);