diff options
Diffstat (limited to 'drivers/media/video/cx88')
-rw-r--r-- | drivers/media/video/cx88/cx88-alsa.c | 31 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-blackbird.c | 234 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-cards.c | 20 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-core.c | 7 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-video.c | 901 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 68 |
6 files changed, 540 insertions, 721 deletions
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c index 04bf6627d362..dfac6e34859f 100644 --- a/drivers/media/video/cx88/cx88-alsa.c +++ b/drivers/media/video/cx88/cx88-alsa.c @@ -585,13 +585,10 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; int left = value->value.integer.value[0]; int right = value->value.integer.value[1]; int v, b; - memset(&client_ctl, 0, sizeof(client_ctl)); - /* Pass volume & balance onto any WM8775 */ if (left >= right) { v = left << 10; @@ -600,13 +597,8 @@ static void snd_cx88_wm8775_volume_put(struct snd_kcontrol *kcontrol, v = right << 10; b = right ? 0xffff - (0x8000 * left) / right : 0x8000; } - client_ctl.value = v; - client_ctl.id = V4L2_CID_AUDIO_VOLUME; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - - client_ctl.value = b; - client_ctl.id = V4L2_CID_AUDIO_BALANCE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); + wm8775_s_ctrl(core, V4L2_CID_AUDIO_VOLUME, v); + wm8775_s_ctrl(core, V4L2_CID_AUDIO_BALANCE, b); } /* OK - TODO: test it */ @@ -687,14 +679,8 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol, cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, vol); /* Pass mute onto any WM8775 */ if ((core->board.audio_chip == V4L2_IDENT_WM8775) && - ((1<<6) == bit)) { - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.value = 0 != (vol & bit); - client_ctl.id = V4L2_CID_AUDIO_MUTE; - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); - } + ((1<<6) == bit)) + wm8775_s_ctrl(core, V4L2_CID_AUDIO_MUTE, 0 != (vol & bit)); ret = 1; } spin_unlock_irq(&chip->reg_lock); @@ -724,13 +710,10 @@ static int snd_cx88_alc_get(struct snd_kcontrol *kcontrol, { snd_cx88_card_t *chip = snd_kcontrol_chip(kcontrol); struct cx88_core *core = chip->core; - struct v4l2_control client_ctl; - - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = V4L2_CID_AUDIO_LOUDNESS; - call_hw(core, WM8775_GID, core, g_ctrl, &client_ctl); - value->value.integer.value[0] = client_ctl.value ? 1 : 0; + s32 val; + val = wm8775_g_ctrl(core, V4L2_CID_AUDIO_LOUDNESS); + value->value.integer.value[0] = val ? 1 : 0; return 0; } diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c index ed7b2aa1ed83..843ffd9e533b 100644 --- a/drivers/media/video/cx88/cx88-blackbird.c +++ b/drivers/media/video/cx88/cx88-blackbird.c @@ -35,6 +35,7 @@ #include <linux/firmware.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <media/cx2341x.h> #include "cx88.h" @@ -523,11 +524,10 @@ static void blackbird_codec_settings(struct cx8802_dev *dev) blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, dev->height, dev->width); - dev->params.width = dev->width; - dev->params.height = dev->height; - dev->params.is_50hz = (dev->core->tvnorm & V4L2_STD_625_50) != 0; - - cx2341x_update(dev, blackbird_mbox_func, NULL, &dev->params); + dev->cxhdl.width = dev->width; + dev->cxhdl.height = dev->height; + cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50); + cx2341x_handler_setup(&dev->cxhdl); } static int blackbird_initialize_codec(struct cx8802_dev *dev) @@ -618,6 +618,8 @@ static int blackbird_start_codec(struct file *file, void *priv) /* initialize the video input */ blackbird_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0); + cx2341x_handler_set_busy(&dev->cxhdl, 1); + /* start capturing to the host interface */ blackbird_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0, BLACKBIRD_MPEG_CAPTURE, @@ -636,6 +638,8 @@ static int blackbird_stop_codec(struct cx8802_dev *dev) BLACKBIRD_RAW_BITS_NONE ); + cx2341x_handler_set_busy(&dev->cxhdl, 0); + dev->mpeg_active = 0; return 0; } @@ -685,58 +689,15 @@ static struct videobuf_queue_ops blackbird_qops = { /* ------------------------------------------------------------------ */ -static const u32 *ctrl_classes[] = { - cx88_user_ctrls, - cx2341x_mpeg_ctrls, - NULL -}; - -static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qctrl) -{ - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (qctrl->id == 0) - return -EINVAL; - - /* Standard V4L2 controls */ - if (cx8800_ctrl_query(dev->core, qctrl) == 0) - return 0; - - /* MPEG V4L2 controls */ - if (cx2341x_ctrl_query(&dev->params, qctrl)) - qctrl->flags |= V4L2_CTRL_FLAG_DISABLED; - return 0; -} - -/* ------------------------------------------------------------------ */ -/* IOCTL Handlers */ - -static int vidioc_querymenu (struct file *file, void *priv, - struct v4l2_querymenu *qmenu) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct v4l2_queryctrl qctrl; - - qctrl.id = qmenu->id; - blackbird_queryctrl(dev, &qctrl); - return v4l2_ctrl_query_menu(qmenu, &qctrl, - cx2341x_ctrl_get_menu(&dev->params, qmenu->id)); -} - -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *cap) { struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; struct cx88_core *core = dev->core; strcpy(cap->driver, "cx88_blackbird"); - strlcpy(cap->card, core->board.name, sizeof(cap->card)); - sprintf(cap->bus_info,"PCI:%s",pci_name(dev->pci)); - cap->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cx88_querycap(file, core, cap); return 0; } @@ -748,6 +709,7 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, strlcpy(f->description, "MPEG", sizeof(f->description)); f->pixelformat = V4L2_PIX_FMT_MPEG; + f->flags = V4L2_FMT_FLAG_COMPRESSED; return 0; } @@ -759,12 +721,12 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */ - f->fmt.pix.colorspace = 0; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.width = dev->width; f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->mpegq.field; - dprintk(0,"VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", + dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); return 0; } @@ -777,9 +739,9 @@ static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; - dprintk(0,"VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n", dev->width, dev->height, fh->mpegq.field ); return 0; } @@ -793,15 +755,15 @@ static int vidioc_s_fmt_vid_cap (struct file *file, void *priv, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.bytesperline = 0; - f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count; /* 188 * 4 * 1024; */; - f->fmt.pix.colorspace = 0; + f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; dev->width = f->fmt.pix.width; dev->height = f->fmt.pix.height; fh->mpegq.field = f->fmt.pix.field; cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field); blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0, f->fmt.pix.height, f->fmt.pix.width); - dprintk(0,"VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", + dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n", f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field ); return 0; } @@ -834,60 +796,21 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx8802_fh *fh = priv; + struct cx8802_dev *dev = fh->dev; + + if (!dev->mpeg_active) + blackbird_start_codec(file, fh); return videobuf_streamon(&fh->mpegq); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { struct cx8802_fh *fh = priv; - return videobuf_streamoff(&fh->mpegq); -} - -static int vidioc_g_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - return cx2341x_ext_ctrls(&dev->params, 0, f, VIDIOC_G_EXT_CTRLS); -} - -static int vidioc_s_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; + struct cx8802_dev *dev = fh->dev; if (dev->mpeg_active) blackbird_stop_codec(dev); - - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_S_EXT_CTRLS); - if (!err) { - err = cx2341x_update(dev, blackbird_mbox_func, &dev->params, &p); - dev->params = p; - } - return err; -} - -static int vidioc_try_ext_ctrls (struct file *file, void *priv, - struct v4l2_ext_controls *f) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - struct cx2341x_mpeg_params p; - int err; - - if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG) - return -EINVAL; - p = dev->params; - err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS); - - return err; + return videobuf_streamoff(&fh->mpegq); } static int vidioc_s_frequency (struct file *file, void *priv, @@ -897,6 +820,10 @@ static int vidioc_s_frequency (struct file *file, void *priv, struct cx8802_dev *dev = fh->dev; struct cx88_core *core = dev->core; + if (unlikely(UNSET == core->board.tuner_type)) + return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; if (dev->mpeg_active) blackbird_stop_codec(dev); @@ -914,29 +841,11 @@ static int vidioc_log_status (struct file *file, void *priv) char name[32 + 2]; snprintf(name, sizeof(name), "%s/2", core->name); - printk("%s/2: ============ START LOG STATUS ============\n", - core->name); call_all(core, core, log_status); - cx2341x_log_status(&dev->params, name); - printk("%s/2: ============= END LOG STATUS =============\n", - core->name); + v4l2_ctrl_handler_log_status(&dev->cxhdl.hdl, name); return 0; } -static int vidioc_queryctrl (struct file *file, void *priv, - struct v4l2_queryctrl *qctrl) -{ - struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev; - - if (blackbird_queryctrl(dev, qctrl) == 0) - return 0; - - qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id); - if (unlikely(qctrl->id == 0)) - return -EINVAL; - return cx8800_ctrl_query(dev->core, qctrl); -} - static int vidioc_enum_input (struct file *file, void *priv, struct v4l2_input *i) { @@ -944,22 +853,6 @@ static int vidioc_enum_input (struct file *file, void *priv, return cx88_enum_input (core,i); } -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctl) -{ - struct cx88_core *core = ((struct cx8802_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 cx8802_fh *)priv)->dev->core; - return - cx88_set_control(core,ctl); -} - static int vidioc_g_frequency (struct file *file, void *priv, struct v4l2_frequency *f) { @@ -968,8 +861,9 @@ static int vidioc_g_frequency (struct file *file, void *priv, if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; + if (unlikely(f->tuner != 0)) + return -EINVAL; - f->type = V4L2_TUNER_ANALOG_TV; f->frequency = core->freq; call_all(core, tuner, g_frequency, f); @@ -990,6 +884,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; + if (0 == INPUT(i).type) + return -EINVAL; mutex_lock(&core->lock); cx88_newstation(core); @@ -1010,9 +906,9 @@ static int vidioc_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; + call_all(core, tuner, g_tuner, t); cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); @@ -1034,6 +930,14 @@ static int vidioc_s_tuner (struct file *file, void *priv, return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) +{ + struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; + + *tvnorm = core->tvnorm; + return 0; +} + static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id) { struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core; @@ -1087,6 +991,7 @@ static int mpeg_open(struct file *file) mutex_unlock(&dev->core->lock); return -ENOMEM; } + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; @@ -1103,6 +1008,7 @@ static int mpeg_open(struct file *file) dev->core->mpeg_users++; mutex_unlock(&dev->core->lock); + v4l2_fh_add(&fh->fh); return 0; } @@ -1123,6 +1029,8 @@ static int mpeg_release(struct file *file) videobuf_mmap_free(&fh->mpegq); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); @@ -1155,13 +1063,14 @@ mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static unsigned int mpeg_poll(struct file *file, struct poll_table_struct *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx8802_fh *fh = file->private_data; struct cx8802_dev *dev = fh->dev; - if (!dev->mpeg_active) + if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM))) blackbird_start_codec(file, fh); - return videobuf_poll_stream(file, &fh->mpegq, wait); + return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait); } static int @@ -1180,11 +1089,10 @@ static const struct v4l2_file_operations mpeg_fops = .read = mpeg_read, .poll = mpeg_poll, .mmap = mpeg_mmap, - .ioctl = video_ioctl2, + .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { - .vidioc_querymenu = vidioc_querymenu, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, @@ -1196,21 +1104,18 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = { .vidioc_dqbuf = vidioc_dqbuf, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, - .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls, - .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls, - .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls, .vidioc_s_frequency = vidioc_s_frequency, .vidioc_log_status = vidioc_log_status, - .vidioc_queryctrl = vidioc_queryctrl, .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device cx8802_mpeg_template = { @@ -1218,7 +1123,6 @@ static struct video_device cx8802_mpeg_template = { .fops = &mpeg_fops, .ioctl_ops = &mpeg_ioctl_ops, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, }; /* ------------------------------------------------------------------ */ @@ -1286,6 +1190,7 @@ static int blackbird_register_video(struct cx8802_dev *dev) dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci, &cx8802_mpeg_template,"mpeg"); + dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl; video_set_drvdata(dev->mpeg_dev, dev); err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1); if (err < 0) { @@ -1318,17 +1223,20 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) goto fail_core; dev->width = 720; - dev->height = 576; - cx2341x_fill_defaults(&dev->params); - dev->params.port = CX2341X_PORT_STREAMING; - - cx8802_mpeg_template.current_norm = core->tvnorm; - if (core->tvnorm & V4L2_STD_525_60) { dev->height = 480; } else { dev->height = 576; } + dev->cxhdl.port = CX2341X_PORT_STREAMING; + dev->cxhdl.width = dev->width; + dev->cxhdl.height = dev->height; + dev->cxhdl.func = blackbird_mbox_func; + dev->cxhdl.priv = dev; + err = cx2341x_handler_init(&dev->cxhdl, 36); + if (err) + goto fail_core; + v4l2_ctrl_add_handler(&dev->cxhdl.hdl, &core->video_hdl); /* blackbird stuff */ printk("%s/2: cx23416 based mpeg encoder (blackbird reference design)\n", @@ -1336,12 +1244,14 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) host_setup(dev->core); blackbird_initialize_codec(dev); - blackbird_register_video(dev); /* initial device configuration: needed ? */ // init_controls(core); cx88_set_tvnorm(core,core->tvnorm); cx88_video_mux(core,0); + cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576); + cx2341x_handler_setup(&dev->cxhdl); + blackbird_register_video(dev); return 0; @@ -1351,8 +1261,12 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv) static int cx8802_blackbird_remove(struct cx8802_driver *drv) { + struct cx88_core *core = drv->core; + struct cx8802_dev *dev = core->dvbdev; + /* blackbird */ blackbird_unregister_video(drv->core->dvbdev); + v4l2_ctrl_handler_free(&dev->cxhdl.hdl); return 0; } diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c index cbd5d119a2c6..4e9d4f722960 100644 --- a/drivers/media/video/cx88/cx88-cards.c +++ b/drivers/media/video/cx88/cx88-cards.c @@ -3693,7 +3693,22 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) return NULL; } + if (v4l2_ctrl_handler_init(&core->video_hdl, 13)) { + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); + return NULL; + } + + if (v4l2_ctrl_handler_init(&core->audio_hdl, 13)) { + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_device_unregister(&core->v4l2_dev); + kfree(core); + return NULL; + } + if (0 != cx88_get_resources(core, pci)) { + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); kfree(core); return NULL; @@ -3706,6 +3721,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr) core->bmmio = (u8 __iomem *)core->lmmio; if (core->lmmio == NULL) { + release_mem_region(pci_resource_start(pci, 0), + pci_resource_len(pci, 0)); + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); + v4l2_device_unregister(&core->v4l2_dev); kfree(core); return NULL; } diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index fbfdd8067937..e81c735f012a 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c @@ -1012,6 +1012,9 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm) // tell i2c chips call_all(core, core, s_std, norm); + /* The chroma_agc control should be inaccessible if the video format is SECAM */ + v4l2_ctrl_grab(core->chroma_agc, cxiformat == VideoFormatSECAM); + // done return 0; } @@ -1030,10 +1033,10 @@ struct video_device *cx88_vdev_init(struct cx88_core *core, return NULL; *vfd = *template_; vfd->v4l2_dev = &core->v4l2_dev; - vfd->parent = &pci->dev; vfd->release = video_device_release; snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", core->name, type, core->board.name); + set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); return vfd; } @@ -1086,6 +1089,8 @@ void cx88_core_put(struct cx88_core *core, struct pci_dev *pci) iounmap(core->lmmio); cx88_devcount--; mutex_unlock(&devlist); + v4l2_ctrl_handler_free(&core->video_hdl); + v4l2_ctrl_handler_free(&core->audio_hdl); v4l2_device_unregister(&core->v4l2_dev); kfree(core); } diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c index 921c56d115d6..f6fcc7e763ab 100644 --- a/drivers/media/video/cx88/cx88-video.c +++ b/drivers/media/video/cx88/cx88-video.c @@ -40,6 +40,7 @@ #include "cx88.h" #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <media/wm8775.h> MODULE_DESCRIPTION("v4l2 driver module for cx2388x based TV cards"); @@ -155,219 +156,147 @@ static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc) /* ------------------------------------------------------------------- */ -static const struct v4l2_queryctrl no_ctl = { - .name = "42", - .flags = V4L2_CTRL_FLAG_DISABLED, +struct cx88_ctrl { + /* control information */ + u32 id; + s32 minimum; + s32 maximum; + u32 step; + s32 default_value; + + /* control register information */ + u32 off; + u32 reg; + u32 sreg; + u32 mask; + u32 shift; }; -static const struct cx88_ctrl cx8800_ctls[] = { +static const struct cx88_ctrl cx8800_vid_ctls[] = { /* --- video --- */ { - .v = { - .id = V4L2_CID_BRIGHTNESS, - .name = "Brightness", - .minimum = 0x00, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_CONTR_BRIGHT, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_BRIGHTNESS, + .minimum = 0x00, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 128, + .reg = MO_CONTR_BRIGHT, + .mask = 0x00ff, + .shift = 0, },{ - .v = { - .id = V4L2_CID_CONTRAST, - .name = "Contrast", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_CONTR_BRIGHT, - .mask = 0xff00, - .shift = 8, + .id = V4L2_CID_CONTRAST, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x3f, + .off = 0, + .reg = MO_CONTR_BRIGHT, + .mask = 0xff00, + .shift = 8, },{ - .v = { - .id = V4L2_CID_HUE, - .name = "Hue", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 128, - .reg = MO_HUE, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_HUE, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 128, + .reg = MO_HUE, + .mask = 0x00ff, + .shift = 0, },{ /* strictly, this only describes only U saturation. * V saturation is handled specially through code. */ - .v = { - .id = V4L2_CID_SATURATION, - .name = "Saturation", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0x7f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_UV_SATURATION, - .mask = 0x00ff, - .shift = 0, + .id = V4L2_CID_SATURATION, + .minimum = 0, + .maximum = 0xff, + .step = 1, + .default_value = 0x7f, + .off = 0, + .reg = MO_UV_SATURATION, + .mask = 0x00ff, + .shift = 0, }, { - .v = { - .id = V4L2_CID_SHARPNESS, - .name = "Sharpness", - .minimum = 0, - .maximum = 4, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, + .id = V4L2_CID_SHARPNESS, + .minimum = 0, + .maximum = 4, + .step = 1, + .default_value = 0x0, + .off = 0, /* NOTE: the value is converted and written to both even and odd registers in the code */ - .reg = MO_FILTER_ODD, - .mask = 7 << 7, - .shift = 7, + .reg = MO_FILTER_ODD, + .mask = 7 << 7, + .shift = 7, }, { - .v = { - .id = V4L2_CID_CHROMA_AGC, - .name = "Chroma AGC", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 10, - .shift = 10, + .id = V4L2_CID_CHROMA_AGC, + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 10, + .shift = 10, }, { - .v = { - .id = V4L2_CID_COLOR_KILLER, - .name = "Color killer", - .minimum = 0, - .maximum = 1, - .default_value = 0x1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = MO_INPUT_FORMAT, - .mask = 1 << 9, - .shift = 9, + .id = V4L2_CID_COLOR_KILLER, + .minimum = 0, + .maximum = 1, + .default_value = 0x1, + .reg = MO_INPUT_FORMAT, + .mask = 1 << 9, + .shift = 9, }, { - .v = { - .id = V4L2_CID_BAND_STOP_FILTER, - .name = "Notch filter", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 0x0, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .off = 0, - .reg = MO_HTOTAL, - .mask = 3 << 11, - .shift = 11, - }, { - /* --- audio --- */ - .v = { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = (1 << 6), - .shift = 6, + .id = V4L2_CID_BAND_STOP_FILTER, + .minimum = 0, + .maximum = 1, + .step = 1, + .default_value = 0x0, + .off = 0, + .reg = MO_HTOTAL, + .mask = 3 << 11, + .shift = 11, + } +}; + +static const struct cx88_ctrl cx8800_aud_ctls[] = { + { + /* --- audio --- */ + .id = V4L2_CID_AUDIO_MUTE, + .minimum = 0, + .maximum = 1, + .default_value = 1, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = (1 << 6), + .shift = 6, },{ - .v = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0x3f, - .step = 1, - .default_value = 0x3f, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_VOL_CTL, - .sreg = SHADOW_AUD_VOL_CTL, - .mask = 0x3f, - .shift = 0, + .id = V4L2_CID_AUDIO_VOLUME, + .minimum = 0, + .maximum = 0x3f, + .step = 1, + .default_value = 0x3f, + .reg = AUD_VOL_CTL, + .sreg = SHADOW_AUD_VOL_CTL, + .mask = 0x3f, + .shift = 0, },{ - .v = { - .id = V4L2_CID_AUDIO_BALANCE, - .name = "Balance", - .minimum = 0, - .maximum = 0x7f, - .step = 1, - .default_value = 0x40, - .type = V4L2_CTRL_TYPE_INTEGER, - }, - .reg = AUD_BAL_CTL, - .sreg = SHADOW_AUD_BAL_CTL, - .mask = 0x7f, - .shift = 0, + .id = V4L2_CID_AUDIO_BALANCE, + .minimum = 0, + .maximum = 0x7f, + .step = 1, + .default_value = 0x40, + .reg = AUD_BAL_CTL, + .sreg = SHADOW_AUD_BAL_CTL, + .mask = 0x7f, + .shift = 0, } }; -enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) }; - -/* Must be sorted from low to high control ID! */ -const u32 cx88_user_ctrls[] = { - V4L2_CID_USER_CLASS, - V4L2_CID_BRIGHTNESS, - V4L2_CID_CONTRAST, - V4L2_CID_SATURATION, - V4L2_CID_HUE, - V4L2_CID_AUDIO_VOLUME, - V4L2_CID_AUDIO_BALANCE, - V4L2_CID_AUDIO_MUTE, - V4L2_CID_SHARPNESS, - V4L2_CID_CHROMA_AGC, - V4L2_CID_COLOR_KILLER, - V4L2_CID_BAND_STOP_FILTER, - 0 -}; -EXPORT_SYMBOL(cx88_user_ctrls); -static const u32 * const ctrl_classes[] = { - cx88_user_ctrls, - NULL +enum { + CX8800_VID_CTLS = ARRAY_SIZE(cx8800_vid_ctls), + CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls), }; -int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl) -{ - int i; - - if (qctrl->id < V4L2_CID_BASE || - qctrl->id >= V4L2_CID_LASTP1) - return -EINVAL; - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == qctrl->id) - break; - if (i == CX8800_CTLS) { - *qctrl = no_ctl; - return 0; - } - *qctrl = cx8800_ctls[i].v; - /* Report chroma AGC as inactive when SECAM is selected */ - if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC && - core->tvnorm & V4L2_STD_SECAM) - qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE; - - return 0; -} -EXPORT_SYMBOL(cx8800_ctrl_query); - /* ------------------------------------------------------------------- */ /* resource management */ @@ -591,8 +520,9 @@ static int buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size) { struct cx8800_fh *fh = q->priv_data; + struct cx8800_dev *dev = fh->dev; - *size = fh->fmt->depth*fh->width*fh->height >> 3; + *size = dev->fmt->depth * dev->width * dev->height >> 3; if (0 == *count) *count = 32; if (*size * *count > vid_limit * 1024 * 1024) @@ -611,21 +541,21 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb); int rc, init_buffer = 0; - BUG_ON(NULL == fh->fmt); - if (fh->width < 48 || fh->width > norm_maxw(core->tvnorm) || - fh->height < 32 || fh->height > norm_maxh(core->tvnorm)) + BUG_ON(NULL == dev->fmt); + if (dev->width < 48 || dev->width > norm_maxw(core->tvnorm) || + dev->height < 32 || dev->height > norm_maxh(core->tvnorm)) return -EINVAL; - buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3; + buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3; if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) return -EINVAL; - if (buf->fmt != fh->fmt || - buf->vb.width != fh->width || - buf->vb.height != fh->height || + if (buf->fmt != dev->fmt || + buf->vb.width != dev->width || + buf->vb.height != dev->height || buf->vb.field != field) { - buf->fmt = fh->fmt; - buf->vb.width = fh->width; - buf->vb.height = fh->height; + buf->fmt = dev->fmt; + buf->vb.width = dev->width; + buf->vb.height = dev->height; buf->vb.field = field; init_buffer = 1; } @@ -675,7 +605,7 @@ buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb, } dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n", buf, buf->vb.i, - fh->width, fh->height, fh->fmt->depth, fh->fmt->name, + dev->width, dev->height, dev->fmt->depth, dev->fmt->name, (unsigned long)buf->risc.dma); buf->vb.state = VIDEOBUF_PREPARED; @@ -755,12 +685,15 @@ static const struct videobuf_queue_ops cx8800_video_qops = { /* ------------------------------------------------------------------ */ -static struct videobuf_queue* get_queue(struct cx8800_fh *fh) +static struct videobuf_queue *get_queue(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + struct cx8800_fh *fh = file->private_data; + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return &fh->vidq; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return &fh->vbiq; default: BUG(); @@ -768,12 +701,14 @@ static struct videobuf_queue* get_queue(struct cx8800_fh *fh) } } -static int get_ressource(struct cx8800_fh *fh) +static int get_resource(struct file *file) { - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + struct video_device *vdev = video_devdata(file); + + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: return RESOURCE_VIDEO; - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: return RESOURCE_VBI; default: BUG(); @@ -810,13 +745,9 @@ static int video_open(struct file *file) if (unlikely(!fh)) return -ENOMEM; + v4l2_fh_init(&fh->fh, vdev); file->private_data = fh; fh->dev = dev; - fh->radio = radio; - fh->type = type; - fh->width = 320; - fh->height = 240; - fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); mutex_lock(&core->lock); @@ -833,7 +764,7 @@ static int video_open(struct file *file) sizeof(struct cx88_buffer), fh, NULL); - if (fh->radio) { + if (vdev->vfl_type == VFL_TYPE_RADIO) { dprintk(1,"video_open: setting radio device\n"); cx_write(MO_GP3_IO, core->board.radio.gpio3); cx_write(MO_GP0_IO, core->board.radio.gpio0); @@ -859,6 +790,7 @@ static int video_open(struct file *file) core->users++; mutex_unlock(&core->lock); + v4l2_fh_add(&fh->fh); return 0; } @@ -866,15 +798,16 @@ static int video_open(struct file *file) static ssize_t video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = file->private_data; - switch (fh->type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: + switch (vdev->vfl_type) { + case VFL_TYPE_GRABBER: if (res_locked(fh->dev,RESOURCE_VIDEO)) return -EBUSY; return videobuf_read_one(&fh->vidq, data, count, ppos, file->f_flags & O_NONBLOCK); - case V4L2_BUF_TYPE_VBI_CAPTURE: + case VFL_TYPE_VBI: if (!res_get(fh->dev,fh,RESOURCE_VBI)) return -EBUSY; return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1, @@ -888,16 +821,16 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static unsigned int video_poll(struct file *file, struct poll_table_struct *wait) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = file->private_data; struct cx88_buffer *buf; - unsigned int rc = POLLERR; + unsigned int rc = v4l2_ctrl_poll(file, wait); - if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) { + if (vdev->vfl_type == VFL_TYPE_VBI) { if (!res_get(fh->dev,fh,RESOURCE_VBI)) - return POLLERR; - return videobuf_poll_stream(file, &fh->vbiq, wait); + return rc | POLLERR; + return rc | videobuf_poll_stream(file, &fh->vbiq, wait); } - mutex_lock(&fh->vidq.vb_lock); if (res_check(fh,RESOURCE_VIDEO)) { /* streaming capture */ @@ -913,9 +846,7 @@ video_poll(struct file *file, struct poll_table_struct *wait) poll_wait(file, &buf->vb.done, wait); if (buf->vb.state == VIDEOBUF_DONE || buf->vb.state == VIDEOBUF_ERROR) - rc = POLLIN|POLLRDNORM; - else - rc = 0; + rc |= POLLIN|POLLRDNORM; done: mutex_unlock(&fh->vidq.vb_lock); return rc; @@ -952,6 +883,8 @@ static int video_release(struct file *file) videobuf_mmap_free(&fh->vbiq); mutex_lock(&dev->core->lock); + v4l2_fh_del(&fh->fh); + v4l2_fh_exit(&fh->fh); file->private_data = NULL; kfree(fh); @@ -966,156 +899,104 @@ static int video_release(struct file *file) static int video_mmap(struct file *file, struct vm_area_struct * vma) { - struct cx8800_fh *fh = file->private_data; - - return videobuf_mmap_mapper(get_queue(fh), vma); + return videobuf_mmap_mapper(get_queue(file), vma); } /* ------------------------------------------------------------------ */ /* VIDEO CTRL IOCTLS */ -int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl) +static int cx8800_s_vid_ctrl(struct v4l2_ctrl *ctrl) { - const struct cx88_ctrl *c = NULL; - u32 value; - int i; + struct cx88_core *core = + container_of(ctrl->handler, struct cx88_core, video_hdl); + const struct cx88_ctrl *cc = ctrl->priv; + u32 value, mask; - for (i = 0; i < CX8800_CTLS; i++) - if (cx8800_ctls[i].v.id == ctl->id) - c = &cx8800_ctls[i]; - if (unlikely(NULL == c)) - return -EINVAL; + mask = cc->mask; + switch (ctrl->id) { + case V4L2_CID_SATURATION: + /* special v_sat handling */ - value = c->sreg ? cx_sread(c->sreg) : cx_read(c->reg); - switch (ctl->id) { - case V4L2_CID_AUDIO_BALANCE: - ctl->value = ((value & 0x7f) < 0x40) ? ((value & 0x7f) + 0x40) - : (0x7f - (value & 0x7f)); - break; - case V4L2_CID_AUDIO_VOLUME: - ctl->value = 0x3f - (value & 0x3f); + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; + + if (core->tvnorm & V4L2_STD_SECAM) { + /* For SECAM, both U and V sat should be equal */ + value = value << 8 | value; + } else { + /* Keeps U Saturation proportional to V Sat */ + value = (value * 0x5a) / 0x7f << 8 | value; + } + mask = 0xffff; break; case V4L2_CID_SHARPNESS: - ctl->value = ((value & 0x0200) ? (((value & 0x0180) >> 7) + 1) - : 0); + /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ + value = (ctrl->val < 1 ? 0 : ((ctrl->val + 3) << 7)); + /* needs to be set for both fields */ + cx_andor(MO_FILTER_EVEN, mask, value); + break; + case V4L2_CID_CHROMA_AGC: + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; default: - ctl->value = ((value + (c->off << c->shift)) & c->mask) >> c->shift; + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } - dprintk(1,"get_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, - value,c->mask, c->sreg ? " [shadowed]" : ""); + dprintk(1, "set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); + if (cc->sreg) + cx_sandor(cc->sreg, cc->reg, mask, value); + else + cx_andor(cc->reg, mask, value); return 0; } -EXPORT_SYMBOL(cx88_get_control); -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl) +static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl) { - const struct cx88_ctrl *c = NULL; + struct cx88_core *core = + container_of(ctrl->handler, struct cx88_core, audio_hdl); + const struct cx88_ctrl *cc = ctrl->priv; u32 value,mask; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == ctl->id) { - c = &cx8800_ctls[i]; - } - } - if (unlikely(NULL == c)) - return -EINVAL; - - if (ctl->value < c->v.minimum) - ctl->value = c->v.minimum; - if (ctl->value > c->v.maximum) - ctl->value = c->v.maximum; /* Pass changes onto any WM8775 */ if (core->board.audio_chip == V4L2_IDENT_WM8775) { - struct v4l2_control client_ctl; - memset(&client_ctl, 0, sizeof(client_ctl)); - client_ctl.id = ctl->id; - - switch (ctl->id) { + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - client_ctl.value = ctl->value; + wm8775_s_ctrl(core, ctrl->id, ctrl->val); break; case V4L2_CID_AUDIO_VOLUME: - client_ctl.value = (ctl->value) ? - (0x90 + ctl->value) << 8 : 0; + wm8775_s_ctrl(core, ctrl->id, (ctrl->val) ? + (0x90 + ctrl->val) << 8 : 0); break; case V4L2_CID_AUDIO_BALANCE: - client_ctl.value = ctl->value << 9; + wm8775_s_ctrl(core, ctrl->id, ctrl->val << 9); break; default: - client_ctl.id = 0; break; } - if (client_ctl.id) - call_hw(core, WM8775_GID, core, s_ctrl, &client_ctl); } - mask=c->mask; - switch (ctl->id) { + mask = cc->mask; + switch (ctrl->id) { case V4L2_CID_AUDIO_BALANCE: - value = (ctl->value < 0x40) ? (0x7f - ctl->value) : (ctl->value - 0x40); + value = (ctrl->val < 0x40) ? (0x7f - ctrl->val) : (ctrl->val - 0x40); break; case V4L2_CID_AUDIO_VOLUME: - value = 0x3f - (ctl->value & 0x3f); - break; - case V4L2_CID_SATURATION: - /* special v_sat handling */ - - value = ((ctl->value - c->off) << c->shift) & c->mask; - - if (core->tvnorm & V4L2_STD_SECAM) { - /* For SECAM, both U and V sat should be equal */ - value=value<<8|value; - } else { - /* Keeps U Saturation proportional to V Sat */ - value=(value*0x5a)/0x7f<<8|value; - } - mask=0xffff; - break; - case V4L2_CID_SHARPNESS: - /* 0b000, 0b100, 0b101, 0b110, or 0b111 */ - value = (ctl->value < 1 ? 0 : ((ctl->value + 3) << 7)); - /* needs to be set for both fields */ - cx_andor(MO_FILTER_EVEN, mask, value); - break; - case V4L2_CID_CHROMA_AGC: - /* Do not allow chroma AGC to be enabled for SECAM */ - value = ((ctl->value - c->off) << c->shift) & c->mask; - if (core->tvnorm & V4L2_STD_SECAM && value) - return -EINVAL; + value = 0x3f - (ctrl->val & 0x3f); break; default: - value = ((ctl->value - c->off) << c->shift) & c->mask; + value = ((ctrl->val - cc->off) << cc->shift) & cc->mask; break; } dprintk(1,"set_control id=0x%X(%s) ctrl=0x%02x, reg=0x%02x val=0x%02x (mask 0x%02x)%s\n", - ctl->id, c->v.name, ctl->value, c->reg, value, - mask, c->sreg ? " [shadowed]" : ""); - if (c->sreg) { - cx_sandor(c->sreg, c->reg, mask, value); - } else { - cx_andor(c->reg, mask, value); - } + ctrl->id, ctrl->name, ctrl->val, cc->reg, value, + mask, cc->sreg ? " [shadowed]" : ""); + if (cc->sreg) + cx_sandor(cc->sreg, cc->reg, mask, value); + else + cx_andor(cc->reg, mask, value); return 0; } -EXPORT_SYMBOL(cx88_set_control); - -static void init_controls(struct cx88_core *core) -{ - struct v4l2_control ctrl; - int i; - - for (i = 0; i < CX8800_CTLS; i++) { - ctrl.id=cx8800_ctls[i].v.id; - ctrl.value=cx8800_ctls[i].v.default_value; - - cx88_set_control(core, &ctrl); - } -} /* ------------------------------------------------------------------ */ /* VIDEO IOCTLS */ @@ -1124,15 +1005,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; - f->fmt.pix.width = fh->width; - f->fmt.pix.height = fh->height; + f->fmt.pix.width = dev->width; + f->fmt.pix.height = dev->height; f->fmt.pix.field = fh->vidq.field; - f->fmt.pix.pixelformat = fh->fmt->fourcc; + f->fmt.pix.pixelformat = dev->fmt->fourcc; f->fmt.pix.bytesperline = - (f->fmt.pix.width * fh->fmt->depth) >> 3; + (f->fmt.pix.width * dev->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; + f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; return 0; } @@ -1184,33 +1067,54 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *f) { struct cx8800_fh *fh = priv; + struct cx8800_dev *dev = fh->dev; int err = vidioc_try_fmt_vid_cap (file,priv,f); if (0 != err) return err; - fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat); - fh->width = f->fmt.pix.width; - fh->height = f->fmt.pix.height; + dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat); + dev->width = f->fmt.pix.width; + dev->height = f->fmt.pix.height; fh->vidq.field = f->fmt.pix.field; return 0; } -static int vidioc_querycap (struct file *file, void *priv, +void cx88_querycap(struct file *file, struct cx88_core *core, + struct v4l2_capability *cap) +{ + struct video_device *vdev = video_devdata(file); + + strlcpy(cap->card, core->board.name, sizeof(cap->card)); + cap->device_caps = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + if (UNSET != core->board.tuner_type) + cap->device_caps |= V4L2_CAP_TUNER; + switch (vdev->vfl_type) { + case VFL_TYPE_RADIO: + cap->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER; + break; + case VFL_TYPE_GRABBER: + cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE; + break; + case VFL_TYPE_VBI: + cap->device_caps |= V4L2_CAP_VBI_CAPTURE; + break; + } + cap->capabilities = cap->device_caps | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_VBI_CAPTURE | V4L2_CAP_DEVICE_CAPS; + if (core->board.radio.type == CX88_RADIO) + cap->capabilities |= V4L2_CAP_RADIO; +} +EXPORT_SYMBOL(cx88_querycap); + +static int vidioc_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->capabilities = - V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - V4L2_CAP_VBI_CAPTURE; - if (UNSET != core->board.tuner_type) - cap->capabilities |= V4L2_CAP_TUNER; + sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci)); + cx88_querycap(file, core, cap); return 0; } @@ -1228,69 +1132,67 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv, static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p) { - struct cx8800_fh *fh = priv; - return (videobuf_reqbufs(get_queue(fh), p)); + return videobuf_reqbufs(get_queue(file), p); } static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_querybuf(get_queue(fh), p)); + return videobuf_querybuf(get_queue(file), p); } static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_qbuf(get_queue(fh), p)); + return videobuf_qbuf(get_queue(file), p); } static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p) { - struct cx8800_fh *fh = priv; - return (videobuf_dqbuf(get_queue(fh), p, - file->f_flags & O_NONBLOCK)); + return videobuf_dqbuf(get_queue(file), p, + file->f_flags & O_NONBLOCK); } static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); struct cx8800_fh *fh = priv; struct cx8800_dev *dev = fh->dev; - /* 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)) + if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; - if (unlikely(!res_get(dev,fh,get_ressource(fh)))) + if (unlikely(!res_get(dev, fh, get_resource(file)))) return -EBUSY; - return videobuf_streamon(get_queue(fh)); + return videobuf_streamon(get_queue(file)); } static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) { + struct video_device *vdev = video_devdata(file); 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)) + if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) || + (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE)) return -EINVAL; - if (i != fh->type) - return -EINVAL; - - res = get_ressource(fh); - err = videobuf_streamoff(get_queue(fh)); + res = get_resource(file); + err = videobuf_streamoff(get_queue(file)); if (err < 0) return err; res_free(dev,fh,res); return 0; } +static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm) +{ + struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core; + + *tvnorm = core->tvnorm; + 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; @@ -1327,8 +1229,8 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i) if ((CX88_VMUX_TELEVISION == INPUT(n).type) || (CX88_VMUX_CABLE == INPUT(n).type)) { i->type = V4L2_INPUT_TYPE_TUNER; - i->std = CX88_NORMS; } + i->std = CX88_NORMS; return 0; } EXPORT_SYMBOL(cx88_enum_input); @@ -1354,6 +1256,8 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) if (i >= 4) return -EINVAL; + if (0 == INPUT(i).type) + return -EINVAL; mutex_lock(&core->lock); cx88_newstation(core); @@ -1362,35 +1266,6 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i) return 0; } - - -static 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) { @@ -1403,9 +1278,9 @@ static int vidioc_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Television"); - t->type = V4L2_TUNER_ANALOG_TV; t->capability = V4L2_TUNER_CAP_NORM; t->rangehigh = 0xffffffffUL; + call_all(core, tuner, g_tuner, t); cx88_get_stereo(core ,t); reg = cx_read(MO_DEVICE_STATUS); @@ -1435,9 +1310,9 @@ static int vidioc_g_frequency (struct file *file, void *priv, if (unlikely(UNSET == core->board.tuner_type)) return -EINVAL; + if (f->tuner) + 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; call_all(core, tuner, g_frequency, f); @@ -1454,9 +1329,10 @@ int cx88_set_freq (struct cx88_core *core, return -EINVAL; mutex_lock(&core->lock); - core->freq = f->frequency; cx88_newstation(core); call_all(core, tuner, s_frequency, f); + call_all(core, tuner, g_frequency, f); + core->freq = f->frequency; /* When changing channels it is required to reset TVAUDIO */ msleep (10); @@ -1474,13 +1350,17 @@ static int vidioc_s_frequency (struct file *file, void *priv, 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); +} - return - cx88_set_freq (core,f); +static int vidioc_g_chip_ident(struct file *file, void *priv, + struct v4l2_dbg_chip_ident *chip) +{ + if (!v4l2_chip_match_host(&chip->match)) + return -EINVAL; + chip->revision = 0; + chip->ident = V4L2_IDENT_UNKNOWN; + return 0; } #ifdef CONFIG_VIDEO_ADV_DEBUG @@ -1513,19 +1393,6 @@ static int vidioc_s_register (struct file *file, void *fh, /* 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->capabilities = V4L2_CAP_TUNER; - return 0; -} - static int radio_g_tuner (struct file *file, void *priv, struct v4l2_tuner *t) { @@ -1535,32 +1402,11 @@ static int radio_g_tuner (struct file *file, void *priv, return -EINVAL; strcpy(t->name, "Radio"); - t->type = V4L2_TUNER_RADIO; call_all(core, tuner, 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; - - strcpy(a->name,"Radio"); - return 0; -} - /* FIXME: Should add a standard for radio */ static int radio_s_tuner (struct file *file, void *priv, @@ -1570,46 +1416,14 @@ static int radio_s_tuner (struct file *file, void *priv, if (0 != t->index) return -EINVAL; + if (t->audmode > V4L2_TUNER_MODE_STEREO) + t->audmode = V4L2_TUNER_MODE_STEREO; call_all(core, tuner, 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 || - c->id == V4L2_CID_AUDIO_VOLUME || - c->id == V4L2_CID_AUDIO_BALANCE) { - for (i = 0; i < CX8800_CTLS; i++) { - if (cx8800_ctls[i].v.id == c->id) - break; - } - if (i == CX8800_CTLS) - return -EINVAL; - *c = cx8800_ctls[i].v; - } else - *c = no_ctl; - return 0; -} - /* ----------------------------------------------------------- */ static void cx8800_vid_timeout(unsigned long data) @@ -1752,63 +1566,89 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = { .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, - .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, - .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, #endif }; -static struct video_device cx8800_vbi_template; - static const struct video_device cx8800_video_template = { .name = "cx8800-video", .fops = &video_fops, .ioctl_ops = &video_ioctl_ops, .tvnorms = CX88_NORMS, - .current_norm = V4L2_STD_NTSC_M, +}; + +static const struct v4l2_ioctl_ops vbi_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt, + .vidioc_reqbufs = vidioc_reqbufs, + .vidioc_querybuf = vidioc_querybuf, + .vidioc_qbuf = vidioc_qbuf, + .vidioc_dqbuf = vidioc_dqbuf, + .vidioc_g_std = vidioc_g_std, + .vidioc_s_std = vidioc_s_std, + .vidioc_enum_input = vidioc_enum_input, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_streamon = vidioc_streamon, + .vidioc_streamoff = vidioc_streamoff, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_g_chip_ident = vidioc_g_chip_ident, +#ifdef CONFIG_VIDEO_ADV_DEBUG + .vidioc_g_register = vidioc_g_register, + .vidioc_s_register = vidioc_s_register, +#endif +}; + +static const struct video_device cx8800_vbi_template = { + .name = "cx8800-vbi", + .fops = &video_fops, + .ioctl_ops = &vbi_ioctl_ops, + .tvnorms = CX88_NORMS, }; static const struct v4l2_file_operations radio_fops = { .owner = THIS_MODULE, .open = video_open, + .poll = v4l2_ctrl_poll, .release = video_release, .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops radio_ioctl_ops = { - .vidioc_querycap = radio_querycap, + .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = radio_g_tuner, - .vidioc_enum_input = radio_enum_input, - .vidioc_g_audio = radio_g_audio, .vidioc_s_tuner = radio_s_tuner, - .vidioc_s_audio = radio_s_audio, - .vidioc_s_input = radio_s_input, - .vidioc_queryctrl = radio_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_g_chip_ident = vidioc_g_chip_ident, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, @@ -1821,6 +1661,14 @@ static const struct video_device cx8800_radio_template = { .ioctl_ops = &radio_ioctl_ops, }; +static const struct v4l2_ctrl_ops cx8800_ctrl_vid_ops = { + .s_ctrl = cx8800_s_vid_ctrl, +}; + +static const struct v4l2_ctrl_ops cx8800_ctrl_aud_ops = { + .s_ctrl = cx8800_s_aud_ctrl, +}; + /* ----------------------------------------------------------- */ static void cx8800_unregister_video(struct cx8800_dev *dev) @@ -1853,8 +1701,8 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, { struct cx8800_dev *dev; struct cx88_core *core; - int err; + int i; dev = kzalloc(sizeof(*dev),GFP_KERNEL); if (NULL == dev) @@ -1888,14 +1736,9 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, goto fail_core; } - /* Initialize VBI template */ - memcpy( &cx8800_vbi_template, &cx8800_video_template, - sizeof(cx8800_vbi_template) ); - strcpy(cx8800_vbi_template.name,"cx8800-vbi"); - /* initialize driver struct */ spin_lock_init(&dev->slock); - core->tvnorm = cx8800_video_template.current_norm; + core->tvnorm = V4L2_STD_NTSC_M; /* init video dma queues */ INIT_LIST_HEAD(&dev->vidq.active); @@ -1925,6 +1768,35 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, } cx_set(MO_PCI_INTMSK, core->pci_irqmask); + for (i = 0; i < CX8800_AUD_CTLS; i++) { + const struct cx88_ctrl *cc = &cx8800_aud_ctls[i]; + struct v4l2_ctrl *vc; + + vc = v4l2_ctrl_new_std(&core->audio_hdl, &cx8800_ctrl_aud_ops, + cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); + if (vc == NULL) { + err = core->audio_hdl.error; + goto fail_core; + } + vc->priv = (void *)cc; + } + + for (i = 0; i < CX8800_VID_CTLS; i++) { + const struct cx88_ctrl *cc = &cx8800_vid_ctls[i]; + struct v4l2_ctrl *vc; + + vc = v4l2_ctrl_new_std(&core->video_hdl, &cx8800_ctrl_vid_ops, + cc->id, cc->minimum, cc->maximum, cc->step, cc->default_value); + if (vc == NULL) { + err = core->video_hdl.error; + goto fail_core; + } + vc->priv = (void *)cc; + if (vc->id == V4L2_CID_CHROMA_AGC) + core->chroma_agc = vc; + } + v4l2_ctrl_add_handler(&core->video_hdl, &core->audio_hdl); + /* load and configure helper modules */ if (core->board.audio_chip == V4L2_IDENT_WM8775) { @@ -1942,8 +1814,10 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, sd = v4l2_i2c_new_subdev_board(&core->v4l2_dev, &core->i2c_adap, &wm8775_info, NULL); - if (sd != NULL) + if (sd != NULL) { + core->sd_wm8775 = sd; sd->grp_id = WM8775_GID; + } } if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) { @@ -1971,16 +1845,22 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, /* Sets device info at pci_dev */ pci_set_drvdata(pci_dev, dev); + dev->width = 320; + dev->height = 240; + dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24); + /* initial device configuration */ mutex_lock(&core->lock); cx88_set_tvnorm(core, core->tvnorm); - init_controls(core); + v4l2_ctrl_handler_setup(&core->video_hdl); + v4l2_ctrl_handler_setup(&core->audio_hdl); cx88_video_mux(core, 0); /* register v4l devices */ dev->video_dev = cx88_vdev_init(core,dev->pci, &cx8800_video_template,"video"); video_set_drvdata(dev->video_dev, dev); + dev->video_dev->ctrl_handler = &core->video_hdl; err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER, video_nr[core->nr]); if (err < 0) { @@ -2007,6 +1887,7 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev, dev->radio_dev = cx88_vdev_init(core,dev->pci, &cx8800_radio_template,"radio"); video_set_drvdata(dev->radio_dev, dev); + dev->radio_dev->ctrl_handler = &core->audio_hdl; err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO, radio_nr[core->nr]); if (err < 0) { diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index c9659def2a78..0cae0fd9e164 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h @@ -26,6 +26,7 @@ #include <linux/kdev_t.h> #include <media/v4l2-device.h> +#include <media/v4l2-fh.h> #include <media/tuner.h> #include <media/tveeprom.h> #include <media/videobuf-dma-sg.h> @@ -115,15 +116,6 @@ struct cx8800_fmt { u32 cxformat; }; -struct cx88_ctrl { - struct v4l2_queryctrl v; - u32 off; - u32 reg; - u32 sreg; - u32 mask; - u32 shift; -}; - /* ----------------------------------------------------------- */ /* SRAM memory management data (see cx88-core.c) */ @@ -359,6 +351,10 @@ struct cx88_core { /* config info -- analog */ struct v4l2_device v4l2_dev; + struct v4l2_ctrl_handler video_hdl; + struct v4l2_ctrl *chroma_agc; + struct v4l2_ctrl_handler audio_hdl; + struct v4l2_subdev *sd_wm8775; struct i2c_client *i2c_rtc; unsigned int boardnr; struct cx88_board board; @@ -409,8 +405,6 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) return container_of(v4l2_dev, struct cx88_core, v4l2_dev); } -#define WM8775_GID (1 << 0) - #define call_hw(core, grpid, o, f, args...) \ do { \ if (!core->i2c_rc) { \ @@ -424,6 +418,36 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev) #define call_all(core, o, f, args...) call_hw(core, 0, o, f, ##args) +#define WM8775_GID (1 << 0) + +#define wm8775_s_ctrl(core, id, val) \ + do { \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + v4l2_ctrl_s_ctrl(ctrl_, val); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + } while (0) + +#define wm8775_g_ctrl(core, id) \ + ({ \ + struct v4l2_ctrl *ctrl_ = \ + v4l2_ctrl_find(core->sd_wm8775->ctrl_handler, id); \ + s32 val = 0; \ + if (ctrl_ && !core->i2c_rc) { \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 1); \ + val = v4l2_ctrl_g_ctrl(ctrl_); \ + if (core->gate_ctrl) \ + core->gate_ctrl(core, 0); \ + } \ + val; \ + }) + struct cx8800_dev; struct cx8802_dev; @@ -431,19 +455,11 @@ struct cx8802_dev; /* function 0: video stuff */ struct cx8800_fh { + struct v4l2_fh fh; struct cx8800_dev *dev; - enum v4l2_buf_type type; - int radio; unsigned int resources; - /* video overlay */ - struct v4l2_window win; - struct v4l2_clip *clips; - unsigned int nclips; - /* video capture */ - const struct cx8800_fmt *fmt; - unsigned int width,height; struct videobuf_queue vidq; /* vbi capture */ @@ -468,6 +484,8 @@ struct cx8800_dev { struct pci_dev *pci; unsigned char pci_rev,pci_lat; + const struct cx8800_fmt *fmt; + unsigned int width, height; /* capture queues */ struct cx88_dmaqueue vidq; @@ -488,6 +506,7 @@ struct cx8800_dev { /* function 2: mpeg stuff */ struct cx8802_fh { + struct v4l2_fh fh; struct cx8802_dev *dev; struct videobuf_queue mpegq; }; @@ -552,7 +571,7 @@ struct cx8802_dev { unsigned char mpeg_active; /* nonzero if mpeg encoder is active */ /* mpeg params */ - struct cx2341x_mpeg_params params; + struct cx2341x_handler cxhdl; #endif #if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE) @@ -722,11 +741,8 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev); /* ----------------------------------------------------------- */ /* cx88-video.c*/ -extern const u32 cx88_user_ctrls[]; -extern int cx8800_ctrl_query(struct cx88_core *core, - struct v4l2_queryctrl *qctrl); int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i); int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f); -int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl); -int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl); int cx88_video_mux(struct cx88_core *core, unsigned int input); +void cx88_querycap(struct file *file, struct cx88_core *core, + struct v4l2_capability *cap); |