X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fmedia%2Fvideo%2Fsaa7134%2Fsaa7134-core.c;h=f0c2111f14ad1f11c5bbe0575edd6aedd23420bd;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=cf87dda32711a7eeaff6486170ab4bd0c477bb82;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c index cf87dda32..f0c2111f1 100644 --- a/drivers/media/video/saa7134/saa7134-core.c +++ b/drivers/media/video/saa7134/saa7134-core.c @@ -1,4 +1,5 @@ /* + * * device driver for philips saa7134 based TV cards * driver core * @@ -19,14 +20,19 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include +#include #include #include #include #include #include +#include +#include +#include #include "saa7134-reg.h" #include "saa7134.h" @@ -35,139 +41,67 @@ MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards"); MODULE_AUTHOR("Gerd Knorr [SuSE Labs]"); MODULE_LICENSE("GPL"); -#define SAA7134_MAXBOARDS 8 - /* ------------------------------------------------------------------ */ static unsigned int irq_debug = 0; -MODULE_PARM(irq_debug,"i"); +module_param(irq_debug, int, 0644); MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]"); static unsigned int core_debug = 0; -MODULE_PARM(core_debug,"i"); +module_param(core_debug, int, 0644); MODULE_PARM_DESC(core_debug,"enable debug messages [core]"); static unsigned int gpio_tracking = 0; -MODULE_PARM(gpio_tracking,"i"); +module_param(gpio_tracking, int, 0644); MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]"); -static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(video_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(video_nr,"video device number"); - -static unsigned int ts_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(ts_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(ts_nr,"ts device number"); +static unsigned int alsa = 0; +module_param(alsa, int, 0644); +MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]"); -static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(vbi_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(vbi_nr,"vbi device number"); +static unsigned int oss = 0; +module_param(oss, int, 0644); +MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]"); -static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(radio_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(radio_nr,"radio device number"); +static unsigned int latency = UNSET; +module_param(latency, int, 0444); +MODULE_PARM_DESC(latency,"pci latency timer"); -static unsigned int oss = 0; -MODULE_PARM(oss,"i"); -MODULE_PARM_DESC(oss,"register oss devices (default: no)"); +int saa7134_no_overlay=-1; +module_param_named(no_overlay, saa7134_no_overlay, int, 0444); +MODULE_PARM_DESC(no_overlay,"allow override overlay default (0 disables, 1 enables)" + " [some VIA/SIS chipsets are known to have problem with overlay]"); -static unsigned int dsp_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(dsp_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(dsp_nr,"oss dsp device number"); +static unsigned int video_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +static unsigned int vbi_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +static unsigned int radio_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; +static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -static unsigned int mixer_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(mixer_nr,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(mixer_nr,"oss mixer device number"); -static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(tuner,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(tuner,"tuner type"); +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); -static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; -MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i"); -MODULE_PARM_DESC(card,"card type"); +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"); -static unsigned int latency = UNSET; -MODULE_PARM(latency,"i"); -MODULE_PARM_DESC(latency,"pci latency timer"); +static DEFINE_MUTEX(devlist_lock); +LIST_HEAD(saa7134_devlist); +static LIST_HEAD(mops_list); +static unsigned int saa7134_devcount; -struct list_head saa7134_devlist; -unsigned int saa7134_devcount; +int (*dmasound_init)(struct saa7134_dev *dev); +int (*dmasound_exit)(struct saa7134_dev *dev); #define dprintk(fmt, arg...) if (core_debug) \ printk(KERN_DEBUG "%s/core: " fmt, dev->name , ## arg) -/* ------------------------------------------------------------------ */ -/* debug help functions */ - -static const char *v4l1_ioctls[] = { - "0", "GCAP", "GCHAN", "SCHAN", "GTUNER", "STUNER", "GPICT", "SPICT", - "CCAPTURE", "GWIN", "SWIN", "GFBUF", "SFBUF", "KEY", "GFREQ", - "SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT", - "GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", - "SMICROCODE", "GVBIFMT", "SVBIFMT" }; -#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls) - -static const char *v4l2_ioctls[] = { - "QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT", - "G_COMP", "S_COMP", "REQBUFS", "QUERYBUF", "G_FBUF", "S_FBUF", - "G_WIN", "S_WIN", "PREVIEW", "QBUF", "16", "DQBUF", "STREAMON", - "STREAMOFF", "G_PERF", "G_PARM", "S_PARM", "G_STD", "S_STD", - "ENUMSTD", "ENUMINPUT", "G_CTRL", "S_CTRL", "G_TUNER", "S_TUNER", - "G_FREQ", "S_FREQ", "G_AUDIO", "S_AUDIO", "35", "QUERYCTRL", - "QUERYMENU", "G_INPUT", "S_INPUT", "ENUMCVT", "41", "42", "43", - "44", "45", "G_OUTPUT", "S_OUTPUT", "ENUMOUTPUT", "G_AUDOUT", - "S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR", - "S_MODULATOR" -}; -#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -static const char *osspcm_ioctls[] = { - "RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT", - "CHANNELS", "?", "POST", "SUBDIVIDE", "SETFRAGMENT", "GETFMTS", - "GETOSPACE", "GETISPACE", "NONBLOCK", "GETCAPS", "GET/SETTRIGGER", - "GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO", - "SETDUPLEX", "GETODELAY" -}; -#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls) - -void saa7134_print_ioctl(char *name, unsigned int cmd) -{ - char *dir; - - switch (_IOC_DIR(cmd)) { - case _IOC_NONE: dir = "--"; break; - case _IOC_READ: dir = "r-"; break; - case _IOC_WRITE: dir = "-w"; break; - case _IOC_READ | _IOC_WRITE: dir = "rw"; break; - default: dir = "??"; break; - } - switch (_IOC_TYPE(cmd)) { - case 'v': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l1, %s, VIDIOC%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L1_IOCTLS) ? - v4l1_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'V': - printk(KERN_DEBUG "%s: ioctl 0x%08x (v4l2, %s, VIDIOC_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < V4L2_IOCTLS) ? - v4l2_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'P': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss dsp, %s, SNDCTL_DSP_%s)\n", - name, cmd, dir, (_IOC_NR(cmd) < OSSPCM_IOCTLS) ? - osspcm_ioctls[_IOC_NR(cmd)] : "???"); - break; - case 'M': - printk(KERN_DEBUG "%s: ioctl 0x%08x (oss mixer, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - break; - default: - printk(KERN_DEBUG "%s: ioctl 0x%08x (???, %s, #%d)\n", - name, cmd, dir, _IOC_NR(cmd)); - } -} - void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) { unsigned long mode,status; @@ -186,51 +120,66 @@ void saa7134_track_gpio(struct saa7134_dev *dev, char *msg) /* ------------------------------------------------------------------ */ -#if 0 -static char *dec1_bits[8] = { - "DCSTD0", "DCSCT1", "WIPA", "GLIMB", - "GLIMT", "SLTCA", "HLCK" -}; -static char *dec2_bits[8] = { - "RDCAP", "COPRO", "COLSTR", "TYPE3", - NULL, "FIDT", "HLVLN", "INTL" -}; -static char *scale1_bits[8] = { - "VID_A", "VBI_A", NULL, NULL, "VID_B", "VBI_B" -}; -static char *scale2_bits[8] = { - "TRERR", "CFERR", "LDERR", "WASRST", - "FIDSCI", "FIDSCO", "D6^D5", "TASK" -}; -static void dump_statusreg(struct saa7134_dev *dev, int reg, - char *regname, char **bits) -{ - int value,i; +/* ----------------------------------------------------------- */ +/* delayed request_module */ - value = saa_readb(reg); - printk(KERN_DEBUG "%s: %s:", dev->name, regname); - for (i = 7; i >= 0; i--) { - if (NULL == bits[i]) - continue; - printk(" %s=%d", bits[i], (value & (1 << i)) ? 1 : 0); - } - printk("\n"); +#if defined(CONFIG_MODULES) && defined(MODULE) +static int need_empress; +static int need_dvb; +static int need_alsa; +static int need_oss; + +static int pending_call(struct notifier_block *self, unsigned long state, + void *module) +{ + if (module != THIS_MODULE || state != MODULE_STATE_LIVE) + return NOTIFY_DONE; + + if (need_empress) + request_module("saa7134-empress"); + if (need_dvb) + request_module("saa7134-dvb"); + if (need_alsa) + request_module("saa7134-alsa"); + if (need_oss) + request_module("saa7134-oss"); + return NOTIFY_DONE; } -static void dump_statusregs(struct saa7134_dev *dev) +static int pending_registered; +static struct notifier_block pending_notifier = { + .notifier_call = pending_call, +}; + +static void request_module_depend(char *name, int *flag) { - dump_statusreg(dev,SAA7134_STATUS_VIDEO1,"dec1",dec1_bits); - dump_statusreg(dev,SAA7134_STATUS_VIDEO2,"dec2",dec2_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS0,"scale0",scale1_bits); - dump_statusreg(dev,SAA7134_SCALER_STATUS1,"scale1",scale2_bits); + int err; + switch (THIS_MODULE->state) { + case MODULE_STATE_COMING: + if (!pending_registered) { + err = register_module_notifier(&pending_notifier); + pending_registered = 1; + } + *flag = 1; + break; + case MODULE_STATE_LIVE: + request_module(name); + break; + default: + /* nothing */; + break; + } } -#endif + +#else +#define request_module_depend(name,flag) +#endif /* CONFIG_MODULES */ /* ------------------------------------------------------------------ */ /* nr of (saa7134-)pages for the given buffer size */ -int saa7134_buffer_pages(int size) +static int saa7134_buffer_pages(int size) { size = PAGE_ALIGN(size); size += PAGE_SIZE; /* for non-page-aligned buffers */ @@ -243,7 +192,7 @@ int saa7134_buffer_pages(int size) int saa7134_buffer_count(unsigned int size, unsigned int count) { unsigned int maxcount; - + maxcount = 1024 / saa7134_buffer_pages(size); if (count > maxcount) count = maxcount; @@ -268,9 +217,9 @@ unsigned long saa7134_buffer_base(struct saa7134_buf *buf) int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt) { - u32 *cpu; - dma_addr_t dma_addr; - + __le32 *cpu; + dma_addr_t dma_addr; + cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); if (NULL == cpu) return -ENOMEM; @@ -284,7 +233,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, struct scatterlist *list, unsigned int length, unsigned int startpage) { - u32 *ptr; + __le32 *ptr; unsigned int i,p; BUG_ON(NULL == pt || NULL == pt->cpu); @@ -292,7 +241,7 @@ int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, ptr = pt->cpu + startpage; for (i = 0; i < length; i++, list++) for (p = 0; p * 4096 < list->length; p++, ptr++) - *ptr = sg_dma_address(list) - list->offset; + *ptr = cpu_to_le32(sg_dma_address(list) - list->offset); return 0; } @@ -306,13 +255,12 @@ void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt) /* ------------------------------------------------------------------ */ -void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf) +void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf) { - if (in_interrupt()) - BUG(); + BUG_ON(in_interrupt()); videobuf_waiton(&buf->vb,0,0); - videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); + videobuf_dma_unmap(q, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); buf->vb.state = STATE_NEEDS_INIT; } @@ -324,10 +272,8 @@ int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_buf *buf) { struct saa7134_buf *next = NULL; -#ifdef DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif - + + assert_spin_locked(&dev->slock); dprintk("buffer_queue %p\n",buf); if (NULL == q->curr) { if (!q->need_two) { @@ -353,11 +299,9 @@ void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, unsigned int state) { -#ifdef DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif + assert_spin_locked(&dev->slock); dprintk("buffer_finish %p\n",q->curr); - + /* finish current buffer */ q->curr->vb.state = state; do_gettimeofday(&q->curr->vb.ts); @@ -370,9 +314,7 @@ void saa7134_buffer_next(struct saa7134_dev *dev, { struct saa7134_buf *buf,*next = NULL; -#ifdef DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif + assert_spin_locked(&dev->slock); BUG_ON(NULL != q->curr); if (!list_empty(&q->queue)) { @@ -427,9 +369,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) enum v4l2_field cap = V4L2_FIELD_ANY; enum v4l2_field ov = V4L2_FIELD_ANY; -#ifdef DEBUG_SPINLOCKS - BUG_ON(!spin_is_locked(&dev->slock)); -#endif + assert_spin_locked(&dev->slock); /* video capture -- dma 0 + video task A */ if (dev->video_q.curr) { @@ -437,7 +377,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) ctrl |= SAA7134_MAIN_CTRL_TE0; irq |= SAA7134_IRQ1_INTE_RA0_1 | SAA7134_IRQ1_INTE_RA0_0; - cap = dev->video_q.curr->vb.field; + cap = dev->video_q.curr->vb.field; } /* video capture -- dma 1+2 (planar modes) */ @@ -466,7 +406,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) } /* audio capture -- dma 3 */ - if (dev->oss.dma_running) { + if (dev->dmasound.dma_running) { ctrl |= SAA7134_MAIN_CTRL_TE6; irq |= SAA7134_IRQ1_INTE_RA3_1 | SAA7134_IRQ1_INTE_RA3_0; @@ -480,7 +420,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) SAA7134_IRQ1_INTE_RA2_1 | SAA7134_IRQ1_INTE_RA2_0; } - + /* set task conditions + field handling */ if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) { /* default config -- use full frames */ @@ -504,7 +444,7 @@ int saa7134_set_dmabits(struct saa7134_dev *dev) saa_writeb(SAA7134_FIELD_HANDLING(TASK_B), 0x01); split = 1; } - + /* irqs */ saa_writeb(SAA7134_REGION_ENABLE, task); saa_writel(SAA7134_IRQ1, irq); @@ -538,7 +478,7 @@ static void print_irqstatus(struct saa7134_dev *dev, int loop, unsigned long report, unsigned long status) { unsigned int i; - + printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx", dev->name,loop,jiffies,report,status); for (i = 0; i < IRQBITS; i++) { @@ -571,17 +511,26 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) dev->name); goto out; } + + /* If dmasound support is active and we get a sound report, exit + and let the saa7134-alsa/oss module deal with it */ + + if ((report & SAA7134_IRQ_REPORT_DONE_RA3) && + (dev->dmasound.priv_data != NULL) ) + { + if (irq_debug > 1) + printk(KERN_DEBUG "%s/irq: ignoring interrupt for DMA sound\n", + dev->name); + goto out; + } + handled = 1; saa_writel(SAA7134_IRQ_REPORT,report); if (irq_debug) print_irqstatus(dev,loop,report,status); -#if 0 - if (report & SAA7134_IRQ_REPORT_CONF_ERR) - dump_statusregs(dev); -#endif - if (report & SAA7134_IRQ_REPORT_INTL) + if (report & SAA7134_IRQ_REPORT_RDCAP /* _INTL */) saa7134_irq_video_intl(dev); if ((report & SAA7134_IRQ_REPORT_DONE_RA0) && @@ -593,18 +542,47 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) saa7134_irq_vbi_done(dev,status); if ((report & SAA7134_IRQ_REPORT_DONE_RA2) && - card_has_ts(dev)) + card_has_mpeg(dev)) saa7134_irq_ts_done(dev,status); - if ((report & SAA7134_IRQ_REPORT_DONE_RA3)) - saa7134_irq_oss_done(dev,status); + if (report & SAA7134_IRQ_REPORT_GPIO16) { + switch (dev->has_remote) { + case SAA7134_REMOTE_GPIO: + if (!dev->remote) + break; + if (dev->remote->mask_keydown & 0x10000) { + saa7134_input_irq(dev); + } + break; + + case SAA7134_REMOTE_I2C: + break; /* FIXME: invoke I2C get_key() */ + + default: /* GPIO16 not used by IR remote */ + break; + } + } - if ((report & (SAA7134_IRQ_REPORT_GPIO16 | - SAA7134_IRQ_REPORT_GPIO18)) && - dev->remote) - saa7134_input_irq(dev); + if (report & SAA7134_IRQ_REPORT_GPIO18) { + switch (dev->has_remote) { + case SAA7134_REMOTE_GPIO: + if (!dev->remote) + break; + if ((dev->remote->mask_keydown & 0x40000) || + (dev->remote->mask_keyup & 0x40000)) { + saa7134_input_irq(dev); + } + break; + + case SAA7134_REMOTE_I2C: + break; /* FIXME: invoke I2C get_key() */ + + default: /* GPIO18 not used by IR remote */ + break; + } + } + } - }; if (10 == loop) { print_irqstatus(dev,loop,report,status); if (report & SAA7134_IRQ_REPORT_PE) { @@ -612,6 +590,16 @@ static irqreturn_t saa7134_irq(int irq, void *dev_id, struct pt_regs *regs) printk(KERN_WARNING "%s/irq: looping -- " "clearing PE (parity error!) enable bit\n",dev->name); saa_clearl(SAA7134_IRQ2,SAA7134_IRQ2_INTE_PE); + } else if (report & SAA7134_IRQ_REPORT_GPIO16) { + /* disable gpio16 IRQ */ + printk(KERN_WARNING "%s/irq: looping -- " + "clearing GPIO16 enable bit\n",dev->name); + saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO16); + } else if (report & SAA7134_IRQ_REPORT_GPIO18) { + /* disable gpio18 IRQs */ + printk(KERN_WARNING "%s/irq: looping -- " + "clearing GPIO18 enable bit\n",dev->name); + saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18); } else { /* disable all irqs */ printk(KERN_WARNING "%s/irq: looping -- " @@ -634,28 +622,20 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) saa_writel(SAA7134_IRQ1, 0); saa_writel(SAA7134_IRQ2, 0); - init_MUTEX(&dev->lock); - dev->slock = SPIN_LOCK_UNLOCKED; + mutex_init(&dev->lock); + spin_lock_init(&dev->slock); saa7134_track_gpio(dev,"pre-init"); saa7134_video_init1(dev); saa7134_vbi_init1(dev); - if (card_has_ts(dev)) + if (card_has_mpeg(dev)) saa7134_ts_init1(dev); saa7134_input_init1(dev); - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa7134_oss_init1(dev); - break; - } - /* RAM FIFO config */ saa_writel(SAA7134_FIFO_SIZE, 0x08070503); saa_writel(SAA7134_THRESHOULD,0x02020202); - + /* enable audio + video processing */ saa_writel(SAA7134_MAIN_CTRL, SAA7134_MAIN_CTRL_VPLLE | @@ -664,42 +644,53 @@ static int saa7134_hwinit1(struct saa7134_dev *dev) SAA7134_MAIN_CTRL_EVFE1 | SAA7134_MAIN_CTRL_EVFE2 | SAA7134_MAIN_CTRL_ESFE | - SAA7134_MAIN_CTRL_EBADC | SAA7134_MAIN_CTRL_EBDAC); + /* + * Initialize OSS _after_ enabling audio clock PLL and audio processing. + * OSS initialization writes to registers via the audio DSP; these + * writes will fail unless the audio clock has been started. At worst, + * audio will not work. + */ + /* enable peripheral devices */ saa_writeb(SAA7134_SPECIAL_MODE, 0x01); /* set vertical line numbering start (vbi needs this) */ saa_writeb(SAA7134_SOURCE_TIMING2, 0x20); - + return 0; } /* late init (with i2c + irq) */ static int saa7134_hwinit2(struct saa7134_dev *dev) { + unsigned int irq2_mask; dprintk("hwinit2\n"); saa7134_video_init2(dev); saa7134_tvaudio_init2(dev); /* enable IRQ's */ + irq2_mask = + SAA7134_IRQ2_INTE_DEC3 | + SAA7134_IRQ2_INTE_DEC2 | + SAA7134_IRQ2_INTE_DEC1 | + SAA7134_IRQ2_INTE_DEC0 | + SAA7134_IRQ2_INTE_PE | + SAA7134_IRQ2_INTE_AR; + + if (dev->has_remote == SAA7134_REMOTE_GPIO && dev->remote) { + if (dev->remote->mask_keydown & 0x10000) + irq2_mask |= SAA7134_IRQ2_INTE_GPIO16; + else if (dev->remote->mask_keydown & 0x40000) + irq2_mask |= SAA7134_IRQ2_INTE_GPIO18; + else if (dev->remote->mask_keyup & 0x40000) + irq2_mask |= SAA7134_IRQ2_INTE_GPIO18A; + } + saa_writel(SAA7134_IRQ1, 0); - saa_writel(SAA7134_IRQ2, - SAA7134_IRQ2_INTE_GPIO18 | - SAA7134_IRQ2_INTE_GPIO18A | - SAA7134_IRQ2_INTE_GPIO16 | - SAA7134_IRQ2_INTE_SC2 | - SAA7134_IRQ2_INTE_SC1 | - SAA7134_IRQ2_INTE_SC0 | - /* SAA7134_IRQ2_INTE_DEC5 | FIXME: TRIG_ERR ??? */ - SAA7134_IRQ2_INTE_DEC3 | - SAA7134_IRQ2_INTE_DEC2 | - /* SAA7134_IRQ2_INTE_DEC1 | */ - SAA7134_IRQ2_INTE_DEC0 | - SAA7134_IRQ2_INTE_PE | - SAA7134_IRQ2_INTE_AR); + saa_writel(SAA7134_IRQ2, irq2_mask); return 0; } @@ -709,14 +700,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev) { dprintk("hwfini\n"); - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - saa7134_oss_fini(dev); - break; - } - if (card_has_ts(dev)) + if (card_has_mpeg(dev)) saa7134_ts_fini(dev); saa7134_input_fini(dev); saa7134_vbi_fini(dev); @@ -757,7 +741,7 @@ static struct video_device *vdev_init(struct saa7134_dev *dev, char *type) { struct video_device *vfd; - + vfd = video_device_alloc(); if (NULL == vfd) return NULL; @@ -779,13 +763,6 @@ static void saa7134_unregister_video(struct saa7134_dev *dev) video_device_release(dev->video_dev); dev->video_dev = NULL; } - if (dev->ts_dev) { - if (-1 != dev->ts_dev->minor) - video_unregister_device(dev->ts_dev); - else - video_device_release(dev->ts_dev); - dev->ts_dev = NULL; - } if (dev->vbi_dev) { if (-1 != dev->vbi_dev->minor) video_unregister_device(dev->vbi_dev); @@ -802,16 +779,43 @@ static void saa7134_unregister_video(struct saa7134_dev *dev) } } +static void mpeg_ops_attach(struct saa7134_mpeg_ops *ops, + struct saa7134_dev *dev) +{ + int err; + + if (NULL != dev->mops) + return; + if (saa7134_boards[dev->board].mpeg != ops->type) + return; + err = ops->init(dev); + if (0 != err) + return; + dev->mops = ops; +} + +static void mpeg_ops_detach(struct saa7134_mpeg_ops *ops, + struct saa7134_dev *dev) +{ + if (NULL == dev->mops) + return; + if (dev->mops != ops) + return; + dev->mops->fini(dev); + dev->mops = NULL; +} + static int __devinit saa7134_initdev(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct saa7134_dev *dev; + struct list_head *item; + struct saa7134_mpeg_ops *mops; int err; - dev = kmalloc(sizeof(*dev),GFP_KERNEL); + dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) return -ENOMEM; - memset(dev,0,sizeof(*dev)); /* pci init */ dev->pci = pci_dev; @@ -819,7 +823,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, err = -EIO; goto fail1; } - sprintf(dev->name,"saa%x[%d]",pci_dev->device,saa7134_devcount); + + dev->nr = saa7134_devcount; + sprintf(dev->name,"saa%x[%d]",pci_dev->device,dev->nr); /* pci quirks */ if (pci_pci_problems) { @@ -838,6 +844,22 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, latency = 0x0A; } #endif + if (pci_pci_problems & PCIPCI_FAIL) { + printk(KERN_INFO "%s: quirk: this driver and your " + "chipset may not work together" + " in overlay mode.\n",dev->name); + if (!saa7134_no_overlay) { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be disabled.\n", + dev->name); + saa7134_no_overlay = 1; + } else { + printk(KERN_INFO "%s: quirk: overlay " + "mode will be forced. Use this" + " option at your own risk.\n", + dev->name); + } + } } if (UNSET != latency) { printk(KERN_INFO "%s: setting pci latency timer to %d\n", @@ -847,13 +869,13 @@ static int __devinit saa7134_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, " + 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%lx\n", dev->name, pci_name(pci_dev), dev->pci_rev, pci_dev->irq, dev->pci_lat,pci_resource_start(pci_dev,0)); pci_set_master(pci_dev); - if (!pci_dma_supported(pci_dev,0xffffffff)) { + if (!pci_dma_supported(pci_dev, DMA_32BIT_MASK)) { printk("%s: Oops: no 32bit PCI DMA ???\n",dev->name); err = -EIO; goto fail1; @@ -861,20 +883,21 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, /* board config */ dev->board = pci_id->driver_data; - if (card[saa7134_devcount] >= 0 && - card[saa7134_devcount] < saa7134_bcount) - dev->board = card[saa7134_devcount]; + if (card[dev->nr] >= 0 && + card[dev->nr] < saa7134_bcount) + dev->board = card[dev->nr]; if (SAA7134_BOARD_NOAUTO == dev->board) { must_configure_manually(); dev->board = SAA7134_BOARD_UNKNOWN; } - dev->tuner_type = saa7134_boards[dev->board].tuner_type; - if (UNSET != tuner[saa7134_devcount]) - dev->tuner_type = tuner[saa7134_devcount]; - printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n", + dev->tuner_type = saa7134_boards[dev->board].tuner_type; + dev->tda9887_conf = saa7134_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,saa7134_boards[dev->board].name, - dev->board, card[saa7134_devcount] == dev->board ? + dev->board, card[dev->nr] == dev->board ? "insmod option" : "autodetected"); /* get mmio */ @@ -887,7 +910,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, goto fail1; } dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000); - dev->bmmio = (__u8*)dev->lmmio; + dev->bmmio = (__u8 __iomem *)dev->lmmio; if (NULL == dev->lmmio) { err = -EIO; printk(KERN_ERR "%s: can't ioremap() MMIO memory\n", @@ -896,7 +919,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* initialize hardware #1 */ - saa7134_board_init(dev); + saa7134_board_init1(dev); saa7134_hwinit1(dev); /* get irq */ @@ -909,29 +932,44 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, } /* wait a bit, register i2c bus */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); saa7134_i2c_register(dev); /* initialize hardware #2 */ + saa7134_board_init2(dev); saa7134_hwinit2(dev); /* load i2c helpers */ if (TUNER_ABSENT != dev->tuner_type) request_module("tuner"); - if (saa7134_boards[dev->board].need_tda9887) + if (dev->tda9887_conf) request_module("tda9887"); - if (card_has_ts(dev)) + if (card_is_empress(dev)) { request_module("saa6752hs"); + request_module_depend("saa7134-empress",&need_empress); + } + + if (card_is_dvb(dev)) + request_module_depend("saa7134-dvb",&need_dvb); + + + if (alsa) + request_module_depend("saa7134-alsa",&need_alsa); + + if (oss) + request_module_depend("saa7134-oss",&need_oss); -#ifdef VIDIOC_G_PRIORITY v4l2_prio_init(&dev->prio); -#endif /* register v4l devices */ + if (saa7134_no_overlay <= 0) { + saa7134_video_template.type |= VID_TYPE_OVERLAY; + } else { + printk("%s: Overlay support disabled.\n",dev->name); + } dev->video_dev = vdev_init(dev,&saa7134_video_template,"video"); err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, - video_nr[saa7134_devcount]); + video_nr[dev->nr]); if (err < 0) { printk(KERN_INFO "%s: can't register video device\n", dev->name); @@ -940,22 +978,9 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, printk(KERN_INFO "%s: registered device video%d [v4l2]\n", dev->name,dev->video_dev->minor & 0x1f); - if (card_has_ts(dev)) { - dev->ts_dev = vdev_init(dev,&saa7134_ts_template,"ts"); - err = video_register_device(dev->ts_dev,VFL_TYPE_GRABBER, - ts_nr[saa7134_devcount]); - if (err < 0) { - printk(KERN_INFO "%s: can't register video device\n", - dev->name); - goto fail4; - } - printk(KERN_INFO "%s: registered device video%d [ts]\n", - dev->name,dev->ts_dev->minor & 0x1f); - } - dev->vbi_dev = vdev_init(dev,&saa7134_vbi_template,"vbi"); err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI, - vbi_nr[saa7134_devcount]); + vbi_nr[dev->nr]); if (err < 0) goto fail4; printk(KERN_INFO "%s: registered device vbi%d\n", @@ -964,54 +989,34 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, if (card_has_radio(dev)) { dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio"); err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, - radio_nr[saa7134_devcount]); + radio_nr[dev->nr]); if (err < 0) goto fail4; printk(KERN_INFO "%s: registered device radio%d\n", dev->name,dev->radio_dev->minor & 0x1f); } - /* register oss devices */ - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (oss) { - err = dev->oss.minor_dsp = - register_sound_dsp(&saa7134_dsp_fops, - dsp_nr[saa7134_devcount]); - if (err < 0) { - goto fail4; - } - printk(KERN_INFO "%s: registered device dsp%d\n", - dev->name,dev->oss.minor_dsp >> 4); - - err = dev->oss.minor_mixer = - register_sound_mixer(&saa7134_mixer_fops, - mixer_nr[saa7134_devcount]); - if (err < 0) - goto fail5; - printk(KERN_INFO "%s: registered device mixer%d\n", - dev->name,dev->oss.minor_mixer >> 4); - } - break; - } - /* everything worked */ - list_add_tail(&dev->devlist,&saa7134_devlist); pci_set_drvdata(pci_dev,dev); saa7134_devcount++; - return 0; - fail5: - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (oss) - unregister_sound_dsp(dev->oss.minor_dsp); - break; + mutex_lock(&devlist_lock); + list_for_each(item,&mops_list) { + mops = list_entry(item, struct saa7134_mpeg_ops, next); + mpeg_ops_attach(mops, dev); + } + list_add_tail(&dev->devlist,&saa7134_devlist); + mutex_unlock(&devlist_lock); + + /* check for signal */ + saa7134_irq_video_intl(dev); + + if (dmasound_init && !dev->dmasound.priv_data) { + dmasound_init(dev); } + + return 0; + fail4: saa7134_unregister_video(dev); saa7134_i2c_unregister(dev); @@ -1029,7 +1034,14 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev, static void __devexit saa7134_finidev(struct pci_dev *pci_dev) { - struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct saa7134_dev *dev = pci_get_drvdata(pci_dev); + struct list_head *item; + struct saa7134_mpeg_ops *mops; + + /* Release DMA sound modules if present */ + if (dmasound_exit && dev->dmasound.priv_data) { + dmasound_exit(dev); + } /* debugging ... */ if (irq_debug) { @@ -1050,41 +1062,80 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev) saa7134_hwfini(dev); /* unregister */ - saa7134_i2c_unregister(dev); - switch (dev->pci->device) { - case PCI_DEVICE_ID_PHILIPS_SAA7134: - case PCI_DEVICE_ID_PHILIPS_SAA7133: - case PCI_DEVICE_ID_PHILIPS_SAA7135: - if (oss) { - unregister_sound_mixer(dev->oss.minor_mixer); - unregister_sound_dsp(dev->oss.minor_dsp); - } - break; + mutex_lock(&devlist_lock); + list_del(&dev->devlist); + list_for_each(item,&mops_list) { + mops = list_entry(item, struct saa7134_mpeg_ops, next); + mpeg_ops_detach(mops, dev); } + mutex_unlock(&devlist_lock); + saa7134_devcount--; + + saa7134_i2c_unregister(dev); saa7134_unregister_video(dev); - /* release ressources */ + + /* 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; + } + + + /* 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)); -#if 0 /* causes some trouble when reinserting the driver ... */ - pci_disable_device(pci_dev); -#endif pci_set_drvdata(pci_dev, NULL); /* free memory */ - list_del(&dev->devlist); - saa7134_devcount--; kfree(dev); } +/* ----------------------------------------------------------- */ + +int saa7134_ts_register(struct saa7134_mpeg_ops *ops) +{ + struct list_head *item; + struct saa7134_dev *dev; + + mutex_lock(&devlist_lock); + list_for_each(item,&saa7134_devlist) { + dev = list_entry(item, struct saa7134_dev, devlist); + mpeg_ops_attach(ops, dev); + } + list_add_tail(&ops->next,&mops_list); + mutex_unlock(&devlist_lock); + return 0; +} + +void saa7134_ts_unregister(struct saa7134_mpeg_ops *ops) +{ + struct list_head *item; + struct saa7134_dev *dev; + + mutex_lock(&devlist_lock); + list_del(&ops->next); + list_for_each(item,&saa7134_devlist) { + dev = list_entry(item, struct saa7134_dev, devlist); + mpeg_ops_detach(ops, dev); + } + mutex_unlock(&devlist_lock); +} + +EXPORT_SYMBOL(saa7134_ts_register); +EXPORT_SYMBOL(saa7134_ts_unregister); + +/* ----------------------------------------------------------- */ + static struct pci_driver saa7134_pci_driver = { - .name = "saa7134", - .id_table = saa7134_pci_tbl, - .probe = saa7134_initdev, - .remove = saa7134_finidev, + .name = "saa7134", + .id_table = saa7134_pci_tbl, + .probe = saa7134_initdev, + .remove = __devexit_p(saa7134_finidev), }; static int saa7134_init(void) @@ -1098,17 +1149,36 @@ static int saa7134_init(void) printk(KERN_INFO "saa7130/34: snapshot date %04d-%02d-%02d\n", SNAPSHOT/10000, (SNAPSHOT/100)%100, SNAPSHOT%100); #endif - return pci_module_init(&saa7134_pci_driver); + return pci_register_driver(&saa7134_pci_driver); } static void saa7134_fini(void) { +#if defined(CONFIG_MODULES) && defined(MODULE) + if (pending_registered) + unregister_module_notifier(&pending_notifier); +#endif /* CONFIG_MODULES */ pci_unregister_driver(&saa7134_pci_driver); } module_init(saa7134_init); module_exit(saa7134_fini); +/* ----------------------------------------------------------- */ + +EXPORT_SYMBOL(saa7134_i2c_call_clients); +EXPORT_SYMBOL(saa7134_devlist); +EXPORT_SYMBOL(saa7134_boards); + +/* ----------------- for the DMA sound modules --------------- */ + +EXPORT_SYMBOL(dmasound_init); +EXPORT_SYMBOL(dmasound_exit); +EXPORT_SYMBOL(saa7134_pgtable_free); +EXPORT_SYMBOL(saa7134_pgtable_build); +EXPORT_SYMBOL(saa7134_pgtable_alloc); +EXPORT_SYMBOL(saa7134_set_dmabits); + /* ----------------------------------------------------------- */ /* * Local variables: