diff options
Diffstat (limited to 'drivers/media/usb/usbvision/usbvision-video.c')
-rw-r--r-- | drivers/media/usb/usbvision/usbvision-video.c | 246 |
1 files changed, 87 insertions, 159 deletions
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c index 1c6d31f7c1b9..b693206f66dd 100644 --- a/drivers/media/usb/usbvision/usbvision-video.c +++ b/drivers/media/usb/usbvision/usbvision-video.c @@ -62,6 +62,7 @@ #include <media/saa7115.h> #include <media/v4l2-common.h> #include <media/v4l2-ioctl.h> +#include <media/v4l2-event.h> #include <media/tuner.h> #include <linux/workqueue.h> @@ -122,8 +123,6 @@ static void usbvision_release(struct usb_usbvision *usbvision); static int isoc_mode = ISOC_MODE_COMPRESS; /* Set the default Debug Mode of the device driver */ static int video_debug; -/* Set the default device to power on at startup */ -static int power_on_at_open = 1; /* Sequential Number of Video Device */ static int video_nr = -1; /* Sequential Number of Radio Device */ @@ -134,13 +133,11 @@ static int radio_nr = -1; /* Showing parameters under SYSFS */ module_param(isoc_mode, int, 0444); module_param(video_debug, int, 0444); -module_param(power_on_at_open, int, 0444); module_param(video_nr, int, 0444); module_param(radio_nr, int, 0444); MODULE_PARM_DESC(isoc_mode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)"); MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)"); -MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)"); MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)"); MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)"); @@ -351,11 +348,14 @@ static int usbvision_v4l2_open(struct file *file) if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; - usbvision_reset_power_off_timer(usbvision); - if (usbvision->user) + if (usbvision->user) { err_code = -EBUSY; - else { + } else { + err_code = v4l2_fh_open(file); + if (err_code) + goto unlock; + /* Allocate memory for the scratch ring buffer */ err_code = usbvision_scratch_alloc(usbvision); if (isoc_mode == ISOC_MODE_COMPRESS) { @@ -372,11 +372,6 @@ static int usbvision_v4l2_open(struct file *file) /* If so far no errors then we shall start the camera */ if (!err_code) { - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } - /* Send init sequence only once, it's large! */ if (!usbvision->initialized) { int setup_ok = 0; @@ -392,18 +387,14 @@ static int usbvision_v4l2_open(struct file *file) err_code = usbvision_init_isoc(usbvision); /* device must be initialized before isoc transfer */ usbvision_muxsel(usbvision, 0); + + /* prepare queues */ + usbvision_empty_framequeues(usbvision); usbvision->user++; - } else { - if (power_on_at_open) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } } } - /* prepare queues */ - usbvision_empty_framequeues(usbvision); +unlock: mutex_unlock(&usbvision->v4l2_lock); PDEBUG(DBG_IO, "success"); @@ -435,23 +426,16 @@ static int usbvision_v4l2_close(struct file *file) usbvision_scratch_free(usbvision); usbvision->user--; - - if (power_on_at_open) { - /* power off in a little while - to avoid off/on every close/open short sequences */ - usbvision_set_power_off_timer(usbvision); - usbvision->initialized = 0; - } + mutex_unlock(&usbvision->v4l2_lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); return 0; } - mutex_unlock(&usbvision->v4l2_lock); PDEBUG(DBG_IO, "success"); - return 0; + return v4l2_fh_release(file); } @@ -503,18 +487,24 @@ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *vc) { struct usb_usbvision *usbvision = video_drvdata(file); + struct video_device *vdev = video_devdata(file); strlcpy(vc->driver, "USBVision", sizeof(vc->driver)); strlcpy(vc->card, usbvision_device_data[usbvision->dev_model].model_string, sizeof(vc->card)); usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info)); - vc->device_caps = V4L2_CAP_VIDEO_CAPTURE | - V4L2_CAP_AUDIO | - V4L2_CAP_READWRITE | - V4L2_CAP_STREAMING | - (usbvision->have_tuner ? V4L2_CAP_TUNER : 0); - vc->capabilities = vc->device_caps | V4L2_CAP_DEVICE_CAPS; + vc->device_caps = usbvision->have_tuner ? V4L2_CAP_TUNER : 0; + if (vdev->vfl_type == VFL_TYPE_GRABBER) + vc->device_caps |= V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING; + else + vc->device_caps |= V4L2_CAP_RADIO; + + vc->capabilities = vc->device_caps | V4L2_CAP_VIDEO_CAPTURE | + V4L2_CAP_READWRITE | V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS; + if (usbvision_device_data[usbvision->dev_model].radio) + vc->capabilities |= V4L2_CAP_RADIO; return 0; } @@ -540,7 +530,6 @@ static int vidioc_enum_input(struct file *file, void *priv, } else { strcpy(vi->name, "Television"); vi->type = V4L2_INPUT_TYPE_TUNER; - vi->audioset = 1; vi->tuner = chan; vi->std = USBVISION_NORMS; } @@ -551,7 +540,7 @@ static int vidioc_enum_input(struct file *file, void *priv, strcpy(vi->name, "Green Video Input"); else strcpy(vi->name, "Composite Video Input"); - vi->std = V4L2_STD_PAL; + vi->std = USBVISION_NORMS; break; case 2: vi->type = V4L2_INPUT_TYPE_CAMERA; @@ -559,12 +548,12 @@ static int vidioc_enum_input(struct file *file, void *priv, strcpy(vi->name, "Yellow Video Input"); else strcpy(vi->name, "S-Video Input"); - vi->std = V4L2_STD_PAL; + vi->std = USBVISION_NORMS; break; case 3: vi->type = V4L2_INPUT_TYPE_CAMERA; strcpy(vi->name, "Red Video Input"); - vi->std = V4L2_STD_PAL; + vi->std = USBVISION_NORMS; break; } return 0; @@ -619,14 +608,13 @@ static int vidioc_g_tuner(struct file *file, void *priv, { struct usb_usbvision *usbvision = video_drvdata(file); - if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */ + if (vt->index) /* Only tuner 0 */ return -EINVAL; - if (usbvision->radio) { + if (vt->type == V4L2_TUNER_RADIO) strcpy(vt->name, "Radio"); - vt->type = V4L2_TUNER_RADIO; - } else { + else strcpy(vt->name, "Television"); - } + /* Let clients fill in the remainder of this struct */ call_all(usbvision, tuner, g_tuner, vt); @@ -638,8 +626,8 @@ static int vidioc_s_tuner(struct file *file, void *priv, { struct usb_usbvision *usbvision = video_drvdata(file); - /* Only no or one tuner for now */ - if (!usbvision->have_tuner || vt->index) + /* Only one tuner for now */ + if (vt->index) return -EINVAL; /* let clients handle this */ call_all(usbvision, tuner, s_tuner, vt); @@ -652,12 +640,13 @@ static int vidioc_g_frequency(struct file *file, void *priv, { struct usb_usbvision *usbvision = video_drvdata(file); - freq->tuner = 0; /* Only one tuner */ - if (usbvision->radio) - freq->type = V4L2_TUNER_RADIO; + /* Only one tuner */ + if (freq->tuner) + return -EINVAL; + if (freq->type == V4L2_TUNER_RADIO) + freq->frequency = usbvision->radio_freq; else - freq->type = V4L2_TUNER_ANALOG_TV; - freq->frequency = usbvision->freq; + freq->frequency = usbvision->tv_freq; return 0; } @@ -666,65 +655,19 @@ static int vidioc_s_frequency(struct file *file, void *priv, const struct v4l2_frequency *freq) { struct usb_usbvision *usbvision = video_drvdata(file); + struct v4l2_frequency new_freq = *freq; - /* Only no or one tuner for now */ - if (!usbvision->have_tuner || freq->tuner) + /* Only one tuner for now */ + if (freq->tuner) return -EINVAL; - usbvision->freq = freq->frequency; call_all(usbvision, tuner, s_frequency, freq); - - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - if (usbvision->radio) - strcpy(a->name, "Radio"); + call_all(usbvision, tuner, g_frequency, &new_freq); + if (freq->type == V4L2_TUNER_RADIO) + usbvision->radio_freq = new_freq.frequency; else - strcpy(a->name, "TV"); - - return 0; -} + usbvision->tv_freq = new_freq.frequency; -static int vidioc_s_audio(struct file *file, void *fh, - const struct v4l2_audio *a) -{ - if (a->index) - return -EINVAL; - return 0; -} - -static int vidioc_queryctrl(struct file *file, void *priv, - struct v4l2_queryctrl *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, queryctrl, ctrl); - - if (!ctrl->type) - return -EINVAL; - - return 0; -} - -static int vidioc_g_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, g_ctrl, ctrl); - return 0; -} - -static int vidioc_s_ctrl(struct file *file, void *priv, - struct v4l2_control *ctrl) -{ - struct usb_usbvision *usbvision = video_drvdata(file); - - call_all(usbvision, core, s_ctrl, ctrl); return 0; } @@ -937,6 +880,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, vf->fmt.pix.bytesperline = vf->fmt.pix.width* usbvision->palette.bytes_per_pixel; vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; + vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; + vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ return 0; } @@ -1167,20 +1112,15 @@ static int usbvision_radio_open(struct file *file) if (mutex_lock_interruptible(&usbvision->v4l2_lock)) return -ERESTARTSYS; + err_code = v4l2_fh_open(file); + if (err_code) + goto out; if (usbvision->user) { dev_err(&usbvision->rdev.dev, "%s: Someone tried to open an already opened USBVision Radio!\n", __func__); err_code = -EBUSY; } else { - if (power_on_at_open) { - usbvision_reset_power_off_timer(usbvision); - if (usbvision->power == 0) { - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } - } - /* Alternate interface 1 is is the biggest frame size */ err_code = usbvision_set_alternate(usbvision); if (err_code < 0) { @@ -1195,14 +1135,6 @@ static int usbvision_radio_open(struct file *file) usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); usbvision->user++; } - - if (err_code) { - if (power_on_at_open) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - usbvision->initialized = 0; - } - } out: mutex_unlock(&usbvision->v4l2_lock); return err_code; @@ -1212,34 +1144,29 @@ out: static int usbvision_radio_close(struct file *file) { struct usb_usbvision *usbvision = video_drvdata(file); - int err_code = 0; PDEBUG(DBG_IO, ""); mutex_lock(&usbvision->v4l2_lock); /* Set packet size to 0 */ usbvision->iface_alt = 0; - err_code = usb_set_interface(usbvision->dev, usbvision->iface, + usb_set_interface(usbvision->dev, usbvision->iface, usbvision->iface_alt); usbvision_audio_off(usbvision); usbvision->radio = 0; usbvision->user--; - if (power_on_at_open) { - usbvision_set_power_off_timer(usbvision); - usbvision->initialized = 0; - } - if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __func__); + v4l2_fh_release(file); usbvision_release(usbvision); - return err_code; + return 0; } mutex_unlock(&usbvision->v4l2_lock); PDEBUG(DBG_IO, "success"); - return err_code; + return v4l2_fh_release(file); } /* Video registration stuff */ @@ -1252,7 +1179,6 @@ static const struct v4l2_file_operations usbvision_fops = { .read = usbvision_v4l2_read, .mmap = usbvision_v4l2_mmap, .unlocked_ioctl = video_ioctl2, -/* .poll = video_poll, */ }; static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { @@ -1270,17 +1196,15 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .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_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, #ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register, @@ -1301,23 +1225,19 @@ static const struct v4l2_file_operations usbvision_radio_fops = { .owner = THIS_MODULE, .open = usbvision_radio_open, .release = usbvision_radio_close, + .poll = v4l2_ctrl_poll, .unlocked_ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, - .vidioc_enum_input = vidioc_enum_input, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, .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_log_status = v4l2_ctrl_log_status, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; static struct video_device usbvision_radio_template = { @@ -1369,9 +1289,17 @@ static void usbvision_unregister_video(struct usb_usbvision *usbvision) /* register video4linux devices */ static int usbvision_register_video(struct usb_usbvision *usbvision) { + int res = -ENOMEM; + /* Video Device: */ usbvision_vdev_init(usbvision, &usbvision->vdev, &usbvision_video_template, "USBVision Video"); + if (!usbvision->have_tuner) { + v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_S_TUNER); + v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_G_FREQUENCY); + v4l2_disable_ioctl(&usbvision->vdev, VIDIOC_S_TUNER); + } if (video_register_device(&usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0) goto err_exit; printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n", @@ -1395,7 +1323,7 @@ static int usbvision_register_video(struct usb_usbvision *usbvision) "USBVision[%d]: video_register_device() failed\n", usbvision->nr); usbvision_unregister_video(usbvision); - return -1; + return res; } /* @@ -1420,6 +1348,9 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev, if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev)) goto err_free; + if (v4l2_ctrl_handler_init(&usbvision->hdl, 4)) + goto err_unreg; + usbvision->v4l2_dev.ctrl_handler = &usbvision->hdl; mutex_init(&usbvision->v4l2_lock); /* prepare control urb for control messages during interrupts */ @@ -1428,11 +1359,10 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev, goto err_unreg; init_waitqueue_head(&usbvision->ctrl_urb_wq); - usbvision_init_power_off_timer(usbvision); - return usbvision; err_unreg: + v4l2_ctrl_handler_free(&usbvision->hdl); v4l2_device_unregister(&usbvision->v4l2_dev); err_free: kfree(usbvision); @@ -1450,8 +1380,6 @@ static void usbvision_release(struct usb_usbvision *usbvision) { PDEBUG(DBG_PROBE, ""); - usbvision_reset_power_off_timer(usbvision); - usbvision->initialized = 0; usbvision_remove_sysfs(&usbvision->vdev); @@ -1460,6 +1388,7 @@ static void usbvision_release(struct usb_usbvision *usbvision) usb_free_urb(usbvision->ctrl_urb); + v4l2_ctrl_handler_free(&usbvision->hdl); v4l2_device_unregister(&usbvision->v4l2_dev); kfree(usbvision); @@ -1487,19 +1416,18 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision) } usbvision->tvnorm_id = usbvision_device_data[model].video_norm; - usbvision->video_inputs = usbvision_device_data[model].video_channels; usbvision->ctl_input = 0; + usbvision->radio_freq = 87.5 * 16000; + usbvision->tv_freq = 400 * 16; /* This should be here to make i2c clients to be able to register */ /* first switch off audio */ if (usbvision_device_data[model].audio_channels > 0) usbvision_audio_off(usbvision); - if (!power_on_at_open) { - /* and then power up the noisy tuner */ - usbvision_power_on(usbvision); - usbvision_i2c_register(usbvision); - } + /* and then power up the tuner */ + usbvision_power_on(usbvision); + usbvision_i2c_register(usbvision); } /* @@ -1592,6 +1520,10 @@ static int usbvision_probe(struct usb_interface *intf, usbvision->nr = usbvision_nr++; + spin_lock_init(&usbvision->queue_lock); + init_waitqueue_head(&usbvision->wait_frame); + init_waitqueue_head(&usbvision->wait_stream); + usbvision->have_tuner = usbvision_device_data[model].tuner; if (usbvision->have_tuner) usbvision->tuner_type = usbvision_device_data[model].tuner_type; @@ -1646,11 +1578,7 @@ static void usbvision_disconnect(struct usb_interface *intf) usbvision_stop_isoc(usbvision); v4l2_device_disconnect(&usbvision->v4l2_dev); - - if (usbvision->power) { - usbvision_i2c_unregister(usbvision); - usbvision_power_off(usbvision); - } + usbvision_i2c_unregister(usbvision); usbvision->remove_pending = 1; /* Now all ISO data will be ignored */ usb_put_dev(usbvision->dev); |