Commit beb0ecd7 authored by Mike Isely's avatar Mike Isely Committed by Mauro Carvalho Chehab

V4L/DVB (7300): pvrusb2: v4l2 implementation fixes for input selection

Now that the pvrusb2 driver can dynamically choose which inputs to
make available depending on the hardware, the enumeration of input
choices is no longer a contiguous range of integers.  Unfortunately
this causes a problem in the v4l2 implementation since the input
enumeration requires continuity in the API.  This change implements a
mapping in order to preserve the v4l2 interface requirement.
Signed-off-by: default avatarMike Isely <isely@pobox.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 7fb20fa3
......@@ -67,6 +67,10 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
/* Map contiguous ordinal value to input id */
unsigned char *input_map;
unsigned int input_cnt;
/* streams - Note that these must be separately, individually,
* allocated pointers. This is because the v4l core is going to
* manage their deletion - separately, individually... */
......@@ -259,13 +263,19 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_input *vi = (struct v4l2_input *)arg;
struct v4l2_input tmp;
unsigned int cnt;
int val;
cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
memset(&tmp,0,sizeof(tmp));
tmp.index = vi->index;
ret = 0;
switch (vi->index) {
if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
ret = -EINVAL;
break;
}
val = vp->input_map[vi->index];
switch (val) {
case PVR2_CVAL_INPUT_TV:
case PVR2_CVAL_INPUT_DTV:
case PVR2_CVAL_INPUT_RADIO:
......@@ -282,7 +292,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
if (ret < 0) break;
cnt = 0;
pvr2_ctrl_get_valname(cptr,vi->index,
pvr2_ctrl_get_valname(cptr,val,
tmp.name,sizeof(tmp.name)-1,&cnt);
tmp.name[cnt] = 0;
......@@ -304,22 +314,33 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_INPUT:
{
unsigned int idx;
struct pvr2_ctrl *cptr;
struct v4l2_input *vi = (struct v4l2_input *)arg;
int val;
cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
val = 0;
ret = pvr2_ctrl_get_value(cptr,&val);
vi->index = val;
vi->index = 0;
for (idx = 0; idx < vp->input_cnt; idx++) {
if (vp->input_map[idx] == val) {
vi->index = idx;
break;
}
}
break;
}
case VIDIOC_S_INPUT:
{
struct v4l2_input *vi = (struct v4l2_input *)arg;
if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
ret = -ERANGE;
break;
}
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
vi->index);
vp->input_map[vi->index]);
break;
}
......@@ -818,6 +839,10 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
pvr2_v4l2_dev_destroy(vp->dev_radio);
vp->dev_radio = NULL;
}
if (vp->input_map) {
kfree(vp->input_map);
vp->input_map = NULL;
}
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
......@@ -1199,27 +1224,46 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
struct pvr2_hdw *hdw;
unsigned int input_mask,input_cnt,idx;
vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
if (!(vp->dev_video && vp->dev_radio)) {
kfree(vp->dev_video);
kfree(vp->dev_radio);
kfree(vp);
return NULL;
}
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;
hdw = vp->channel.mc_head->hdw;
input_mask = pvr2_hdw_get_input_available(hdw);
input_cnt = 0;
for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
if (input_mask & (1 << idx)) input_cnt++;
}
vp->input_cnt = input_cnt;
vp->input_map = kzalloc(input_cnt,GFP_KERNEL);
if (!vp->input_map) goto fail;
input_cnt = 0;
for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
if (!(input_mask & (1 << idx))) continue;
vp->input_map[input_cnt++] = idx;
}
/* register streams */
vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
if (!vp->dev_video) goto fail;
pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
if (input_mask & (1 << PVR2_CVAL_INPUT_RADIO)) {
vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
if (!vp->dev_radio) goto fail;
pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
}
return vp;
fail:
pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
pvr2_v4l2_destroy_no_lock(vp);
return 0;
}
/*
......
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