diff options
| -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); |
