📄 saa7134-core.c
字号:
/* * device driver for philips saa7134 based TV cards * driver core * * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs] * * 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 * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * 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., 675 Mass Ave, Cambridge, MA 02139, USA. */#include <linux/init.h>#include <linux/list.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/kmod.h>#include <linux/sound.h>#include <linux/interrupt.h>#include "saa7134-reg.h"#include "saa7134.h"MODULE_DESCRIPTION("v4l2 driver module for saa7130/34 based TV cards");MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");MODULE_LICENSE("GPL");#define SAA7134_MAXBOARDS 8/* ------------------------------------------------------------------ */static unsigned int irq_debug = 0;MODULE_PARM(irq_debug,"i");MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");static unsigned int core_debug = 0;MODULE_PARM(core_debug,"i");MODULE_PARM_DESC(core_debug,"enable debug messages [core]");static unsigned int gpio_tracking = 0;MODULE_PARM(gpio_tracking,"i");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 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 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 oss = 0;MODULE_PARM(oss,"i");MODULE_PARM_DESC(oss,"register oss devices (default: no)");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 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");static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i");MODULE_PARM_DESC(card,"card type");static unsigned int latency = UNSET;MODULE_PARM(latency,"i");MODULE_PARM_DESC(latency,"pci latency timer");struct list_head saa7134_devlist;unsigned int saa7134_devcount;#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; if (!gpio_tracking) return; /* rising SAA7134_GPIO_GPRESCAN reads the status */ saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,0); saa_andorb(SAA7134_GPIO_GPMODE3,SAA7134_GPIO_GPRESCAN,SAA7134_GPIO_GPRESCAN); mode = saa_readl(SAA7134_GPIO_GPMODE0 >> 2) & 0xfffffff; status = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & 0xfffffff; printk(KERN_DEBUG "%s: gpio: mode=0x%07lx in=0x%07lx out=0x%07lx [%s]\n", dev->name, mode, (~mode) & status, mode & status, msg);}/* ------------------------------------------------------------------ */#if 0static 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; 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");}static void dump_statusregs(struct saa7134_dev *dev){ 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);}#endif/* ------------------------------------------------------------------ *//* nr of (saa7134-)pages for the given buffer size */int saa7134_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 saa7134_buffer_count(unsigned int size, unsigned int count){ unsigned int maxcount; maxcount = 1024 / saa7134_buffer_pages(size); if (count > maxcount) count = maxcount; return count;}int saa7134_buffer_startpage(struct saa7134_buf *buf){ return saa7134_buffer_pages(buf->vb.bsize) * buf->vb.i;}unsigned long saa7134_buffer_base(struct saa7134_buf *buf){ unsigned long base; base = saa7134_buffer_startpage(buf) * 4096; base += buf->vb.dma.sglist[0].offset; return base;}/* ------------------------------------------------------------------ */int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt){ u32 *cpu; dma_addr_t dma_addr; cpu = pci_alloc_consistent(pci, SAA7134_PGTABLE_SIZE, &dma_addr); if (NULL == cpu) return -ENOMEM; pt->size = SAA7134_PGTABLE_SIZE; pt->cpu = cpu; pt->dma = dma_addr; return 0;}int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt, struct scatterlist *list, unsigned int length, unsigned int startpage){ u32 *ptr; unsigned int i,p; BUG_ON(NULL == pt || NULL == pt->cpu); 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; return 0;}void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt){ if (NULL == pt->cpu) return; pci_free_consistent(pci, pt->size, pt->cpu, pt->dma); pt->cpu = NULL;}/* ------------------------------------------------------------------ */void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf){ if (in_interrupt()) BUG(); videobuf_waiton(&buf->vb,0,0); videobuf_dma_pci_unmap(dev->pci, &buf->vb.dma); videobuf_dma_free(&buf->vb.dma); buf->vb.state = STATE_NEEDS_INIT;}/* ------------------------------------------------------------------ */int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, struct saa7134_buf *buf){ struct saa7134_buf *next = NULL;#if DEBUG_SPINLOCKS BUG_ON(!spin_is_locked(&dev->slock));#endif dprintk("buffer_queue %p\n",buf); if (NULL == q->curr) { if (!q->need_two) { q->curr = buf; buf->activate(dev,buf,NULL); } else if (list_empty(&q->queue)) { list_add_tail(&buf->vb.queue,&q->queue); buf->vb.state = STATE_QUEUED; } else { next = list_entry(q->queue.next,struct saa7134_buf, vb.queue); q->curr = buf; buf->activate(dev,buf,next); } } else { list_add_tail(&buf->vb.queue,&q->queue); buf->vb.state = STATE_QUEUED; } return 0;}void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q, unsigned int state){#if DEBUG_SPINLOCKS BUG_ON(!spin_is_locked(&dev->slock));#endif dprintk("buffer_finish %p\n",q->curr); /* finish current buffer */ q->curr->vb.state = state; do_gettimeofday(&q->curr->vb.ts); wake_up(&q->curr->vb.done); q->curr = NULL;}void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q){ struct saa7134_buf *buf,*next = NULL;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -