Commit ae2b9e25 authored by Pantelis Koukousoulas's avatar Pantelis Koukousoulas Committed by Mauro Carvalho Chehab

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: default avatarPantelis Koukousoulas <pakt223@freemail.gr>
Signed-off-by: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 99cfdf5c
...@@ -32,6 +32,8 @@ ...@@ -32,6 +32,8 @@
#include <media/v4l2-dev.h> #include <media/v4l2-dev.h>
#include <media/v4l2-common.h> #include <media/v4l2-common.h>
#define PVR2_NR_STREAMS 3
struct pvr2_v4l2_dev; struct pvr2_v4l2_dev;
struct pvr2_v4l2_fh; struct pvr2_v4l2_fh;
struct pvr2_v4l2; struct pvr2_v4l2;
...@@ -77,7 +79,7 @@ static struct v4l2_capability pvr_capability ={ ...@@ -77,7 +79,7 @@ static struct v4l2_capability pvr_capability ={
.bus_info = "usb", .bus_info = "usb",
.version = KERNEL_VERSION(0,8,0), .version = KERNEL_VERSION(0,8,0),
.capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | .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), V4L2_CAP_READWRITE),
.reserved = {0,0,0,0} .reserved = {0,0,0,0}
}; };
...@@ -784,6 +786,18 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file) ...@@ -784,6 +786,18 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
pvr2_ioread_destroy(fhp->rhp); pvr2_ioread_destroy(fhp->rhp);
fhp->rhp = NULL; 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); v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL; file->private_data = NULL;
...@@ -845,6 +859,32 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) ...@@ -845,6 +859,32 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
pvr2_context_enter(vp->channel.mc_head); do { pvr2_context_enter(vp->channel.mc_head); do {
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
pvr2_channel_init(&fhp->channel,vp->channel.mc_head); 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->vnext = NULL;
fhp->vprev = vp->vlast; fhp->vprev = vp->vlast;
if (vp->vlast) { if (vp->vlast) {
...@@ -942,6 +982,12 @@ static ssize_t pvr2_v4l2_read(struct file *file, ...@@ -942,6 +982,12 @@ static ssize_t pvr2_v4l2_read(struct file *file,
return tcnt; 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) { if (!fh->rhp) {
ret = pvr2_v4l2_iosetup(fh); ret = pvr2_v4l2_iosetup(fh);
if (ret) { if (ret) {
...@@ -976,6 +1022,12 @@ static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait) ...@@ -976,6 +1022,12 @@ static unsigned int pvr2_v4l2_poll(struct file *file, poll_table *wait)
return mask; 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) { if (!fh->rhp) {
ret = pvr2_v4l2_iosetup(fh); ret = pvr2_v4l2_iosetup(fh);
if (ret) return POLLERR; if (ret) return POLLERR;
...@@ -1044,7 +1096,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, ...@@ -1044,7 +1096,8 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
return; 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" err("Failed to set up pvrusb2 v4l dev"
" due to missing stream instance"); " due to missing stream instance");
return; return;
...@@ -1060,10 +1113,25 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, ...@@ -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) && if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) &&
(video_register_device(&dip->devbase, v4l_type, -1) < 0)) { (video_register_device(&dip->devbase, v4l_type, -1) < 0)) {
err("Failed to register pvrusb2 v4l video device"); err("Failed to register pvrusb2 v4l device");
} else { }
switch (cfg) {
case pvr2_config_mpeg:
printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n", printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n",
dip->devbase.minor,pvr2_config_get_name(dip->config)); 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, 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) ...@@ -1078,19 +1146,20 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
vp = kmalloc(sizeof(*vp),GFP_KERNEL); vp = kmalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp; if (!vp) return vp;
memset(vp,0,sizeof(*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) { if (!vp->vdev) {
kfree(vp); kfree(vp);
return NULL; 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_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check; vp->channel.check_func = pvr2_v4l2_internal_check;
/* register streams */ /* 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; return vp;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment