📄 cx88-video.c
字号:
/* We should remember that this driver also supports teletext, */ /* so we have to test if the v4l2_buf_type is VBI capture data. */ if (unlikely((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE))) return -EINVAL; if (unlikely(i != fh->type)) return -EINVAL; if (unlikely(!res_get(dev,fh,get_ressource(fh)))) return -EBUSY; return videobuf_streamon(get_queue(fh));}static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i){ struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev; int err, res; if ((fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && (fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; if (i != fh->type) return -EINVAL; res = get_ressource(fh); err = videobuf_streamoff(get_queue(fh)); if (err < 0) return err; res_free(dev,fh,res); return 0;}static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; mutex_lock(&core->lock); cx88_set_tvnorm(core,*tvnorms); mutex_unlock(&core->lock); return 0;}/* only one input in this sample driver */int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i){ static const char *iname[] = { [ CX88_VMUX_COMPOSITE1 ] = "Composite1", [ CX88_VMUX_COMPOSITE2 ] = "Composite2", [ CX88_VMUX_COMPOSITE3 ] = "Composite3", [ CX88_VMUX_COMPOSITE4 ] = "Composite4", [ CX88_VMUX_SVIDEO ] = "S-Video", [ CX88_VMUX_TELEVISION ] = "Television", [ CX88_VMUX_CABLE ] = "Cable TV", [ CX88_VMUX_DVB ] = "DVB", [ CX88_VMUX_DEBUG ] = "for debug only", }; 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) || (CX88_VMUX_CABLE == INPUT(n).type)) i->type = V4L2_INPUT_TYPE_TUNER; i->std = CX88_NORMS; return 0;}EXPORT_SYMBOL(cx88_enum_input);static int vidioc_enum_input (struct file *file, void *priv, struct v4l2_input *i){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; return cx88_enum_input (core,i);}static int vidioc_g_input (struct file *file, void *priv, unsigned int *i){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; *i = core->input; return 0;}static int vidioc_s_input (struct file *file, void *priv, unsigned int i){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (i >= 4) return -EINVAL; mutex_lock(&core->lock); cx88_newstation(core); cx88_video_mux(core,i); mutex_unlock(&core->lock); return 0;}#if 0static int vidioc_g_audio (struct file *file, void *priv, unsigned int i){ struct v4l2_audio *a = arg; unsigned int n = a->index; memset(a,0,sizeof(*a)); a->index = n; switch (n) { case 0: if ((CX88_VMUX_TELEVISION == INPUT(n).type) || (CX88_VMUX_CABLE == INPUT(n).type)) { strcpy(a->name,"Television"); /* FIXME figure out if stereo received and set V4L2_AUDCAP_STEREO. */ return 0; } break; case 1: if (CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q == core->boardnr) { strcpy(a->name,"Line In"); a->capability = V4L2_AUDCAP_STEREO; return 0; } break; } /* Audio input not available. */ return -EINVAL;}#endifstatic int vidioc_queryctrl (struct file *file, void *priv, struct v4l2_queryctrl *qctrl){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); if (unlikely(qctrl->id == 0)) return -EINVAL; return cx8800_ctrl_query(core, qctrl);}static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control *ctl){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; return cx88_get_control(core,ctl);}static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctl){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; return cx88_set_control(core,ctl);}static int vidioc_g_tuner (struct file *file, void *priv, struct v4l2_tuner *t){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; u32 reg; if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (0 != t->index) return -EINVAL; strcpy(t->name, "Television"); t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); t->signal = (reg & (1<<5)) ? 0xffff : 0x0000; return 0;}static int vidioc_s_tuner (struct file *file, void *priv, struct v4l2_tuner *t){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (UNSET == core->board.tuner_type) return -EINVAL; if (0 != t->index) return -EINVAL; cx88_set_stereo(core, t->audmode, 1); return 0;}static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *f){ struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; /* f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; */ f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV; f->frequency = core->freq; cx88_call_i2c_clients(core,VIDIOC_G_FREQUENCY,f); return 0;}int cx88_set_freq (struct cx88_core *core, struct v4l2_frequency *f){ if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; if (unlikely(f->tuner != 0)) return -EINVAL; mutex_lock(&core->lock); core->freq = f->frequency; cx88_newstation(core); cx88_call_i2c_clients(core,VIDIOC_S_FREQUENCY,f); /* When changing channels it is required to reset TVAUDIO */ msleep (10); cx88_set_tvaudio(core); mutex_unlock(&core->lock); return 0;}EXPORT_SYMBOL(cx88_set_freq);static int vidioc_s_frequency (struct file *file, void *priv, struct v4l2_frequency *f){ struct cx8800_fh *fh = priv; struct cx88_core *core = fh->dev->core; if (unlikely(0 == fh->radio && f->type != V4L2_TUNER_ANALOG_TV)) return -EINVAL; if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO)) return -EINVAL; return cx88_set_freq (core,f);}#ifdef CONFIG_VIDEO_ADV_DEBUGstatic int vidioc_g_register (struct file *file, void *fh, struct v4l2_register *reg){ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; /* cx2388x has a 24-bit register space */ reg->val = cx_read(reg->reg&0xffffff); return 0;}static int vidioc_s_register (struct file *file, void *fh, struct v4l2_register *reg){ struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core; if (!v4l2_chip_match_host(reg->match_type, reg->match_chip)) return -EINVAL; cx_write(reg->reg&0xffffff, reg->val); return 0;}#endif/* ----------------------------------------------------------- *//* RADIO ESPECIFIC IOCTLS *//* ----------------------------------------------------------- */static int radio_querycap (struct file *file, void *priv, struct v4l2_capability *cap){ struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev; struct cx88_core *core = dev->core; strcpy(cap->driver, "cx8800"); strlcpy(cap->card, core->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;}static int radio_g_tuner (struct file *file, void *priv, struct v4l2_tuner *t){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (unlikely(t->index > 0)) return -EINVAL; strcpy(t->name, "Radio"); t->type = V4L2_TUNER_RADIO; cx88_call_i2c_clients(core,VIDIOC_G_TUNER,t); return 0;}static int radio_enum_input (struct file *file, void *priv, struct v4l2_input *i){ if (i->index != 0) return -EINVAL; strcpy(i->name,"Radio"); i->type = V4L2_INPUT_TYPE_TUNER; return 0;}static int radio_g_audio (struct file *file, void *priv, struct v4l2_audio *a){ if (unlikely(a->index)) return -EINVAL; memset(a,0,sizeof(*a)); strcpy(a->name,"Radio"); return 0;}/* FIXME: Should add a standard for radio */static int radio_s_tuner (struct file *file, void *priv, struct v4l2_tuner *t){ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; if (0 != t->index) return -EINVAL; cx88_call_i2c_clients(core,VIDIOC_S_TUNER,t); return 0;}static int radio_s_audio (struct file *file, void *fh, struct v4l2_audio *a){ return 0;}static int radio_s_input (struct file *file, void *fh, unsigned int i){ return 0;}static int radio_queryctrl (struct file *file, void *priv, struct v4l2_queryctrl *c){ 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;}/* ----------------------------------------------------------- */static void cx8800_vid_timeout(unsigned long data){ struct cx8800_dev *dev = (struct cx8800_dev*)data; struct cx88_core *core = dev->core; struct cx88_dmaqueue *q = &dev->vidq; struct cx88_buffer *buf; unsigned long flags; cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); 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 = VIDEOBUF_ERROR; wake_up(&buf->vb.done); printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name, buf, buf->vb.i, (unsigned long)buf->risc.dma); } restart_video_queue(dev,q); spin_unlock_irqrestore(&dev->slock,flags);}static char *cx88_vid_irqs[32] = { "y_risci1", "u_risci1", "v_risci1", "vbi_risc1", "y_risci2", "u_risci2", "v_risci2", "vbi_risc2", "y_oflow", "u_oflow", "v_oflow", "vbi_oflow", "y_sync", "u_sync", "v_sync", "vbi_sync", "opc_err", "par_err", "rip_err", "pci_abort",};static void cx8800_vid_irq(struct cx8800_dev *dev){ struct cx88_core *core = dev->core; u32 status, mask, count; status = cx_read(MO_VID_INTSTAT); mask = cx_read(MO_VID_INTMSK); if (0 == (status & mask)) return; cx_write(MO_VID_INTSTAT, status); if (irq_debug || (status & mask & ~0xff)) cx88_print_irqbits(core->name, "irq vid", cx88_vid_irqs, ARRAY_SIZE(cx88_vid_irqs), status, mask); /* risc op code error */ if (status & (1 << 16)) { printk(KERN_WARNING "%s/0: video risc op code error\n",core->name); cx_clear(MO_VID_DMACNTRL, 0x11); cx_clear(VID_CAPTURE_CONTROL, 0x06); cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]); } /* risc1 y */ if (status & 0x01) { spin_lock(&dev->slock); count = cx_read(MO_VIDY_GPCNT); cx88_wakeup(core, &dev->vidq, count); spin_unlock(&dev->slock); } /* risc1 vbi */ if (status & 0x08) { spin_lock(&dev->slock); count = cx_read(MO_VBI_GPCNT); cx88_wakeup(core, &dev->vbiq, count); spin_unlock(&dev->slock); } /* risc2 y */ if (status & 0x10) { dprintk(2,"stopper video\n"); spin_lock(&dev->slock); restart_video_queue(dev,&dev->vidq); spin_unlock(&dev->slock); } /* risc2 vbi */ if (status & 0x80) { dprintk(2,"stopper vbi\n"); spin_lock(&dev->slock); cx8800_restart_vbi_queue(dev,&dev->vbiq); spin_unlock(&dev->slock); }}#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)static irqreturn_t cx8800_irq(int irq, void *dev_id, struct pt_regs *regs)#elsestatic irqreturn_t cx8800_irq(int irq, void *dev_id)#endif{ struct cx8800_dev *dev = dev_id; struct cx88_core *core = dev->core; u32 status; int loop, handled = 0; for (loop = 0; loop < 10; loop++) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -