diff options
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 70 |
1 files changed, 57 insertions, 13 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 5e2292726e94..e878c6445ae2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -67,6 +67,10 @@ struct pvr2_v4l2 { | |||
67 | 67 | ||
68 | struct v4l2_prio_state prio; | 68 | struct v4l2_prio_state prio; |
69 | 69 | ||
70 | /* Map contiguous ordinal value to input id */ | ||
71 | unsigned char *input_map; | ||
72 | unsigned int input_cnt; | ||
73 | |||
70 | /* streams - Note that these must be separately, individually, | 74 | /* streams - Note that these must be separately, individually, |
71 | * allocated pointers. This is because the v4l core is going to | 75 | * allocated pointers. This is because the v4l core is going to |
72 | * manage their deletion - separately, individually... */ | 76 | * manage their deletion - separately, individually... */ |
@@ -259,13 +263,19 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
259 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 263 | struct v4l2_input *vi = (struct v4l2_input *)arg; |
260 | struct v4l2_input tmp; | 264 | struct v4l2_input tmp; |
261 | unsigned int cnt; | 265 | unsigned int cnt; |
266 | int val; | ||
262 | 267 | ||
263 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | 268 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); |
264 | 269 | ||
265 | memset(&tmp,0,sizeof(tmp)); | 270 | memset(&tmp,0,sizeof(tmp)); |
266 | tmp.index = vi->index; | 271 | tmp.index = vi->index; |
267 | ret = 0; | 272 | ret = 0; |
268 | switch (vi->index) { | 273 | if ((vi->index < 0) || (vi->index >= vp->input_cnt)) { |
274 | ret = -EINVAL; | ||
275 | break; | ||
276 | } | ||
277 | val = vp->input_map[vi->index]; | ||
278 | switch (val) { | ||
269 | case PVR2_CVAL_INPUT_TV: | 279 | case PVR2_CVAL_INPUT_TV: |
270 | case PVR2_CVAL_INPUT_DTV: | 280 | case PVR2_CVAL_INPUT_DTV: |
271 | case PVR2_CVAL_INPUT_RADIO: | 281 | case PVR2_CVAL_INPUT_RADIO: |
@@ -282,7 +292,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
282 | if (ret < 0) break; | 292 | if (ret < 0) break; |
283 | 293 | ||
284 | cnt = 0; | 294 | cnt = 0; |
285 | pvr2_ctrl_get_valname(cptr,vi->index, | 295 | pvr2_ctrl_get_valname(cptr,val, |
286 | tmp.name,sizeof(tmp.name)-1,&cnt); | 296 | tmp.name,sizeof(tmp.name)-1,&cnt); |
287 | tmp.name[cnt] = 0; | 297 | tmp.name[cnt] = 0; |
288 | 298 | ||
@@ -304,22 +314,33 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
304 | 314 | ||
305 | case VIDIOC_G_INPUT: | 315 | case VIDIOC_G_INPUT: |
306 | { | 316 | { |
317 | unsigned int idx; | ||
307 | struct pvr2_ctrl *cptr; | 318 | struct pvr2_ctrl *cptr; |
308 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 319 | struct v4l2_input *vi = (struct v4l2_input *)arg; |
309 | int val; | 320 | int val; |
310 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | 321 | cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); |
311 | val = 0; | 322 | val = 0; |
312 | ret = pvr2_ctrl_get_value(cptr,&val); | 323 | ret = pvr2_ctrl_get_value(cptr,&val); |
313 | vi->index = val; | 324 | vi->index = 0; |
325 | for (idx = 0; idx < vp->input_cnt; idx++) { | ||
326 | if (vp->input_map[idx] == val) { | ||
327 | vi->index = idx; | ||
328 | break; | ||
329 | } | ||
330 | } | ||
314 | break; | 331 | break; |
315 | } | 332 | } |
316 | 333 | ||
317 | case VIDIOC_S_INPUT: | 334 | case VIDIOC_S_INPUT: |
318 | { | 335 | { |
319 | struct v4l2_input *vi = (struct v4l2_input *)arg; | 336 | struct v4l2_input *vi = (struct v4l2_input *)arg; |
337 | if ((vi->index < 0) || (vi->index >= vp->input_cnt)) { | ||
338 | ret = -ERANGE; | ||
339 | break; | ||
340 | } | ||
320 | ret = pvr2_ctrl_set_value( | 341 | ret = pvr2_ctrl_set_value( |
321 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), | 342 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), |
322 | vi->index); | 343 | vp->input_map[vi->index]); |
323 | break; | 344 | break; |
324 | } | 345 | } |
325 | 346 | ||
@@ -818,6 +839,10 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) | |||
818 | pvr2_v4l2_dev_destroy(vp->dev_radio); | 839 | pvr2_v4l2_dev_destroy(vp->dev_radio); |
819 | vp->dev_radio = NULL; | 840 | vp->dev_radio = NULL; |
820 | } | 841 | } |
842 | if (vp->input_map) { | ||
843 | kfree(vp->input_map); | ||
844 | vp->input_map = NULL; | ||
845 | } | ||
821 | 846 | ||
822 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); | 847 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); |
823 | pvr2_channel_done(&vp->channel); | 848 | pvr2_channel_done(&vp->channel); |
@@ -1199,27 +1224,46 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | |||
1199 | struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) | 1224 | struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) |
1200 | { | 1225 | { |
1201 | struct pvr2_v4l2 *vp; | 1226 | struct pvr2_v4l2 *vp; |
1227 | struct pvr2_hdw *hdw; | ||
1228 | unsigned int input_mask,input_cnt,idx; | ||
1202 | 1229 | ||
1203 | vp = kzalloc(sizeof(*vp),GFP_KERNEL); | 1230 | vp = kzalloc(sizeof(*vp),GFP_KERNEL); |
1204 | if (!vp) return vp; | 1231 | if (!vp) return vp; |
1205 | vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL); | ||
1206 | vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL); | ||
1207 | if (!(vp->dev_video && vp->dev_radio)) { | ||
1208 | kfree(vp->dev_video); | ||
1209 | kfree(vp->dev_radio); | ||
1210 | kfree(vp); | ||
1211 | return NULL; | ||
1212 | } | ||
1213 | pvr2_channel_init(&vp->channel,mnp); | 1232 | pvr2_channel_init(&vp->channel,mnp); |
1214 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); | 1233 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); |
1215 | 1234 | ||
1216 | vp->channel.check_func = pvr2_v4l2_internal_check; | 1235 | vp->channel.check_func = pvr2_v4l2_internal_check; |
1217 | 1236 | ||
1237 | hdw = vp->channel.mc_head->hdw; | ||
1238 | input_mask = pvr2_hdw_get_input_available(hdw); | ||
1239 | input_cnt = 0; | ||
1240 | for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { | ||
1241 | if (input_mask & (1 << idx)) input_cnt++; | ||
1242 | } | ||
1243 | vp->input_cnt = input_cnt; | ||
1244 | vp->input_map = kzalloc(input_cnt,GFP_KERNEL); | ||
1245 | if (!vp->input_map) goto fail; | ||
1246 | input_cnt = 0; | ||
1247 | for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) { | ||
1248 | if (!(input_mask & (1 << idx))) continue; | ||
1249 | vp->input_map[input_cnt++] = idx; | ||
1250 | } | ||
1251 | |||
1218 | /* register streams */ | 1252 | /* register streams */ |
1253 | vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL); | ||
1254 | if (!vp->dev_video) goto fail; | ||
1219 | pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER); | 1255 | pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER); |
1220 | pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO); | 1256 | if (input_mask & (1 << PVR2_CVAL_INPUT_RADIO)) { |
1257 | vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL); | ||
1258 | if (!vp->dev_radio) goto fail; | ||
1259 | pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO); | ||
1260 | } | ||
1221 | 1261 | ||
1222 | return vp; | 1262 | return vp; |
1263 | fail: | ||
1264 | pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp); | ||
1265 | pvr2_v4l2_destroy_no_lock(vp); | ||
1266 | return 0; | ||
1223 | } | 1267 | } |
1224 | 1268 | ||
1225 | /* | 1269 | /* |