diff options
Diffstat (limited to 'drivers/media/pci/tw68/tw68-core.c')
-rw-r--r-- | drivers/media/pci/tw68/tw68-core.c | 801 |
1 files changed, 72 insertions, 729 deletions
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c index 2c5d7a5f3f8e..baf93af1d764 100644 --- a/drivers/media/pci/tw68/tw68-core.c +++ b/drivers/media/pci/tw68/tw68-core.c @@ -9,7 +9,11 @@ * acknowledged. Full credit goes to them - any problems within this code * are mine. * - * Copyright (C) 2009 William M. Brack <wbrack@mmm.com.hk> + * Copyright (C) 2009 William M. Brack + * + * Refactored and updated to the latest v4l core frameworks: + * + * Copyright (C) 2014 Hans Verkuil <hverkuil@xs4all.nl> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,10 +24,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <linux/init.h> @@ -44,320 +44,44 @@ #include "tw68-reg.h" MODULE_DESCRIPTION("v4l2 driver module for tw6800 based video capture cards"); -MODULE_AUTHOR("William M. Brack <wbrack@mmm.com.hk>"); +MODULE_AUTHOR("William M. Brack"); +MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>"); MODULE_LICENSE("GPL"); -static unsigned int core_debug; -module_param(core_debug, int, 0644); -MODULE_PARM_DESC(core_debug, "enable debug messages [core]"); - -static unsigned int gpio_tracking; -module_param(gpio_tracking, int, 0644); -MODULE_PARM_DESC(gpio_tracking, "enable debug messages [gpio]"); - -static unsigned int alsa = 1; -module_param(alsa, int, 0644); -MODULE_PARM_DESC(alsa, "enable/disable ALSA DMA sound [dmasound]"); - static unsigned int latency = UNSET; module_param(latency, int, 0444); MODULE_PARM_DESC(latency, "pci latency timer"); -static unsigned int nocomb; -module_param(nocomb, int, 0644); -MODULE_PARM_DESC(nocomb, "disable comb filter"); - static unsigned int video_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int vbi_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int radio_nr[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int tuner[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; -static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; - module_param_array(video_nr, int, NULL, 0444); -module_param_array(vbi_nr, int, NULL, 0444); -module_param_array(radio_nr, int, NULL, 0444); -module_param_array(tuner, int, NULL, 0444); -module_param_array(card, int, NULL, 0444); - MODULE_PARM_DESC(video_nr, "video device number"); -MODULE_PARM_DESC(vbi_nr, "vbi device number"); -MODULE_PARM_DESC(radio_nr, "radio device number"); -MODULE_PARM_DESC(tuner, "tuner type"); -MODULE_PARM_DESC(card, "card type"); - -LIST_HEAD(tw68_devlist); -EXPORT_SYMBOL(tw68_devlist); -DEFINE_MUTEX(tw68_devlist_lock); -EXPORT_SYMBOL(tw68_devlist_lock); -static LIST_HEAD(mops_list); -static unsigned int tw68_devcount; /* curr tot num of devices present */ -int (*tw68_dmasound_init)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_init); -int (*tw68_dmasound_exit)(struct tw68_dev *dev); -EXPORT_SYMBOL(tw68_dmasound_exit); +static unsigned int card[] = {[0 ... (TW68_MAXBOARDS - 1)] = UNSET }; +module_param_array(card, int, NULL, 0444); +MODULE_PARM_DESC(card, "card type"); -#define dprintk(level, fmt, arg...) if (core_debug & (level)) \ - printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg) +static atomic_t tw68_instance = ATOMIC_INIT(0); /* ------------------------------------------------------------------ */ -void tw68_dma_free(struct videobuf_queue *q, struct tw68_buf *buf) -{ - struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb); - - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - BUG_ON(in_interrupt()); - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,36) - videobuf_waiton(&buf->vb, 0, 0); -#else - videobuf_waiton(q, &buf->vb, 0, 0); -#endif -#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,35) - videobuf_dma_unmap(q, dma); -#else - videobuf_dma_unmap(q->dev, dma); -#endif - videobuf_dma_free(dma); - /* if no risc area allocated, btcx_riscmem_free just returns */ - btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc); - buf->vb.state = VIDEOBUF_NEEDS_INIT; -} - -/* ------------------------------------------------------------------ */ -/* ------------- placeholders for later development ----------------- */ - -static int tw68_input_init1(struct tw68_dev *dev) -{ - return 0; -} - -static void tw68_input_fini(struct tw68_dev *dev) -{ - return; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -static void tw68_ir_start(struct tw68_dev *dev, struct card_ir *ir) -{ - return; -} - -static void tw68_ir_stop(struct tw68_dev *dev) -{ - return; -} -#endif - -/* ------------------------------------------------------------------ */ /* - * Buffer handling routines - * - * These routines are "generic", i.e. are intended to be used by more - * than one module, e.g. the video and the transport stream modules. - * To accomplish this generality, callbacks are used whenever some - * module-specific test or action is required. + * Please add any new PCI IDs to: http://pci-ids.ucw.cz. This keeps + * the PCI ID database up to date. Note that the entries must be + * added under vendor 0x1797 (Techwell Inc.) as subsystem IDs. */ - -/* resends a current buffer in queue after resume */ -int tw68_buffer_requeue(struct tw68_dev *dev, - struct tw68_dmaqueue *q) -{ - struct tw68_buf *buf, *prev; - - dprintk(DBG_FLOW | DBG_TESTING, "%s: called\n", __func__); - if (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - dprintk(DBG_BUFF, "%s: [%p/%d] restart dma\n", __func__, - buf, buf->vb.i); - q->start_dma(dev, q, buf); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); - return 0; - } - - prev = NULL; - for (;;) { - if (list_empty(&q->queued)) - return 0; - buf = list_entry(q->queued.next, struct tw68_buf, vb.queue); - /* if nothing precedes this one */ - if (NULL == prev) { - list_move_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); - buf->activate(dev, buf, NULL); - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - - } else if (q->buf_compat(prev, buf) && - (prev->fmt == buf->fmt)) { - list_move_tail(&buf->vb.queue, &q->active); - buf->activate(dev, buf, NULL); - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - dprintk(DBG_BUFF, "%s: [%p/%d] move to active\n", - __func__, buf, buf->vb.i); - } else { - dprintk(DBG_BUFF, "%s: no action taken\n", __func__); - return 0; - } - prev = buf; - } -} - -/* nr of (tw68-)pages for the given buffer size */ -static int tw68_buffer_pages(int size) -{ - size = PAGE_ALIGN(size); - size += PAGE_SIZE; /* for non-page-aligned buffers */ - size /= 4096; - return size; -} - -/* calc max # of buffers from size (must not exceed the 4MB virtual - * address space per DMA channel) */ -int tw68_buffer_count(unsigned int size, unsigned int count) -{ - unsigned int maxcount; - - maxcount = 1024 / tw68_buffer_pages(size); - if (count > maxcount) - count = maxcount; - return count; -} - -/* - * tw68_wakeup - * - * Called when the driver completes filling a buffer, and tasks waiting - * for the data need to be awakened. - */ -void tw68_wakeup(struct tw68_dmaqueue *q, unsigned int *fc) -{ - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (list_empty(&q->active)) { - dprintk(DBG_BUFF | DBG_TESTING, "%s: active list empty", - __func__); - del_timer(&q->timeout); - return; - } - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - do_gettimeofday(&buf->vb.ts); - buf->vb.field_count = (*fc)++; - dprintk(DBG_BUFF | DBG_TESTING, "%s: [%p/%d] field_count=%d\n", - __func__, buf, buf->vb.i, *fc); - buf->vb.state = VIDEOBUF_DONE; - list_del(&buf->vb.queue); - wake_up(&buf->vb.done); - mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT); -} - -/* - * tw68_buffer_queue - * - * Add specified buffer to specified queue - */ -void tw68_buffer_queue(struct tw68_dev *dev, - struct tw68_dmaqueue *q, - struct tw68_buf *buf) -{ - struct tw68_buf *prev; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - assert_spin_locked(&dev->slock); - dprintk(DBG_BUFF, "%s: queuing buffer %p\n", __func__, buf); - - /* append a 'JUMP to stopper' to the buffer risc program */ - buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_INT_BIT); - buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma); - - /* if this buffer is not "compatible" (in dimensions and format) - * with the currently active chain of buffers, we must change - * settings before filling it; if a previous buffer has already - * been determined to require changes, this buffer must follow - * it. To do this, we maintain a "queued" chain. If that - * chain exists, append this buffer to it */ - if (!list_empty(&q->queued)) { - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] appended to queued\n", - __func__, buf, buf->vb.i); - - /* else if the 'active' chain doesn't yet exist we create it now */ - } else if (list_empty(&q->active)) { - dprintk(DBG_BUFF, "%s: [%p/%d] first active\n", - __func__, buf, buf->vb.i); - list_add_tail(&buf->vb.queue, &q->active); - q->start_dma(dev, q, buf); /* 1st one - start dma */ - /* TODO - why have we removed buf->count and q->count? */ - buf->activate(dev, buf, NULL); - - /* else we would like to put this buffer on the tail of the - * active chain, provided it is "compatible". */ - } else { - /* "compatibility" depends upon the type of buffer */ - prev = list_entry(q->active.prev, struct tw68_buf, vb.queue); - if (q->buf_compat(prev, buf)) { - /* If "compatible", append to active chain */ - prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma); - /* the param 'prev' is only for debug printing */ - buf->activate(dev, buf, prev); - list_add_tail(&buf->vb.queue, &q->active); - dprintk(DBG_BUFF, "%s: [%p/%d] appended to active\n", - __func__, buf, buf->vb.i); - } else { - /* If "incompatible", append to queued chain */ - list_add_tail(&buf->vb.queue, &q->queued); - buf->vb.state = VIDEOBUF_QUEUED; - dprintk(DBG_BUFF, "%s: [%p/%d] incompatible - appended " - "to queued\n", __func__, buf, buf->vb.i); - } - } -} - -/* - * tw68_buffer_timeout - * - * This routine is set as the video_q.timeout.function - * - * Log the event, try to reset the h/w. - * Flag the current buffer as failed, try to start again with next buff - */ -void tw68_buffer_timeout(unsigned long data) -{ - struct tw68_dmaqueue *q = (struct tw68_dmaqueue *)data; - struct tw68_dev *dev = q->dev; - struct tw68_buf *buf; - unsigned long flags; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - spin_lock_irqsave(&dev->slock, flags); - - /* flag all current active buffers as failed */ - while (!list_empty(&q->active)) { - buf = list_entry(q->active.next, struct tw68_buf, vb.queue); - list_del(&buf->vb.queue); - buf->vb.state = VIDEOBUF_ERROR; - wake_up(&buf->vb.done); - printk(KERN_INFO "%s/0: [%p/%d] timeout - dma=0x%08lx\n", - dev->name, buf, buf->vb.i, - (unsigned long)buf->risc.dma); - } - tw68_buffer_requeue(dev, q); - spin_unlock_irqrestore(&dev->slock, flags); -} +struct pci_device_id tw68_pci_tbl[] = { + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6800)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6801)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6804)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_1)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_2)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_3)}, + {PCI_DEVICE(PCI_VENDOR_ID_TECHWELL, PCI_DEVICE_ID_6816_4)}, + {0,} +}; /* ------------------------------------------------------------------ */ -/* early init (no i2c, no irq) */ -/* Called from tw68_hw_init1 and tw68_resume */ -static int tw68_hw_enable1(struct tw68_dev *dev) -{ - return 0; -} /* * The device is given a "soft reset". According to the specifications, @@ -367,7 +91,6 @@ static int tw68_hw_enable1(struct tw68_dev *dev) */ static int tw68_hw_init1(struct tw68_dev *dev) { - dprintk(DBG_FLOW, "%s: called\n", __func__); /* Assure all interrupts are disabled */ tw_writel(TW68_INTMASK, 0); /* 020 */ /* Clear any pending interrupts */ @@ -415,7 +138,7 @@ static int tw68_hw_init1(struct tw68_dev *dev) tw_writeb(TW68_AGCGAIN, 0xf0); /* 288 AGC gain when loop disabled */ tw_writeb(TW68_PEAKWT, 0xd8); /* 28C White peak threshold */ tw_writeb(TW68_CLMPL, 0x3c); /* 290 Y channel clamp level */ -// tw_writeb(TW68_SYNCT, 0x38); /* 294 Sync amplitude */ +/* tw_writeb(TW68_SYNCT, 0x38);*/ /* 294 Sync amplitude */ tw_writeb(TW68_SYNCT, 0x30); /* 294 Sync amplitude */ tw_writeb(TW68_MISSCNT, 0x44); /* 298 Horiz sync, VCR detect sens */ tw_writeb(TW68_PCLAMP, 0x28); /* 29C Clamp pos from PLL sync */ @@ -465,80 +188,9 @@ static int tw68_hw_init1(struct tw68_dev *dev) /* Initialize any subsystems */ tw68_video_init1(dev); - tw68_vbi_init1(dev); - if (card_has_mpeg(dev)) - tw68_ts_init1(dev); - tw68_input_init1(dev); - - /* Do any other h/w early initialisation at this point */ - tw68_hw_enable1(dev); - - return 0; -} - -/* late init (with i2c + irq) */ -static int tw68_hw_enable2(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_I2C_INTS; -#endif - tw_setl(TW68_INTMASK, dev->pci_irqmask); return 0; } -static int tw68_hw_init2(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - tw68_video_init2(dev); /* initialise video function first */ - tw68_tvaudio_init2(dev);/* audio next */ - - /* all other board-related things, incl. enabling interrupts */ - tw68_hw_enable2(dev); - return 0; -} - -/* shutdown */ -static int tw68_hwfini(struct tw68_dev *dev) -{ - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (card_has_mpeg(dev)) - tw68_ts_fini(dev); - tw68_input_fini(dev); - tw68_vbi_fini(dev); - tw68_tvaudio_fini(dev); - return 0; -} - -static void __devinit must_configure_manually(void) -{ - unsigned int i, p; - - printk(KERN_WARNING - "tw68: <rant>\n" - "tw68: Congratulations! Your TV card vendor saved a few\n" - "tw68: cents for a eeprom, thus your pci board has no\n" - "tw68: subsystem ID and I can't identify it automatically\n" - "tw68: </rant>\n" - "tw68: I feel better now. Ok, here is the good news:\n" - "tw68: You can use the card=<nr> insmod option to specify\n" - "tw68: which board you have. The list:\n"); - for (i = 0; i < tw68_bcount; i++) { - printk(KERN_WARNING "tw68: card=%d -> %-40.40s", - i, tw68_boards[i].name); - for (p = 0; tw68_pci_tbl[p].driver_data; p++) { - if (tw68_pci_tbl[p].driver_data != i) - continue; - printk(" %04x:%04x", - tw68_pci_tbl[p].subvendor, - tw68_pci_tbl[p].subdevice); - } - printk("\n"); - } -} - - static irqreturn_t tw68_irq(int irq, void *dev_id) { struct tw68_dev *dev = dev_id; @@ -548,126 +200,39 @@ static irqreturn_t tw68_irq(int irq, void *dev_id) status = orig = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; /* Check if anything to do */ if (0 == status) - return IRQ_RETVAL(0); /* Nope - return */ + return IRQ_NONE; /* Nope - return */ for (loop = 0; loop < 10; loop++) { if (status & dev->board_virqmask) /* video interrupt */ tw68_irq_video_done(dev, status); -#ifdef TW68_TESTING - if (status & TW68_I2C_INTS) - tw68_irq_i2c(dev, status); -#endif status = tw_readl(TW68_INTSTAT) & dev->pci_irqmask; if (0 == status) - goto out; + return IRQ_HANDLED; } - dprintk(DBG_UNEXPECTED, "%s: **** INTERRUPT NOT HANDLED - clearing mask" - " (orig 0x%08x, cur 0x%08x)", - dev->name, orig, tw_readl(TW68_INTSTAT)); - dprintk(DBG_UNEXPECTED, "%s: pci_irqmask 0x%08x; board_virqmask " - "0x%08x ****\n", dev->name, - dev->pci_irqmask, dev->board_virqmask); + dev_dbg(&dev->pci->dev, "%s: **** INTERRUPT NOT HANDLED - clearing mask (orig 0x%08x, cur 0x%08x)", + dev->name, orig, tw_readl(TW68_INTSTAT)); + dev_dbg(&dev->pci->dev, "%s: pci_irqmask 0x%08x; board_virqmask 0x%08x ****\n", + dev->name, dev->pci_irqmask, dev->board_virqmask); tw_clearl(TW68_INTMASK, dev->pci_irqmask); -out: - return IRQ_RETVAL(1); -} - -int tw68_set_dmabits(struct tw68_dev *dev) -{ - return 0; -} - -static struct video_device *vdev_init(struct tw68_dev *dev, - struct video_device *template, - char *type) -{ - struct video_device *vfd; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - vfd = video_device_alloc(); - if (NULL == vfd) - return NULL; - *vfd = *template; - vfd->minor = -1; - vfd->parent = &dev->pci->dev; - vfd->release = video_device_release; - /* vfd->debug = tw_video_debug; */ - snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", - dev->name, type, tw68_boards[dev->board].name); - return vfd; + return IRQ_HANDLED; } -static void tw68_unregister_video(struct tw68_dev *dev) -{ - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (dev->video_dev) { - if (-1 != dev->video_dev->minor) - video_unregister_device(dev->video_dev); - else - video_device_release(dev->video_dev); - dev->video_dev = NULL; - } - if (dev->vbi_dev) { - if (-1 != dev->vbi_dev->minor) - video_unregister_device(dev->vbi_dev); - else - video_device_release(dev->vbi_dev); - dev->vbi_dev = NULL; - } - if (dev->radio_dev) { - if (-1 != dev->radio_dev->minor) - video_unregister_device(dev->radio_dev); - else - video_device_release(dev->radio_dev); - dev->radio_dev = NULL; - } -} - -static void mpeg_ops_attach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - int err; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - if (NULL != dev->mops) - return; - if (tw68_boards[dev->board].mpeg != ops->type) - return; - err = ops->init(dev); - if (0 != err) - return; - dev->mops = ops; -} - -static void mpeg_ops_detach(struct tw68_mpeg_ops *ops, - struct tw68_dev *dev) -{ - - if (NULL == dev->mops) - return; - if (dev->mops != ops) - return; - dev->mops->fini(dev); - dev->mops = NULL; -} - -static int __devinit tw68_initdev(struct pci_dev *pci_dev, +static int tw68_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct tw68_dev *dev; - struct tw68_mpeg_ops *mops; + int vidnr = -1; int err; - if (tw68_devcount == TW68_MAXBOARDS) - return -ENOMEM; - - dev = kzalloc(sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(&pci_dev->dev, sizeof(*dev), GFP_KERNEL); if (NULL == dev) return -ENOMEM; + dev->instance = v4l2_device_set_name(&dev->v4l2_dev, "tw68", + &tw68_instance); + err = v4l2_device_register(&pci_dev->dev, &dev->v4l2_dev); if (err) - goto fail0; + return err; /* pci init */ dev->pci = pci_dev; @@ -676,33 +241,10 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, goto fail1; } - dev->nr = tw68_devcount; - sprintf(dev->name, "tw%x[%d]", pci_dev->device, dev->nr); + dev->name = dev->v4l2_dev.name; - /* pci quirks */ - if (pci_pci_problems) { - if (pci_pci_problems & PCIPCI_TRITON) - printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", - dev->name); - if (pci_pci_problems & PCIPCI_NATOMA) - printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", - dev->name); - if (pci_pci_problems & PCIPCI_VIAETBF) - printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", - dev->name); - if (pci_pci_problems & PCIPCI_VSFX) - printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n", - dev->name); -#ifdef PCIPCI_ALIMAGIK - if (pci_pci_problems & PCIPCI_ALIMAGIK) { - printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK " - "-- latency fixup\n", dev->name); - latency = 0x0A; - } -#endif - } if (UNSET != latency) { - printk(KERN_INFO "%s: setting pci latency timer to %d\n", + pr_info("%s: setting pci latency timer to %d\n", dev->name, latency); pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency); } @@ -710,13 +252,12 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, /* print pci info */ pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev); pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &dev->pci_lat); - printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, " - "latency: %d, mmio: 0x%llx\n", dev->name, - pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat, - (unsigned long long)pci_resource_start(pci_dev, 0)); + pr_info("%s: found at %s, rev: %d, irq: %d, latency: %d, mmio: 0x%llx\n", + dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, + dev->pci_lat, (u64)pci_resource_start(pci_dev, 0)); pci_set_master(pci_dev); if (!pci_dma_supported(pci_dev, DMA_BIT_MASK(32))) { - printk("%s: Oops: no 32bit PCI DMA ???\n", dev->name); + pr_info("%s: Oops: no 32bit PCI DMA ???\n", dev->name); err = -EIO; goto fail1; } @@ -730,7 +271,7 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->vdecoder = TW6801; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; - case PCI_DEVICE_ID_6804: /* Video decoder for TW6805 */ + case PCI_DEVICE_ID_6804: /* Video decoder for TW6804 */ dev->vdecoder = TW6804; dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; @@ -739,35 +280,13 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->board_virqmask = TW68_VID_INTS | TW68_VID_INTSX; break; } - /* board config */ - dev->board = pci_id->driver_data; - if (card[dev->nr] >= 0 && - card[dev->nr] < tw68_bcount) - dev->board = card[dev->nr]; - if (TW68_BOARD_NOAUTO == dev->board) { - must_configure_manually(); - dev->board = TW68_BOARD_UNKNOWN; - } - dev->autodetected = card[dev->nr] != dev->board; - dev->tuner_type = tw68_boards[dev->board].tuner_type; - dev->tuner_addr = tw68_boards[dev->board].tuner_addr; - dev->radio_type = tw68_boards[dev->board].radio_type; - dev->radio_addr = tw68_boards[dev->board].radio_addr; - dev->tda9887_conf = tw68_boards[dev->board].tda9887_conf; - if (UNSET != tuner[dev->nr]) - dev->tuner_type = tuner[dev->nr]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", - dev->name, pci_dev->subsystem_vendor, - pci_dev->subsystem_device, tw68_boards[dev->board].name, - dev->board, dev->autodetected ? - "autodetected" : "insmod option"); /* get mmio */ if (!request_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0), dev->name)) { err = -EBUSY; - printk(KERN_ERR "%s: can't get MMIO memory @ 0x%llx\n", + pr_err("%s: can't get MMIO memory @ 0x%llx\n", dev->name, (unsigned long long)pci_resource_start(pci_dev, 0)); goto fail1; @@ -777,185 +296,75 @@ static int __devinit tw68_initdev(struct pci_dev *pci_dev, dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; - printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", + pr_err("%s: can't ioremap() MMIO memory\n", dev->name); goto fail2; } /* initialize hardware #1 */ - /* First, take care of anything unique to a particular card */ - tw68_board_init1(dev); /* Then do any initialisation wanted before interrupts are on */ tw68_hw_init1(dev); /* get irq */ - err = request_irq(pci_dev->irq, tw68_irq, + err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq, IRQF_SHARED | IRQF_DISABLED, dev->name, dev); if (err < 0) { - printk(KERN_ERR "%s: can't get IRQ %d\n", + pr_err("%s: can't get IRQ %d\n", dev->name, pci_dev->irq); goto fail3; } -#ifdef TW68_TESTING - dev->pci_irqmask |= TW68_SBDONE; - tw_setl(TW68_INTMASK, dev->pci_irqmask); - printk(KERN_INFO "Calling tw68_i2c_register\n"); - /* Register the i2c bus */ - tw68_i2c_register(dev); -#endif - /* * Now do remainder of initialisation, first for * things unique for this card, then for general board */ - tw68_board_init2(dev); - - tw68_hw_init2(dev); - -#if 0 - /* load i2c helpers */ - if (card_is_empress(dev)) { - struct v4l2_subdev *sd = - v4l2_i2c_new_subdev(&dev->i2c_adap, "saa6752hs", - "saa6752hs", 0x20); - - if (sd) - sd->grp_id = GRP_EMPRESS; - } - - request_submodules(dev); -#endif - - v4l2_prio_init(&dev->prio); - - mutex_lock(&tw68_devlist_lock); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_attach(mops, dev); - list_add_tail(&dev->devlist, &tw68_devlist); - mutex_unlock(&tw68_devlist_lock); - - /* check for signal */ - tw68_irq_video_signalchange(dev); - -#if 0 - if (TUNER_ABSENT != dev->tuner_type) - tw_call_all(dev, core, s_standby, 0); -#endif - - dev->video_dev = vdev_init(dev, &tw68_video_template, "video"); - err = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, - video_nr[dev->nr]); + if (dev->instance < TW68_MAXBOARDS) + vidnr = video_nr[dev->instance]; + /* initialise video function first */ + err = tw68_video_init2(dev, vidnr); if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", + pr_err("%s: can't register video device\n", dev->name); goto fail4; } - printk(KERN_INFO "%s: registered device video%d [v4l2]\n", - dev->name, dev->video_dev->num); - - dev->vbi_dev = vdev_init(dev, &tw68_video_template, "vbi"); - - err = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, - vbi_nr[dev->nr]); - if (err < 0) { - printk(KERN_INFO "%s: can't register vbi device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device vbi%d\n", - dev->name, dev->vbi_dev->num); - - if (card_has_radio(dev)) { - dev->radio_dev = vdev_init(dev, &tw68_radio_template, - "radio"); - err = video_register_device(dev->radio_dev, VFL_TYPE_RADIO, - radio_nr[dev->nr]); - if (err < 0) { - /* TODO - need to unregister vbi? */ - printk(KERN_INFO "%s: can't register radio device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device radio%d\n", - dev->name, dev->radio_dev->num); - } - - /* everything worked */ - tw68_devcount++; + tw_setl(TW68_INTMASK, dev->pci_irqmask); - if (tw68_dmasound_init && !dev->dmasound.priv_data) - tw68_dmasound_init(dev); + pr_info("%s: registered device %s\n", + dev->name, video_device_node_name(&dev->vdev)); return 0; - fail4: - tw68_unregister_video(dev); -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - free_irq(pci_dev->irq, dev); - fail3: - tw68_hwfini(dev); +fail4: + video_unregister_device(&dev->vdev); +fail3: iounmap(dev->lmmio); - fail2: +fail2: release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); - fail1: +fail1: v4l2_device_unregister(&dev->v4l2_dev); - fail0: - kfree(dev); return err; } -static void __devexit tw68_finidev(struct pci_dev *pci_dev) +static void tw68_finidev(struct pci_dev *pci_dev) { struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - struct tw68_mpeg_ops *mops; - - dprintk(DBG_FLOW, "%s: called\n", __func__); - /* Release DMA sound modules if present */ - if (tw68_dmasound_exit && dev->dmasound.priv_data) - tw68_dmasound_exit(dev); /* shutdown subsystems */ - tw68_hwfini(dev); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); tw_writel(TW68_INTMASK, 0); /* unregister */ - mutex_lock(&tw68_devlist_lock); - list_del(&dev->devlist); - list_for_each_entry(mops, &mops_list, next) - mpeg_ops_detach(mops, dev); - mutex_unlock(&tw68_devlist_lock); - tw68_devcount--; - -#ifdef TW68_TESTING - tw68_i2c_unregister(dev); -#endif - tw68_unregister_video(dev); - - - /* the DMA sound modules should be unloaded before reaching - this, but just in case they are still present... */ - if (dev->dmasound.priv_data != NULL) { - free_irq(pci_dev->irq, &dev->dmasound); - dev->dmasound.priv_data = NULL; - } - + video_unregister_device(&dev->vdev); + v4l2_ctrl_handler_free(&dev->hdl); /* release resources */ - free_irq(pci_dev->irq, dev); iounmap(dev->lmmio); release_mem_region(pci_resource_start(pci_dev, 0), pci_resource_len(pci_dev, 0)); v4l2_device_unregister(&dev->v4l2_dev); - - /* free memory */ - kfree(dev); } #ifdef CONFIG_PM @@ -966,28 +375,15 @@ static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); - dprintk(DBG_FLOW, "%s: called\n", __func__); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask &= ~TW68_VID_INTS; tw_writel(TW68_INTMASK, 0); - dev->insuspend = 1; synchronize_irq(pci_dev->irq); - /* Disable timeout timers - if we have active buffers, we will - fill them on resume*/ - - del_timer(&dev->video_q.timeout); - del_timer(&dev->vbi_q.timeout); - del_timer(&dev->ts_q.timeout); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_stop(dev); -#endif - pci_save_state(pci_dev); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); + vb2_discard_done(&dev->vidq); return 0; } @@ -997,54 +393,25 @@ static int tw68_resume(struct pci_dev *pci_dev) struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); + struct tw68_buf *buf; unsigned long flags; - dprintk(DBG_FLOW, "%s: called\n", __func__); pci_set_power_state(pci_dev, PCI_D0); pci_restore_state(pci_dev); /* Do things that are done in tw68_initdev , except of initializing memory structures.*/ - tw68_board_init1(dev); - - /* tw68_hw_init1 */ - if (tw68_boards[dev->board].video_out) - tw68_videoport_init(dev); - if (card_has_mpeg(dev)) - tw68_ts_init_hw(dev); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) - if (dev->remote) - tw68_ir_start(dev, dev->remote); -#endif - tw68_hw_enable1(dev); - msleep(100); - tw68_board_init2(dev); - - /*tw68_hw_init2*/ tw68_set_tvnorm_hw(dev); - tw68_tvaudio_setmute(dev); -/* tw68_tvaudio_setvolume(dev, dev->ctl_volume); */ - tw68_tvaudio_init(dev); - tw68_irq_video_signalchange(dev); /*resume unfinished buffer(s)*/ spin_lock_irqsave(&dev->slock, flags); - tw68_buffer_requeue(dev, &dev->video_q); - tw68_buffer_requeue(dev, &dev->vbi_q); - tw68_buffer_requeue(dev, &dev->ts_q); - - /* FIXME: Disable DMA audio sound - temporary till proper support - is implemented*/ + buf = container_of(dev->active.next, struct tw68_buf, list); - dev->dmasound.dma_running = 0; + tw68_video_start_dma(dev, buf); - /* start DMA now*/ - dev->insuspend = 0; - smp_wmb(); - tw68_set_dmabits(dev); spin_unlock_irqrestore(&dev->slock, flags); return 0; @@ -1057,35 +424,11 @@ static struct pci_driver tw68_pci_driver = { .name = "tw68", .id_table = tw68_pci_tbl, .probe = tw68_initdev, - .remove = __devexit_p(tw68_finidev), + .remove = tw68_finidev, #ifdef CONFIG_PM .suspend = tw68_suspend, .resume = tw68_resume #endif }; -static int tw68_init(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - INIT_LIST_HEAD(&tw68_devlist); - printk(KERN_INFO "tw68: v4l2 driver version %d.%d.%d loaded\n", - (TW68_VERSION_CODE >> 16) & 0xff, - (TW68_VERSION_CODE >> 8) & 0xff, - TW68_VERSION_CODE & 0xff); -#if 0 - printk(KERN_INFO "tw68: snapshot date %04d-%02d-%02d\n", - SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); -#endif - return pci_register_driver(&tw68_pci_driver); -} - -static void module_cleanup(void) -{ - if (core_debug & DBG_FLOW) - printk(KERN_DEBUG "%s: called\n", __func__); - pci_unregister_driver(&tw68_pci_driver); -} - -module_init(tw68_init); -module_exit(module_cleanup); +module_pci_driver(tw68_pci_driver); |