diff options
author | Mike Isely <isely@pobox.com> | 2008-04-21 02:47:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:09:49 -0400 |
commit | 1cb03b76d09d20accfa5c1664c16ba6566f539a0 (patch) | |
tree | 8c58f23151ab54f71472b80f6d0d29df25ddbb9f | |
parent | d3f8d8fb304a8b9a81eae16ff7b50f5379f2437e (diff) |
V4L/DVB (7719): pvrusb2: Implement input selection enforcement
In the pvrusb2 driver, different interfaces (e.g. V4L, DVB) have
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-context.c | 69 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-context.h | 3 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-dvb.c | 47 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | 4 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.c | 132 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-hdw.h | 13 | ||||
-rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 52 |
7 files changed, 246 insertions, 74 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c index a2ce022c515a..b5db6a5bab31 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.c +++ b/drivers/media/video/pvrusb2/pvrusb2-context.c | |||
@@ -245,6 +245,22 @@ struct pvr2_context *pvr2_context_create( | |||
245 | } | 245 | } |
246 | 246 | ||
247 | 247 | ||
248 | static void pvr2_context_reset_input_limits(struct pvr2_context *mp) | ||
249 | { | ||
250 | unsigned int tmsk,mmsk; | ||
251 | struct pvr2_channel *cp; | ||
252 | struct pvr2_hdw *hdw = mp->hdw; | ||
253 | mmsk = pvr2_hdw_get_input_available(hdw); | ||
254 | tmsk = mmsk; | ||
255 | for (cp = mp->mc_first; cp; cp = cp->mc_next) { | ||
256 | if (!cp->input_mask) continue; | ||
257 | tmsk &= cp->input_mask; | ||
258 | } | ||
259 | pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk); | ||
260 | pvr2_hdw_commit_ctl(hdw); | ||
261 | } | ||
262 | |||
263 | |||
248 | static void pvr2_context_enter(struct pvr2_context *mp) | 264 | static void pvr2_context_enter(struct pvr2_context *mp) |
249 | { | 265 | { |
250 | mutex_lock(&mp->mutex); | 266 | mutex_lock(&mp->mutex); |
@@ -300,7 +316,9 @@ void pvr2_channel_done(struct pvr2_channel *cp) | |||
300 | { | 316 | { |
301 | struct pvr2_context *mp = cp->mc_head; | 317 | struct pvr2_context *mp = cp->mc_head; |
302 | pvr2_context_enter(mp); | 318 | pvr2_context_enter(mp); |
319 | cp->input_mask = 0; | ||
303 | pvr2_channel_disclaim_stream(cp); | 320 | pvr2_channel_disclaim_stream(cp); |
321 | pvr2_context_reset_input_limits(mp); | ||
304 | if (cp->mc_next) { | 322 | if (cp->mc_next) { |
305 | cp->mc_next->mc_prev = cp->mc_prev; | 323 | cp->mc_next->mc_prev = cp->mc_prev; |
306 | } else { | 324 | } else { |
@@ -316,6 +334,57 @@ void pvr2_channel_done(struct pvr2_channel *cp) | |||
316 | } | 334 | } |
317 | 335 | ||
318 | 336 | ||
337 | int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk) | ||
338 | { | ||
339 | unsigned int tmsk,mmsk; | ||
340 | int ret = 0; | ||
341 | struct pvr2_channel *p2; | ||
342 | struct pvr2_hdw *hdw = cp->hdw; | ||
343 | |||
344 | mmsk = pvr2_hdw_get_input_available(hdw); | ||
345 | cmsk &= mmsk; | ||
346 | if (cmsk == cp->input_mask) { | ||
347 | /* No change; nothing to do */ | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | pvr2_context_enter(cp->mc_head); | ||
352 | do { | ||
353 | if (!cmsk) { | ||
354 | cp->input_mask = 0; | ||
355 | pvr2_context_reset_input_limits(cp->mc_head); | ||
356 | break; | ||
357 | } | ||
358 | tmsk = mmsk; | ||
359 | for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) { | ||
360 | if (p2 == cp) continue; | ||
361 | if (!p2->input_mask) continue; | ||
362 | tmsk &= p2->input_mask; | ||
363 | } | ||
364 | if (!(tmsk & cmsk)) { | ||
365 | ret = -EPERM; | ||
366 | break; | ||
367 | } | ||
368 | tmsk &= cmsk; | ||
369 | if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) { | ||
370 | /* Internal failure changing allowed list; probably | ||
371 | should not happen, but react if it does. */ | ||
372 | break; | ||
373 | } | ||
374 | cp->input_mask = cmsk; | ||
375 | pvr2_hdw_commit_ctl(hdw); | ||
376 | } while (0); | ||
377 | pvr2_context_exit(cp->mc_head); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | |||
382 | unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp) | ||
383 | { | ||
384 | return cp->input_mask; | ||
385 | } | ||
386 | |||
387 | |||
319 | int pvr2_channel_claim_stream(struct pvr2_channel *cp, | 388 | int pvr2_channel_claim_stream(struct pvr2_channel *cp, |
320 | struct pvr2_context_stream *sp) | 389 | struct pvr2_context_stream *sp) |
321 | { | 390 | { |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h index 6fb6ab022851..745e270233c2 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-context.h +++ b/drivers/media/video/pvrusb2/pvrusb2-context.h | |||
@@ -62,6 +62,7 @@ struct pvr2_channel { | |||
62 | struct pvr2_channel *mc_prev; | 62 | struct pvr2_channel *mc_prev; |
63 | struct pvr2_context_stream *stream; | 63 | struct pvr2_context_stream *stream; |
64 | struct pvr2_hdw *hdw; | 64 | struct pvr2_hdw *hdw; |
65 | unsigned int input_mask; | ||
65 | void (*check_func)(struct pvr2_channel *); | 66 | void (*check_func)(struct pvr2_channel *); |
66 | }; | 67 | }; |
67 | 68 | ||
@@ -72,6 +73,8 @@ void pvr2_context_disconnect(struct pvr2_context *); | |||
72 | 73 | ||
73 | void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *); | 74 | void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *); |
74 | void pvr2_channel_done(struct pvr2_channel *); | 75 | void pvr2_channel_done(struct pvr2_channel *); |
76 | int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int); | ||
77 | unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *); | ||
75 | int pvr2_channel_claim_stream(struct pvr2_channel *, | 78 | int pvr2_channel_claim_stream(struct pvr2_channel *, |
76 | struct pvr2_context_stream *); | 79 | struct pvr2_context_stream *); |
77 | struct pvr2_ioread *pvr2_channel_create_mpeg_stream( | 80 | struct pvr2_ioread *pvr2_channel_create_mpeg_stream( |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c index c20eef0f077e..2e64f98d1241 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-dvb.c +++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c | |||
@@ -244,13 +244,10 @@ static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
244 | 244 | ||
245 | static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) | 245 | static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire) |
246 | { | 246 | { |
247 | /* TO DO: This function will call into the core and request for | 247 | struct pvr2_dvb_adapter *adap = fe->dvb->priv; |
248 | * input to be set to 'dtv' if (acquire) and if it isn't set already. | 248 | return pvr2_channel_limit_inputs( |
249 | * | 249 | &adap->channel, |
250 | * If (!acquire) then we should do nothing -- don't switch inputs | 250 | (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0)); |
251 | * again unless the analog side of the driver requests the bus. | ||
252 | */ | ||
253 | return 0; | ||
254 | } | 251 | } |
255 | 252 | ||
256 | static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) | 253 | static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap) |
@@ -320,32 +317,26 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) | |||
320 | { | 317 | { |
321 | struct pvr2_hdw *hdw = adap->channel.hdw; | 318 | struct pvr2_hdw *hdw = adap->channel.hdw; |
322 | struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; | 319 | struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props; |
323 | int ret; | 320 | int ret = 0; |
324 | 321 | ||
325 | if (dvb_props == NULL) { | 322 | if (dvb_props == NULL) { |
326 | err("fe_props not defined!"); | 323 | err("fe_props not defined!"); |
327 | return -EINVAL; | 324 | return -EINVAL; |
328 | } | 325 | } |
329 | 326 | ||
330 | /* FIXME: This code should be moved into the core, | 327 | ret = pvr2_channel_limit_inputs( |
331 | * and should only be called if we don't already have | 328 | &adap->channel, |
332 | * control of the bus. | 329 | (1 << PVR2_CVAL_INPUT_DTV)); |
333 | * | 330 | if (ret) { |
334 | * We can't call "pvr2_dvb_bus_ctrl(adap->fe, 1)" from here, | 331 | err("failed to grab control of dtv input (code=%d)", |
335 | * because adap->fe isn't defined yet. | 332 | ret); |
336 | */ | ||
337 | ret = pvr2_ctrl_set_value(pvr2_hdw_get_ctrl_by_id(hdw, | ||
338 | PVR2_CID_INPUT), | ||
339 | PVR2_CVAL_INPUT_DTV); | ||
340 | if (ret != 0) | ||
341 | return ret; | 333 | return ret; |
342 | 334 | } | |
343 | pvr2_hdw_commit_ctl(hdw); | ||
344 | |||
345 | 335 | ||
346 | if (dvb_props->frontend_attach == NULL) { | 336 | if (dvb_props->frontend_attach == NULL) { |
347 | err("frontend_attach not defined!"); | 337 | err("frontend_attach not defined!"); |
348 | return -EINVAL; | 338 | ret = -EINVAL; |
339 | goto done; | ||
349 | } | 340 | } |
350 | 341 | ||
351 | if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { | 342 | if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) { |
@@ -354,7 +345,8 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) | |||
354 | err("frontend registration failed!"); | 345 | err("frontend registration failed!"); |
355 | dvb_frontend_detach(adap->fe); | 346 | dvb_frontend_detach(adap->fe); |
356 | adap->fe = NULL; | 347 | adap->fe = NULL; |
357 | return -ENODEV; | 348 | ret = -ENODEV; |
349 | goto done; | ||
358 | } | 350 | } |
359 | 351 | ||
360 | if (dvb_props->tuner_attach) | 352 | if (dvb_props->tuner_attach) |
@@ -368,10 +360,13 @@ static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap) | |||
368 | 360 | ||
369 | } else { | 361 | } else { |
370 | err("no frontend was attached!"); | 362 | err("no frontend was attached!"); |
371 | return -ENODEV; | 363 | ret = -ENODEV; |
364 | return ret; | ||
372 | } | 365 | } |
373 | 366 | ||
374 | return 0; | 367 | done: |
368 | pvr2_channel_limit_inputs(&adap->channel, 0); | ||
369 | return ret; | ||
375 | } | 370 | } |
376 | 371 | ||
377 | static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) | 372 | static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap) |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h index a67dcf84b596..a3fe251d6fd9 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h | |||
@@ -336,8 +336,10 @@ struct pvr2_hdw { | |||
336 | int v4l_minor_number_vbi; | 336 | int v4l_minor_number_vbi; |
337 | int v4l_minor_number_radio; | 337 | int v4l_minor_number_radio; |
338 | 338 | ||
339 | /* Bit mask of PVR2_CVAL_INPUT choices which are valid */ | 339 | /* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */ |
340 | unsigned int input_avail_mask; | 340 | unsigned int input_avail_mask; |
341 | /* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */ | ||
342 | unsigned int input_allowed_mask; | ||
341 | 343 | ||
342 | /* Location of eeprom or a negative number if none */ | 344 | /* Location of eeprom or a negative number if none */ |
343 | int eeprom_addr; | 345 | int eeprom_addr; |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c index 63d0af759ed8..72e9056557bd 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c | |||
@@ -249,6 +249,7 @@ static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = { | |||
249 | }; | 249 | }; |
250 | 250 | ||
251 | 251 | ||
252 | static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v); | ||
252 | static void pvr2_hdw_state_sched(struct pvr2_hdw *); | 253 | static void pvr2_hdw_state_sched(struct pvr2_hdw *); |
253 | static int pvr2_hdw_state_eval(struct pvr2_hdw *); | 254 | static int pvr2_hdw_state_eval(struct pvr2_hdw *); |
254 | static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); | 255 | static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long); |
@@ -404,30 +405,12 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp) | |||
404 | 405 | ||
405 | static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) | 406 | static int ctrl_check_input(struct pvr2_ctrl *cptr,int v) |
406 | { | 407 | { |
407 | return ((1 << v) & cptr->hdw->input_avail_mask) != 0; | 408 | return ((1 << v) & cptr->hdw->input_allowed_mask) != 0; |
408 | } | 409 | } |
409 | 410 | ||
410 | static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) | 411 | static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v) |
411 | { | 412 | { |
412 | struct pvr2_hdw *hdw = cptr->hdw; | 413 | return pvr2_hdw_set_input(cptr->hdw,v); |
413 | |||
414 | if (hdw->input_val != v) { | ||
415 | hdw->input_val = v; | ||
416 | hdw->input_dirty = !0; | ||
417 | } | ||
418 | |||
419 | /* Handle side effects - if we switch to a mode that needs the RF | ||
420 | tuner, then select the right frequency choice as well and mark | ||
421 | it dirty. */ | ||
422 | if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { | ||
423 | hdw->freqSelector = 0; | ||
424 | hdw->freqDirty = !0; | ||
425 | } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || | ||
426 | (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { | ||
427 | hdw->freqSelector = 1; | ||
428 | hdw->freqDirty = !0; | ||
429 | } | ||
430 | return 0; | ||
431 | } | 414 | } |
432 | 415 | ||
433 | static int ctrl_isdirty_input(struct pvr2_ctrl *cptr) | 416 | static int ctrl_isdirty_input(struct pvr2_ctrl *cptr) |
@@ -1916,6 +1899,7 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf, | |||
1916 | if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; | 1899 | if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE; |
1917 | if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; | 1900 | if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO; |
1918 | hdw->input_avail_mask = m; | 1901 | hdw->input_avail_mask = m; |
1902 | hdw->input_allowed_mask = hdw->input_avail_mask; | ||
1919 | 1903 | ||
1920 | /* If not a hybrid device, pathway_state never changes. So | 1904 | /* If not a hybrid device, pathway_state never changes. So |
1921 | initialize it here to what it should forever be. */ | 1905 | initialize it here to what it should forever be. */ |
@@ -3948,6 +3932,24 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw) | |||
3948 | } | 3932 | } |
3949 | 3933 | ||
3950 | 3934 | ||
3935 | static unsigned int print_input_mask(unsigned int msk, | ||
3936 | char *buf,unsigned int acnt) | ||
3937 | { | ||
3938 | unsigned int idx,ccnt; | ||
3939 | unsigned int tcnt = 0; | ||
3940 | for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) { | ||
3941 | if (!((1 << idx) & msk)) continue; | ||
3942 | ccnt = scnprintf(buf+tcnt, | ||
3943 | acnt-tcnt, | ||
3944 | "%s%s", | ||
3945 | (tcnt ? ", " : ""), | ||
3946 | control_values_input[idx]); | ||
3947 | tcnt += ccnt; | ||
3948 | } | ||
3949 | return tcnt; | ||
3950 | } | ||
3951 | |||
3952 | |||
3951 | static const char *pvr2_pathway_state_name(int id) | 3953 | static const char *pvr2_pathway_state_name(int id) |
3952 | { | 3954 | { |
3953 | switch (id) { | 3955 | switch (id) { |
@@ -4016,6 +4018,28 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which, | |||
4016 | "state: %s", | 4018 | "state: %s", |
4017 | pvr2_get_state_name(hdw->master_state)); | 4019 | pvr2_get_state_name(hdw->master_state)); |
4018 | case 4: { | 4020 | case 4: { |
4021 | unsigned int tcnt = 0; | ||
4022 | unsigned int ccnt; | ||
4023 | |||
4024 | ccnt = scnprintf(buf, | ||
4025 | acnt, | ||
4026 | "Hardware supported inputs: "); | ||
4027 | tcnt += ccnt; | ||
4028 | tcnt += print_input_mask(hdw->input_avail_mask, | ||
4029 | buf+tcnt, | ||
4030 | acnt-tcnt); | ||
4031 | if (hdw->input_avail_mask != hdw->input_allowed_mask) { | ||
4032 | ccnt = scnprintf(buf+tcnt, | ||
4033 | acnt-tcnt, | ||
4034 | "; allowed inputs: "); | ||
4035 | tcnt += ccnt; | ||
4036 | tcnt += print_input_mask(hdw->input_allowed_mask, | ||
4037 | buf+tcnt, | ||
4038 | acnt-tcnt); | ||
4039 | } | ||
4040 | return tcnt; | ||
4041 | } | ||
4042 | case 5: { | ||
4019 | struct pvr2_stream_stats stats; | 4043 | struct pvr2_stream_stats stats; |
4020 | if (!hdw->vid_stream) break; | 4044 | if (!hdw->vid_stream) break; |
4021 | pvr2_stream_get_stats(hdw->vid_stream, | 4045 | pvr2_stream_get_stats(hdw->vid_stream, |
@@ -4210,6 +4234,74 @@ unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw) | |||
4210 | } | 4234 | } |
4211 | 4235 | ||
4212 | 4236 | ||
4237 | unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw) | ||
4238 | { | ||
4239 | return hdw->input_allowed_mask; | ||
4240 | } | ||
4241 | |||
4242 | |||
4243 | static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v) | ||
4244 | { | ||
4245 | if (hdw->input_val != v) { | ||
4246 | hdw->input_val = v; | ||
4247 | hdw->input_dirty = !0; | ||
4248 | } | ||
4249 | |||
4250 | /* Handle side effects - if we switch to a mode that needs the RF | ||
4251 | tuner, then select the right frequency choice as well and mark | ||
4252 | it dirty. */ | ||
4253 | if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) { | ||
4254 | hdw->freqSelector = 0; | ||
4255 | hdw->freqDirty = !0; | ||
4256 | } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) || | ||
4257 | (hdw->input_val == PVR2_CVAL_INPUT_DTV)) { | ||
4258 | hdw->freqSelector = 1; | ||
4259 | hdw->freqDirty = !0; | ||
4260 | } | ||
4261 | return 0; | ||
4262 | } | ||
4263 | |||
4264 | |||
4265 | int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw, | ||
4266 | unsigned int change_mask, | ||
4267 | unsigned int change_val) | ||
4268 | { | ||
4269 | int ret = 0; | ||
4270 | unsigned int nv,m,idx; | ||
4271 | LOCK_TAKE(hdw->big_lock); | ||
4272 | do { | ||
4273 | nv = hdw->input_allowed_mask & ~change_mask; | ||
4274 | nv |= (change_val & change_mask); | ||
4275 | nv &= hdw->input_avail_mask; | ||
4276 | if (!nv) { | ||
4277 | /* No legal modes left; return error instead. */ | ||
4278 | ret = -EPERM; | ||
4279 | break; | ||
4280 | } | ||
4281 | hdw->input_allowed_mask = nv; | ||
4282 | if ((1 << hdw->input_val) & hdw->input_allowed_mask) { | ||
4283 | /* Current mode is still in the allowed mask, so | ||
4284 | we're done. */ | ||
4285 | break; | ||
4286 | } | ||
4287 | /* Select and switch to a mode that is still in the allowed | ||
4288 | mask */ | ||
4289 | if (!hdw->input_allowed_mask) { | ||
4290 | /* Nothing legal; give up */ | ||
4291 | break; | ||
4292 | } | ||
4293 | m = hdw->input_allowed_mask; | ||
4294 | for (idx = 0; idx < (sizeof(m) << 3); idx++) { | ||
4295 | if (!((1 << idx) & m)) continue; | ||
4296 | pvr2_hdw_set_input(hdw,idx); | ||
4297 | break; | ||
4298 | } | ||
4299 | } while (0); | ||
4300 | LOCK_GIVE(hdw->big_lock); | ||
4301 | return ret; | ||
4302 | } | ||
4303 | |||
4304 | |||
4213 | /* Find I2C address of eeprom */ | 4305 | /* Find I2C address of eeprom */ |
4214 | static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) | 4306 | static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw) |
4215 | { | 4307 | { |
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h index 74c2503f8e3f..20295e0c1995 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h +++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h | |||
@@ -149,6 +149,19 @@ int pvr2_hdw_commit_ctl(struct pvr2_hdw *); | |||
149 | * will be according to PVR_CVAL_INPUT_xxxx definitions. */ | 149 | * will be according to PVR_CVAL_INPUT_xxxx definitions. */ |
150 | unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *); | 150 | unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *); |
151 | 151 | ||
152 | /* Return a bit mask of allowed input selections for this device. Mask bits | ||
153 | * will be according to PVR_CVAL_INPUT_xxxx definitions. */ | ||
154 | unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *); | ||
155 | |||
156 | /* Change the set of allowed input selections for this device. Both | ||
157 | change_mask and change_valu are mask bits according to | ||
158 | PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate | ||
159 | which settings are being changed and the change_val parameter indicates | ||
160 | whether corresponding settings are being set or cleared. */ | ||
161 | int pvr2_hdw_set_input_allowed(struct pvr2_hdw *, | ||
162 | unsigned int change_mask, | ||
163 | unsigned int change_val); | ||
164 | |||
152 | /* Return name for this driver instance */ | 165 | /* Return name for this driver instance */ |
153 | const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *); | 166 | const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *); |
154 | 167 | ||
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 249d7488e482..b415141b2859 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
@@ -57,7 +57,6 @@ struct pvr2_v4l2_fh { | |||
57 | struct pvr2_v4l2_fh *vprev; | 57 | struct pvr2_v4l2_fh *vprev; |
58 | wait_queue_head_t wait_data; | 58 | wait_queue_head_t wait_data; |
59 | int fw_mode_flag; | 59 | int fw_mode_flag; |
60 | int prev_input_val; | ||
61 | }; | 60 | }; |
62 | 61 | ||
63 | struct pvr2_v4l2 { | 62 | struct pvr2_v4l2 { |
@@ -900,20 +899,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file) | |||
900 | v4l2_prio_close(&vp->prio, &fhp->prio); | 899 | v4l2_prio_close(&vp->prio, &fhp->prio); |
901 | file->private_data = NULL; | 900 | file->private_data = NULL; |
902 | 901 | ||
903 | /* Restore the previous input selection, if it makes sense | ||
904 | to do so. */ | ||
905 | if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) { | ||
906 | struct pvr2_ctrl *cp; | ||
907 | int pval; | ||
908 | cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
909 | pvr2_ctrl_get_value(cp,&pval); | ||
910 | /* Only restore if we're still selecting the radio */ | ||
911 | if (pval == PVR2_CVAL_INPUT_RADIO) { | ||
912 | pvr2_ctrl_set_value(cp,fhp->prev_input_val); | ||
913 | pvr2_hdw_commit_ctl(hdw); | ||
914 | } | ||
915 | } | ||
916 | |||
917 | if (fhp->vnext) { | 902 | if (fhp->vnext) { |
918 | fhp->vnext->vprev = fhp->vprev; | 903 | fhp->vnext->vprev = fhp->vprev; |
919 | } else { | 904 | } else { |
@@ -944,6 +929,8 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
944 | struct pvr2_v4l2_fh *fhp; | 929 | struct pvr2_v4l2_fh *fhp; |
945 | struct pvr2_v4l2 *vp; | 930 | struct pvr2_v4l2 *vp; |
946 | struct pvr2_hdw *hdw; | 931 | struct pvr2_hdw *hdw; |
932 | unsigned int input_mask = 0; | ||
933 | int ret = 0; | ||
947 | 934 | ||
948 | dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase); | 935 | dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase); |
949 | 936 | ||
@@ -969,6 +956,29 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
969 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); | 956 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); |
970 | pvr2_channel_init(&fhp->channel,vp->channel.mc_head); | 957 | pvr2_channel_init(&fhp->channel,vp->channel.mc_head); |
971 | 958 | ||
959 | if (dip->v4l_type == VFL_TYPE_RADIO) { | ||
960 | /* Opening device as a radio, legal input selection subset | ||
961 | is just the radio. */ | ||
962 | input_mask = (1 << PVR2_CVAL_INPUT_RADIO); | ||
963 | } else { | ||
964 | /* Opening the main V4L device, legal input selection | ||
965 | subset includes all analog inputs. */ | ||
966 | input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) | | ||
967 | (1 << PVR2_CVAL_INPUT_TV) | | ||
968 | (1 << PVR2_CVAL_INPUT_COMPOSITE) | | ||
969 | (1 << PVR2_CVAL_INPUT_SVIDEO)); | ||
970 | } | ||
971 | ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask); | ||
972 | if (ret) { | ||
973 | pvr2_channel_done(&fhp->channel); | ||
974 | pvr2_trace(PVR2_TRACE_STRUCT, | ||
975 | "Destroying pvr_v4l2_fh id=%p (input mask error)", | ||
976 | fhp); | ||
977 | |||
978 | kfree(fhp); | ||
979 | return ret; | ||
980 | } | ||
981 | |||
972 | fhp->vnext = NULL; | 982 | fhp->vnext = NULL; |
973 | fhp->vprev = vp->vlast; | 983 | fhp->vprev = vp->vlast; |
974 | if (vp->vlast) { | 984 | if (vp->vlast) { |
@@ -979,18 +989,6 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
979 | vp->vlast = fhp; | 989 | vp->vlast = fhp; |
980 | fhp->vhead = vp; | 990 | fhp->vhead = vp; |
981 | 991 | ||
982 | /* Opening the /dev/radioX device implies a mode switch. | ||
983 | So execute that here. Note that you can get the | ||
984 | IDENTICAL effect merely by opening the normal video | ||
985 | device and setting the input appropriately. */ | ||
986 | if (dip->v4l_type == VFL_TYPE_RADIO) { | ||
987 | struct pvr2_ctrl *cp; | ||
988 | cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
989 | pvr2_ctrl_get_value(cp,&fhp->prev_input_val); | ||
990 | pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO); | ||
991 | pvr2_hdw_commit_ctl(hdw); | ||
992 | } | ||
993 | |||
994 | fhp->file = file; | 992 | fhp->file = file; |
995 | file->private_data = fhp; | 993 | file->private_data = fhp; |
996 | v4l2_prio_open(&vp->prio,&fhp->prio); | 994 | v4l2_prio_open(&vp->prio,&fhp->prio); |