📄 cx88-video.c
字号:
cx8800_vbi_fmt(dev, f); return 0; default: return -EINVAL; }}/* * This function is _not_ called directly, but from * video_generic_ioctl (and maybe others). userspace * copying is done already, arg is a kernel pointer. */static int video_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev;#if 0 unsigned long flags;#endif int err; if (video_debug > 1) cx88_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE |#if 0 V4L2_CAP_VIDEO_OVERLAY |#endif 0; if (UNSET != dev->tuner_type) cap->capabilities |= V4L2_CAP_TUNER; return 0; } /* ---------- tv norms ---------- */ case VIDIOC_ENUMSTD: { struct v4l2_standard *e = arg; unsigned int i; i = e->index; if (i >= ARRAY_SIZE(tvnorms)) return -EINVAL; err = v4l2_video_std_construct(e, tvnorms[e->index].id, tvnorms[e->index].name); e->index = i; if (err < 0) return err; return 0; } case VIDIOC_G_STD: { v4l2_std_id *id = arg; *id = dev->tvnorm->id; return 0; } case VIDIOC_S_STD: { v4l2_std_id *id = arg; unsigned int i; for(i = 0; i < ARRAY_SIZE(tvnorms); i++) if (*id & tvnorms[i].id) break; if (i == ARRAY_SIZE(tvnorms)) return -EINVAL; down(&dev->lock); set_tvnorm(dev,&tvnorms[i]); up(&dev->lock); return 0; } /* ------ input switching ---------- */ case VIDIOC_ENUMINPUT: { static const char *iname[] = { [ CX88_VMUX_COMPOSITE1 ] = "Composite1", [ CX88_VMUX_COMPOSITE2 ] = "Composite2", [ CX88_VMUX_COMPOSITE3 ] = "Composite3", [ CX88_VMUX_COMPOSITE4 ] = "Composite4", [ CX88_VMUX_TELEVISION ] = "Television", [ CX88_VMUX_SVIDEO ] = "S-Video", [ CX88_VMUX_DEBUG ] = "for debug only", }; struct v4l2_input *i = arg; unsigned int n; n = i->index; if (n >= 4) return -EINVAL; if (0 == INPUT(n)->type) return -EINVAL; memset(i,0,sizeof(*i)); i->index = n; i->type = V4L2_INPUT_TYPE_CAMERA; strcpy(i->name,iname[INPUT(n)->type]); if (CX88_VMUX_TELEVISION == INPUT(n)->type) i->type = V4L2_INPUT_TYPE_TUNER; for (n = 0; n < ARRAY_SIZE(tvnorms); n++) i->std |= tvnorms[n].id; return 0; } case VIDIOC_G_INPUT: { unsigned int *i = arg; *i = dev->input; return 0; } case VIDIOC_S_INPUT: { unsigned int *i = arg; if (*i >= 4) return -EINVAL; down(&dev->lock); video_mux(dev,*i); up(&dev->lock); return 0; } /* --- capture ioctls ---------------------------------------- */ case VIDIOC_ENUM_FMT: { struct v4l2_fmtdesc *f = arg; enum v4l2_buf_type type; unsigned int index; index = f->index; type = f->type; switch (type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: if (index >= ARRAY_SIZE(formats)) return -EINVAL; memset(f,0,sizeof(*f)); f->index = index; f->type = type; strlcpy(f->description,formats[index].name,sizeof(f->description)); f->pixelformat = formats[index].fourcc; break; default: return -EINVAL; } return 0; } case VIDIOC_G_FMT: { struct v4l2_format *f = arg; return cx8800_g_fmt(dev,fh,f); } case VIDIOC_S_FMT: { struct v4l2_format *f = arg; return cx8800_s_fmt(dev,fh,f); } case VIDIOC_TRY_FMT: { struct v4l2_format *f = arg; return cx8800_try_fmt(dev,fh,f); } /* --- controls ---------------------------------------------- */ case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; int i; if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; for (i = 0; i < CX8800_CTLS; i++) if (cx8800_ctls[i].v.id == c->id) break; if (i == CX8800_CTLS) { *c = no_ctl; return 0; } *c = cx8800_ctls[i].v; return 0; } case VIDIOC_G_CTRL: return get_control(dev,arg); case VIDIOC_S_CTRL: return set_control(dev,arg); /* --- tuner ioctls ------------------------------------------ */ case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; u32 reg; if (UNSET == dev->tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; memset(t,0,sizeof(*t)); strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; cx88_get_stereo(dev ,t); reg = cx_read(MO_DEVICE_STATUS); t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; return 0; } case VIDIOC_S_TUNER: { struct v4l2_tuner *t = arg; if (UNSET == dev->tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; cx88_set_stereo(dev,t->audmode); return 0; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *f = arg; if (UNSET == dev->tuner_type) return -EINVAL; if (f->tuner != 0) return -EINVAL; memset(f,0,sizeof(*f)); f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = dev->freq; return 0; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *f = arg; if (UNSET == dev->tuner_type) return -EINVAL; if (f->tuner != 0) return -EINVAL; if (0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV) return -EINVAL; if (1 == fh->radio && f->type != V4L2_TUNER_RADIO) return -EINVAL; down(&dev->lock); dev->freq = f->frequency;#ifdef V4L2_I2C_CLIENTS cx8800_call_i2c_clients(dev,VIDIOC_S_FREQUENCY,f);#else cx8800_call_i2c_clients(dev,VIDIOCSFREQ,&dev->freq);#endif up(&dev->lock); return 0; } /* --- streaming capture ------------------------------------- */ case VIDIOCGMBUF: { struct video_mbuf *mbuf = arg; struct videobuf_queue *q; struct v4l2_requestbuffers req; unsigned int i; q = get_queue(fh); memset(&req,0,sizeof(req)); req.type = q->type; req.count = 8; req.memory = V4L2_MEMORY_MMAP; err = videobuf_reqbufs(file,q,&req); if (err < 0) return err; memset(mbuf,0,sizeof(*mbuf)); mbuf->frames = req.count; mbuf->size = 0; for (i = 0; i < mbuf->frames; i++) { mbuf->offsets[i] = q->bufs[i]->boff; mbuf->size += q->bufs[i]->bsize; } return 0; } case VIDIOC_REQBUFS: return videobuf_reqbufs(file, get_queue(fh), arg); case VIDIOC_QUERYBUF: return videobuf_querybuf(get_queue(fh), arg); case VIDIOC_QBUF: return videobuf_qbuf(file, get_queue(fh), arg); case VIDIOC_DQBUF: return videobuf_dqbuf(file, get_queue(fh), arg); case VIDIOC_STREAMON: { int res = get_ressource(fh); if (!res_get(dev,fh,res)) return -EBUSY; return videobuf_streamon(file, get_queue(fh)); } case VIDIOC_STREAMOFF: { int res = get_ressource(fh); err = videobuf_streamoff(file, get_queue(fh)); if (err < 0) return err; res_free(dev,fh,res); return 0; } default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, video_do_ioctl); } return 0;}static int video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, video_do_ioctl);}/* ----------------------------------------------------------- */static int radio_do_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ struct cx8800_fh *fh = file->private_data; struct cx8800_dev *dev = fh->dev; if (video_debug > 1) cx88_print_ioctl(dev->name,cmd); switch (cmd) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; memset(cap,0,sizeof(*cap)); strcpy(cap->driver, "cx8800"); strlcpy(cap->card, cx88_boards[dev->board].name, sizeof(cap->card)); sprintf(cap->bus_info,"PCI:%s", pci_name(dev->pci)); cap->version = CX88_VERSION_CODE; cap->capabilities = V4L2_CAP_TUNER; return 0; } case VIDIOC_G_TUNER: { struct v4l2_tuner *t = arg; if (t->index > 0) return -EINVAL; memset(t,0,sizeof(*t)); strcpy(t->name, "Radio"); t->rangelow = (int)(65*16); t->rangehigh = (int)(108*16); #ifdef V4L2_I2C_CLIENTS cx8800_call_i2c_clients(dev,VIDIOC_G_TUNER,t);#else { struct video_tuner vt; memset(&vt,0,sizeof(vt)); cx8800_call_i2c_clients(dev,VIDIOCGTUNER,&vt); t->signal = vt.signal; }#endif return 0; } case VIDIOC_ENUMINPUT: { struct v4l2_input *i = arg; if (i->index != 0) return -EINVAL; strcpy(i->name,"Radio"); i->type = V4L2_INPUT_TYPE_TUNER; return 0; } case VIDIOC_G_INPUT: { int *i = arg; *i = 0; return 0; } case VIDIOC_G_AUDIO: { struct v4l2_audio *a = arg; memset(a,0,sizeof(*a)); strcpy(a->name,"Radio"); return 0; } case VIDIOC_G_STD: { v4l2_std_id *id = arg; *id = 0; return 0; } case VIDIOC_S_AUDIO: case VIDIOC_S_TUNER: case VIDIOC_S_INPUT: case VIDIOC_S_STD: return 0; case VIDIOC_QUERYCTRL: { struct v4l2_queryctrl *c = arg; int i; if (c->id < V4L2_CID_BASE || c->id >= V4L2_CID_LASTP1) return -EINVAL; if (c->id == V4L2_CID_AUDIO_MUTE) { for (i = 0; i < CX8800_CTLS; i++) if (cx8800_ctls[i].v.id == c->id) break; *c = cx8800_ctls[i].v; } else *c = no_ctl; return 0; } case VIDIOC_G_CTRL: case VIDIOC_S_CTRL: case VIDIOC_G_FREQUENCY: case VIDIOC_S_FREQUENCY: return video_do_ioctl(inode,file,cmd,arg); default: return v4l_compat_translate_ioctl(inode,file,cmd,arg, radio_do_ioctl); } return 0;};static int radio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, radio_do_ioctl);};/* ----------------------------------------------------------- */static void cx8800_vid_timeout(unsigned long data){ struct cx8800_dev *dev = (struct cx8800_dev*)data; struct cx88_dmaqueue *q = &dev->vidq; struct cx88_buffer *buf; unsigned long flags; cx88_sram_channel_dump(dev, &cx88_sram_channels[SRAM_CH21]); //cx88_risc_disasm(dev,&dev->vidq.stopper); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); spin_lock_irqsave(&dev->slock,flags); while (!list_empty(&q->active)) { buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); list_del(&buf->vb.queue); buf->vb.state = STATE_ERROR; wake_up(&buf->vb.done); printk("%s: [%p/%d] timeout - dma=0x%08lx\n", dev->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); } restart_video_queue(dev,q); spin_unlock_irqrestore(&dev->slock,flags);}static void cx8800_wakeup(struct cx8800_dev *dev, struct cx88_dmaqueue *q, u32 count){ struct cx88_buffer *buf; for (;;) { if (list_empty(&q->active)) break; buf = list_entry(q->active.next, struct cx88_buffer, vb.queue); if (buf->count > count) break; do_gettimeofday(&buf->vb.ts); dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i, count, buf->count); buf->vb.state = STATE_DONE; list_del(&buf->vb.queue); wake_up(&buf->vb.done); } if (list_empty(&q->active)) { del_timer(&q->timeout); } else { mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -