diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-09 16:03:58 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-09 16:03:58 -0500 |
commit | f17578decc40df8fceff82b106582e30bdfb3189 (patch) | |
tree | 911a435a2094ac03ae649f020237674224e4124a /drivers/media/dvb/cinergyT2/cinergyT2.c | |
parent | 682e852e2638ed0aff84aa51181c9e5d2f939562 (diff) | |
parent | cec418346e5a411e907293aba7cc21ac53c95834 (diff) |
Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
Diffstat (limited to 'drivers/media/dvb/cinergyT2/cinergyT2.c')
-rw-r--r-- | drivers/media/dvb/cinergyT2/cinergyT2.c | 82 |
1 files changed, 55 insertions, 27 deletions
diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 1d69bf031fb9..c4b4c5b6b7c8 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c | |||
@@ -131,6 +131,8 @@ struct cinergyt2 { | |||
131 | 131 | ||
132 | wait_queue_head_t poll_wq; | 132 | wait_queue_head_t poll_wq; |
133 | int pending_fe_events; | 133 | int pending_fe_events; |
134 | int disconnect_pending; | ||
135 | atomic_t inuse; | ||
134 | 136 | ||
135 | void *streambuf; | 137 | void *streambuf; |
136 | dma_addr_t streambuf_dmahandle; | 138 | dma_addr_t streambuf_dmahandle; |
@@ -343,7 +345,7 @@ static int cinergyt2_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
343 | struct dvb_demux *demux = dvbdmxfeed->demux; | 345 | struct dvb_demux *demux = dvbdmxfeed->demux; |
344 | struct cinergyt2 *cinergyt2 = demux->priv; | 346 | struct cinergyt2 *cinergyt2 = demux->priv; |
345 | 347 | ||
346 | if (down_interruptible(&cinergyt2->sem)) | 348 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
347 | return -ERESTARTSYS; | 349 | return -ERESTARTSYS; |
348 | 350 | ||
349 | if (cinergyt2->streaming == 0) | 351 | if (cinergyt2->streaming == 0) |
@@ -359,7 +361,7 @@ static int cinergyt2_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | |||
359 | struct dvb_demux *demux = dvbdmxfeed->demux; | 361 | struct dvb_demux *demux = dvbdmxfeed->demux; |
360 | struct cinergyt2 *cinergyt2 = demux->priv; | 362 | struct cinergyt2 *cinergyt2 = demux->priv; |
361 | 363 | ||
362 | if (down_interruptible(&cinergyt2->sem)) | 364 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
363 | return -ERESTARTSYS; | 365 | return -ERESTARTSYS; |
364 | 366 | ||
365 | if (--cinergyt2->streaming == 0) | 367 | if (--cinergyt2->streaming == 0) |
@@ -479,23 +481,37 @@ static int cinergyt2_open (struct inode *inode, struct file *file) | |||
479 | { | 481 | { |
480 | struct dvb_device *dvbdev = file->private_data; | 482 | struct dvb_device *dvbdev = file->private_data; |
481 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | 483 | struct cinergyt2 *cinergyt2 = dvbdev->priv; |
482 | int err; | 484 | int err = -ERESTARTSYS; |
483 | 485 | ||
484 | if ((err = dvb_generic_open(inode, file))) | 486 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
487 | return -ERESTARTSYS; | ||
488 | |||
489 | if ((err = dvb_generic_open(inode, file))) { | ||
490 | up(&cinergyt2->sem); | ||
485 | return err; | 491 | return err; |
492 | } | ||
486 | 493 | ||
487 | if (down_interruptible(&cinergyt2->sem)) | ||
488 | return -ERESTARTSYS; | ||
489 | 494 | ||
490 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | 495 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { |
491 | cinergyt2_sleep(cinergyt2, 0); | 496 | cinergyt2_sleep(cinergyt2, 0); |
492 | schedule_delayed_work(&cinergyt2->query_work, HZ/2); | 497 | schedule_delayed_work(&cinergyt2->query_work, HZ/2); |
493 | } | 498 | } |
494 | 499 | ||
500 | atomic_inc(&cinergyt2->inuse); | ||
501 | |||
495 | up(&cinergyt2->sem); | 502 | up(&cinergyt2->sem); |
496 | return 0; | 503 | return 0; |
497 | } | 504 | } |
498 | 505 | ||
506 | static void cinergyt2_unregister(struct cinergyt2 *cinergyt2) | ||
507 | { | ||
508 | dvb_unregister_device(cinergyt2->fedev); | ||
509 | dvb_unregister_adapter(&cinergyt2->adapter); | ||
510 | |||
511 | cinergyt2_free_stream_urbs(cinergyt2); | ||
512 | kfree(cinergyt2); | ||
513 | } | ||
514 | |||
499 | static int cinergyt2_release (struct inode *inode, struct file *file) | 515 | static int cinergyt2_release (struct inode *inode, struct file *file) |
500 | { | 516 | { |
501 | struct dvb_device *dvbdev = file->private_data; | 517 | struct dvb_device *dvbdev = file->private_data; |
@@ -504,7 +520,7 @@ static int cinergyt2_release (struct inode *inode, struct file *file) | |||
504 | if (down_interruptible(&cinergyt2->sem)) | 520 | if (down_interruptible(&cinergyt2->sem)) |
505 | return -ERESTARTSYS; | 521 | return -ERESTARTSYS; |
506 | 522 | ||
507 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | 523 | if (!cinergyt2->disconnect_pending && (file->f_flags & O_ACCMODE) != O_RDONLY) { |
508 | cancel_delayed_work(&cinergyt2->query_work); | 524 | cancel_delayed_work(&cinergyt2->query_work); |
509 | flush_scheduled_work(); | 525 | flush_scheduled_work(); |
510 | cinergyt2_sleep(cinergyt2, 1); | 526 | cinergyt2_sleep(cinergyt2, 1); |
@@ -512,6 +528,11 @@ static int cinergyt2_release (struct inode *inode, struct file *file) | |||
512 | 528 | ||
513 | up(&cinergyt2->sem); | 529 | up(&cinergyt2->sem); |
514 | 530 | ||
531 | if (atomic_dec_and_test(&cinergyt2->inuse) && cinergyt2->disconnect_pending) { | ||
532 | warn("delayed unregister in release"); | ||
533 | cinergyt2_unregister(cinergyt2); | ||
534 | } | ||
535 | |||
515 | return dvb_generic_release(inode, file); | 536 | return dvb_generic_release(inode, file); |
516 | } | 537 | } |
517 | 538 | ||
@@ -519,7 +540,14 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct | |||
519 | { | 540 | { |
520 | struct dvb_device *dvbdev = file->private_data; | 541 | struct dvb_device *dvbdev = file->private_data; |
521 | struct cinergyt2 *cinergyt2 = dvbdev->priv; | 542 | struct cinergyt2 *cinergyt2 = dvbdev->priv; |
543 | |||
544 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) | ||
545 | return -ERESTARTSYS; | ||
546 | |||
522 | poll_wait(file, &cinergyt2->poll_wq, wait); | 547 | poll_wait(file, &cinergyt2->poll_wq, wait); |
548 | |||
549 | up(&cinergyt2->sem); | ||
550 | |||
523 | return (POLLIN | POLLRDNORM | POLLPRI); | 551 | return (POLLIN | POLLRDNORM | POLLPRI); |
524 | } | 552 | } |
525 | 553 | ||
@@ -564,10 +592,15 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, | |||
564 | (__u16 __user *) arg); | 592 | (__u16 __user *) arg); |
565 | 593 | ||
566 | case FE_READ_UNCORRECTED_BLOCKS: | 594 | case FE_READ_UNCORRECTED_BLOCKS: |
567 | /* UNC are already converted to host byte order... */ | 595 | { |
568 | return put_user(stat->uncorrected_block_count, | 596 | uint32_t unc_count; |
569 | (__u32 __user *) arg); | 597 | |
598 | unc_count = stat->uncorrected_block_count; | ||
599 | stat->uncorrected_block_count = 0; | ||
570 | 600 | ||
601 | /* UNC are already converted to host byte order... */ | ||
602 | return put_user(unc_count,(__u32 __user *) arg); | ||
603 | } | ||
571 | case FE_SET_FRONTEND: | 604 | case FE_SET_FRONTEND: |
572 | { | 605 | { |
573 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; | 606 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; |
@@ -580,7 +613,7 @@ static int cinergyt2_ioctl (struct inode *inode, struct file *file, | |||
580 | if (copy_from_user(&p, (void __user*) arg, sizeof(p))) | 613 | if (copy_from_user(&p, (void __user*) arg, sizeof(p))) |
581 | return -EFAULT; | 614 | return -EFAULT; |
582 | 615 | ||
583 | if (down_interruptible(&cinergyt2->sem)) | 616 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
584 | return -ERESTARTSYS; | 617 | return -ERESTARTSYS; |
585 | 618 | ||
586 | param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; | 619 | param->cmd = CINERGYT2_EP1_SET_TUNER_PARAMETERS; |
@@ -691,7 +724,7 @@ static void cinergyt2_query_rc (void *data) | |||
691 | struct cinergyt2_rc_event rc_events[12]; | 724 | struct cinergyt2_rc_event rc_events[12]; |
692 | int n, len, i; | 725 | int n, len, i; |
693 | 726 | ||
694 | if (down_interruptible(&cinergyt2->sem)) | 727 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
695 | return; | 728 | return; |
696 | 729 | ||
697 | len = cinergyt2_command(cinergyt2, buf, sizeof(buf), | 730 | len = cinergyt2_command(cinergyt2, buf, sizeof(buf), |
@@ -786,7 +819,6 @@ static int cinergyt2_register_rc(struct cinergyt2 *cinergyt2) | |||
786 | static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) | 819 | static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) |
787 | { | 820 | { |
788 | cancel_delayed_work(&cinergyt2->rc_query_work); | 821 | cancel_delayed_work(&cinergyt2->rc_query_work); |
789 | flush_scheduled_work(); | ||
790 | input_unregister_device(cinergyt2->rc_input_dev); | 822 | input_unregister_device(cinergyt2->rc_input_dev); |
791 | } | 823 | } |
792 | 824 | ||
@@ -817,7 +849,7 @@ static void cinergyt2_query (void *data) | |||
817 | uint8_t lock_bits; | 849 | uint8_t lock_bits; |
818 | uint32_t unc; | 850 | uint32_t unc; |
819 | 851 | ||
820 | if (down_interruptible(&cinergyt2->sem)) | 852 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
821 | return; | 853 | return; |
822 | 854 | ||
823 | unc = s->uncorrected_block_count; | 855 | unc = s->uncorrected_block_count; |
@@ -917,28 +949,25 @@ static void cinergyt2_disconnect (struct usb_interface *intf) | |||
917 | { | 949 | { |
918 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | 950 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); |
919 | 951 | ||
920 | if (down_interruptible(&cinergyt2->sem)) | 952 | flush_scheduled_work(); |
921 | return; | ||
922 | 953 | ||
923 | cinergyt2_unregister_rc(cinergyt2); | 954 | cinergyt2_unregister_rc(cinergyt2); |
924 | 955 | ||
956 | cancel_delayed_work(&cinergyt2->query_work); | ||
957 | wake_up_interruptible(&cinergyt2->poll_wq); | ||
958 | |||
925 | cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); | 959 | cinergyt2->demux.dmx.close(&cinergyt2->demux.dmx); |
926 | dvb_net_release(&cinergyt2->dvbnet); | 960 | cinergyt2->disconnect_pending = 1; |
927 | dvb_dmxdev_release(&cinergyt2->dmxdev); | ||
928 | dvb_dmx_release(&cinergyt2->demux); | ||
929 | dvb_unregister_device(cinergyt2->fedev); | ||
930 | dvb_unregister_adapter(&cinergyt2->adapter); | ||
931 | 961 | ||
932 | cinergyt2_free_stream_urbs(cinergyt2); | 962 | if (!atomic_read(&cinergyt2->inuse)) |
933 | up(&cinergyt2->sem); | 963 | cinergyt2_unregister(cinergyt2); |
934 | kfree(cinergyt2); | ||
935 | } | 964 | } |
936 | 965 | ||
937 | static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) | 966 | static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) |
938 | { | 967 | { |
939 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | 968 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); |
940 | 969 | ||
941 | if (down_interruptible(&cinergyt2->sem)) | 970 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
942 | return -ERESTARTSYS; | 971 | return -ERESTARTSYS; |
943 | 972 | ||
944 | if (state.event > PM_EVENT_ON) { | 973 | if (state.event > PM_EVENT_ON) { |
@@ -961,7 +990,7 @@ static int cinergyt2_resume (struct usb_interface *intf) | |||
961 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); | 990 | struct cinergyt2 *cinergyt2 = usb_get_intfdata (intf); |
962 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; | 991 | struct dvbt_set_parameters_msg *param = &cinergyt2->param; |
963 | 992 | ||
964 | if (down_interruptible(&cinergyt2->sem)) | 993 | if (cinergyt2->disconnect_pending || down_interruptible(&cinergyt2->sem)) |
965 | return -ERESTARTSYS; | 994 | return -ERESTARTSYS; |
966 | 995 | ||
967 | if (!cinergyt2->sleeping) { | 996 | if (!cinergyt2->sleeping) { |
@@ -1014,4 +1043,3 @@ module_exit (cinergyt2_exit); | |||
1014 | 1043 | ||
1015 | MODULE_LICENSE("GPL"); | 1044 | MODULE_LICENSE("GPL"); |
1016 | MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); | 1045 | MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); |
1017 | |||