aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/dvb/cinergyT2/cinergyT2.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-01-09 16:03:58 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-09 16:03:58 -0500
commitf17578decc40df8fceff82b106582e30bdfb3189 (patch)
tree911a435a2094ac03ae649f020237674224e4124a /drivers/media/dvb/cinergyT2/cinergyT2.c
parent682e852e2638ed0aff84aa51181c9e5d2f939562 (diff)
parentcec418346e5a411e907293aba7cc21ac53c95834 (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.c82
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
506static 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
499static int cinergyt2_release (struct inode *inode, struct file *file) 515static 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)
786static void cinergyt2_unregister_rc(struct cinergyt2 *cinergyt2) 819static 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
937static int cinergyt2_suspend (struct usb_interface *intf, pm_message_t state) 966static 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
1015MODULE_LICENSE("GPL"); 1044MODULE_LICENSE("GPL");
1016MODULE_AUTHOR("Holger Waechtler, Daniel Mack"); 1045MODULE_AUTHOR("Holger Waechtler, Daniel Mack");
1017