diff options
Diffstat (limited to 'drivers/media/radio/radio-si470x.c')
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 291 |
1 files changed, 156 insertions, 135 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index d54fe6405351..8e4bd4769048 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
@@ -55,13 +55,17 @@ | |||
55 | * - applied all checkpatch.pl v1.12 suggestions | 55 | * - applied all checkpatch.pl v1.12 suggestions |
56 | * except the warning about the too long lines with bit comments | 56 | * except the warning about the too long lines with bit comments |
57 | * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) | 57 | * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) |
58 | * 2008-01-22 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
59 | * Version 1.0.4 | ||
60 | * - avoid poss. locking when doing copy_to_user which may sleep | ||
61 | * - RDS is automatically activated on read now | ||
62 | * - code cleaned of unnecessary rds_commands | ||
63 | * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified | ||
64 | * (thanks to Guillaume RAMOUSSE) | ||
58 | * | 65 | * |
59 | * ToDo: | 66 | * ToDo: |
60 | * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver | ||
61 | * (formerly Instant FM Music) (RDX-155-EF) is 06e1:a155 | ||
62 | * - add seeking support | 67 | * - add seeking support |
63 | * - add firmware download/update support | 68 | * - add firmware download/update support |
64 | * - add possibility to switch off RDS | ||
65 | * - RDS support: interrupt mode, instead of polling | 69 | * - RDS support: interrupt mode, instead of polling |
66 | * - add LED status output (check if that's not already done in firmware) | 70 | * - add LED status output (check if that's not already done in firmware) |
67 | */ | 71 | */ |
@@ -70,7 +74,7 @@ | |||
70 | /* driver definitions */ | 74 | /* driver definitions */ |
71 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" | 75 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" |
72 | #define DRIVER_NAME "radio-si470x" | 76 | #define DRIVER_NAME "radio-si470x" |
73 | #define DRIVER_VERSION KERNEL_VERSION(1, 0, 3) | 77 | #define DRIVER_VERSION KERNEL_VERSION(1, 0, 4) |
74 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | 78 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" |
75 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" | 79 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" |
76 | 80 | ||
@@ -93,6 +97,8 @@ | |||
93 | static struct usb_device_id si470x_usb_driver_id_table[] = { | 97 | static struct usb_device_id si470x_usb_driver_id_table[] = { |
94 | /* Silicon Labs USB FM Radio Reference Design */ | 98 | /* Silicon Labs USB FM Radio Reference Design */ |
95 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, | 99 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, |
100 | /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ | ||
101 | { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, | ||
96 | /* Terminating entry */ | 102 | /* Terminating entry */ |
97 | { } | 103 | { } |
98 | }; | 104 | }; |
@@ -159,6 +165,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | |||
159 | /* RDS poll frequency */ | 165 | /* RDS poll frequency */ |
160 | static int rds_poll_time = 40; | 166 | static int rds_poll_time = 40; |
161 | /* 40 is used by the original USBRadio.exe */ | 167 | /* 40 is used by the original USBRadio.exe */ |
168 | /* 50 is used by radio-cadet */ | ||
162 | /* 75 should be okay */ | 169 | /* 75 should be okay */ |
163 | /* 80 is the usual RDS receive interval */ | 170 | /* 80 is the usual RDS receive interval */ |
164 | module_param(rds_poll_time, int, 0); | 171 | module_param(rds_poll_time, int, 0); |
@@ -399,16 +406,13 @@ struct si470x_device { | |||
399 | 406 | ||
400 | /* RDS receive buffer */ | 407 | /* RDS receive buffer */ |
401 | struct work_struct work; | 408 | struct work_struct work; |
409 | wait_queue_head_t read_queue; | ||
402 | struct timer_list timer; | 410 | struct timer_list timer; |
403 | spinlock_t lock; /* buffer locking */ | 411 | spinlock_t lock; /* buffer locking */ |
404 | unsigned char *buffer; | 412 | unsigned char *buffer; /* size is always multiple of three */ |
405 | unsigned int buf_size; | 413 | unsigned int buf_size; |
406 | unsigned int rd_index; | 414 | unsigned int rd_index; |
407 | unsigned int wr_index; | 415 | unsigned int wr_index; |
408 | unsigned int block_count; | ||
409 | unsigned char last_blocknum; | ||
410 | wait_queue_head_t read_queue; | ||
411 | int data_available_for_read; | ||
412 | }; | 416 | }; |
413 | 417 | ||
414 | 418 | ||
@@ -658,8 +662,7 @@ static int si470x_start(struct si470x_device *radio) | |||
658 | return retval; | 662 | return retval; |
659 | 663 | ||
660 | /* sysconfig 1 */ | 664 | /* sysconfig 1 */ |
661 | radio->registers[SYSCONFIG1] = | 665 | radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; |
662 | SYSCONFIG1_DE | SYSCONFIG1_RDS; | ||
663 | retval = si470x_set_register(radio, SYSCONFIG1); | 666 | retval = si470x_set_register(radio, SYSCONFIG1); |
664 | if (retval < 0) | 667 | if (retval < 0) |
665 | return retval; | 668 | return retval; |
@@ -685,6 +688,14 @@ static int si470x_start(struct si470x_device *radio) | |||
685 | */ | 688 | */ |
686 | static int si470x_stop(struct si470x_device *radio) | 689 | static int si470x_stop(struct si470x_device *radio) |
687 | { | 690 | { |
691 | int retval; | ||
692 | |||
693 | /* sysconfig 1 */ | ||
694 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; | ||
695 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
696 | if (retval < 0) | ||
697 | return retval; | ||
698 | |||
688 | /* powercfg */ | 699 | /* powercfg */ |
689 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | 700 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; |
690 | /* POWERCFG_ENABLE has to automatically go low */ | 701 | /* POWERCFG_ENABLE has to automatically go low */ |
@@ -693,6 +704,17 @@ static int si470x_stop(struct si470x_device *radio) | |||
693 | } | 704 | } |
694 | 705 | ||
695 | 706 | ||
707 | /* | ||
708 | * si470x_rds_on - switch on rds reception | ||
709 | */ | ||
710 | static int si470x_rds_on(struct si470x_device *radio) | ||
711 | { | ||
712 | /* sysconfig 1 */ | ||
713 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; | ||
714 | return si470x_set_register(radio, SYSCONFIG1); | ||
715 | } | ||
716 | |||
717 | |||
696 | 718 | ||
697 | /************************************************************************** | 719 | /************************************************************************** |
698 | * RDS Driver Functions | 720 | * RDS Driver Functions |
@@ -703,15 +725,13 @@ static int si470x_stop(struct si470x_device *radio) | |||
703 | */ | 725 | */ |
704 | static void si470x_rds(struct si470x_device *radio) | 726 | static void si470x_rds(struct si470x_device *radio) |
705 | { | 727 | { |
706 | unsigned long flags; | ||
707 | unsigned char tmpbuf[3]; | 728 | unsigned char tmpbuf[3]; |
708 | unsigned char blocknum; | 729 | unsigned char blocknum; |
709 | unsigned char bler; /* RDS block errors */ | 730 | unsigned char bler; /* rds block errors */ |
710 | unsigned short rds; | 731 | unsigned short rds; |
711 | unsigned int i; | 732 | unsigned int i; |
712 | 733 | ||
713 | if (radio->users == 0) | 734 | /* get rds blocks */ |
714 | return; | ||
715 | if (si470x_get_rds_registers(radio) < 0) | 735 | if (si470x_get_rds_registers(radio) < 0) |
716 | return; | 736 | return; |
717 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { | 737 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { |
@@ -723,63 +743,67 @@ static void si470x_rds(struct si470x_device *radio) | |||
723 | return; | 743 | return; |
724 | } | 744 | } |
725 | 745 | ||
726 | for (blocknum = 0; blocknum < 4; blocknum++) { | 746 | /* copy four RDS blocks to internal buffer */ |
727 | switch (blocknum) { | 747 | if (spin_trylock(&radio->lock)) { |
728 | default: | 748 | /* process each rds block */ |
729 | bler = (radio->registers[STATUSRSSI] & | 749 | for (blocknum = 0; blocknum < 4; blocknum++) { |
730 | STATUSRSSI_BLERA) >> 9; | 750 | switch (blocknum) { |
731 | rds = radio->registers[RDSA]; | 751 | default: |
732 | break; | 752 | bler = (radio->registers[STATUSRSSI] & |
733 | case 1: | 753 | STATUSRSSI_BLERA) >> 9; |
734 | bler = (radio->registers[READCHAN] & | 754 | rds = radio->registers[RDSA]; |
735 | READCHAN_BLERB) >> 14; | 755 | break; |
736 | rds = radio->registers[RDSB]; | 756 | case 1: |
737 | break; | 757 | bler = (radio->registers[READCHAN] & |
738 | case 2: | 758 | READCHAN_BLERB) >> 14; |
739 | bler = (radio->registers[READCHAN] & | 759 | rds = radio->registers[RDSB]; |
740 | READCHAN_BLERC) >> 12; | 760 | break; |
741 | rds = radio->registers[RDSC]; | 761 | case 2: |
742 | break; | 762 | bler = (radio->registers[READCHAN] & |
743 | case 3: | 763 | READCHAN_BLERC) >> 12; |
744 | bler = (radio->registers[READCHAN] & | 764 | rds = radio->registers[RDSC]; |
745 | READCHAN_BLERD) >> 10; | 765 | break; |
746 | rds = radio->registers[RDSD]; | 766 | case 3: |
747 | break; | 767 | bler = (radio->registers[READCHAN] & |
748 | }; | 768 | READCHAN_BLERD) >> 10; |
749 | 769 | rds = radio->registers[RDSD]; | |
750 | /* Fill the V4L2 RDS buffer */ | 770 | break; |
751 | tmpbuf[0] = rds & 0x00ff; /* LSB */ | 771 | }; |
752 | tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ | 772 | |
753 | tmpbuf[2] = blocknum; /* offset name */ | 773 | /* Fill the V4L2 RDS buffer */ |
754 | tmpbuf[2] |= blocknum << 3; /* received offset */ | 774 | tmpbuf[0] = rds & 0x00ff; /* LSB */ |
755 | if (bler > max_rds_errors) | 775 | tmpbuf[1] = (rds & 0xff00) >> 8;/* MSB */ |
756 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | 776 | tmpbuf[2] = blocknum; /* offset name */ |
757 | else if (bler > 0) | 777 | tmpbuf[2] |= blocknum << 3; /* received offset */ |
758 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | 778 | if (bler > max_rds_errors) |
759 | 779 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | |
760 | spin_lock_irqsave(&radio->lock, flags); | 780 | else if (bler > 0) |
761 | 781 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | |
762 | /* copy RDS block to internal buffer */ | 782 | |
763 | for (i = 0; i < 3; i++) { | 783 | /* copy RDS block to internal buffer */ |
764 | radio->buffer[radio->wr_index] = tmpbuf[i]; | 784 | for (i = 0; i < 3; i++) { |
765 | radio->wr_index++; | 785 | radio->buffer[radio->wr_index] = tmpbuf[i]; |
786 | radio->wr_index++; | ||
787 | } | ||
788 | |||
789 | /* wrap write pointer */ | ||
790 | if (radio->wr_index >= radio->buf_size) | ||
791 | radio->wr_index = 0; | ||
792 | |||
793 | /* check for overflow */ | ||
794 | if (radio->wr_index == radio->rd_index) { | ||
795 | /* increment and wrap read pointer */ | ||
796 | radio->rd_index += 3; | ||
797 | if (radio->rd_index >= radio->buf_size) | ||
798 | radio->rd_index = 0; | ||
799 | } | ||
766 | } | 800 | } |
767 | 801 | spin_unlock(&radio->lock); | |
768 | if (radio->wr_index >= radio->buf_size) | ||
769 | radio->wr_index = 0; | ||
770 | |||
771 | if (radio->wr_index == radio->rd_index) { | ||
772 | radio->rd_index += 3; | ||
773 | if (radio->rd_index >= radio->buf_size) | ||
774 | radio->rd_index = 0; | ||
775 | } else | ||
776 | radio->block_count++; | ||
777 | |||
778 | spin_unlock_irqrestore(&radio->lock, flags); | ||
779 | } | 802 | } |
780 | 803 | ||
781 | radio->data_available_for_read = 1; | 804 | /* wake up read queue */ |
782 | wake_up_interruptible(&radio->read_queue); | 805 | if (radio->wr_index != radio->rd_index) |
806 | wake_up_interruptible(&radio->read_queue); | ||
783 | } | 807 | } |
784 | 808 | ||
785 | 809 | ||
@@ -795,14 +819,14 @@ static void si470x_timer(unsigned long data) | |||
795 | 819 | ||
796 | 820 | ||
797 | /* | 821 | /* |
798 | * si470x_timer - rds work function | 822 | * si470x_work - rds work function |
799 | */ | 823 | */ |
800 | static void si470x_work(struct work_struct *work) | 824 | static void si470x_work(struct work_struct *work) |
801 | { | 825 | { |
802 | struct si470x_device *radio = container_of(work, struct si470x_device, | 826 | struct si470x_device *radio = container_of(work, struct si470x_device, |
803 | work); | 827 | work); |
804 | 828 | ||
805 | if (radio->users == 0) | 829 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) |
806 | return; | 830 | return; |
807 | 831 | ||
808 | si470x_rds(radio); | 832 | si470x_rds(radio); |
@@ -822,53 +846,52 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf, | |||
822 | size_t count, loff_t *ppos) | 846 | size_t count, loff_t *ppos) |
823 | { | 847 | { |
824 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 848 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
825 | struct rds_command cmd; | 849 | int retval = 0; |
826 | unsigned long flags; | 850 | unsigned int block_count = 0; |
827 | unsigned int i; | ||
828 | unsigned int rd_blocks; | ||
829 | |||
830 | cmd.block_count = count / 3; /* each RDS block needs 3 bytes */ | ||
831 | cmd.result = 0; | ||
832 | cmd.buffer = buf; | ||
833 | cmd.instance = file; | ||
834 | |||
835 | /* copy RDS block out of internal buffer */ | ||
836 | while (!radio->data_available_for_read) { | ||
837 | if (wait_event_interruptible(radio->read_queue, | ||
838 | radio->data_available_for_read) < 0) | ||
839 | return -EINTR; | ||
840 | } | ||
841 | 851 | ||
842 | spin_lock_irqsave(&radio->lock, flags); | 852 | /* switch on rds reception */ |
843 | rd_blocks = cmd.block_count; | 853 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { |
844 | if (rd_blocks > radio->block_count) | 854 | si470x_rds_on(radio); |
845 | rd_blocks = radio->block_count; | 855 | schedule_work(&radio->work); |
856 | } | ||
846 | 857 | ||
847 | if (!rd_blocks) { | 858 | /* block if no new data available */ |
848 | spin_unlock_irqrestore(&radio->lock, flags); | 859 | while (radio->wr_index == radio->rd_index) { |
849 | return cmd.result; | 860 | if (file->f_flags & O_NONBLOCK) |
861 | return -EWOULDBLOCK; | ||
862 | interruptible_sleep_on(&radio->read_queue); | ||
850 | } | 863 | } |
851 | 864 | ||
852 | for (i = 0; i < rd_blocks; i++) { | 865 | /* calculate block count from byte count */ |
853 | /* copy RDS block to user buffer */ | 866 | count /= 3; |
854 | if (radio->rd_index == radio->wr_index) | 867 | |
855 | break; | 868 | /* copy RDS block out of internal buffer and to user buffer */ |
869 | if (spin_trylock(&radio->lock)) { | ||
870 | while (block_count < count) { | ||
871 | if (radio->rd_index == radio->wr_index) | ||
872 | break; | ||
856 | 873 | ||
857 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | 874 | /* always transfer rds complete blocks */ |
858 | break; | 875 | if (copy_to_user(buf, |
876 | &radio->buffer[radio->rd_index], 3)) | ||
877 | /* retval = -EFAULT; */ | ||
878 | break; | ||
859 | 879 | ||
860 | radio->rd_index += 3; | 880 | /* increment and wrap read pointer */ |
861 | if (radio->rd_index >= radio->buf_size) | 881 | radio->rd_index += 3; |
862 | radio->rd_index = 0; | 882 | if (radio->rd_index >= radio->buf_size) |
863 | radio->block_count--; | 883 | radio->rd_index = 0; |
884 | |||
885 | /* increment counters */ | ||
886 | block_count++; | ||
887 | buf += 3; | ||
888 | retval += 3; | ||
889 | } | ||
864 | 890 | ||
865 | buf += 3; | 891 | spin_unlock(&radio->lock); |
866 | cmd.result += 3; | ||
867 | } | 892 | } |
868 | radio->data_available_for_read = (radio->block_count > 0); | ||
869 | spin_unlock_irqrestore(&radio->lock, flags); | ||
870 | 893 | ||
871 | return cmd.result; | 894 | return retval; |
872 | } | 895 | } |
873 | 896 | ||
874 | 897 | ||
@@ -879,14 +902,19 @@ static unsigned int si470x_fops_poll(struct file *file, | |||
879 | struct poll_table_struct *pts) | 902 | struct poll_table_struct *pts) |
880 | { | 903 | { |
881 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 904 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
882 | int retval; | ||
883 | 905 | ||
884 | retval = 0; | 906 | /* switch on rds reception */ |
885 | if (radio->data_available_for_read) | 907 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { |
886 | retval = POLLIN | POLLRDNORM; | 908 | si470x_rds_on(radio); |
909 | schedule_work(&radio->work); | ||
910 | } | ||
911 | |||
887 | poll_wait(file, &radio->read_queue, pts); | 912 | poll_wait(file, &radio->read_queue, pts); |
888 | 913 | ||
889 | return retval; | 914 | if (radio->rd_index != radio->wr_index) |
915 | return POLLIN | POLLRDNORM; | ||
916 | |||
917 | return 0; | ||
890 | } | 918 | } |
891 | 919 | ||
892 | 920 | ||
@@ -895,17 +923,11 @@ static unsigned int si470x_fops_poll(struct file *file, | |||
895 | */ | 923 | */ |
896 | static int si470x_fops_open(struct inode *inode, struct file *file) | 924 | static int si470x_fops_open(struct inode *inode, struct file *file) |
897 | { | 925 | { |
898 | int retval; | ||
899 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 926 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
900 | 927 | ||
901 | radio->users++; | 928 | radio->users++; |
902 | if (radio->users == 1) { | 929 | if (radio->users == 1) |
903 | retval = si470x_start(radio); | 930 | return si470x_start(radio); |
904 | if (retval < 0) | ||
905 | return retval; | ||
906 | |||
907 | schedule_work(&radio->work); | ||
908 | } | ||
909 | 931 | ||
910 | return 0; | 932 | return 0; |
911 | } | 933 | } |
@@ -916,7 +938,6 @@ static int si470x_fops_open(struct inode *inode, struct file *file) | |||
916 | */ | 938 | */ |
917 | static int si470x_fops_release(struct inode *inode, struct file *file) | 939 | static int si470x_fops_release(struct inode *inode, struct file *file) |
918 | { | 940 | { |
919 | int retval; | ||
920 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 941 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
921 | 942 | ||
922 | if (!radio) | 943 | if (!radio) |
@@ -924,12 +945,14 @@ static int si470x_fops_release(struct inode *inode, struct file *file) | |||
924 | 945 | ||
925 | radio->users--; | 946 | radio->users--; |
926 | if (radio->users == 0) { | 947 | if (radio->users == 0) { |
927 | radio->data_available_for_read = 1; /* ? */ | 948 | /* stop rds reception */ |
928 | wake_up_interruptible(&radio->read_queue); /* ? */ | 949 | del_timer_sync(&radio->timer); |
950 | flush_scheduled_work(); | ||
929 | 951 | ||
930 | retval = si470x_stop(radio); | 952 | /* cancel read processes */ |
931 | if (retval < 0) | 953 | wake_up_interruptible(&radio->read_queue); |
932 | return retval; | 954 | |
955 | return si470x_stop(radio); | ||
933 | } | 956 | } |
934 | 957 | ||
935 | return 0; | 958 | return 0; |
@@ -1314,9 +1337,10 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
1314 | < RADIO_SW_VERSION_CURRENT) | 1337 | < RADIO_SW_VERSION_CURRENT) |
1315 | printk(KERN_WARNING DRIVER_NAME | 1338 | printk(KERN_WARNING DRIVER_NAME |
1316 | ": This driver is known to work with chip version %d, " | 1339 | ": This driver is known to work with chip version %d, " |
1317 | "but the device has firmware %d. If you have some " | 1340 | "but the device has firmware %d.\n" |
1318 | "trouble using this driver, please report to V4L ML " | 1341 | DRIVER_NAME |
1319 | "at video4linux-list@redhat.com\n", | 1342 | "If you have some trouble using this driver, please " |
1343 | "report to V4L ML at video4linux-list@redhat.com\n", | ||
1320 | radio->registers[CHIPID] & CHIPID_FIRMWARE, | 1344 | radio->registers[CHIPID] & CHIPID_FIRMWARE, |
1321 | RADIO_SW_VERSION_CURRENT); | 1345 | RADIO_SW_VERSION_CURRENT); |
1322 | 1346 | ||
@@ -1331,12 +1355,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, | |||
1331 | kfree(radio); | 1355 | kfree(radio); |
1332 | return -ENOMEM; | 1356 | return -ENOMEM; |
1333 | } | 1357 | } |
1334 | radio->block_count = 0; | ||
1335 | radio->wr_index = 0; | 1358 | radio->wr_index = 0; |
1336 | radio->rd_index = 0; | 1359 | radio->rd_index = 0; |
1337 | radio->last_blocknum = 0xff; | ||
1338 | init_waitqueue_head(&radio->read_queue); | 1360 | init_waitqueue_head(&radio->read_queue); |
1339 | radio->data_available_for_read = 0; | ||
1340 | 1361 | ||
1341 | /* prepare polling via eventd */ | 1362 | /* prepare polling via eventd */ |
1342 | INIT_WORK(&radio->work, si470x_work); | 1363 | INIT_WORK(&radio->work, si470x_work); |
@@ -1408,4 +1429,4 @@ module_exit(si470x_module_exit); | |||
1408 | MODULE_LICENSE("GPL"); | 1429 | MODULE_LICENSE("GPL"); |
1409 | MODULE_AUTHOR(DRIVER_AUTHOR); | 1430 | MODULE_AUTHOR(DRIVER_AUTHOR); |
1410 | MODULE_DESCRIPTION(DRIVER_DESC); | 1431 | MODULE_DESCRIPTION(DRIVER_DESC); |
1411 | MODULE_VERSION("1.0.3"); | 1432 | MODULE_VERSION("1.0.4"); |