diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 330 |
1 files changed, 167 insertions, 163 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index d428c3aa2bf9..c72a9e7ad885 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
@@ -66,8 +66,21 @@ | |||
66 | * Version 1.0.5 | 66 | * Version 1.0.5 |
67 | * - number of seek_retries changed to tune_timeout | 67 | * - number of seek_retries changed to tune_timeout |
68 | * - fixed problem with incomplete tune operations by own buffers | 68 | * - fixed problem with incomplete tune operations by own buffers |
69 | * - optimization of variables | 69 | * - optimization of variables and printf types |
70 | * - improved error logging | 70 | * - improved error logging |
71 | * 2008-01-31 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
72 | * Oliver Neukum <oliver@neukum.org> | ||
73 | * Version 1.0.6 | ||
74 | * - fixed coverity checker warnings in *_usb_driver_disconnect | ||
75 | * - probe()/open() race by correct ordering in probe() | ||
76 | * - DMA coherency rules by separate allocation of all buffers | ||
77 | * - use of endianness macros | ||
78 | * - abuse of spinlock, replaced by mutex | ||
79 | * - racy handling of timer in disconnect, | ||
80 | * replaced by delayed_work | ||
81 | * - racy interruptible_sleep_on(), | ||
82 | * replaced with wait_event_interruptible() | ||
83 | * - handle signals in read() | ||
71 | * | 84 | * |
72 | * ToDo: | 85 | * ToDo: |
73 | * - add seeking support | 86 | * - add seeking support |
@@ -80,10 +93,10 @@ | |||
80 | /* driver definitions */ | 93 | /* driver definitions */ |
81 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" | 94 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" |
82 | #define DRIVER_NAME "radio-si470x" | 95 | #define DRIVER_NAME "radio-si470x" |
83 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 5) | 96 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 6) |
84 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | 97 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" |
85 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" | 98 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" |
86 | #define DRIVER_VERSION "1.0.5" | 99 | #define DRIVER_VERSION "1.0.6" |
87 | 100 | ||
88 | 101 | ||
89 | /* kernel includes */ | 102 | /* kernel includes */ |
@@ -96,8 +109,10 @@ | |||
96 | #include <linux/hid.h> | 109 | #include <linux/hid.h> |
97 | #include <linux/version.h> | 110 | #include <linux/version.h> |
98 | #include <linux/videodev2.h> | 111 | #include <linux/videodev2.h> |
112 | #include <linux/mutex.h> | ||
99 | #include <media/v4l2-common.h> | 113 | #include <media/v4l2-common.h> |
100 | #include <media/rds.h> | 114 | #include <media/rds.h> |
115 | #include <asm/unaligned.h> | ||
101 | 116 | ||
102 | 117 | ||
103 | /* USB Device ID List */ | 118 | /* USB Device ID List */ |
@@ -409,10 +424,9 @@ struct si470x_device { | |||
409 | unsigned short registers[RADIO_REGISTER_NUM]; | 424 | unsigned short registers[RADIO_REGISTER_NUM]; |
410 | 425 | ||
411 | /* RDS receive buffer */ | 426 | /* RDS receive buffer */ |
412 | struct work_struct work; | 427 | struct delayed_work work; |
413 | wait_queue_head_t read_queue; | 428 | wait_queue_head_t read_queue; |
414 | struct timer_list timer; | 429 | struct mutex lock; /* buffer locking */ |
415 | spinlock_t lock; /* buffer locking */ | ||
416 | unsigned char *buffer; /* size is always multiple of three */ | 430 | unsigned char *buffer; /* size is always multiple of three */ |
417 | unsigned int buf_size; | 431 | unsigned int buf_size; |
418 | unsigned int rd_index; | 432 | unsigned int rd_index; |
@@ -494,7 +508,8 @@ static int si470x_get_register(struct si470x_device *radio, int regnr) | |||
494 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | 508 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); |
495 | 509 | ||
496 | if (retval >= 0) | 510 | if (retval >= 0) |
497 | radio->registers[regnr] = (buf[1] << 8) | buf[2]; | 511 | radio->registers[regnr] = be16_to_cpu(get_unaligned( |
512 | (unsigned short *) &buf[1])); | ||
498 | 513 | ||
499 | return (retval < 0) ? -EINVAL : 0; | 514 | return (retval < 0) ? -EINVAL : 0; |
500 | } | 515 | } |
@@ -509,8 +524,8 @@ static int si470x_set_register(struct si470x_device *radio, int regnr) | |||
509 | int retval; | 524 | int retval; |
510 | 525 | ||
511 | buf[0] = REGISTER_REPORT(regnr); | 526 | buf[0] = REGISTER_REPORT(regnr); |
512 | buf[1] = (radio->registers[regnr] & 0xff00) >> 8; | 527 | put_unaligned(cpu_to_be16(radio->registers[regnr]), |
513 | buf[2] = (radio->registers[regnr] & 0x00ff); | 528 | (unsigned short *) &buf[1]); |
514 | 529 | ||
515 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); | 530 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); |
516 | 531 | ||
@@ -533,9 +548,9 @@ static int si470x_get_all_registers(struct si470x_device *radio) | |||
533 | 548 | ||
534 | if (retval >= 0) | 549 | if (retval >= 0) |
535 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) | 550 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) |
536 | radio->registers[regnr] = | 551 | radio->registers[regnr] = be16_to_cpu(get_unaligned( |
537 | (buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | | 552 | (unsigned short *) |
538 | buf[regnr * RADIO_REGISTER_SIZE + 2]; | 553 | &buf[regnr * RADIO_REGISTER_SIZE + 1])); |
539 | 554 | ||
540 | return (retval < 0) ? -EINVAL : 0; | 555 | return (retval < 0) ? -EINVAL : 0; |
541 | } | 556 | } |
@@ -558,7 +573,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio) | |||
558 | (void *) &buf, sizeof(buf), &size, usb_timeout); | 573 | (void *) &buf, sizeof(buf), &size, usb_timeout); |
559 | if (size != sizeof(buf)) | 574 | if (size != sizeof(buf)) |
560 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: " | 575 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: " |
561 | "return size differs: %d != %uld\n", size, sizeof(buf)); | 576 | "return size differs: %d != %zu\n", size, sizeof(buf)); |
562 | if (retval < 0) | 577 | if (retval < 0) |
563 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " | 578 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " |
564 | "usb_interrupt_msg returned %d\n", retval); | 579 | "usb_interrupt_msg returned %d\n", retval); |
@@ -566,8 +581,8 @@ static int si470x_get_rds_registers(struct si470x_device *radio) | |||
566 | if (retval >= 0) | 581 | if (retval >= 0) |
567 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) | 582 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) |
568 | radio->registers[STATUSRSSI + regnr] = | 583 | radio->registers[STATUSRSSI + regnr] = |
569 | (buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | | 584 | be16_to_cpu(get_unaligned((unsigned short *) |
570 | buf[regnr * RADIO_REGISTER_SIZE + 2]; | 585 | &buf[regnr * RADIO_REGISTER_SIZE + 1])); |
571 | 586 | ||
572 | return (retval < 0) ? -EINVAL : 0; | 587 | return (retval < 0) ? -EINVAL : 0; |
573 | } | 588 | } |
@@ -600,7 +615,7 @@ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) | |||
600 | (!timed_out)); | 615 | (!timed_out)); |
601 | if (timed_out) | 616 | if (timed_out) |
602 | printk(KERN_WARNING DRIVER_NAME | 617 | printk(KERN_WARNING DRIVER_NAME |
603 | ": seek does not finish after %d ms\n", tune_timeout); | 618 | ": seek does not finish after %u ms\n", tune_timeout); |
604 | 619 | ||
605 | /* stop tuning */ | 620 | /* stop tuning */ |
606 | radio->registers[CHANNEL] &= ~CHANNEL_TUNE; | 621 | radio->registers[CHANNEL] &= ~CHANNEL_TUNE; |
@@ -763,6 +778,11 @@ static int si470x_rds_on(struct si470x_device *radio) | |||
763 | */ | 778 | */ |
764 | static void si470x_rds(struct si470x_device *radio) | 779 | static void si470x_rds(struct si470x_device *radio) |
765 | { | 780 | { |
781 | unsigned char blocknum; | ||
782 | unsigned short bler; /* rds block errors */ | ||
783 | unsigned short rds; | ||
784 | unsigned char tmpbuf[3]; | ||
785 | |||
766 | /* get rds blocks */ | 786 | /* get rds blocks */ |
767 | if (si470x_get_rds_registers(radio) < 0) | 787 | if (si470x_get_rds_registers(radio) < 0) |
768 | return; | 788 | return; |
@@ -775,69 +795,58 @@ static void si470x_rds(struct si470x_device *radio) | |||
775 | return; | 795 | return; |
776 | } | 796 | } |
777 | 797 | ||
778 | /* copy four RDS blocks to internal buffer */ | 798 | /* copy all four RDS blocks to internal buffer */ |
779 | if (spin_trylock(&radio->lock)) { | 799 | mutex_lock(&radio->lock); |
780 | unsigned char blocknum; | 800 | for (blocknum = 0; blocknum < 4; blocknum++) { |
781 | unsigned short bler; /* rds block errors */ | 801 | switch (blocknum) { |
782 | unsigned short rds; | 802 | default: |
783 | unsigned char tmpbuf[3]; | 803 | bler = (radio->registers[STATUSRSSI] & |
784 | unsigned char i; | 804 | STATUSRSSI_BLERA) >> 9; |
785 | 805 | rds = radio->registers[RDSA]; | |
786 | /* process each rds block */ | 806 | break; |
787 | for (blocknum = 0; blocknum < 4; blocknum++) { | 807 | case 1: |
788 | switch (blocknum) { | 808 | bler = (radio->registers[READCHAN] & |
789 | default: | 809 | READCHAN_BLERB) >> 14; |
790 | bler = (radio->registers[STATUSRSSI] & | 810 | rds = radio->registers[RDSB]; |
791 | STATUSRSSI_BLERA) >> 9; | 811 | break; |
792 | rds = radio->registers[RDSA]; | 812 | case 2: |
793 | break; | 813 | bler = (radio->registers[READCHAN] & |
794 | case 1: | 814 | READCHAN_BLERC) >> 12; |
795 | bler = (radio->registers[READCHAN] & | 815 | rds = radio->registers[RDSC]; |
796 | READCHAN_BLERB) >> 14; | 816 | break; |
797 | rds = radio->registers[RDSB]; | 817 | case 3: |
798 | break; | 818 | bler = (radio->registers[READCHAN] & |
799 | case 2: | 819 | READCHAN_BLERD) >> 10; |
800 | bler = (radio->registers[READCHAN] & | 820 | rds = radio->registers[RDSD]; |
801 | READCHAN_BLERC) >> 12; | 821 | break; |
802 | rds = radio->registers[RDSC]; | 822 | }; |
803 | break; | 823 | |
804 | case 3: | 824 | /* Fill the V4L2 RDS buffer */ |
805 | bler = (radio->registers[READCHAN] & | 825 | put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf); |
806 | READCHAN_BLERD) >> 10; | 826 | tmpbuf[2] = blocknum; /* offset name */ |
807 | rds = radio->registers[RDSD]; | 827 | tmpbuf[2] |= blocknum << 3; /* received offset */ |
808 | break; | 828 | if (bler > max_rds_errors) |
809 | }; | 829 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ |
810 | 830 | else if (bler > 0) | |
811 | /* Fill the V4L2 RDS buffer */ | 831 | tmpbuf[2] |= 0x40; /* corrected error(s) */ |
812 | tmpbuf[0] = rds & 0x00ff; /* LSB */ | 832 | |
813 | tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ | 833 | /* copy RDS block to internal buffer */ |
814 | tmpbuf[2] = blocknum; /* offset name */ | 834 | memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); |
815 | tmpbuf[2] |= blocknum << 3; /* received offset */ | 835 | radio->wr_index += 3; |
816 | if (bler > max_rds_errors) | 836 | |
817 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | 837 | /* wrap write pointer */ |
818 | else if (bler > 0) | 838 | if (radio->wr_index >= radio->buf_size) |
819 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | 839 | radio->wr_index = 0; |
820 | 840 | ||
821 | /* copy RDS block to internal buffer */ | 841 | /* check for overflow */ |
822 | for (i = 0; i < 3; i++) { | 842 | if (radio->wr_index == radio->rd_index) { |
823 | radio->buffer[radio->wr_index] = tmpbuf[i]; | 843 | /* increment and wrap read pointer */ |
824 | radio->wr_index++; | 844 | radio->rd_index += 3; |
825 | } | 845 | if (radio->rd_index >= radio->buf_size) |
826 | 846 | radio->rd_index = 0; | |
827 | /* wrap write pointer */ | ||
828 | if (radio->wr_index >= radio->buf_size) | ||
829 | radio->wr_index = 0; | ||
830 | |||
831 | /* check for overflow */ | ||
832 | if (radio->wr_index == radio->rd_index) { | ||
833 | /* increment and wrap read pointer */ | ||
834 | radio->rd_index += 3; | ||
835 | if (radio->rd_index >= radio->buf_size) | ||
836 | radio->rd_index = 0; | ||
837 | } | ||
838 | } | 847 | } |
839 | spin_unlock(&radio->lock); | ||
840 | } | 848 | } |
849 | mutex_unlock(&radio->lock); | ||
841 | 850 | ||
842 | /* wake up read queue */ | 851 | /* wake up read queue */ |
843 | if (radio->wr_index != radio->rd_index) | 852 | if (radio->wr_index != radio->rd_index) |
@@ -846,29 +855,18 @@ static void si470x_rds(struct si470x_device *radio) | |||
846 | 855 | ||
847 | 856 | ||
848 | /* | 857 | /* |
849 | * si470x_timer - rds timer function | ||
850 | */ | ||
851 | static void si470x_timer(unsigned long data) | ||
852 | { | ||
853 | struct si470x_device *radio = (struct si470x_device *) data; | ||
854 | |||
855 | schedule_work(&radio->work); | ||
856 | } | ||
857 | |||
858 | |||
859 | /* | ||
860 | * si470x_work - rds work function | 858 | * si470x_work - rds work function |
861 | */ | 859 | */ |
862 | static void si470x_work(struct work_struct *work) | 860 | static void si470x_work(struct work_struct *work) |
863 | { | 861 | { |
864 | struct si470x_device *radio = container_of(work, struct si470x_device, | 862 | struct si470x_device *radio = container_of(work, struct si470x_device, |
865 | work); | 863 | work.work); |
866 | 864 | ||
867 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | 865 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) |
868 | return; | 866 | return; |
869 | 867 | ||
870 | si470x_rds(radio); | 868 | si470x_rds(radio); |
871 | mod_timer(&radio->timer, jiffies + msecs_to_jiffies(rds_poll_time)); | 869 | schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time)); |
872 | } | 870 | } |
873 | 871 | ||
874 | 872 | ||
@@ -885,49 +883,49 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, | |||
885 | { | 883 | { |
886 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 884 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
887 | int retval = 0; | 885 | int retval = 0; |
886 | unsigned int block_count = 0; | ||
888 | 887 | ||
889 | /* switch on rds reception */ | 888 | /* switch on rds reception */ |
890 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { | 889 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { |
891 | si470x_rds_on(radio); | 890 | si470x_rds_on(radio); |
892 | schedule_work(&radio->work); | 891 | schedule_delayed_work(&radio->work, |
892 | msecs_to_jiffies(rds_poll_time)); | ||
893 | } | 893 | } |
894 | 894 | ||
895 | /* block if no new data available */ | 895 | /* block if no new data available */ |
896 | while (radio->wr_index == radio->rd_index) { | 896 | while (radio->wr_index == radio->rd_index) { |
897 | if (file->f_flags & O_NONBLOCK) | 897 | if (file->f_flags & O_NONBLOCK) |
898 | return -EWOULDBLOCK; | 898 | return -EWOULDBLOCK; |
899 | interruptible_sleep_on(&radio->read_queue); | 899 | if (wait_event_interruptible(radio->read_queue, |
900 | radio->wr_index != radio->rd_index) < 0) | ||
901 | return -EINTR; | ||
900 | } | 902 | } |
901 | 903 | ||
902 | /* calculate block count from byte count */ | 904 | /* calculate block count from byte count */ |
903 | count /= 3; | 905 | count /= 3; |
904 | 906 | ||
905 | /* copy RDS block out of internal buffer and to user buffer */ | 907 | /* copy RDS block out of internal buffer and to user buffer */ |
906 | if (spin_trylock(&radio->lock)) { | 908 | mutex_lock(&radio->lock); |
907 | unsigned int block_count = 0; | 909 | while (block_count < count) { |
908 | while (block_count < count) { | 910 | if (radio->rd_index == radio->wr_index) |
909 | if (radio->rd_index == radio->wr_index) | 911 | break; |
910 | break; | ||
911 | |||
912 | /* always transfer rds complete blocks */ | ||
913 | if (copy_to_user(buf, | ||
914 | &radio->buffer[radio->rd_index], 3)) | ||
915 | /* retval = -EFAULT; */ | ||
916 | break; | ||
917 | 912 | ||
918 | /* increment and wrap read pointer */ | 913 | /* always transfer rds complete blocks */ |
919 | radio->rd_index += 3; | 914 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) |
920 | if (radio->rd_index >= radio->buf_size) | 915 | /* retval = -EFAULT; */ |
921 | radio->rd_index = 0; | 916 | break; |
922 | 917 | ||
923 | /* increment counters */ | 918 | /* increment and wrap read pointer */ |
924 | block_count++; | 919 | radio->rd_index += 3; |
925 | buf += 3; | 920 | if (radio->rd_index >= radio->buf_size) |
926 | retval += 3; | 921 | radio->rd_index = 0; |
927 | } | ||
928 | 922 | ||
929 | spin_unlock(&radio->lock); | 923 | /* increment counters */ |
924 | block_count++; | ||
925 | buf += 3; | ||
926 | retval += 3; | ||
930 | } | 927 | } |
928 | mutex_unlock(&radio->lock); | ||
931 | 929 | ||
932 | return retval; | 930 | return retval; |
933 | } | 931 | } |
@@ -944,7 +942,8 @@ static unsigned int si470x_fops_poll(struct file *file, | |||
944 | /* switch on rds reception */ | 942 | /* switch on rds reception */ |
945 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { | 943 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { |
946 | si470x_rds_on(radio); | 944 | si470x_rds_on(radio); |
947 | schedule_work(&radio->work); | 945 | schedule_delayed_work(&radio->work, |
946 | msecs_to_jiffies(rds_poll_time)); | ||
948 | } | 947 | } |
949 | 948 | ||
950 | poll_wait(file, &radio->read_queue, pts); | 949 | poll_wait(file, &radio->read_queue, pts); |
@@ -984,8 +983,7 @@ static int si470x_fops_release(struct inode *inode, struct file *file) | |||
984 | radio->users--; | 983 | radio->users--; |
985 | if (radio->users == 0) { | 984 | if (radio->users == 0) { |
986 | /* stop rds reception */ | 985 | /* stop rds reception */ |
987 | del_timer_sync(&radio->timer); | 986 | cancel_delayed_work_sync(&radio->work); |
988 | flush_scheduled_work(); | ||
989 | 987 | ||
990 | /* cancel read processes */ | 988 | /* cancel read processes */ |
991 | wake_up_interruptible(&radio->read_queue); | 989 | wake_up_interruptible(&radio->read_queue); |
@@ -1362,73 +1360,82 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
1362 | const struct usb_device_id *id) | 1360 | const struct usb_device_id *id) |
1363 | { | 1361 | { |
1364 | struct si470x_device *radio; | 1362 | struct si470x_device *radio; |
1363 | int retval = -ENOMEM; | ||
1365 | 1364 | ||
1366 | /* memory and interface allocations */ | 1365 | /* private data allocation */ |
1367 | radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); | 1366 | radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); |
1368 | if (!radio) | 1367 | if (!radio) |
1369 | return -ENOMEM; | 1368 | goto err_initial; |
1369 | |||
1370 | /* video device allocation */ | ||
1370 | radio->videodev = video_device_alloc(); | 1371 | radio->videodev = video_device_alloc(); |
1371 | if (!radio->videodev) { | 1372 | if (!radio->videodev) |
1372 | kfree(radio); | 1373 | goto err_radio; |
1373 | return -ENOMEM; | 1374 | |
1374 | } | 1375 | /* initial configuration */ |
1375 | memcpy(radio->videodev, &si470x_viddev_template, | 1376 | memcpy(radio->videodev, &si470x_viddev_template, |
1376 | sizeof(si470x_viddev_template)); | 1377 | sizeof(si470x_viddev_template)); |
1377 | radio->users = 0; | 1378 | radio->users = 0; |
1378 | radio->usbdev = interface_to_usbdev(intf); | 1379 | radio->usbdev = interface_to_usbdev(intf); |
1380 | mutex_init(&radio->lock); | ||
1379 | video_set_drvdata(radio->videodev, radio); | 1381 | video_set_drvdata(radio->videodev, radio); |
1380 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { | ||
1381 | printk(KERN_WARNING DRIVER_NAME | ||
1382 | ": Could not register video device\n"); | ||
1383 | video_device_release(radio->videodev); | ||
1384 | kfree(radio); | ||
1385 | return -EIO; | ||
1386 | } | ||
1387 | usb_set_intfdata(intf, radio); | ||
1388 | 1382 | ||
1389 | /* show some infos about the specific device */ | 1383 | /* show some infos about the specific device */ |
1390 | if (si470x_get_all_registers(radio) < 0) { | 1384 | retval = -EIO; |
1391 | video_device_release(radio->videodev); | 1385 | if (si470x_get_all_registers(radio) < 0) |
1392 | kfree(radio); | 1386 | goto err_all; |
1393 | return -EIO; | 1387 | printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", |
1394 | } | ||
1395 | printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", | ||
1396 | radio->registers[DEVICEID], radio->registers[CHIPID]); | 1388 | radio->registers[DEVICEID], radio->registers[CHIPID]); |
1397 | 1389 | ||
1398 | /* check if firmware is current */ | 1390 | /* check if firmware is current */ |
1399 | if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) | 1391 | if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) |
1400 | < RADIO_SW_VERSION_CURRENT) | 1392 | < RADIO_SW_VERSION_CURRENT) { |
1393 | printk(KERN_WARNING DRIVER_NAME | ||
1394 | ": This driver is known to work with " | ||
1395 | "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT); | ||
1396 | printk(KERN_WARNING DRIVER_NAME | ||
1397 | ": but the device has firmware version %hu.\n", | ||
1398 | radio->registers[CHIPID] & CHIPID_FIRMWARE); | ||
1399 | printk(KERN_WARNING DRIVER_NAME | ||
1400 | ": If you have some trouble using this driver,\n"); | ||
1401 | printk(KERN_WARNING DRIVER_NAME | 1401 | printk(KERN_WARNING DRIVER_NAME |
1402 | ": This driver is known to work with chip version %d, " | 1402 | ": please report to V4L ML at " |
1403 | "but the device has firmware %d.\n" | 1403 | "video4linux-list@redhat.com\n"); |
1404 | DRIVER_NAME | 1404 | } |
1405 | "If you have some trouble using this driver, please " | ||
1406 | "report to V4L ML at video4linux-list@redhat.com\n", | ||
1407 | radio->registers[CHIPID] & CHIPID_FIRMWARE, | ||
1408 | RADIO_SW_VERSION_CURRENT); | ||
1409 | 1405 | ||
1410 | /* set initial frequency */ | 1406 | /* set initial frequency */ |
1411 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | 1407 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ |
1412 | 1408 | ||
1413 | /* rds initialization */ | 1409 | /* rds buffer allocation */ |
1414 | radio->buf_size = rds_buf * 3; | 1410 | radio->buf_size = rds_buf * 3; |
1415 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | 1411 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); |
1416 | if (!radio->buffer) { | 1412 | if (!radio->buffer) |
1417 | video_device_release(radio->videodev); | 1413 | goto err_all; |
1418 | kfree(radio); | 1414 | |
1419 | return -ENOMEM; | 1415 | /* rds buffer configuration */ |
1420 | } | ||
1421 | radio->wr_index = 0; | 1416 | radio->wr_index = 0; |
1422 | radio->rd_index = 0; | 1417 | radio->rd_index = 0; |
1423 | init_waitqueue_head(&radio->read_queue); | 1418 | init_waitqueue_head(&radio->read_queue); |
1424 | 1419 | ||
1425 | /* prepare polling via eventd */ | 1420 | /* prepare rds work function */ |
1426 | INIT_WORK(&radio->work, si470x_work); | 1421 | INIT_DELAYED_WORK(&radio->work, si470x_work); |
1427 | init_timer(&radio->timer); | 1422 | |
1428 | radio->timer.function = si470x_timer; | 1423 | /* register video device */ |
1429 | radio->timer.data = (unsigned long) radio; | 1424 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { |
1425 | printk(KERN_WARNING DRIVER_NAME | ||
1426 | ": Could not register video device\n"); | ||
1427 | goto err_all; | ||
1428 | } | ||
1429 | usb_set_intfdata(intf, radio); | ||
1430 | 1430 | ||
1431 | return 0; | 1431 | return 0; |
1432 | err_all: | ||
1433 | video_device_release(radio->videodev); | ||
1434 | kfree(radio->buffer); | ||
1435 | err_radio: | ||
1436 | kfree(radio); | ||
1437 | err_initial: | ||
1438 | return retval; | ||
1432 | } | 1439 | } |
1433 | 1440 | ||
1434 | 1441 | ||
@@ -1439,14 +1446,11 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf) | |||
1439 | { | 1446 | { |
1440 | struct si470x_device *radio = usb_get_intfdata(intf); | 1447 | struct si470x_device *radio = usb_get_intfdata(intf); |
1441 | 1448 | ||
1449 | cancel_delayed_work_sync(&radio->work); | ||
1442 | usb_set_intfdata(intf, NULL); | 1450 | usb_set_intfdata(intf, NULL); |
1443 | if (radio) { | 1451 | video_unregister_device(radio->videodev); |
1444 | del_timer_sync(&radio->timer); | 1452 | kfree(radio->buffer); |
1445 | flush_scheduled_work(); | 1453 | kfree(radio); |
1446 | video_unregister_device(radio->videodev); | ||
1447 | kfree(radio->buffer); | ||
1448 | kfree(radio); | ||
1449 | } | ||
1450 | } | 1454 | } |
1451 | 1455 | ||
1452 | 1456 | ||