aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorPantelis Koukousoulas <pakt223@freemail.gr>2006-12-27 23:09:55 -0300
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-02-21 13:34:23 -0200
commitae2b9e25fdfb63efed3659b19c5cc8778fd981ba (patch)
treefbe27d954b42b17e9f663a95fc2433d897568f24 /drivers
parent99cfdf5cc6dbe0bd748d810953874d4e08051a9f (diff)
V4L/DVB (5039): Pvrusb2: Implement /dev/radioX
The "main" V4L2 interface patch. This is yet very incomplete, incorrect and probably inappropriate for inclusion as-is, but at least with this I 'm able to tune and play radio through a V4L2 program (pvr-radio.c, a "thumb" version of ivtv-radio.c with just the essentials). Therefore, it kinda gives an idea of what is needed to support this, hm, interface (partly used also by e.g., kradio). Please point out any mistakes on this code. I 'm sure I 'm messing up some struct initialization somewhere but currently I 'm too lazy to actually think this through until I complete the functionality (e.g., handle the VIDIOC_S_STD, ENUMINPUT, etc ioctls appropriately). Signed-off-by: Pantelis Koukousoulas <pakt223@freemail.gr> Signed-off-by: Mike Isely <isely@pobox.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c83
1 files changed, 76 insertions, 7 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 02a541fbeff..3cea6101e9f 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -32,6 +32,8 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-common.h>
+#define PVR2_NR_STREAMS 3
+
struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh;
struct pvr2_v4l2;
@@ -77,7 +79,7 @@ static struct v4l2_capability pvr_capability ={
.bus_info = "usb",
.version = KERNEL_VERSION(0,8,0),
.capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
V4L2_CAP_READWRITE),
.reserved = {0,0,0,0}
};
@@ -784,6 +786,18 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
pvr2_ioread_destroy(fhp->rhp);
fhp->rhp = NULL;
}
+
+ if (fhp->dev_info->config == pvr2_config_radio) {
+ int ret;
+ struct pvr2_hdw *hdw;
+ hdw = fhp->channel.mc_head->hdw;
+ if ((ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ PVR2_CVAL_INPUT_TV))) {
+ return ret;
+ }
+ }
+
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
@@ -845,6 +859,32 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_context_enter(vp->channel.mc_head); do {
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+
+ /* pk: warning, severe ugliness follows. 18+ only.
+ please blaim V4L(ivtv) for braindamaged interfaces,
+ not the implementor. This is probably flawed, but
+ suggestions on how to do this "right" are welcome! */
+ if (dip->config == pvr2_config_radio) {
+ int ret;
+ if ((pvr2_channel_check_stream_no_lock(&fhp->channel,
+ fhp->dev_info->stream)) != 0) {
+ /* We can 't switch modes while streaming */
+ pvr2_channel_done(&fhp->channel);
+ kfree(fhp);
+ pvr2_context_exit(vp->channel.mc_head);
+ return -EBUSY;
+ }
+
+ if ((ret = pvr2_ctrl_set_value(
+ pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
+ PVR2_CVAL_INPUT_RADIO))) {
+ pvr2_channel_done(&fhp->channel);
+ kfree(fhp);
+ pvr2_context_exit(vp->channel.mc_head);
+ return ret;
+ }
+ }
+
fhp->vnext = NULL;
fhp->vprev = vp->vlast;
if (vp->vlast) {
@@ -942,6 +982,12 @@ static ssize_t pvr2_v4l2_read(struct file *file,
return tcnt;
}
+ if (fh->dev_info->config == pvr2_config_radio) {
+ /* Radio device nodes on this device
+ cannot be read or written. */
+ return -EPERM;
+ }
+
if (!fh->rhp) {
ret = pvr2_v4l2_iosetup(fh);
if (ret) {
@@ -976,6 +1022,12 @@ static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
return mask;
}
+ if (fh->dev_info->config == pvr2_config_radio) {
+ /* Radio device nodes on this device
+ cannot be read or written. */
+ return -EPERM;
+ }
+
if (!fh->rhp) {
ret = pvr2_v4l2_iosetup(fh);
if (ret) return POLLERR;
@@ -1044,7 +1096,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return;
}
- if (!dip->stream) {
+ /* radio device doesn 't need its own stream */
+ if (!dip->stream && cfg != pvr2_config_radio) {
err("Failed to set up pvrusb2 v4l dev"
" due to missing stream instance");
return;
@@ -1060,10 +1113,25 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
}
if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
(video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
- err("Failed to register pvrusb2 v4l video device");
- } else {
+ err("Failed to register pvrusb2 v4l device");
+ }
+ switch (cfg) {
+ case pvr2_config_mpeg:
printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
dip->devbase.minor,pvr2_config_get_name(dip->config));
+ break;
+ case pvr2_config_vbi:
+ printk(KERN_INFO "pvrusb2: registered device vbi%d [%s]\n",
+ dip->devbase.minor - MINOR_VFL_TYPE_VBI_MIN,
+ pvr2_config_get_name(dip->config));
+ break;
+ case pvr2_config_radio:
+ printk(KERN_INFO "pvrusb2: registered device radio%d [%s]\n",
+ dip->devbase.minor - MINOR_VFL_TYPE_RADIO_MIN,
+ pvr2_config_get_name(dip->config));
+ break;
+ default:
+ break;
}
pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,
@@ -1078,19 +1146,20 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp = kmalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
memset(vp,0,sizeof(*vp));
- vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL);
+ vp->vdev = kmalloc(sizeof(*vp->vdev)*PVR2_NR_STREAMS,GFP_KERNEL);
if (!vp->vdev) {
kfree(vp);
return NULL;
}
- memset(vp->vdev,0,sizeof(*vp->vdev));
+ memset(vp->vdev,0,sizeof(*vp->vdev)*PVR2_NR_STREAMS);
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */
- pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(&vp->vdev[0],vp,pvr2_config_mpeg);
+ pvr2_v4l2_dev_init(&vp->vdev[2],vp,pvr2_config_radio);
return vp;
}