summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Isely <isely@pobox.com>2006-12-27 20:09:55 -0600
committerMike Isely <isely@pobox.com>2006-12-27 20:09:55 -0600
commit7ac7042e1d5a22709dfad7388e70d4d7a2cfd96b (patch)
treea85d4f5d8e82a5f6cc3f7c2d1dbf8f3c6cd4106a
parent7f98a4f1c403739faaf9a7c9feda8437215e8ae7 (diff)
downloadmediapointer-dvb-s2-7ac7042e1d5a22709dfad7388e70d4d7a2cfd96b.tar.gz
mediapointer-dvb-s2-7ac7042e1d5a22709dfad7388e70d4d7a2cfd96b.tar.bz2
pvrusb2: Implement /dev/radioX
From: Pantelis Koukousoulas <pakt223@freemail.gr> 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). --Pantelis Signed-off-by: Pantelis Koukousoulas <pakt223@freemail.gr> Signed-off-by: Mike Isely <isely@pobox.com>
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c83
1 files changed, 76 insertions, 7 deletions
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 37929d6e5..307e82054 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -33,6 +33,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;
@@ -78,7 +80,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}
};
@@ -800,6 +802,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;
@@ -861,6 +875,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) {
@@ -958,6 +998,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) {
@@ -992,6 +1038,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;
@@ -1066,7 +1118,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;
@@ -1089,10 +1142,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,
@@ -1107,19 +1175,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;
}