diff options
Diffstat (limited to 'drivers/media/video/pvrusb2/pvrusb2-v4l2.c')
| -rw-r--r-- | drivers/media/video/pvrusb2/pvrusb2-v4l2.c | 335 |
1 files changed, 234 insertions, 101 deletions
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c index 6cf17080eb49..4fe4136204c7 100644 --- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c | |||
| @@ -40,7 +40,10 @@ struct pvr2_v4l2_dev { | |||
| 40 | struct video_device devbase; /* MUST be first! */ | 40 | struct video_device devbase; /* MUST be first! */ |
| 41 | struct pvr2_v4l2 *v4lp; | 41 | struct pvr2_v4l2 *v4lp; |
| 42 | struct pvr2_context_stream *stream; | 42 | struct pvr2_context_stream *stream; |
| 43 | enum pvr2_config config; | 43 | /* Information about this device: */ |
| 44 | enum pvr2_config config; /* Expected stream format */ | ||
| 45 | int v4l_type; /* V4L defined type for this device node */ | ||
| 46 | enum pvr2_v4l_type minor_type; /* pvr2-understood minor device type */ | ||
| 44 | }; | 47 | }; |
| 45 | 48 | ||
| 46 | struct pvr2_v4l2_fh { | 49 | struct pvr2_v4l2_fh { |
| @@ -54,6 +57,7 @@ struct pvr2_v4l2_fh { | |||
| 54 | struct pvr2_v4l2_fh *vprev; | 57 | struct pvr2_v4l2_fh *vprev; |
| 55 | wait_queue_head_t wait_data; | 58 | wait_queue_head_t wait_data; |
| 56 | int fw_mode_flag; | 59 | int fw_mode_flag; |
| 60 | int prev_input_val; | ||
| 57 | }; | 61 | }; |
| 58 | 62 | ||
| 59 | struct pvr2_v4l2 { | 63 | struct pvr2_v4l2 { |
| @@ -63,13 +67,22 @@ struct pvr2_v4l2 { | |||
| 63 | 67 | ||
| 64 | struct v4l2_prio_state prio; | 68 | struct v4l2_prio_state prio; |
| 65 | 69 | ||
| 66 | /* streams */ | 70 | /* streams - Note that these must be separately, individually, |
| 67 | struct pvr2_v4l2_dev *vdev; | 71 | * allocated pointers. This is because the v4l core is going to |
| 72 | * manage their deletion - separately, individually... */ | ||
| 73 | struct pvr2_v4l2_dev *dev_video; | ||
| 74 | struct pvr2_v4l2_dev *dev_radio; | ||
| 68 | }; | 75 | }; |
| 69 | 76 | ||
| 70 | static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; | 77 | static int video_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; |
| 71 | module_param_array(video_nr, int, NULL, 0444); | 78 | module_param_array(video_nr, int, NULL, 0444); |
| 72 | MODULE_PARM_DESC(video_nr, "Offset for device's minor"); | 79 | MODULE_PARM_DESC(video_nr, "Offset for device's video dev minor"); |
| 80 | static int radio_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; | ||
| 81 | module_param_array(radio_nr, int, NULL, 0444); | ||
| 82 | MODULE_PARM_DESC(radio_nr, "Offset for device's radio dev minor"); | ||
| 83 | static int vbi_nr[PVR_NUM] = {[0 ... PVR_NUM-1] = -1}; | ||
| 84 | module_param_array(vbi_nr, int, NULL, 0444); | ||
| 85 | MODULE_PARM_DESC(vbi_nr, "Offset for device's vbi dev minor"); | ||
| 73 | 86 | ||
| 74 | static struct v4l2_capability pvr_capability ={ | 87 | static struct v4l2_capability pvr_capability ={ |
| 75 | .driver = "pvrusb2", | 88 | .driver = "pvrusb2", |
| @@ -77,30 +90,11 @@ static struct v4l2_capability pvr_capability ={ | |||
| 77 | .bus_info = "usb", | 90 | .bus_info = "usb", |
| 78 | .version = KERNEL_VERSION(0,8,0), | 91 | .version = KERNEL_VERSION(0,8,0), |
| 79 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | | 92 | .capabilities = (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE | |
| 80 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | | 93 | V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO | |
| 81 | V4L2_CAP_READWRITE), | 94 | V4L2_CAP_READWRITE), |
| 82 | .reserved = {0,0,0,0} | 95 | .reserved = {0,0,0,0} |
| 83 | }; | 96 | }; |
| 84 | 97 | ||
| 85 | static struct v4l2_tuner pvr_v4l2_tuners[]= { | ||
| 86 | { | ||
| 87 | .index = 0, | ||
| 88 | .name = "TV Tuner", | ||
| 89 | .type = V4L2_TUNER_ANALOG_TV, | ||
| 90 | .capability = (V4L2_TUNER_CAP_NORM | | ||
| 91 | V4L2_TUNER_CAP_STEREO | | ||
| 92 | V4L2_TUNER_CAP_LANG1 | | ||
| 93 | V4L2_TUNER_CAP_LANG2), | ||
| 94 | .rangelow = 0, | ||
| 95 | .rangehigh = 0, | ||
| 96 | .rxsubchans = V4L2_TUNER_SUB_STEREO, | ||
| 97 | .audmode = V4L2_TUNER_MODE_STEREO, | ||
| 98 | .signal = 0, | ||
| 99 | .afc = 0, | ||
| 100 | .reserved = {0,0,0,0} | ||
| 101 | } | ||
| 102 | }; | ||
| 103 | |||
| 104 | static struct v4l2_fmtdesc pvr_fmtdesc [] = { | 98 | static struct v4l2_fmtdesc pvr_fmtdesc [] = { |
| 105 | { | 99 | { |
| 106 | .index = 0, | 100 | .index = 0, |
| @@ -154,6 +148,18 @@ static struct v4l2_format pvr_format [] = { | |||
| 154 | } | 148 | } |
| 155 | }; | 149 | }; |
| 156 | 150 | ||
| 151 | |||
| 152 | static const char *get_v4l_name(int v4l_type) | ||
| 153 | { | ||
| 154 | switch (v4l_type) { | ||
| 155 | case VFL_TYPE_GRABBER: return "video"; | ||
| 156 | case VFL_TYPE_RADIO: return "radio"; | ||
| 157 | case VFL_TYPE_VBI: return "vbi"; | ||
| 158 | default: return "?"; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 162 | |||
| 157 | /* | 163 | /* |
| 158 | * pvr_ioctl() | 164 | * pvr_ioctl() |
| 159 | * | 165 | * |
| @@ -315,13 +321,39 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 315 | 321 | ||
| 316 | case VIDIOC_ENUMAUDIO: | 322 | case VIDIOC_ENUMAUDIO: |
| 317 | { | 323 | { |
| 324 | /* pkt: FIXME: We are returning one "fake" input here | ||
| 325 | which could very well be called "whatever_we_like". | ||
| 326 | This is for apps that want to see an audio input | ||
| 327 | just to feel comfortable, as well as to test if | ||
| 328 | it can do stereo or sth. There is actually no guarantee | ||
| 329 | that the actual audio input cannot change behind the app's | ||
| 330 | back, but most applications should not mind that either. | ||
| 331 | |||
| 332 | Hopefully, mplayer people will work with us on this (this | ||
| 333 | whole mess is to support mplayer pvr://), or Hans will come | ||
| 334 | up with a more standard way to say "we have inputs but we | ||
| 335 | don 't want you to change them independent of video" which | ||
| 336 | will sort this mess. | ||
| 337 | */ | ||
| 338 | struct v4l2_audio *vin = arg; | ||
| 318 | ret = -EINVAL; | 339 | ret = -EINVAL; |
| 340 | if (vin->index > 0) break; | ||
| 341 | strncpy(vin->name, "PVRUSB2 Audio",14); | ||
| 342 | vin->capability = V4L2_AUDCAP_STEREO; | ||
| 343 | ret = 0; | ||
| 344 | break; | ||
| 319 | break; | 345 | break; |
| 320 | } | 346 | } |
| 321 | 347 | ||
| 322 | case VIDIOC_G_AUDIO: | 348 | case VIDIOC_G_AUDIO: |
| 323 | { | 349 | { |
| 324 | ret = -EINVAL; | 350 | /* pkt: FIXME: see above comment (VIDIOC_ENUMAUDIO) */ |
| 351 | struct v4l2_audio *vin = arg; | ||
| 352 | memset(vin,0,sizeof(*vin)); | ||
| 353 | vin->index = 0; | ||
| 354 | strncpy(vin->name, "PVRUSB2 Audio",14); | ||
| 355 | vin->capability = V4L2_AUDCAP_STEREO; | ||
| 356 | ret = 0; | ||
| 325 | break; | 357 | break; |
| 326 | } | 358 | } |
| 327 | 359 | ||
| @@ -333,34 +365,11 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 333 | case VIDIOC_G_TUNER: | 365 | case VIDIOC_G_TUNER: |
| 334 | { | 366 | { |
| 335 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | 367 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; |
| 336 | unsigned int status_mask; | ||
| 337 | int val; | ||
| 338 | if (vt->index !=0) break; | ||
| 339 | 368 | ||
| 340 | status_mask = pvr2_hdw_get_signal_status(hdw); | 369 | if (vt->index != 0) break; /* Only answer for the 1st tuner */ |
| 341 | 370 | ||
| 342 | memcpy(vt, &pvr_v4l2_tuners[vt->index], | 371 | pvr2_hdw_execute_tuner_poll(hdw); |
| 343 | sizeof(struct v4l2_tuner)); | 372 | ret = pvr2_hdw_get_tuner_status(hdw,vt); |
| 344 | |||
| 345 | vt->signal = 0; | ||
| 346 | if (status_mask & PVR2_SIGNAL_OK) { | ||
| 347 | if (status_mask & PVR2_SIGNAL_STEREO) { | ||
| 348 | vt->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
| 349 | } else { | ||
| 350 | vt->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
| 351 | } | ||
| 352 | if (status_mask & PVR2_SIGNAL_SAP) { | ||
| 353 | vt->rxsubchans |= (V4L2_TUNER_SUB_LANG1 | | ||
| 354 | V4L2_TUNER_SUB_LANG2); | ||
| 355 | } | ||
| 356 | vt->signal = 65535; | ||
| 357 | } | ||
| 358 | |||
| 359 | val = 0; | ||
| 360 | ret = pvr2_ctrl_get_value( | ||
| 361 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), | ||
| 362 | &val); | ||
| 363 | vt->audmode = val; | ||
| 364 | break; | 373 | break; |
| 365 | } | 374 | } |
| 366 | 375 | ||
| @@ -374,14 +383,40 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 374 | ret = pvr2_ctrl_set_value( | 383 | ret = pvr2_ctrl_set_value( |
| 375 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), | 384 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_AUDIOMODE), |
| 376 | vt->audmode); | 385 | vt->audmode); |
| 386 | break; | ||
| 377 | } | 387 | } |
| 378 | 388 | ||
| 379 | case VIDIOC_S_FREQUENCY: | 389 | case VIDIOC_S_FREQUENCY: |
| 380 | { | 390 | { |
| 381 | const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | 391 | const struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; |
| 392 | unsigned long fv; | ||
| 393 | struct v4l2_tuner vt; | ||
| 394 | int cur_input; | ||
| 395 | struct pvr2_ctrl *ctrlp; | ||
| 396 | ret = pvr2_hdw_get_tuner_status(hdw,&vt); | ||
| 397 | if (ret != 0) break; | ||
| 398 | ctrlp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
| 399 | ret = pvr2_ctrl_get_value(ctrlp,&cur_input); | ||
| 400 | if (ret != 0) break; | ||
| 401 | if (vf->type == V4L2_TUNER_RADIO) { | ||
| 402 | if (cur_input != PVR2_CVAL_INPUT_RADIO) { | ||
| 403 | pvr2_ctrl_set_value(ctrlp, | ||
| 404 | PVR2_CVAL_INPUT_RADIO); | ||
| 405 | } | ||
| 406 | } else { | ||
| 407 | if (cur_input == PVR2_CVAL_INPUT_RADIO) { | ||
| 408 | pvr2_ctrl_set_value(ctrlp, | ||
| 409 | PVR2_CVAL_INPUT_TV); | ||
| 410 | } | ||
| 411 | } | ||
| 412 | fv = vf->frequency; | ||
| 413 | if (vt.capability & V4L2_TUNER_CAP_LOW) { | ||
| 414 | fv = (fv * 125) / 2; | ||
| 415 | } else { | ||
| 416 | fv = fv * 62500; | ||
| 417 | } | ||
| 382 | ret = pvr2_ctrl_set_value( | 418 | ret = pvr2_ctrl_set_value( |
| 383 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), | 419 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY),fv); |
| 384 | vf->frequency * 62500); | ||
| 385 | break; | 420 | break; |
| 386 | } | 421 | } |
| 387 | 422 | ||
| @@ -389,10 +424,27 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 389 | { | 424 | { |
| 390 | struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; | 425 | struct v4l2_frequency *vf = (struct v4l2_frequency *)arg; |
| 391 | int val = 0; | 426 | int val = 0; |
| 427 | int cur_input; | ||
| 428 | struct v4l2_tuner vt; | ||
| 429 | ret = pvr2_hdw_get_tuner_status(hdw,&vt); | ||
| 430 | if (ret != 0) break; | ||
| 392 | ret = pvr2_ctrl_get_value( | 431 | ret = pvr2_ctrl_get_value( |
| 393 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), | 432 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_FREQUENCY), |
| 394 | &val); | 433 | &val); |
| 395 | val /= 62500; | 434 | if (ret != 0) break; |
| 435 | pvr2_ctrl_get_value( | ||
| 436 | pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT), | ||
| 437 | &cur_input); | ||
| 438 | if (cur_input == PVR2_CVAL_INPUT_RADIO) { | ||
| 439 | vf->type = V4L2_TUNER_RADIO; | ||
| 440 | } else { | ||
| 441 | vf->type = V4L2_TUNER_ANALOG_TV; | ||
| 442 | } | ||
| 443 | if (vt.capability & V4L2_TUNER_CAP_LOW) { | ||
| 444 | val = (val * 2) / 125; | ||
| 445 | } else { | ||
| 446 | val /= 62500; | ||
| 447 | } | ||
| 396 | vf->frequency = val; | 448 | vf->frequency = val; |
| 397 | break; | 449 | break; |
| 398 | } | 450 | } |
| @@ -449,7 +501,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 449 | ret = 0; | 501 | ret = 0; |
| 450 | switch(vf->type) { | 502 | switch(vf->type) { |
| 451 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { | 503 | case V4L2_BUF_TYPE_VIDEO_CAPTURE: { |
| 452 | int lmin,lmax; | 504 | int lmin,lmax,ldef; |
| 453 | struct pvr2_ctrl *hcp,*vcp; | 505 | struct pvr2_ctrl *hcp,*vcp; |
| 454 | int h = vf->fmt.pix.height; | 506 | int h = vf->fmt.pix.height; |
| 455 | int w = vf->fmt.pix.width; | 507 | int w = vf->fmt.pix.width; |
| @@ -458,14 +510,20 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 458 | 510 | ||
| 459 | lmin = pvr2_ctrl_get_min(hcp); | 511 | lmin = pvr2_ctrl_get_min(hcp); |
| 460 | lmax = pvr2_ctrl_get_max(hcp); | 512 | lmax = pvr2_ctrl_get_max(hcp); |
| 461 | if (w < lmin) { | 513 | ldef = pvr2_ctrl_get_def(hcp); |
| 514 | if (w == -1) { | ||
| 515 | w = ldef; | ||
| 516 | } else if (w < lmin) { | ||
| 462 | w = lmin; | 517 | w = lmin; |
| 463 | } else if (w > lmax) { | 518 | } else if (w > lmax) { |
| 464 | w = lmax; | 519 | w = lmax; |
| 465 | } | 520 | } |
| 466 | lmin = pvr2_ctrl_get_min(vcp); | 521 | lmin = pvr2_ctrl_get_min(vcp); |
| 467 | lmax = pvr2_ctrl_get_max(vcp); | 522 | lmax = pvr2_ctrl_get_max(vcp); |
| 468 | if (h < lmin) { | 523 | ldef = pvr2_ctrl_get_def(vcp); |
| 524 | if (h == -1) { | ||
| 525 | h = ldef; | ||
| 526 | } else if (h < lmin) { | ||
| 469 | h = lmin; | 527 | h = lmin; |
| 470 | } else if (h > lmax) { | 528 | } else if (h > lmax) { |
| 471 | h = lmax; | 529 | h = lmax; |
| @@ -494,6 +552,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 494 | 552 | ||
| 495 | case VIDIOC_STREAMON: | 553 | case VIDIOC_STREAMON: |
| 496 | { | 554 | { |
| 555 | if (!fh->dev_info->stream) { | ||
| 556 | /* No stream defined for this node. This means | ||
| 557 | that we're not currently allowed to stream from | ||
| 558 | this node. */ | ||
| 559 | ret = -EPERM; | ||
| 560 | break; | ||
| 561 | } | ||
| 497 | ret = pvr2_hdw_set_stream_type(hdw,dev_info->config); | 562 | ret = pvr2_hdw_set_stream_type(hdw,dev_info->config); |
| 498 | if (ret < 0) return ret; | 563 | if (ret < 0) return ret; |
| 499 | ret = pvr2_hdw_set_streaming(hdw,!0); | 564 | ret = pvr2_hdw_set_streaming(hdw,!0); |
| @@ -502,6 +567,13 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 502 | 567 | ||
| 503 | case VIDIOC_STREAMOFF: | 568 | case VIDIOC_STREAMOFF: |
| 504 | { | 569 | { |
| 570 | if (!fh->dev_info->stream) { | ||
| 571 | /* No stream defined for this node. This means | ||
| 572 | that we're not currently allowed to stream from | ||
| 573 | this node. */ | ||
| 574 | ret = -EPERM; | ||
| 575 | break; | ||
| 576 | } | ||
| 505 | ret = pvr2_hdw_set_streaming(hdw,0); | 577 | ret = pvr2_hdw_set_streaming(hdw,0); |
| 506 | break; | 578 | break; |
| 507 | } | 579 | } |
| @@ -599,6 +671,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 599 | struct v4l2_ext_control *ctrl; | 671 | struct v4l2_ext_control *ctrl; |
| 600 | unsigned int idx; | 672 | unsigned int idx; |
| 601 | int val; | 673 | int val; |
| 674 | ret = 0; | ||
| 602 | for (idx = 0; idx < ctls->count; idx++) { | 675 | for (idx = 0; idx < ctls->count; idx++) { |
| 603 | ctrl = ctls->controls + idx; | 676 | ctrl = ctls->controls + idx; |
| 604 | ret = pvr2_ctrl_get_value( | 677 | ret = pvr2_ctrl_get_value( |
| @@ -621,6 +694,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 621 | (struct v4l2_ext_controls *)arg; | 694 | (struct v4l2_ext_controls *)arg; |
| 622 | struct v4l2_ext_control *ctrl; | 695 | struct v4l2_ext_control *ctrl; |
| 623 | unsigned int idx; | 696 | unsigned int idx; |
| 697 | ret = 0; | ||
| 624 | for (idx = 0; idx < ctls->count; idx++) { | 698 | for (idx = 0; idx < ctls->count; idx++) { |
| 625 | ctrl = ctls->controls + idx; | 699 | ctrl = ctls->controls + idx; |
| 626 | ret = pvr2_ctrl_set_value( | 700 | ret = pvr2_ctrl_set_value( |
| @@ -643,6 +717,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 643 | unsigned int idx; | 717 | unsigned int idx; |
| 644 | /* For the moment just validate that the requested control | 718 | /* For the moment just validate that the requested control |
| 645 | actually exists. */ | 719 | actually exists. */ |
| 720 | ret = 0; | ||
| 646 | for (idx = 0; idx < ctls->count; idx++) { | 721 | for (idx = 0; idx < ctls->count; idx++) { |
| 647 | ctrl = ctls->controls + idx; | 722 | ctrl = ctls->controls + idx; |
| 648 | pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id); | 723 | pctl = pvr2_hdw_get_ctrl_v4l(hdw,ctrl->id); |
| @@ -662,16 +737,16 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 662 | break; | 737 | break; |
| 663 | } | 738 | } |
| 664 | #ifdef CONFIG_VIDEO_ADV_DEBUG | 739 | #ifdef CONFIG_VIDEO_ADV_DEBUG |
| 665 | case VIDIOC_INT_G_REGISTER: | 740 | case VIDIOC_DBG_S_REGISTER: |
| 666 | case VIDIOC_INT_S_REGISTER: | 741 | case VIDIOC_DBG_G_REGISTER: |
| 667 | { | 742 | { |
| 668 | u32 val; | 743 | u32 val; |
| 669 | struct v4l2_register *req = (struct v4l2_register *)arg; | 744 | struct v4l2_register *req = (struct v4l2_register *)arg; |
| 670 | if (cmd == VIDIOC_INT_S_REGISTER) val = req->val; | 745 | if (cmd == VIDIOC_DBG_S_REGISTER) val = req->val; |
| 671 | ret = pvr2_hdw_register_access( | 746 | ret = pvr2_hdw_register_access( |
| 672 | hdw,req->i2c_id,req->reg, | 747 | hdw,req->i2c_id,req->reg, |
| 673 | cmd == VIDIOC_INT_S_REGISTER,&val); | 748 | cmd == VIDIOC_DBG_S_REGISTER,&val); |
| 674 | if (cmd == VIDIOC_INT_G_REGISTER) req->val = val; | 749 | if (cmd == VIDIOC_DBG_G_REGISTER) req->val = val; |
| 675 | break; | 750 | break; |
| 676 | } | 751 | } |
| 677 | #endif | 752 | #endif |
| @@ -707,8 +782,12 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file, | |||
| 707 | 782 | ||
| 708 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | 783 | static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) |
| 709 | { | 784 | { |
| 710 | printk(KERN_INFO "pvrusb2: unregistering device video%d [%s]\n", | 785 | int minor_id = dip->devbase.minor; |
| 711 | dip->devbase.minor,pvr2_config_get_name(dip->config)); | 786 | struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw; |
| 787 | enum pvr2_config cfg = dip->config; | ||
| 788 | int v4l_type = dip->v4l_type; | ||
| 789 | |||
| 790 | pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1); | ||
| 712 | 791 | ||
| 713 | /* Paranoia */ | 792 | /* Paranoia */ |
| 714 | dip->v4lp = NULL; | 793 | dip->v4lp = NULL; |
| @@ -717,13 +796,24 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip) | |||
| 717 | /* Actual deallocation happens later when all internal references | 796 | /* Actual deallocation happens later when all internal references |
| 718 | are gone. */ | 797 | are gone. */ |
| 719 | video_unregister_device(&dip->devbase); | 798 | video_unregister_device(&dip->devbase); |
| 799 | |||
| 800 | printk(KERN_INFO "pvrusb2: unregistered device %s%u [%s]\n", | ||
| 801 | get_v4l_name(v4l_type),minor_id & 0x1f, | ||
| 802 | pvr2_config_get_name(cfg)); | ||
| 803 | |||
| 720 | } | 804 | } |
| 721 | 805 | ||
| 722 | 806 | ||
| 723 | static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) | 807 | static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp) |
| 724 | { | 808 | { |
| 725 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw,-1); | 809 | if (vp->dev_video) { |
| 726 | pvr2_v4l2_dev_destroy(vp->vdev); | 810 | pvr2_v4l2_dev_destroy(vp->dev_video); |
| 811 | vp->dev_video = 0; | ||
| 812 | } | ||
| 813 | if (vp->dev_radio) { | ||
| 814 | pvr2_v4l2_dev_destroy(vp->dev_radio); | ||
| 815 | vp->dev_radio = 0; | ||
| 816 | } | ||
| 727 | 817 | ||
| 728 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); | 818 | pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp); |
| 729 | pvr2_channel_done(&vp->channel); | 819 | pvr2_channel_done(&vp->channel); |
| @@ -766,23 +856,37 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file) | |||
| 766 | struct pvr2_v4l2_fh *fhp = file->private_data; | 856 | struct pvr2_v4l2_fh *fhp = file->private_data; |
| 767 | struct pvr2_v4l2 *vp = fhp->vhead; | 857 | struct pvr2_v4l2 *vp = fhp->vhead; |
| 768 | struct pvr2_context *mp = fhp->vhead->channel.mc_head; | 858 | struct pvr2_context *mp = fhp->vhead->channel.mc_head; |
| 859 | struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw; | ||
| 769 | 860 | ||
| 770 | pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); | 861 | pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release"); |
| 771 | 862 | ||
| 772 | if (fhp->rhp) { | 863 | if (fhp->rhp) { |
| 773 | struct pvr2_stream *sp; | 864 | struct pvr2_stream *sp; |
| 774 | struct pvr2_hdw *hdw; | ||
| 775 | hdw = fhp->channel.mc_head->hdw; | ||
| 776 | pvr2_hdw_set_streaming(hdw,0); | 865 | pvr2_hdw_set_streaming(hdw,0); |
| 777 | sp = pvr2_ioread_get_stream(fhp->rhp); | 866 | sp = pvr2_ioread_get_stream(fhp->rhp); |
| 778 | if (sp) pvr2_stream_set_callback(sp,NULL,NULL); | 867 | if (sp) pvr2_stream_set_callback(sp,NULL,NULL); |
| 779 | pvr2_ioread_destroy(fhp->rhp); | 868 | pvr2_ioread_destroy(fhp->rhp); |
| 780 | fhp->rhp = NULL; | 869 | fhp->rhp = NULL; |
| 781 | } | 870 | } |
| 871 | |||
| 782 | v4l2_prio_close(&vp->prio, &fhp->prio); | 872 | v4l2_prio_close(&vp->prio, &fhp->prio); |
| 783 | file->private_data = NULL; | 873 | file->private_data = NULL; |
| 784 | 874 | ||
| 785 | pvr2_context_enter(mp); do { | 875 | pvr2_context_enter(mp); do { |
| 876 | /* Restore the previous input selection, if it makes sense | ||
| 877 | to do so. */ | ||
| 878 | if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) { | ||
| 879 | struct pvr2_ctrl *cp; | ||
| 880 | int pval; | ||
| 881 | cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
| 882 | pvr2_ctrl_get_value(cp,&pval); | ||
| 883 | /* Only restore if we're still selecting the radio */ | ||
| 884 | if (pval == PVR2_CVAL_INPUT_RADIO) { | ||
| 885 | pvr2_ctrl_set_value(cp,fhp->prev_input_val); | ||
| 886 | pvr2_hdw_commit_ctl(hdw); | ||
| 887 | } | ||
| 888 | } | ||
| 889 | |||
| 786 | if (fhp->vnext) { | 890 | if (fhp->vnext) { |
| 787 | fhp->vnext->vprev = fhp->vprev; | 891 | fhp->vnext->vprev = fhp->vprev; |
| 788 | } else { | 892 | } else { |
| @@ -828,11 +932,10 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
| 828 | return -EIO; | 932 | return -EIO; |
| 829 | } | 933 | } |
| 830 | 934 | ||
| 831 | fhp = kmalloc(sizeof(*fhp),GFP_KERNEL); | 935 | fhp = kzalloc(sizeof(*fhp),GFP_KERNEL); |
| 832 | if (!fhp) { | 936 | if (!fhp) { |
| 833 | return -ENOMEM; | 937 | return -ENOMEM; |
| 834 | } | 938 | } |
| 835 | memset(fhp,0,sizeof(*fhp)); | ||
| 836 | 939 | ||
| 837 | init_waitqueue_head(&fhp->wait_data); | 940 | init_waitqueue_head(&fhp->wait_data); |
| 838 | fhp->dev_info = dip; | 941 | fhp->dev_info = dip; |
| @@ -840,6 +943,7 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
| 840 | pvr2_context_enter(vp->channel.mc_head); do { | 943 | pvr2_context_enter(vp->channel.mc_head); do { |
| 841 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); | 944 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp); |
| 842 | pvr2_channel_init(&fhp->channel,vp->channel.mc_head); | 945 | pvr2_channel_init(&fhp->channel,vp->channel.mc_head); |
| 946 | |||
| 843 | fhp->vnext = NULL; | 947 | fhp->vnext = NULL; |
| 844 | fhp->vprev = vp->vlast; | 948 | fhp->vprev = vp->vlast; |
| 845 | if (vp->vlast) { | 949 | if (vp->vlast) { |
| @@ -849,6 +953,18 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file) | |||
| 849 | } | 953 | } |
| 850 | vp->vlast = fhp; | 954 | vp->vlast = fhp; |
| 851 | fhp->vhead = vp; | 955 | fhp->vhead = vp; |
| 956 | |||
| 957 | /* Opening the /dev/radioX device implies a mode switch. | ||
| 958 | So execute that here. Note that you can get the | ||
| 959 | IDENTICAL effect merely by opening the normal video | ||
| 960 | device and setting the input appropriately. */ | ||
| 961 | if (dip->v4l_type == VFL_TYPE_RADIO) { | ||
| 962 | struct pvr2_ctrl *cp; | ||
| 963 | cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT); | ||
| 964 | pvr2_ctrl_get_value(cp,&fhp->prev_input_val); | ||
| 965 | pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO); | ||
| 966 | pvr2_hdw_commit_ctl(hdw); | ||
| 967 | } | ||
| 852 | } while (0); pvr2_context_exit(vp->channel.mc_head); | 968 | } while (0); pvr2_context_exit(vp->channel.mc_head); |
| 853 | 969 | ||
| 854 | fhp->file = file; | 970 | fhp->file = file; |
| @@ -873,6 +989,12 @@ static int pvr2_v4l2_iosetup(struct pvr2_v4l2_fh *fh) | |||
| 873 | struct pvr2_hdw *hdw; | 989 | struct pvr2_hdw *hdw; |
| 874 | if (fh->rhp) return 0; | 990 | if (fh->rhp) return 0; |
| 875 | 991 | ||
| 992 | if (!fh->dev_info->stream) { | ||
| 993 | /* No stream defined for this node. This means that we're | ||
| 994 | not currently allowed to stream from this node. */ | ||
| 995 | return -EPERM; | ||
| 996 | } | ||
| 997 | |||
| 876 | /* First read() attempt. Try to claim the stream and start | 998 | /* First read() attempt. Try to claim the stream and start |
| 877 | it... */ | 999 | it... */ |
| 878 | if ((ret = pvr2_channel_claim_stream(&fh->channel, | 1000 | if ((ret = pvr2_channel_claim_stream(&fh->channel, |
| @@ -1012,25 +1134,37 @@ static struct video_device vdev_template = { | |||
| 1012 | 1134 | ||
| 1013 | static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | 1135 | static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, |
| 1014 | struct pvr2_v4l2 *vp, | 1136 | struct pvr2_v4l2 *vp, |
| 1015 | enum pvr2_config cfg) | 1137 | int v4l_type) |
| 1016 | { | 1138 | { |
| 1017 | int mindevnum; | 1139 | int mindevnum; |
| 1018 | int unit_number; | 1140 | int unit_number; |
| 1019 | int v4l_type; | 1141 | int *nr_ptr = 0; |
| 1020 | dip->v4lp = vp; | 1142 | dip->v4lp = vp; |
| 1021 | dip->config = cfg; | ||
| 1022 | 1143 | ||
| 1023 | 1144 | ||
| 1024 | switch (cfg) { | 1145 | dip->v4l_type = v4l_type; |
| 1025 | case pvr2_config_mpeg: | 1146 | switch (v4l_type) { |
| 1026 | v4l_type = VFL_TYPE_GRABBER; | 1147 | case VFL_TYPE_GRABBER: |
| 1027 | dip->stream = &vp->channel.mc_head->video_stream; | 1148 | dip->stream = &vp->channel.mc_head->video_stream; |
| 1149 | dip->config = pvr2_config_mpeg; | ||
| 1150 | dip->minor_type = pvr2_v4l_type_video; | ||
| 1151 | nr_ptr = video_nr; | ||
| 1152 | if (!dip->stream) { | ||
| 1153 | err("Failed to set up pvrusb2 v4l video dev" | ||
| 1154 | " due to missing stream instance"); | ||
| 1155 | return; | ||
| 1156 | } | ||
| 1028 | break; | 1157 | break; |
| 1029 | case pvr2_config_vbi: | 1158 | case VFL_TYPE_VBI: |
| 1030 | v4l_type = VFL_TYPE_VBI; | 1159 | dip->config = pvr2_config_vbi; |
| 1160 | dip->minor_type = pvr2_v4l_type_vbi; | ||
| 1161 | nr_ptr = vbi_nr; | ||
| 1031 | break; | 1162 | break; |
| 1032 | case pvr2_config_radio: | 1163 | case VFL_TYPE_RADIO: |
| 1033 | v4l_type = VFL_TYPE_RADIO; | 1164 | dip->stream = &vp->channel.mc_head->video_stream; |
| 1165 | dip->config = pvr2_config_mpeg; | ||
| 1166 | dip->minor_type = pvr2_v4l_type_radio; | ||
| 1167 | nr_ptr = radio_nr; | ||
| 1034 | break; | 1168 | break; |
| 1035 | default: | 1169 | default: |
| 1036 | /* Bail out (this should be impossible) */ | 1170 | /* Bail out (this should be impossible) */ |
| @@ -1039,30 +1173,27 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip, | |||
| 1039 | return; | 1173 | return; |
| 1040 | } | 1174 | } |
| 1041 | 1175 | ||
| 1042 | if (!dip->stream) { | ||
| 1043 | err("Failed to set up pvrusb2 v4l dev" | ||
| 1044 | " due to missing stream instance"); | ||
| 1045 | return; | ||
| 1046 | } | ||
| 1047 | |||
| 1048 | memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template)); | 1176 | memcpy(&dip->devbase,&vdev_template,sizeof(vdev_template)); |
| 1049 | dip->devbase.release = pvr2_video_device_release; | 1177 | dip->devbase.release = pvr2_video_device_release; |
| 1050 | 1178 | ||
| 1051 | mindevnum = -1; | 1179 | mindevnum = -1; |
| 1052 | unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); | 1180 | unit_number = pvr2_hdw_get_unit_number(vp->channel.mc_head->hdw); |
| 1053 | if ((unit_number >= 0) && (unit_number < PVR_NUM)) { | 1181 | if (nr_ptr && (unit_number >= 0) && (unit_number < PVR_NUM)) { |
| 1054 | mindevnum = video_nr[unit_number]; | 1182 | mindevnum = nr_ptr[unit_number]; |
| 1055 | } | 1183 | } |
| 1056 | if ((video_register_device(&dip->devbase, v4l_type, mindevnum) < 0) && | 1184 | if ((video_register_device(&dip->devbase, |
| 1057 | (video_register_device(&dip->devbase, v4l_type, -1) < 0)) { | 1185 | dip->v4l_type, mindevnum) < 0) && |
| 1058 | err("Failed to register pvrusb2 v4l video device"); | 1186 | (video_register_device(&dip->devbase, |
| 1059 | } else { | 1187 | dip->v4l_type, -1) < 0)) { |
| 1060 | printk(KERN_INFO "pvrusb2: registered device video%d [%s]\n", | 1188 | err("Failed to register pvrusb2 v4l device"); |
| 1061 | dip->devbase.minor,pvr2_config_get_name(dip->config)); | ||
| 1062 | } | 1189 | } |
| 1063 | 1190 | ||
| 1191 | printk(KERN_INFO "pvrusb2: registered device %s%u [%s]\n", | ||
| 1192 | get_v4l_name(dip->v4l_type),dip->devbase.minor & 0x1f, | ||
| 1193 | pvr2_config_get_name(dip->config)); | ||
| 1194 | |||
| 1064 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, | 1195 | pvr2_hdw_v4l_store_minor_number(vp->channel.mc_head->hdw, |
| 1065 | dip->devbase.minor); | 1196 | dip->minor_type,dip->devbase.minor); |
| 1066 | } | 1197 | } |
| 1067 | 1198 | ||
| 1068 | 1199 | ||
| @@ -1070,22 +1201,24 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp) | |||
| 1070 | { | 1201 | { |
| 1071 | struct pvr2_v4l2 *vp; | 1202 | struct pvr2_v4l2 *vp; |
| 1072 | 1203 | ||
| 1073 | vp = kmalloc(sizeof(*vp),GFP_KERNEL); | 1204 | vp = kzalloc(sizeof(*vp),GFP_KERNEL); |
| 1074 | if (!vp) return vp; | 1205 | if (!vp) return vp; |
| 1075 | memset(vp,0,sizeof(*vp)); | 1206 | vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL); |
| 1076 | vp->vdev = kmalloc(sizeof(*vp->vdev),GFP_KERNEL); | 1207 | vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL); |
| 1077 | if (!vp->vdev) { | 1208 | if (!(vp->dev_video && vp->dev_radio)) { |
| 1209 | kfree(vp->dev_video); | ||
| 1210 | kfree(vp->dev_radio); | ||
| 1078 | kfree(vp); | 1211 | kfree(vp); |
| 1079 | return NULL; | 1212 | return NULL; |
| 1080 | } | 1213 | } |
| 1081 | memset(vp->vdev,0,sizeof(*vp->vdev)); | ||
| 1082 | pvr2_channel_init(&vp->channel,mnp); | 1214 | pvr2_channel_init(&vp->channel,mnp); |
| 1083 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); | 1215 | pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp); |
| 1084 | 1216 | ||
| 1085 | vp->channel.check_func = pvr2_v4l2_internal_check; | 1217 | vp->channel.check_func = pvr2_v4l2_internal_check; |
| 1086 | 1218 | ||
| 1087 | /* register streams */ | 1219 | /* register streams */ |
| 1088 | pvr2_v4l2_dev_init(vp->vdev,vp,pvr2_config_mpeg); | 1220 | pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER); |
| 1221 | pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO); | ||
| 1089 | 1222 | ||
| 1090 | return vp; | 1223 | return vp; |
| 1091 | } | 1224 | } |
