diff options
Diffstat (limited to 'drivers/media/radio/radio-si470x.c')
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 1863 |
1 files changed, 0 insertions, 1863 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c deleted file mode 100644 index e85f318b4d2b..000000000000 --- a/drivers/media/radio/radio-si470x.c +++ /dev/null | |||
@@ -1,1863 +0,0 @@ | |||
1 | /* | ||
2 | * drivers/media/radio/radio-si470x.c | ||
3 | * | ||
4 | * Driver for USB radios for the Silicon Labs Si470x FM Radio Receivers: | ||
5 | * - Silicon Labs USB FM Radio Reference Design | ||
6 | * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) | ||
7 | * - KWorld USB FM Radio SnapMusic Mobile 700 (FM700) | ||
8 | * - Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) | ||
9 | * | ||
10 | * Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
25 | */ | ||
26 | |||
27 | |||
28 | /* | ||
29 | * History: | ||
30 | * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
31 | * Version 1.0.0 | ||
32 | * - First working version | ||
33 | * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
34 | * Version 1.0.1 | ||
35 | * - Improved error handling, every function now returns errno | ||
36 | * - Improved multi user access (start/mute/stop) | ||
37 | * - Channel doesn't get lost anymore after start/mute/stop | ||
38 | * - RDS support added (polling mode via interrupt EP 1) | ||
39 | * - marked default module parameters with *value* | ||
40 | * - switched from bit structs to bit masks | ||
41 | * - header file cleaned and integrated | ||
42 | * 2008-01-14 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
43 | * Version 1.0.2 | ||
44 | * - hex values are now lower case | ||
45 | * - commented USB ID for ADS/Tech moved on todo list | ||
46 | * - blacklisted si470x in hid-quirks.c | ||
47 | * - rds buffer handling functions integrated into *_work, *_read | ||
48 | * - rds_command in si470x_poll exchanged against simple retval | ||
49 | * - check for firmware version 15 | ||
50 | * - code order and prototypes still remain the same | ||
51 | * - spacing and bottom of band codes remain the same | ||
52 | * 2008-01-16 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
53 | * Version 1.0.3 | ||
54 | * - code reordered to avoid function prototypes | ||
55 | * - switch/case defaults are now more user-friendly | ||
56 | * - unified comment style | ||
57 | * - applied all checkpatch.pl v1.12 suggestions | ||
58 | * except the warning about the too long lines with bit comments | ||
59 | * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) | ||
60 | * 2008-01-22 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
61 | * Version 1.0.4 | ||
62 | * - avoid poss. locking when doing copy_to_user which may sleep | ||
63 | * - RDS is automatically activated on read now | ||
64 | * - code cleaned of unnecessary rds_commands | ||
65 | * - USB Vendor/Product ID for ADS/Tech FM Radio Receiver verified | ||
66 | * (thanks to Guillaume RAMOUSSE) | ||
67 | * 2008-01-27 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
68 | * Version 1.0.5 | ||
69 | * - number of seek_retries changed to tune_timeout | ||
70 | * - fixed problem with incomplete tune operations by own buffers | ||
71 | * - optimization of variables and printf types | ||
72 | * - improved error logging | ||
73 | * 2008-01-31 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
74 | * Oliver Neukum <oliver@neukum.org> | ||
75 | * Version 1.0.6 | ||
76 | * - fixed coverity checker warnings in *_usb_driver_disconnect | ||
77 | * - probe()/open() race by correct ordering in probe() | ||
78 | * - DMA coherency rules by separate allocation of all buffers | ||
79 | * - use of endianness macros | ||
80 | * - abuse of spinlock, replaced by mutex | ||
81 | * - racy handling of timer in disconnect, | ||
82 | * replaced by delayed_work | ||
83 | * - racy interruptible_sleep_on(), | ||
84 | * replaced with wait_event_interruptible() | ||
85 | * - handle signals in read() | ||
86 | * 2008-02-08 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
87 | * Oliver Neukum <oliver@neukum.org> | ||
88 | * Version 1.0.7 | ||
89 | * - usb autosuspend support | ||
90 | * - unplugging fixed | ||
91 | * 2008-05-07 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
92 | * Version 1.0.8 | ||
93 | * - hardware frequency seek support | ||
94 | * - afc indication | ||
95 | * - more safety checks, let si470x_get_freq return errno | ||
96 | * - vidioc behavior corrected according to v4l2 spec | ||
97 | * 2008-10-20 Alexey Klimov <klimov.linux@gmail.com> | ||
98 | * - add support for KWorld USB FM Radio FM700 | ||
99 | * - blacklisted KWorld radio in hid-core.c and hid-ids.h | ||
100 | * 2008-12-03 Mark Lord <mlord@pobox.com> | ||
101 | * - add support for DealExtreme USB Radio | ||
102 | * 2009-01-31 Bob Ross <pigiron@gmx.com> | ||
103 | * - correction of stereo detection/setting | ||
104 | * - correction of signal strength indicator scaling | ||
105 | * 2009-01-31 Rick Bronson <rick@efn.org> | ||
106 | * Tobias Lorenz <tobias.lorenz@gmx.net> | ||
107 | * - add LED status output | ||
108 | * - get HW/SW version from scratchpad | ||
109 | * | ||
110 | * ToDo: | ||
111 | * - add firmware download/update support | ||
112 | * - RDS support: interrupt mode, instead of polling | ||
113 | */ | ||
114 | |||
115 | |||
116 | /* driver definitions */ | ||
117 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" | ||
118 | #define DRIVER_NAME "radio-si470x" | ||
119 | #define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9) | ||
120 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | ||
121 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" | ||
122 | #define DRIVER_VERSION "1.0.9" | ||
123 | |||
124 | |||
125 | /* kernel includes */ | ||
126 | #include <linux/kernel.h> | ||
127 | #include <linux/module.h> | ||
128 | #include <linux/init.h> | ||
129 | #include <linux/slab.h> | ||
130 | #include <linux/smp_lock.h> | ||
131 | #include <linux/input.h> | ||
132 | #include <linux/usb.h> | ||
133 | #include <linux/hid.h> | ||
134 | #include <linux/version.h> | ||
135 | #include <linux/videodev2.h> | ||
136 | #include <linux/mutex.h> | ||
137 | #include <media/v4l2-common.h> | ||
138 | #include <media/v4l2-ioctl.h> | ||
139 | #include <media/rds.h> | ||
140 | #include <asm/unaligned.h> | ||
141 | |||
142 | |||
143 | /* USB Device ID List */ | ||
144 | static struct usb_device_id si470x_usb_driver_id_table[] = { | ||
145 | /* Silicon Labs USB FM Radio Reference Design */ | ||
146 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, | ||
147 | /* ADS/Tech FM Radio Receiver (formerly Instant FM Music) */ | ||
148 | { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, | ||
149 | /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */ | ||
150 | { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) }, | ||
151 | /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */ | ||
152 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) }, | ||
153 | /* Terminating entry */ | ||
154 | { } | ||
155 | }; | ||
156 | MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); | ||
157 | |||
158 | |||
159 | |||
160 | /************************************************************************** | ||
161 | * Module Parameters | ||
162 | **************************************************************************/ | ||
163 | |||
164 | /* Radio Nr */ | ||
165 | static int radio_nr = -1; | ||
166 | module_param(radio_nr, int, 0444); | ||
167 | MODULE_PARM_DESC(radio_nr, "Radio Nr"); | ||
168 | |||
169 | /* Spacing (kHz) */ | ||
170 | /* 0: 200 kHz (USA, Australia) */ | ||
171 | /* 1: 100 kHz (Europe, Japan) */ | ||
172 | /* 2: 50 kHz */ | ||
173 | static unsigned short space = 2; | ||
174 | module_param(space, ushort, 0444); | ||
175 | MODULE_PARM_DESC(space, "Spacing: 0=200kHz 1=100kHz *2=50kHz*"); | ||
176 | |||
177 | /* Bottom of Band (MHz) */ | ||
178 | /* 0: 87.5 - 108 MHz (USA, Europe)*/ | ||
179 | /* 1: 76 - 108 MHz (Japan wide band) */ | ||
180 | /* 2: 76 - 90 MHz (Japan) */ | ||
181 | static unsigned short band = 1; | ||
182 | module_param(band, ushort, 0444); | ||
183 | MODULE_PARM_DESC(band, "Band: 0=87.5..108MHz *1=76..108MHz* 2=76..90MHz"); | ||
184 | |||
185 | /* De-emphasis */ | ||
186 | /* 0: 75 us (USA) */ | ||
187 | /* 1: 50 us (Europe, Australia, Japan) */ | ||
188 | static unsigned short de = 1; | ||
189 | module_param(de, ushort, 0444); | ||
190 | MODULE_PARM_DESC(de, "De-emphasis: 0=75us *1=50us*"); | ||
191 | |||
192 | /* USB timeout */ | ||
193 | static unsigned int usb_timeout = 500; | ||
194 | module_param(usb_timeout, uint, 0644); | ||
195 | MODULE_PARM_DESC(usb_timeout, "USB timeout (ms): *500*"); | ||
196 | |||
197 | /* Tune timeout */ | ||
198 | static unsigned int tune_timeout = 3000; | ||
199 | module_param(tune_timeout, uint, 0644); | ||
200 | MODULE_PARM_DESC(tune_timeout, "Tune timeout: *3000*"); | ||
201 | |||
202 | /* Seek timeout */ | ||
203 | static unsigned int seek_timeout = 5000; | ||
204 | module_param(seek_timeout, uint, 0644); | ||
205 | MODULE_PARM_DESC(seek_timeout, "Seek timeout: *5000*"); | ||
206 | |||
207 | /* RDS buffer blocks */ | ||
208 | static unsigned int rds_buf = 100; | ||
209 | module_param(rds_buf, uint, 0444); | ||
210 | MODULE_PARM_DESC(rds_buf, "RDS buffer entries: *100*"); | ||
211 | |||
212 | /* RDS maximum block errors */ | ||
213 | static unsigned short max_rds_errors = 1; | ||
214 | /* 0 means 0 errors requiring correction */ | ||
215 | /* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ | ||
216 | /* 2 means 3-5 errors requiring correction */ | ||
217 | /* 3 means 6+ errors or errors in checkword, correction not possible */ | ||
218 | module_param(max_rds_errors, ushort, 0644); | ||
219 | MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*"); | ||
220 | |||
221 | /* RDS poll frequency */ | ||
222 | static unsigned int rds_poll_time = 40; | ||
223 | /* 40 is used by the original USBRadio.exe */ | ||
224 | /* 50 is used by radio-cadet */ | ||
225 | /* 75 should be okay */ | ||
226 | /* 80 is the usual RDS receive interval */ | ||
227 | module_param(rds_poll_time, uint, 0644); | ||
228 | MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | ||
229 | |||
230 | |||
231 | |||
232 | /************************************************************************** | ||
233 | * Register Definitions | ||
234 | **************************************************************************/ | ||
235 | #define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ | ||
236 | #define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ | ||
237 | #define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ | ||
238 | |||
239 | #define DEVICEID 0 /* Device ID */ | ||
240 | #define DEVICEID_PN 0xf000 /* bits 15..12: Part Number */ | ||
241 | #define DEVICEID_MFGID 0x0fff /* bits 11..00: Manufacturer ID */ | ||
242 | |||
243 | #define CHIPID 1 /* Chip ID */ | ||
244 | #define CHIPID_REV 0xfc00 /* bits 15..10: Chip Version */ | ||
245 | #define CHIPID_DEV 0x0200 /* bits 09..09: Device */ | ||
246 | #define CHIPID_FIRMWARE 0x01ff /* bits 08..00: Firmware Version */ | ||
247 | |||
248 | #define POWERCFG 2 /* Power Configuration */ | ||
249 | #define POWERCFG_DSMUTE 0x8000 /* bits 15..15: Softmute Disable */ | ||
250 | #define POWERCFG_DMUTE 0x4000 /* bits 14..14: Mute Disable */ | ||
251 | #define POWERCFG_MONO 0x2000 /* bits 13..13: Mono Select */ | ||
252 | #define POWERCFG_RDSM 0x0800 /* bits 11..11: RDS Mode (Si4701 only) */ | ||
253 | #define POWERCFG_SKMODE 0x0400 /* bits 10..10: Seek Mode */ | ||
254 | #define POWERCFG_SEEKUP 0x0200 /* bits 09..09: Seek Direction */ | ||
255 | #define POWERCFG_SEEK 0x0100 /* bits 08..08: Seek */ | ||
256 | #define POWERCFG_DISABLE 0x0040 /* bits 06..06: Powerup Disable */ | ||
257 | #define POWERCFG_ENABLE 0x0001 /* bits 00..00: Powerup Enable */ | ||
258 | |||
259 | #define CHANNEL 3 /* Channel */ | ||
260 | #define CHANNEL_TUNE 0x8000 /* bits 15..15: Tune */ | ||
261 | #define CHANNEL_CHAN 0x03ff /* bits 09..00: Channel Select */ | ||
262 | |||
263 | #define SYSCONFIG1 4 /* System Configuration 1 */ | ||
264 | #define SYSCONFIG1_RDSIEN 0x8000 /* bits 15..15: RDS Interrupt Enable (Si4701 only) */ | ||
265 | #define SYSCONFIG1_STCIEN 0x4000 /* bits 14..14: Seek/Tune Complete Interrupt Enable */ | ||
266 | #define SYSCONFIG1_RDS 0x1000 /* bits 12..12: RDS Enable (Si4701 only) */ | ||
267 | #define SYSCONFIG1_DE 0x0800 /* bits 11..11: De-emphasis (0=75us 1=50us) */ | ||
268 | #define SYSCONFIG1_AGCD 0x0400 /* bits 10..10: AGC Disable */ | ||
269 | #define SYSCONFIG1_BLNDADJ 0x00c0 /* bits 07..06: Stereo/Mono Blend Level Adjustment */ | ||
270 | #define SYSCONFIG1_GPIO3 0x0030 /* bits 05..04: General Purpose I/O 3 */ | ||
271 | #define SYSCONFIG1_GPIO2 0x000c /* bits 03..02: General Purpose I/O 2 */ | ||
272 | #define SYSCONFIG1_GPIO1 0x0003 /* bits 01..00: General Purpose I/O 1 */ | ||
273 | |||
274 | #define SYSCONFIG2 5 /* System Configuration 2 */ | ||
275 | #define SYSCONFIG2_SEEKTH 0xff00 /* bits 15..08: RSSI Seek Threshold */ | ||
276 | #define SYSCONFIG2_BAND 0x0080 /* bits 07..06: Band Select */ | ||
277 | #define SYSCONFIG2_SPACE 0x0030 /* bits 05..04: Channel Spacing */ | ||
278 | #define SYSCONFIG2_VOLUME 0x000f /* bits 03..00: Volume */ | ||
279 | |||
280 | #define SYSCONFIG3 6 /* System Configuration 3 */ | ||
281 | #define SYSCONFIG3_SMUTER 0xc000 /* bits 15..14: Softmute Attack/Recover Rate */ | ||
282 | #define SYSCONFIG3_SMUTEA 0x3000 /* bits 13..12: Softmute Attenuation */ | ||
283 | #define SYSCONFIG3_SKSNR 0x00f0 /* bits 07..04: Seek SNR Threshold */ | ||
284 | #define SYSCONFIG3_SKCNT 0x000f /* bits 03..00: Seek FM Impulse Detection Threshold */ | ||
285 | |||
286 | #define TEST1 7 /* Test 1 */ | ||
287 | #define TEST1_AHIZEN 0x4000 /* bits 14..14: Audio High-Z Enable */ | ||
288 | |||
289 | #define TEST2 8 /* Test 2 */ | ||
290 | /* TEST2 only contains reserved bits */ | ||
291 | |||
292 | #define BOOTCONFIG 9 /* Boot Configuration */ | ||
293 | /* BOOTCONFIG only contains reserved bits */ | ||
294 | |||
295 | #define STATUSRSSI 10 /* Status RSSI */ | ||
296 | #define STATUSRSSI_RDSR 0x8000 /* bits 15..15: RDS Ready (Si4701 only) */ | ||
297 | #define STATUSRSSI_STC 0x4000 /* bits 14..14: Seek/Tune Complete */ | ||
298 | #define STATUSRSSI_SF 0x2000 /* bits 13..13: Seek Fail/Band Limit */ | ||
299 | #define STATUSRSSI_AFCRL 0x1000 /* bits 12..12: AFC Rail */ | ||
300 | #define STATUSRSSI_RDSS 0x0800 /* bits 11..11: RDS Synchronized (Si4701 only) */ | ||
301 | #define STATUSRSSI_BLERA 0x0600 /* bits 10..09: RDS Block A Errors (Si4701 only) */ | ||
302 | #define STATUSRSSI_ST 0x0100 /* bits 08..08: Stereo Indicator */ | ||
303 | #define STATUSRSSI_RSSI 0x00ff /* bits 07..00: RSSI (Received Signal Strength Indicator) */ | ||
304 | |||
305 | #define READCHAN 11 /* Read Channel */ | ||
306 | #define READCHAN_BLERB 0xc000 /* bits 15..14: RDS Block D Errors (Si4701 only) */ | ||
307 | #define READCHAN_BLERC 0x3000 /* bits 13..12: RDS Block C Errors (Si4701 only) */ | ||
308 | #define READCHAN_BLERD 0x0c00 /* bits 11..10: RDS Block B Errors (Si4701 only) */ | ||
309 | #define READCHAN_READCHAN 0x03ff /* bits 09..00: Read Channel */ | ||
310 | |||
311 | #define RDSA 12 /* RDSA */ | ||
312 | #define RDSA_RDSA 0xffff /* bits 15..00: RDS Block A Data (Si4701 only) */ | ||
313 | |||
314 | #define RDSB 13 /* RDSB */ | ||
315 | #define RDSB_RDSB 0xffff /* bits 15..00: RDS Block B Data (Si4701 only) */ | ||
316 | |||
317 | #define RDSC 14 /* RDSC */ | ||
318 | #define RDSC_RDSC 0xffff /* bits 15..00: RDS Block C Data (Si4701 only) */ | ||
319 | |||
320 | #define RDSD 15 /* RDSD */ | ||
321 | #define RDSD_RDSD 0xffff /* bits 15..00: RDS Block D Data (Si4701 only) */ | ||
322 | |||
323 | |||
324 | |||
325 | /************************************************************************** | ||
326 | * USB HID Reports | ||
327 | **************************************************************************/ | ||
328 | |||
329 | /* Reports 1-16 give direct read/write access to the 16 Si470x registers */ | ||
330 | /* with the (REPORT_ID - 1) corresponding to the register address across USB */ | ||
331 | /* endpoint 0 using GET_REPORT and SET_REPORT */ | ||
332 | #define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) | ||
333 | #define REGISTER_REPORT(reg) ((reg) + 1) | ||
334 | |||
335 | /* Report 17 gives direct read/write access to the entire Si470x register */ | ||
336 | /* map across endpoint 0 using GET_REPORT and SET_REPORT */ | ||
337 | #define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) | ||
338 | #define ENTIRE_REPORT 17 | ||
339 | |||
340 | /* Report 18 is used to send the lowest 6 Si470x registers up the HID */ | ||
341 | /* interrupt endpoint 1 to Windows every 20 milliseconds for status */ | ||
342 | #define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) | ||
343 | #define RDS_REPORT 18 | ||
344 | |||
345 | /* Report 19: LED state */ | ||
346 | #define LED_REPORT_SIZE 3 | ||
347 | #define LED_REPORT 19 | ||
348 | |||
349 | /* Report 19: stream */ | ||
350 | #define STREAM_REPORT_SIZE 3 | ||
351 | #define STREAM_REPORT 19 | ||
352 | |||
353 | /* Report 20: scratch */ | ||
354 | #define SCRATCH_PAGE_SIZE 63 | ||
355 | #define SCRATCH_REPORT_SIZE (SCRATCH_PAGE_SIZE + 1) | ||
356 | #define SCRATCH_REPORT 20 | ||
357 | |||
358 | /* Reports 19-22: flash upgrade of the C8051F321 */ | ||
359 | #define WRITE_REPORT_SIZE 4 | ||
360 | #define WRITE_REPORT 19 | ||
361 | #define FLASH_REPORT_SIZE 64 | ||
362 | #define FLASH_REPORT 20 | ||
363 | #define CRC_REPORT_SIZE 3 | ||
364 | #define CRC_REPORT 21 | ||
365 | #define RESPONSE_REPORT_SIZE 2 | ||
366 | #define RESPONSE_REPORT 22 | ||
367 | |||
368 | /* Report 23: currently unused, but can accept 60 byte reports on the HID */ | ||
369 | /* interrupt out endpoint 2 every 1 millisecond */ | ||
370 | #define UNUSED_REPORT 23 | ||
371 | |||
372 | |||
373 | |||
374 | /************************************************************************** | ||
375 | * Software/Hardware Versions | ||
376 | **************************************************************************/ | ||
377 | #define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 | ||
378 | #define RADIO_SW_VERSION 7 | ||
379 | #define RADIO_SW_VERSION_CURRENT 15 | ||
380 | #define RADIO_HW_VERSION 1 | ||
381 | |||
382 | #define SCRATCH_PAGE_SW_VERSION 1 | ||
383 | #define SCRATCH_PAGE_HW_VERSION 2 | ||
384 | |||
385 | |||
386 | |||
387 | /************************************************************************** | ||
388 | * LED State Definitions | ||
389 | **************************************************************************/ | ||
390 | #define LED_COMMAND 0x35 | ||
391 | |||
392 | #define NO_CHANGE_LED 0x00 | ||
393 | #define ALL_COLOR_LED 0x01 /* streaming state */ | ||
394 | #define BLINK_GREEN_LED 0x02 /* connect state */ | ||
395 | #define BLINK_RED_LED 0x04 | ||
396 | #define BLINK_ORANGE_LED 0x10 /* disconnect state */ | ||
397 | #define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ | ||
398 | #define SOLID_RED_LED 0x40 /* bootload state */ | ||
399 | #define SOLID_ORANGE_LED 0x80 | ||
400 | |||
401 | |||
402 | |||
403 | /************************************************************************** | ||
404 | * Stream State Definitions | ||
405 | **************************************************************************/ | ||
406 | #define STREAM_COMMAND 0x36 | ||
407 | #define STREAM_VIDPID 0x00 | ||
408 | #define STREAM_AUDIO 0xff | ||
409 | |||
410 | |||
411 | |||
412 | /************************************************************************** | ||
413 | * Bootloader / Flash Commands | ||
414 | **************************************************************************/ | ||
415 | |||
416 | /* unique id sent to bootloader and required to put into a bootload state */ | ||
417 | #define UNIQUE_BL_ID 0x34 | ||
418 | |||
419 | /* mask for the flash data */ | ||
420 | #define FLASH_DATA_MASK 0x55 | ||
421 | |||
422 | /* bootloader commands */ | ||
423 | #define GET_SW_VERSION_COMMAND 0x00 | ||
424 | #define SET_PAGE_COMMAND 0x01 | ||
425 | #define ERASE_PAGE_COMMAND 0x02 | ||
426 | #define WRITE_PAGE_COMMAND 0x03 | ||
427 | #define CRC_ON_PAGE_COMMAND 0x04 | ||
428 | #define READ_FLASH_BYTE_COMMAND 0x05 | ||
429 | #define RESET_DEVICE_COMMAND 0x06 | ||
430 | #define GET_HW_VERSION_COMMAND 0x07 | ||
431 | #define BLANK 0xff | ||
432 | |||
433 | /* bootloader command responses */ | ||
434 | #define COMMAND_OK 0x01 | ||
435 | #define COMMAND_FAILED 0x02 | ||
436 | #define COMMAND_PENDING 0x03 | ||
437 | |||
438 | |||
439 | |||
440 | /************************************************************************** | ||
441 | * General Driver Definitions | ||
442 | **************************************************************************/ | ||
443 | |||
444 | /* | ||
445 | * si470x_device - private data | ||
446 | */ | ||
447 | struct si470x_device { | ||
448 | /* reference to USB and video device */ | ||
449 | struct usb_device *usbdev; | ||
450 | struct usb_interface *intf; | ||
451 | struct video_device *videodev; | ||
452 | |||
453 | /* driver management */ | ||
454 | unsigned int users; | ||
455 | unsigned char disconnected; | ||
456 | struct mutex disconnect_lock; | ||
457 | |||
458 | /* Silabs internal registers (0..15) */ | ||
459 | unsigned short registers[RADIO_REGISTER_NUM]; | ||
460 | |||
461 | /* RDS receive buffer */ | ||
462 | struct delayed_work work; | ||
463 | wait_queue_head_t read_queue; | ||
464 | struct mutex lock; /* buffer locking */ | ||
465 | unsigned char *buffer; /* size is always multiple of three */ | ||
466 | unsigned int buf_size; | ||
467 | unsigned int rd_index; | ||
468 | unsigned int wr_index; | ||
469 | |||
470 | /* scratch page */ | ||
471 | unsigned char software_version; | ||
472 | unsigned char hardware_version; | ||
473 | }; | ||
474 | |||
475 | |||
476 | /* | ||
477 | * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, | ||
478 | * 62.5 kHz otherwise. | ||
479 | * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. | ||
480 | * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW | ||
481 | * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 | ||
482 | */ | ||
483 | #define FREQ_MUL (1000000 / 62.5) | ||
484 | |||
485 | |||
486 | |||
487 | /************************************************************************** | ||
488 | * General Driver Functions - REGISTER_REPORTs | ||
489 | **************************************************************************/ | ||
490 | |||
491 | /* | ||
492 | * si470x_get_report - receive a HID report | ||
493 | */ | ||
494 | static int si470x_get_report(struct si470x_device *radio, void *buf, int size) | ||
495 | { | ||
496 | unsigned char *report = (unsigned char *) buf; | ||
497 | int retval; | ||
498 | |||
499 | retval = usb_control_msg(radio->usbdev, | ||
500 | usb_rcvctrlpipe(radio->usbdev, 0), | ||
501 | HID_REQ_GET_REPORT, | ||
502 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
503 | report[0], 2, | ||
504 | buf, size, usb_timeout); | ||
505 | |||
506 | if (retval < 0) | ||
507 | printk(KERN_WARNING DRIVER_NAME | ||
508 | ": si470x_get_report: usb_control_msg returned %d\n", | ||
509 | retval); | ||
510 | return retval; | ||
511 | } | ||
512 | |||
513 | |||
514 | /* | ||
515 | * si470x_set_report - send a HID report | ||
516 | */ | ||
517 | static int si470x_set_report(struct si470x_device *radio, void *buf, int size) | ||
518 | { | ||
519 | unsigned char *report = (unsigned char *) buf; | ||
520 | int retval; | ||
521 | |||
522 | retval = usb_control_msg(radio->usbdev, | ||
523 | usb_sndctrlpipe(radio->usbdev, 0), | ||
524 | HID_REQ_SET_REPORT, | ||
525 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
526 | report[0], 2, | ||
527 | buf, size, usb_timeout); | ||
528 | |||
529 | if (retval < 0) | ||
530 | printk(KERN_WARNING DRIVER_NAME | ||
531 | ": si470x_set_report: usb_control_msg returned %d\n", | ||
532 | retval); | ||
533 | return retval; | ||
534 | } | ||
535 | |||
536 | |||
537 | /* | ||
538 | * si470x_get_register - read register | ||
539 | */ | ||
540 | static int si470x_get_register(struct si470x_device *radio, int regnr) | ||
541 | { | ||
542 | unsigned char buf[REGISTER_REPORT_SIZE]; | ||
543 | int retval; | ||
544 | |||
545 | buf[0] = REGISTER_REPORT(regnr); | ||
546 | |||
547 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | ||
548 | |||
549 | if (retval >= 0) | ||
550 | radio->registers[regnr] = get_unaligned_be16(&buf[1]); | ||
551 | |||
552 | return (retval < 0) ? -EINVAL : 0; | ||
553 | } | ||
554 | |||
555 | |||
556 | /* | ||
557 | * si470x_set_register - write register | ||
558 | */ | ||
559 | static int si470x_set_register(struct si470x_device *radio, int regnr) | ||
560 | { | ||
561 | unsigned char buf[REGISTER_REPORT_SIZE]; | ||
562 | int retval; | ||
563 | |||
564 | buf[0] = REGISTER_REPORT(regnr); | ||
565 | put_unaligned_be16(radio->registers[regnr], &buf[1]); | ||
566 | |||
567 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); | ||
568 | |||
569 | return (retval < 0) ? -EINVAL : 0; | ||
570 | } | ||
571 | |||
572 | |||
573 | /* | ||
574 | * si470x_set_chan - set the channel | ||
575 | */ | ||
576 | static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) | ||
577 | { | ||
578 | int retval; | ||
579 | unsigned long timeout; | ||
580 | bool timed_out = 0; | ||
581 | |||
582 | /* start tuning */ | ||
583 | radio->registers[CHANNEL] &= ~CHANNEL_CHAN; | ||
584 | radio->registers[CHANNEL] |= CHANNEL_TUNE | chan; | ||
585 | retval = si470x_set_register(radio, CHANNEL); | ||
586 | if (retval < 0) | ||
587 | goto done; | ||
588 | |||
589 | /* wait till tune operation has completed */ | ||
590 | timeout = jiffies + msecs_to_jiffies(tune_timeout); | ||
591 | do { | ||
592 | retval = si470x_get_register(radio, STATUSRSSI); | ||
593 | if (retval < 0) | ||
594 | goto stop; | ||
595 | timed_out = time_after(jiffies, timeout); | ||
596 | } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && | ||
597 | (!timed_out)); | ||
598 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) | ||
599 | printk(KERN_WARNING DRIVER_NAME ": tune does not complete\n"); | ||
600 | if (timed_out) | ||
601 | printk(KERN_WARNING DRIVER_NAME | ||
602 | ": tune timed out after %u ms\n", tune_timeout); | ||
603 | |||
604 | stop: | ||
605 | /* stop tuning */ | ||
606 | radio->registers[CHANNEL] &= ~CHANNEL_TUNE; | ||
607 | retval = si470x_set_register(radio, CHANNEL); | ||
608 | |||
609 | done: | ||
610 | return retval; | ||
611 | } | ||
612 | |||
613 | |||
614 | /* | ||
615 | * si470x_get_freq - get the frequency | ||
616 | */ | ||
617 | static int si470x_get_freq(struct si470x_device *radio, unsigned int *freq) | ||
618 | { | ||
619 | unsigned int spacing, band_bottom; | ||
620 | unsigned short chan; | ||
621 | int retval; | ||
622 | |||
623 | /* Spacing (kHz) */ | ||
624 | switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { | ||
625 | /* 0: 200 kHz (USA, Australia) */ | ||
626 | case 0: | ||
627 | spacing = 0.200 * FREQ_MUL; break; | ||
628 | /* 1: 100 kHz (Europe, Japan) */ | ||
629 | case 1: | ||
630 | spacing = 0.100 * FREQ_MUL; break; | ||
631 | /* 2: 50 kHz */ | ||
632 | default: | ||
633 | spacing = 0.050 * FREQ_MUL; break; | ||
634 | }; | ||
635 | |||
636 | /* Bottom of Band (MHz) */ | ||
637 | switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { | ||
638 | /* 0: 87.5 - 108 MHz (USA, Europe) */ | ||
639 | case 0: | ||
640 | band_bottom = 87.5 * FREQ_MUL; break; | ||
641 | /* 1: 76 - 108 MHz (Japan wide band) */ | ||
642 | default: | ||
643 | band_bottom = 76 * FREQ_MUL; break; | ||
644 | /* 2: 76 - 90 MHz (Japan) */ | ||
645 | case 2: | ||
646 | band_bottom = 76 * FREQ_MUL; break; | ||
647 | }; | ||
648 | |||
649 | /* read channel */ | ||
650 | retval = si470x_get_register(radio, READCHAN); | ||
651 | chan = radio->registers[READCHAN] & READCHAN_READCHAN; | ||
652 | |||
653 | /* Frequency (MHz) = Spacing (kHz) x Channel + Bottom of Band (MHz) */ | ||
654 | *freq = chan * spacing + band_bottom; | ||
655 | |||
656 | return retval; | ||
657 | } | ||
658 | |||
659 | |||
660 | /* | ||
661 | * si470x_set_freq - set the frequency | ||
662 | */ | ||
663 | static int si470x_set_freq(struct si470x_device *radio, unsigned int freq) | ||
664 | { | ||
665 | unsigned int spacing, band_bottom; | ||
666 | unsigned short chan; | ||
667 | |||
668 | /* Spacing (kHz) */ | ||
669 | switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_SPACE) >> 4) { | ||
670 | /* 0: 200 kHz (USA, Australia) */ | ||
671 | case 0: | ||
672 | spacing = 0.200 * FREQ_MUL; break; | ||
673 | /* 1: 100 kHz (Europe, Japan) */ | ||
674 | case 1: | ||
675 | spacing = 0.100 * FREQ_MUL; break; | ||
676 | /* 2: 50 kHz */ | ||
677 | default: | ||
678 | spacing = 0.050 * FREQ_MUL; break; | ||
679 | }; | ||
680 | |||
681 | /* Bottom of Band (MHz) */ | ||
682 | switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { | ||
683 | /* 0: 87.5 - 108 MHz (USA, Europe) */ | ||
684 | case 0: | ||
685 | band_bottom = 87.5 * FREQ_MUL; break; | ||
686 | /* 1: 76 - 108 MHz (Japan wide band) */ | ||
687 | default: | ||
688 | band_bottom = 76 * FREQ_MUL; break; | ||
689 | /* 2: 76 - 90 MHz (Japan) */ | ||
690 | case 2: | ||
691 | band_bottom = 76 * FREQ_MUL; break; | ||
692 | }; | ||
693 | |||
694 | /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ | ||
695 | chan = (freq - band_bottom) / spacing; | ||
696 | |||
697 | return si470x_set_chan(radio, chan); | ||
698 | } | ||
699 | |||
700 | |||
701 | /* | ||
702 | * si470x_set_seek - set seek | ||
703 | */ | ||
704 | static int si470x_set_seek(struct si470x_device *radio, | ||
705 | unsigned int wrap_around, unsigned int seek_upward) | ||
706 | { | ||
707 | int retval = 0; | ||
708 | unsigned long timeout; | ||
709 | bool timed_out = 0; | ||
710 | |||
711 | /* start seeking */ | ||
712 | radio->registers[POWERCFG] |= POWERCFG_SEEK; | ||
713 | if (wrap_around == 1) | ||
714 | radio->registers[POWERCFG] &= ~POWERCFG_SKMODE; | ||
715 | else | ||
716 | radio->registers[POWERCFG] |= POWERCFG_SKMODE; | ||
717 | if (seek_upward == 1) | ||
718 | radio->registers[POWERCFG] |= POWERCFG_SEEKUP; | ||
719 | else | ||
720 | radio->registers[POWERCFG] &= ~POWERCFG_SEEKUP; | ||
721 | retval = si470x_set_register(radio, POWERCFG); | ||
722 | if (retval < 0) | ||
723 | goto done; | ||
724 | |||
725 | /* wait till seek operation has completed */ | ||
726 | timeout = jiffies + msecs_to_jiffies(seek_timeout); | ||
727 | do { | ||
728 | retval = si470x_get_register(radio, STATUSRSSI); | ||
729 | if (retval < 0) | ||
730 | goto stop; | ||
731 | timed_out = time_after(jiffies, timeout); | ||
732 | } while (((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) && | ||
733 | (!timed_out)); | ||
734 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_STC) == 0) | ||
735 | printk(KERN_WARNING DRIVER_NAME ": seek does not complete\n"); | ||
736 | if (radio->registers[STATUSRSSI] & STATUSRSSI_SF) | ||
737 | printk(KERN_WARNING DRIVER_NAME | ||
738 | ": seek failed / band limit reached\n"); | ||
739 | if (timed_out) | ||
740 | printk(KERN_WARNING DRIVER_NAME | ||
741 | ": seek timed out after %u ms\n", seek_timeout); | ||
742 | |||
743 | stop: | ||
744 | /* stop seeking */ | ||
745 | radio->registers[POWERCFG] &= ~POWERCFG_SEEK; | ||
746 | retval = si470x_set_register(radio, POWERCFG); | ||
747 | |||
748 | done: | ||
749 | /* try again, if timed out */ | ||
750 | if ((retval == 0) && timed_out) | ||
751 | retval = -EAGAIN; | ||
752 | |||
753 | return retval; | ||
754 | } | ||
755 | |||
756 | |||
757 | /* | ||
758 | * si470x_start - switch on radio | ||
759 | */ | ||
760 | static int si470x_start(struct si470x_device *radio) | ||
761 | { | ||
762 | int retval; | ||
763 | |||
764 | /* powercfg */ | ||
765 | radio->registers[POWERCFG] = | ||
766 | POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; | ||
767 | retval = si470x_set_register(radio, POWERCFG); | ||
768 | if (retval < 0) | ||
769 | goto done; | ||
770 | |||
771 | /* sysconfig 1 */ | ||
772 | radio->registers[SYSCONFIG1] = SYSCONFIG1_DE; | ||
773 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
774 | if (retval < 0) | ||
775 | goto done; | ||
776 | |||
777 | /* sysconfig 2 */ | ||
778 | radio->registers[SYSCONFIG2] = | ||
779 | (0x3f << 8) | /* SEEKTH */ | ||
780 | ((band << 6) & SYSCONFIG2_BAND) | /* BAND */ | ||
781 | ((space << 4) & SYSCONFIG2_SPACE) | /* SPACE */ | ||
782 | 15; /* VOLUME (max) */ | ||
783 | retval = si470x_set_register(radio, SYSCONFIG2); | ||
784 | if (retval < 0) | ||
785 | goto done; | ||
786 | |||
787 | /* reset last channel */ | ||
788 | retval = si470x_set_chan(radio, | ||
789 | radio->registers[CHANNEL] & CHANNEL_CHAN); | ||
790 | |||
791 | done: | ||
792 | return retval; | ||
793 | } | ||
794 | |||
795 | |||
796 | /* | ||
797 | * si470x_stop - switch off radio | ||
798 | */ | ||
799 | static int si470x_stop(struct si470x_device *radio) | ||
800 | { | ||
801 | int retval; | ||
802 | |||
803 | /* sysconfig 1 */ | ||
804 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; | ||
805 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
806 | if (retval < 0) | ||
807 | goto done; | ||
808 | |||
809 | /* powercfg */ | ||
810 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | ||
811 | /* POWERCFG_ENABLE has to automatically go low */ | ||
812 | radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; | ||
813 | retval = si470x_set_register(radio, POWERCFG); | ||
814 | |||
815 | done: | ||
816 | return retval; | ||
817 | } | ||
818 | |||
819 | |||
820 | /* | ||
821 | * si470x_rds_on - switch on rds reception | ||
822 | */ | ||
823 | static int si470x_rds_on(struct si470x_device *radio) | ||
824 | { | ||
825 | int retval; | ||
826 | |||
827 | /* sysconfig 1 */ | ||
828 | mutex_lock(&radio->lock); | ||
829 | radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS; | ||
830 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
831 | if (retval < 0) | ||
832 | radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS; | ||
833 | mutex_unlock(&radio->lock); | ||
834 | |||
835 | return retval; | ||
836 | } | ||
837 | |||
838 | |||
839 | |||
840 | /************************************************************************** | ||
841 | * General Driver Functions - ENTIRE_REPORT | ||
842 | **************************************************************************/ | ||
843 | |||
844 | /* | ||
845 | * si470x_get_all_registers - read entire registers | ||
846 | */ | ||
847 | static int si470x_get_all_registers(struct si470x_device *radio) | ||
848 | { | ||
849 | unsigned char buf[ENTIRE_REPORT_SIZE]; | ||
850 | int retval; | ||
851 | unsigned char regnr; | ||
852 | |||
853 | buf[0] = ENTIRE_REPORT; | ||
854 | |||
855 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | ||
856 | |||
857 | if (retval >= 0) | ||
858 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) | ||
859 | radio->registers[regnr] = get_unaligned_be16( | ||
860 | &buf[regnr * RADIO_REGISTER_SIZE + 1]); | ||
861 | |||
862 | return (retval < 0) ? -EINVAL : 0; | ||
863 | } | ||
864 | |||
865 | |||
866 | |||
867 | /************************************************************************** | ||
868 | * General Driver Functions - RDS_REPORT | ||
869 | **************************************************************************/ | ||
870 | |||
871 | /* | ||
872 | * si470x_get_rds_registers - read rds registers | ||
873 | */ | ||
874 | static int si470x_get_rds_registers(struct si470x_device *radio) | ||
875 | { | ||
876 | unsigned char buf[RDS_REPORT_SIZE]; | ||
877 | int retval; | ||
878 | int size; | ||
879 | unsigned char regnr; | ||
880 | |||
881 | buf[0] = RDS_REPORT; | ||
882 | |||
883 | retval = usb_interrupt_msg(radio->usbdev, | ||
884 | usb_rcvintpipe(radio->usbdev, 1), | ||
885 | (void *) &buf, sizeof(buf), &size, usb_timeout); | ||
886 | if (size != sizeof(buf)) | ||
887 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " | ||
888 | "return size differs: %d != %zu\n", size, sizeof(buf)); | ||
889 | if (retval < 0) | ||
890 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " | ||
891 | "usb_interrupt_msg returned %d\n", retval); | ||
892 | |||
893 | if (retval >= 0) | ||
894 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) | ||
895 | radio->registers[STATUSRSSI + regnr] = | ||
896 | get_unaligned_be16( | ||
897 | &buf[regnr * RADIO_REGISTER_SIZE + 1]); | ||
898 | |||
899 | return (retval < 0) ? -EINVAL : 0; | ||
900 | } | ||
901 | |||
902 | |||
903 | |||
904 | /************************************************************************** | ||
905 | * General Driver Functions - LED_REPORT | ||
906 | **************************************************************************/ | ||
907 | |||
908 | /* | ||
909 | * si470x_set_led_state - sets the led state | ||
910 | */ | ||
911 | static int si470x_set_led_state(struct si470x_device *radio, | ||
912 | unsigned char led_state) | ||
913 | { | ||
914 | unsigned char buf[LED_REPORT_SIZE]; | ||
915 | int retval; | ||
916 | |||
917 | buf[0] = LED_REPORT; | ||
918 | buf[1] = LED_COMMAND; | ||
919 | buf[2] = led_state; | ||
920 | |||
921 | retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); | ||
922 | |||
923 | return (retval < 0) ? -EINVAL : 0; | ||
924 | } | ||
925 | |||
926 | |||
927 | |||
928 | /************************************************************************** | ||
929 | * General Driver Functions - SCRATCH_REPORT | ||
930 | **************************************************************************/ | ||
931 | |||
932 | /* | ||
933 | * si470x_get_scratch_versions - gets the scratch page and version infos | ||
934 | */ | ||
935 | static int si470x_get_scratch_page_versions(struct si470x_device *radio) | ||
936 | { | ||
937 | unsigned char buf[SCRATCH_REPORT_SIZE]; | ||
938 | int retval; | ||
939 | |||
940 | buf[0] = SCRATCH_REPORT; | ||
941 | |||
942 | retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); | ||
943 | |||
944 | if (retval < 0) | ||
945 | printk(KERN_WARNING DRIVER_NAME ": si470x_get_scratch: " | ||
946 | "si470x_get_report returned %d\n", retval); | ||
947 | else { | ||
948 | radio->software_version = buf[1]; | ||
949 | radio->hardware_version = buf[2]; | ||
950 | } | ||
951 | |||
952 | return (retval < 0) ? -EINVAL : 0; | ||
953 | } | ||
954 | |||
955 | |||
956 | |||
957 | /************************************************************************** | ||
958 | * RDS Driver Functions | ||
959 | **************************************************************************/ | ||
960 | |||
961 | /* | ||
962 | * si470x_rds - rds processing function | ||
963 | */ | ||
964 | static void si470x_rds(struct si470x_device *radio) | ||
965 | { | ||
966 | unsigned char blocknum; | ||
967 | unsigned short bler; /* rds block errors */ | ||
968 | unsigned short rds; | ||
969 | unsigned char tmpbuf[3]; | ||
970 | |||
971 | /* get rds blocks */ | ||
972 | if (si470x_get_rds_registers(radio) < 0) | ||
973 | return; | ||
974 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSR) == 0) { | ||
975 | /* No RDS group ready */ | ||
976 | return; | ||
977 | } | ||
978 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_RDSS) == 0) { | ||
979 | /* RDS decoder not synchronized */ | ||
980 | return; | ||
981 | } | ||
982 | |||
983 | /* copy all four RDS blocks to internal buffer */ | ||
984 | mutex_lock(&radio->lock); | ||
985 | for (blocknum = 0; blocknum < 4; blocknum++) { | ||
986 | switch (blocknum) { | ||
987 | default: | ||
988 | bler = (radio->registers[STATUSRSSI] & | ||
989 | STATUSRSSI_BLERA) >> 9; | ||
990 | rds = radio->registers[RDSA]; | ||
991 | break; | ||
992 | case 1: | ||
993 | bler = (radio->registers[READCHAN] & | ||
994 | READCHAN_BLERB) >> 14; | ||
995 | rds = radio->registers[RDSB]; | ||
996 | break; | ||
997 | case 2: | ||
998 | bler = (radio->registers[READCHAN] & | ||
999 | READCHAN_BLERC) >> 12; | ||
1000 | rds = radio->registers[RDSC]; | ||
1001 | break; | ||
1002 | case 3: | ||
1003 | bler = (radio->registers[READCHAN] & | ||
1004 | READCHAN_BLERD) >> 10; | ||
1005 | rds = radio->registers[RDSD]; | ||
1006 | break; | ||
1007 | }; | ||
1008 | |||
1009 | /* Fill the V4L2 RDS buffer */ | ||
1010 | put_unaligned_le16(rds, &tmpbuf); | ||
1011 | tmpbuf[2] = blocknum; /* offset name */ | ||
1012 | tmpbuf[2] |= blocknum << 3; /* received offset */ | ||
1013 | if (bler > max_rds_errors) | ||
1014 | tmpbuf[2] |= 0x80; /* uncorrectable errors */ | ||
1015 | else if (bler > 0) | ||
1016 | tmpbuf[2] |= 0x40; /* corrected error(s) */ | ||
1017 | |||
1018 | /* copy RDS block to internal buffer */ | ||
1019 | memcpy(&radio->buffer[radio->wr_index], &tmpbuf, 3); | ||
1020 | radio->wr_index += 3; | ||
1021 | |||
1022 | /* wrap write pointer */ | ||
1023 | if (radio->wr_index >= radio->buf_size) | ||
1024 | radio->wr_index = 0; | ||
1025 | |||
1026 | /* check for overflow */ | ||
1027 | if (radio->wr_index == radio->rd_index) { | ||
1028 | /* increment and wrap read pointer */ | ||
1029 | radio->rd_index += 3; | ||
1030 | if (radio->rd_index >= radio->buf_size) | ||
1031 | radio->rd_index = 0; | ||
1032 | } | ||
1033 | } | ||
1034 | mutex_unlock(&radio->lock); | ||
1035 | |||
1036 | /* wake up read queue */ | ||
1037 | if (radio->wr_index != radio->rd_index) | ||
1038 | wake_up_interruptible(&radio->read_queue); | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | /* | ||
1043 | * si470x_work - rds work function | ||
1044 | */ | ||
1045 | static void si470x_work(struct work_struct *work) | ||
1046 | { | ||
1047 | struct si470x_device *radio = container_of(work, struct si470x_device, | ||
1048 | work.work); | ||
1049 | |||
1050 | /* safety checks */ | ||
1051 | if (radio->disconnected) | ||
1052 | return; | ||
1053 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) | ||
1054 | return; | ||
1055 | |||
1056 | si470x_rds(radio); | ||
1057 | schedule_delayed_work(&radio->work, msecs_to_jiffies(rds_poll_time)); | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | |||
1062 | /************************************************************************** | ||
1063 | * File Operations Interface | ||
1064 | **************************************************************************/ | ||
1065 | |||
1066 | /* | ||
1067 | * si470x_fops_read - read RDS data | ||
1068 | */ | ||
1069 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
1070 | size_t count, loff_t *ppos) | ||
1071 | { | ||
1072 | struct si470x_device *radio = video_drvdata(file); | ||
1073 | int retval = 0; | ||
1074 | unsigned int block_count = 0; | ||
1075 | |||
1076 | /* switch on rds reception */ | ||
1077 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { | ||
1078 | si470x_rds_on(radio); | ||
1079 | schedule_delayed_work(&radio->work, | ||
1080 | msecs_to_jiffies(rds_poll_time)); | ||
1081 | } | ||
1082 | |||
1083 | /* block if no new data available */ | ||
1084 | while (radio->wr_index == radio->rd_index) { | ||
1085 | if (file->f_flags & O_NONBLOCK) { | ||
1086 | retval = -EWOULDBLOCK; | ||
1087 | goto done; | ||
1088 | } | ||
1089 | if (wait_event_interruptible(radio->read_queue, | ||
1090 | radio->wr_index != radio->rd_index) < 0) { | ||
1091 | retval = -EINTR; | ||
1092 | goto done; | ||
1093 | } | ||
1094 | } | ||
1095 | |||
1096 | /* calculate block count from byte count */ | ||
1097 | count /= 3; | ||
1098 | |||
1099 | /* copy RDS block out of internal buffer and to user buffer */ | ||
1100 | mutex_lock(&radio->lock); | ||
1101 | while (block_count < count) { | ||
1102 | if (radio->rd_index == radio->wr_index) | ||
1103 | break; | ||
1104 | |||
1105 | /* always transfer rds complete blocks */ | ||
1106 | if (copy_to_user(buf, &radio->buffer[radio->rd_index], 3)) | ||
1107 | /* retval = -EFAULT; */ | ||
1108 | break; | ||
1109 | |||
1110 | /* increment and wrap read pointer */ | ||
1111 | radio->rd_index += 3; | ||
1112 | if (radio->rd_index >= radio->buf_size) | ||
1113 | radio->rd_index = 0; | ||
1114 | |||
1115 | /* increment counters */ | ||
1116 | block_count++; | ||
1117 | buf += 3; | ||
1118 | retval += 3; | ||
1119 | } | ||
1120 | mutex_unlock(&radio->lock); | ||
1121 | |||
1122 | done: | ||
1123 | return retval; | ||
1124 | } | ||
1125 | |||
1126 | |||
1127 | /* | ||
1128 | * si470x_fops_poll - poll RDS data | ||
1129 | */ | ||
1130 | static unsigned int si470x_fops_poll(struct file *file, | ||
1131 | struct poll_table_struct *pts) | ||
1132 | { | ||
1133 | struct si470x_device *radio = video_drvdata(file); | ||
1134 | int retval = 0; | ||
1135 | |||
1136 | /* switch on rds reception */ | ||
1137 | if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0) { | ||
1138 | si470x_rds_on(radio); | ||
1139 | schedule_delayed_work(&radio->work, | ||
1140 | msecs_to_jiffies(rds_poll_time)); | ||
1141 | } | ||
1142 | |||
1143 | poll_wait(file, &radio->read_queue, pts); | ||
1144 | |||
1145 | if (radio->rd_index != radio->wr_index) | ||
1146 | retval = POLLIN | POLLRDNORM; | ||
1147 | |||
1148 | return retval; | ||
1149 | } | ||
1150 | |||
1151 | |||
1152 | /* | ||
1153 | * si470x_fops_open - file open | ||
1154 | */ | ||
1155 | static int si470x_fops_open(struct file *file) | ||
1156 | { | ||
1157 | struct si470x_device *radio = video_drvdata(file); | ||
1158 | int retval; | ||
1159 | |||
1160 | lock_kernel(); | ||
1161 | radio->users++; | ||
1162 | |||
1163 | retval = usb_autopm_get_interface(radio->intf); | ||
1164 | if (retval < 0) { | ||
1165 | radio->users--; | ||
1166 | retval = -EIO; | ||
1167 | goto done; | ||
1168 | } | ||
1169 | |||
1170 | if (radio->users == 1) { | ||
1171 | /* start radio */ | ||
1172 | retval = si470x_start(radio); | ||
1173 | if (retval < 0) | ||
1174 | usb_autopm_put_interface(radio->intf); | ||
1175 | } | ||
1176 | |||
1177 | done: | ||
1178 | unlock_kernel(); | ||
1179 | return retval; | ||
1180 | } | ||
1181 | |||
1182 | |||
1183 | /* | ||
1184 | * si470x_fops_release - file release | ||
1185 | */ | ||
1186 | static int si470x_fops_release(struct file *file) | ||
1187 | { | ||
1188 | struct si470x_device *radio = video_drvdata(file); | ||
1189 | int retval = 0; | ||
1190 | |||
1191 | /* safety check */ | ||
1192 | if (!radio) { | ||
1193 | retval = -ENODEV; | ||
1194 | goto done; | ||
1195 | } | ||
1196 | |||
1197 | mutex_lock(&radio->disconnect_lock); | ||
1198 | radio->users--; | ||
1199 | if (radio->users == 0) { | ||
1200 | if (radio->disconnected) { | ||
1201 | video_unregister_device(radio->videodev); | ||
1202 | kfree(radio->buffer); | ||
1203 | kfree(radio); | ||
1204 | goto unlock; | ||
1205 | } | ||
1206 | |||
1207 | /* stop rds reception */ | ||
1208 | cancel_delayed_work_sync(&radio->work); | ||
1209 | |||
1210 | /* cancel read processes */ | ||
1211 | wake_up_interruptible(&radio->read_queue); | ||
1212 | |||
1213 | /* stop radio */ | ||
1214 | retval = si470x_stop(radio); | ||
1215 | usb_autopm_put_interface(radio->intf); | ||
1216 | } | ||
1217 | unlock: | ||
1218 | mutex_unlock(&radio->disconnect_lock); | ||
1219 | done: | ||
1220 | return retval; | ||
1221 | } | ||
1222 | |||
1223 | |||
1224 | /* | ||
1225 | * si470x_fops - file operations interface | ||
1226 | */ | ||
1227 | static const struct v4l2_file_operations si470x_fops = { | ||
1228 | .owner = THIS_MODULE, | ||
1229 | .read = si470x_fops_read, | ||
1230 | .poll = si470x_fops_poll, | ||
1231 | .ioctl = video_ioctl2, | ||
1232 | .open = si470x_fops_open, | ||
1233 | .release = si470x_fops_release, | ||
1234 | }; | ||
1235 | |||
1236 | |||
1237 | |||
1238 | /************************************************************************** | ||
1239 | * Video4Linux Interface | ||
1240 | **************************************************************************/ | ||
1241 | |||
1242 | /* | ||
1243 | * si470x_v4l2_queryctrl - query control | ||
1244 | */ | ||
1245 | static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { | ||
1246 | { | ||
1247 | .id = V4L2_CID_AUDIO_VOLUME, | ||
1248 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1249 | .name = "Volume", | ||
1250 | .minimum = 0, | ||
1251 | .maximum = 15, | ||
1252 | .step = 1, | ||
1253 | .default_value = 15, | ||
1254 | }, | ||
1255 | { | ||
1256 | .id = V4L2_CID_AUDIO_MUTE, | ||
1257 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1258 | .name = "Mute", | ||
1259 | .minimum = 0, | ||
1260 | .maximum = 1, | ||
1261 | .step = 1, | ||
1262 | .default_value = 1, | ||
1263 | }, | ||
1264 | }; | ||
1265 | |||
1266 | |||
1267 | /* | ||
1268 | * si470x_vidioc_querycap - query device capabilities | ||
1269 | */ | ||
1270 | static int si470x_vidioc_querycap(struct file *file, void *priv, | ||
1271 | struct v4l2_capability *capability) | ||
1272 | { | ||
1273 | struct si470x_device *radio = video_drvdata(file); | ||
1274 | |||
1275 | strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); | ||
1276 | strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); | ||
1277 | usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info)); | ||
1278 | capability->version = DRIVER_KERNEL_VERSION; | ||
1279 | capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | | ||
1280 | V4L2_CAP_TUNER | V4L2_CAP_RADIO; | ||
1281 | |||
1282 | return 0; | ||
1283 | } | ||
1284 | |||
1285 | |||
1286 | /* | ||
1287 | * si470x_vidioc_queryctrl - enumerate control items | ||
1288 | */ | ||
1289 | static int si470x_vidioc_queryctrl(struct file *file, void *priv, | ||
1290 | struct v4l2_queryctrl *qc) | ||
1291 | { | ||
1292 | unsigned char i = 0; | ||
1293 | int retval = -EINVAL; | ||
1294 | |||
1295 | /* abort if qc->id is below V4L2_CID_BASE */ | ||
1296 | if (qc->id < V4L2_CID_BASE) | ||
1297 | goto done; | ||
1298 | |||
1299 | /* search video control */ | ||
1300 | for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { | ||
1301 | if (qc->id == si470x_v4l2_queryctrl[i].id) { | ||
1302 | memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); | ||
1303 | retval = 0; /* found */ | ||
1304 | break; | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | /* disable unsupported base controls */ | ||
1309 | /* to satisfy kradio and such apps */ | ||
1310 | if ((retval == -EINVAL) && (qc->id < V4L2_CID_LASTP1)) { | ||
1311 | qc->flags = V4L2_CTRL_FLAG_DISABLED; | ||
1312 | retval = 0; | ||
1313 | } | ||
1314 | |||
1315 | done: | ||
1316 | if (retval < 0) | ||
1317 | printk(KERN_WARNING DRIVER_NAME | ||
1318 | ": query controls failed with %d\n", retval); | ||
1319 | return retval; | ||
1320 | } | ||
1321 | |||
1322 | |||
1323 | /* | ||
1324 | * si470x_vidioc_g_ctrl - get the value of a control | ||
1325 | */ | ||
1326 | static int si470x_vidioc_g_ctrl(struct file *file, void *priv, | ||
1327 | struct v4l2_control *ctrl) | ||
1328 | { | ||
1329 | struct si470x_device *radio = video_drvdata(file); | ||
1330 | int retval = 0; | ||
1331 | |||
1332 | /* safety checks */ | ||
1333 | if (radio->disconnected) { | ||
1334 | retval = -EIO; | ||
1335 | goto done; | ||
1336 | } | ||
1337 | |||
1338 | switch (ctrl->id) { | ||
1339 | case V4L2_CID_AUDIO_VOLUME: | ||
1340 | ctrl->value = radio->registers[SYSCONFIG2] & | ||
1341 | SYSCONFIG2_VOLUME; | ||
1342 | break; | ||
1343 | case V4L2_CID_AUDIO_MUTE: | ||
1344 | ctrl->value = ((radio->registers[POWERCFG] & | ||
1345 | POWERCFG_DMUTE) == 0) ? 1 : 0; | ||
1346 | break; | ||
1347 | default: | ||
1348 | retval = -EINVAL; | ||
1349 | } | ||
1350 | |||
1351 | done: | ||
1352 | if (retval < 0) | ||
1353 | printk(KERN_WARNING DRIVER_NAME | ||
1354 | ": get control failed with %d\n", retval); | ||
1355 | return retval; | ||
1356 | } | ||
1357 | |||
1358 | |||
1359 | /* | ||
1360 | * si470x_vidioc_s_ctrl - set the value of a control | ||
1361 | */ | ||
1362 | static int si470x_vidioc_s_ctrl(struct file *file, void *priv, | ||
1363 | struct v4l2_control *ctrl) | ||
1364 | { | ||
1365 | struct si470x_device *radio = video_drvdata(file); | ||
1366 | int retval = 0; | ||
1367 | |||
1368 | /* safety checks */ | ||
1369 | if (radio->disconnected) { | ||
1370 | retval = -EIO; | ||
1371 | goto done; | ||
1372 | } | ||
1373 | |||
1374 | switch (ctrl->id) { | ||
1375 | case V4L2_CID_AUDIO_VOLUME: | ||
1376 | radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; | ||
1377 | radio->registers[SYSCONFIG2] |= ctrl->value; | ||
1378 | retval = si470x_set_register(radio, SYSCONFIG2); | ||
1379 | break; | ||
1380 | case V4L2_CID_AUDIO_MUTE: | ||
1381 | if (ctrl->value == 1) | ||
1382 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | ||
1383 | else | ||
1384 | radio->registers[POWERCFG] |= POWERCFG_DMUTE; | ||
1385 | retval = si470x_set_register(radio, POWERCFG); | ||
1386 | break; | ||
1387 | default: | ||
1388 | retval = -EINVAL; | ||
1389 | } | ||
1390 | |||
1391 | done: | ||
1392 | if (retval < 0) | ||
1393 | printk(KERN_WARNING DRIVER_NAME | ||
1394 | ": set control failed with %d\n", retval); | ||
1395 | return retval; | ||
1396 | } | ||
1397 | |||
1398 | |||
1399 | /* | ||
1400 | * si470x_vidioc_g_audio - get audio attributes | ||
1401 | */ | ||
1402 | static int si470x_vidioc_g_audio(struct file *file, void *priv, | ||
1403 | struct v4l2_audio *audio) | ||
1404 | { | ||
1405 | /* driver constants */ | ||
1406 | audio->index = 0; | ||
1407 | strcpy(audio->name, "Radio"); | ||
1408 | audio->capability = V4L2_AUDCAP_STEREO; | ||
1409 | audio->mode = 0; | ||
1410 | |||
1411 | return 0; | ||
1412 | } | ||
1413 | |||
1414 | |||
1415 | /* | ||
1416 | * si470x_vidioc_g_tuner - get tuner attributes | ||
1417 | */ | ||
1418 | static int si470x_vidioc_g_tuner(struct file *file, void *priv, | ||
1419 | struct v4l2_tuner *tuner) | ||
1420 | { | ||
1421 | struct si470x_device *radio = video_drvdata(file); | ||
1422 | int retval = 0; | ||
1423 | |||
1424 | /* safety checks */ | ||
1425 | if (radio->disconnected) { | ||
1426 | retval = -EIO; | ||
1427 | goto done; | ||
1428 | } | ||
1429 | if (tuner->index != 0) { | ||
1430 | retval = -EINVAL; | ||
1431 | goto done; | ||
1432 | } | ||
1433 | |||
1434 | retval = si470x_get_register(radio, STATUSRSSI); | ||
1435 | if (retval < 0) | ||
1436 | goto done; | ||
1437 | |||
1438 | /* driver constants */ | ||
1439 | strcpy(tuner->name, "FM"); | ||
1440 | tuner->type = V4L2_TUNER_RADIO; | ||
1441 | tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; | ||
1442 | |||
1443 | /* range limits */ | ||
1444 | switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) { | ||
1445 | /* 0: 87.5 - 108 MHz (USA, Europe, default) */ | ||
1446 | default: | ||
1447 | tuner->rangelow = 87.5 * FREQ_MUL; | ||
1448 | tuner->rangehigh = 108 * FREQ_MUL; | ||
1449 | break; | ||
1450 | /* 1: 76 - 108 MHz (Japan wide band) */ | ||
1451 | case 1 : | ||
1452 | tuner->rangelow = 76 * FREQ_MUL; | ||
1453 | tuner->rangehigh = 108 * FREQ_MUL; | ||
1454 | break; | ||
1455 | /* 2: 76 - 90 MHz (Japan) */ | ||
1456 | case 2 : | ||
1457 | tuner->rangelow = 76 * FREQ_MUL; | ||
1458 | tuner->rangehigh = 90 * FREQ_MUL; | ||
1459 | break; | ||
1460 | }; | ||
1461 | |||
1462 | /* stereo indicator == stereo (instead of mono) */ | ||
1463 | if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0) | ||
1464 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1465 | else | ||
1466 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | ||
1467 | |||
1468 | /* mono/stereo selector */ | ||
1469 | if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0) | ||
1470 | tuner->audmode = V4L2_TUNER_MODE_STEREO; | ||
1471 | else | ||
1472 | tuner->audmode = V4L2_TUNER_MODE_MONO; | ||
1473 | |||
1474 | /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */ | ||
1475 | /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */ | ||
1476 | tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI); | ||
1477 | /* the ideal factor is 0xffff/75 = 873,8 */ | ||
1478 | tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10); | ||
1479 | |||
1480 | /* automatic frequency control: -1: freq to low, 1 freq to high */ | ||
1481 | /* AFCRL does only indicate that freq. differs, not if too low/high */ | ||
1482 | tuner->afc = (radio->registers[STATUSRSSI] & STATUSRSSI_AFCRL) ? 1 : 0; | ||
1483 | |||
1484 | done: | ||
1485 | if (retval < 0) | ||
1486 | printk(KERN_WARNING DRIVER_NAME | ||
1487 | ": get tuner failed with %d\n", retval); | ||
1488 | return retval; | ||
1489 | } | ||
1490 | |||
1491 | |||
1492 | /* | ||
1493 | * si470x_vidioc_s_tuner - set tuner attributes | ||
1494 | */ | ||
1495 | static int si470x_vidioc_s_tuner(struct file *file, void *priv, | ||
1496 | struct v4l2_tuner *tuner) | ||
1497 | { | ||
1498 | struct si470x_device *radio = video_drvdata(file); | ||
1499 | int retval = -EINVAL; | ||
1500 | |||
1501 | /* safety checks */ | ||
1502 | if (radio->disconnected) { | ||
1503 | retval = -EIO; | ||
1504 | goto done; | ||
1505 | } | ||
1506 | if (tuner->index != 0) | ||
1507 | goto done; | ||
1508 | |||
1509 | /* mono/stereo selector */ | ||
1510 | switch (tuner->audmode) { | ||
1511 | case V4L2_TUNER_MODE_MONO: | ||
1512 | radio->registers[POWERCFG] |= POWERCFG_MONO; /* force mono */ | ||
1513 | break; | ||
1514 | case V4L2_TUNER_MODE_STEREO: | ||
1515 | radio->registers[POWERCFG] &= ~POWERCFG_MONO; /* try stereo */ | ||
1516 | break; | ||
1517 | default: | ||
1518 | goto done; | ||
1519 | } | ||
1520 | |||
1521 | retval = si470x_set_register(radio, POWERCFG); | ||
1522 | |||
1523 | done: | ||
1524 | if (retval < 0) | ||
1525 | printk(KERN_WARNING DRIVER_NAME | ||
1526 | ": set tuner failed with %d\n", retval); | ||
1527 | return retval; | ||
1528 | } | ||
1529 | |||
1530 | |||
1531 | /* | ||
1532 | * si470x_vidioc_g_frequency - get tuner or modulator radio frequency | ||
1533 | */ | ||
1534 | static int si470x_vidioc_g_frequency(struct file *file, void *priv, | ||
1535 | struct v4l2_frequency *freq) | ||
1536 | { | ||
1537 | struct si470x_device *radio = video_drvdata(file); | ||
1538 | int retval = 0; | ||
1539 | |||
1540 | /* safety checks */ | ||
1541 | if (radio->disconnected) { | ||
1542 | retval = -EIO; | ||
1543 | goto done; | ||
1544 | } | ||
1545 | if (freq->tuner != 0) { | ||
1546 | retval = -EINVAL; | ||
1547 | goto done; | ||
1548 | } | ||
1549 | |||
1550 | freq->type = V4L2_TUNER_RADIO; | ||
1551 | retval = si470x_get_freq(radio, &freq->frequency); | ||
1552 | |||
1553 | done: | ||
1554 | if (retval < 0) | ||
1555 | printk(KERN_WARNING DRIVER_NAME | ||
1556 | ": get frequency failed with %d\n", retval); | ||
1557 | return retval; | ||
1558 | } | ||
1559 | |||
1560 | |||
1561 | /* | ||
1562 | * si470x_vidioc_s_frequency - set tuner or modulator radio frequency | ||
1563 | */ | ||
1564 | static int si470x_vidioc_s_frequency(struct file *file, void *priv, | ||
1565 | struct v4l2_frequency *freq) | ||
1566 | { | ||
1567 | struct si470x_device *radio = video_drvdata(file); | ||
1568 | int retval = 0; | ||
1569 | |||
1570 | /* safety checks */ | ||
1571 | if (radio->disconnected) { | ||
1572 | retval = -EIO; | ||
1573 | goto done; | ||
1574 | } | ||
1575 | if (freq->tuner != 0) { | ||
1576 | retval = -EINVAL; | ||
1577 | goto done; | ||
1578 | } | ||
1579 | |||
1580 | retval = si470x_set_freq(radio, freq->frequency); | ||
1581 | |||
1582 | done: | ||
1583 | if (retval < 0) | ||
1584 | printk(KERN_WARNING DRIVER_NAME | ||
1585 | ": set frequency failed with %d\n", retval); | ||
1586 | return retval; | ||
1587 | } | ||
1588 | |||
1589 | |||
1590 | /* | ||
1591 | * si470x_vidioc_s_hw_freq_seek - set hardware frequency seek | ||
1592 | */ | ||
1593 | static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv, | ||
1594 | struct v4l2_hw_freq_seek *seek) | ||
1595 | { | ||
1596 | struct si470x_device *radio = video_drvdata(file); | ||
1597 | int retval = 0; | ||
1598 | |||
1599 | /* safety checks */ | ||
1600 | if (radio->disconnected) { | ||
1601 | retval = -EIO; | ||
1602 | goto done; | ||
1603 | } | ||
1604 | if (seek->tuner != 0) { | ||
1605 | retval = -EINVAL; | ||
1606 | goto done; | ||
1607 | } | ||
1608 | |||
1609 | retval = si470x_set_seek(radio, seek->wrap_around, seek->seek_upward); | ||
1610 | |||
1611 | done: | ||
1612 | if (retval < 0) | ||
1613 | printk(KERN_WARNING DRIVER_NAME | ||
1614 | ": set hardware frequency seek failed with %d\n", | ||
1615 | retval); | ||
1616 | return retval; | ||
1617 | } | ||
1618 | |||
1619 | |||
1620 | /* | ||
1621 | * si470x_ioctl_ops - video device ioctl operations | ||
1622 | */ | ||
1623 | static const struct v4l2_ioctl_ops si470x_ioctl_ops = { | ||
1624 | .vidioc_querycap = si470x_vidioc_querycap, | ||
1625 | .vidioc_queryctrl = si470x_vidioc_queryctrl, | ||
1626 | .vidioc_g_ctrl = si470x_vidioc_g_ctrl, | ||
1627 | .vidioc_s_ctrl = si470x_vidioc_s_ctrl, | ||
1628 | .vidioc_g_audio = si470x_vidioc_g_audio, | ||
1629 | .vidioc_g_tuner = si470x_vidioc_g_tuner, | ||
1630 | .vidioc_s_tuner = si470x_vidioc_s_tuner, | ||
1631 | .vidioc_g_frequency = si470x_vidioc_g_frequency, | ||
1632 | .vidioc_s_frequency = si470x_vidioc_s_frequency, | ||
1633 | .vidioc_s_hw_freq_seek = si470x_vidioc_s_hw_freq_seek, | ||
1634 | }; | ||
1635 | |||
1636 | |||
1637 | /* | ||
1638 | * si470x_viddev_template - video device interface | ||
1639 | */ | ||
1640 | static struct video_device si470x_viddev_template = { | ||
1641 | .fops = &si470x_fops, | ||
1642 | .name = DRIVER_NAME, | ||
1643 | .release = video_device_release, | ||
1644 | .ioctl_ops = &si470x_ioctl_ops, | ||
1645 | }; | ||
1646 | |||
1647 | |||
1648 | |||
1649 | /************************************************************************** | ||
1650 | * USB Interface | ||
1651 | **************************************************************************/ | ||
1652 | |||
1653 | /* | ||
1654 | * si470x_usb_driver_probe - probe for the device | ||
1655 | */ | ||
1656 | static int si470x_usb_driver_probe(struct usb_interface *intf, | ||
1657 | const struct usb_device_id *id) | ||
1658 | { | ||
1659 | struct si470x_device *radio; | ||
1660 | int retval = 0; | ||
1661 | |||
1662 | /* private data allocation and initialization */ | ||
1663 | radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); | ||
1664 | if (!radio) { | ||
1665 | retval = -ENOMEM; | ||
1666 | goto err_initial; | ||
1667 | } | ||
1668 | radio->users = 0; | ||
1669 | radio->disconnected = 0; | ||
1670 | radio->usbdev = interface_to_usbdev(intf); | ||
1671 | radio->intf = intf; | ||
1672 | mutex_init(&radio->disconnect_lock); | ||
1673 | mutex_init(&radio->lock); | ||
1674 | |||
1675 | /* video device allocation and initialization */ | ||
1676 | radio->videodev = video_device_alloc(); | ||
1677 | if (!radio->videodev) { | ||
1678 | retval = -ENOMEM; | ||
1679 | goto err_radio; | ||
1680 | } | ||
1681 | memcpy(radio->videodev, &si470x_viddev_template, | ||
1682 | sizeof(si470x_viddev_template)); | ||
1683 | video_set_drvdata(radio->videodev, radio); | ||
1684 | |||
1685 | /* show some infos about the specific si470x device */ | ||
1686 | if (si470x_get_all_registers(radio) < 0) { | ||
1687 | retval = -EIO; | ||
1688 | goto err_video; | ||
1689 | } | ||
1690 | printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", | ||
1691 | radio->registers[DEVICEID], radio->registers[CHIPID]); | ||
1692 | |||
1693 | /* get software and hardware versions */ | ||
1694 | if (si470x_get_scratch_page_versions(radio) < 0) { | ||
1695 | retval = -EIO; | ||
1696 | goto err_video; | ||
1697 | } | ||
1698 | printk(KERN_INFO DRIVER_NAME | ||
1699 | ": software version %d, hardware version %d\n", | ||
1700 | radio->software_version, radio->hardware_version); | ||
1701 | |||
1702 | /* check if device and firmware is current */ | ||
1703 | if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) | ||
1704 | < RADIO_SW_VERSION_CURRENT) { | ||
1705 | printk(KERN_WARNING DRIVER_NAME | ||
1706 | ": This driver is known to work with " | ||
1707 | "firmware version %hu,\n", RADIO_SW_VERSION_CURRENT); | ||
1708 | printk(KERN_WARNING DRIVER_NAME | ||
1709 | ": but the device has firmware version %hu.\n", | ||
1710 | radio->registers[CHIPID] & CHIPID_FIRMWARE); | ||
1711 | printk(KERN_WARNING DRIVER_NAME | ||
1712 | ": If you have some trouble using this driver,\n"); | ||
1713 | printk(KERN_WARNING DRIVER_NAME | ||
1714 | ": please report to V4L ML at " | ||
1715 | "linux-media@vger.kernel.org\n"); | ||
1716 | } | ||
1717 | |||
1718 | /* set initial frequency */ | ||
1719 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | ||
1720 | |||
1721 | /* set led to connect state */ | ||
1722 | si470x_set_led_state(radio, BLINK_GREEN_LED); | ||
1723 | |||
1724 | /* rds buffer allocation */ | ||
1725 | radio->buf_size = rds_buf * 3; | ||
1726 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | ||
1727 | if (!radio->buffer) { | ||
1728 | retval = -EIO; | ||
1729 | goto err_video; | ||
1730 | } | ||
1731 | |||
1732 | /* rds buffer configuration */ | ||
1733 | radio->wr_index = 0; | ||
1734 | radio->rd_index = 0; | ||
1735 | init_waitqueue_head(&radio->read_queue); | ||
1736 | |||
1737 | /* prepare rds work function */ | ||
1738 | INIT_DELAYED_WORK(&radio->work, si470x_work); | ||
1739 | |||
1740 | /* register video device */ | ||
1741 | retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); | ||
1742 | if (retval) { | ||
1743 | printk(KERN_WARNING DRIVER_NAME | ||
1744 | ": Could not register video device\n"); | ||
1745 | goto err_all; | ||
1746 | } | ||
1747 | usb_set_intfdata(intf, radio); | ||
1748 | |||
1749 | return 0; | ||
1750 | err_all: | ||
1751 | kfree(radio->buffer); | ||
1752 | err_video: | ||
1753 | video_device_release(radio->videodev); | ||
1754 | err_radio: | ||
1755 | kfree(radio); | ||
1756 | err_initial: | ||
1757 | return retval; | ||
1758 | } | ||
1759 | |||
1760 | |||
1761 | /* | ||
1762 | * si470x_usb_driver_suspend - suspend the device | ||
1763 | */ | ||
1764 | static int si470x_usb_driver_suspend(struct usb_interface *intf, | ||
1765 | pm_message_t message) | ||
1766 | { | ||
1767 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1768 | |||
1769 | printk(KERN_INFO DRIVER_NAME ": suspending now...\n"); | ||
1770 | |||
1771 | cancel_delayed_work_sync(&radio->work); | ||
1772 | |||
1773 | return 0; | ||
1774 | } | ||
1775 | |||
1776 | |||
1777 | /* | ||
1778 | * si470x_usb_driver_resume - resume the device | ||
1779 | */ | ||
1780 | static int si470x_usb_driver_resume(struct usb_interface *intf) | ||
1781 | { | ||
1782 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1783 | |||
1784 | printk(KERN_INFO DRIVER_NAME ": resuming now...\n"); | ||
1785 | |||
1786 | mutex_lock(&radio->lock); | ||
1787 | if (radio->users && radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) | ||
1788 | schedule_delayed_work(&radio->work, | ||
1789 | msecs_to_jiffies(rds_poll_time)); | ||
1790 | mutex_unlock(&radio->lock); | ||
1791 | |||
1792 | return 0; | ||
1793 | } | ||
1794 | |||
1795 | |||
1796 | /* | ||
1797 | * si470x_usb_driver_disconnect - disconnect the device | ||
1798 | */ | ||
1799 | static void si470x_usb_driver_disconnect(struct usb_interface *intf) | ||
1800 | { | ||
1801 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1802 | |||
1803 | mutex_lock(&radio->disconnect_lock); | ||
1804 | radio->disconnected = 1; | ||
1805 | cancel_delayed_work_sync(&radio->work); | ||
1806 | usb_set_intfdata(intf, NULL); | ||
1807 | if (radio->users == 0) { | ||
1808 | /* set led to disconnect state */ | ||
1809 | si470x_set_led_state(radio, BLINK_ORANGE_LED); | ||
1810 | |||
1811 | video_unregister_device(radio->videodev); | ||
1812 | kfree(radio->buffer); | ||
1813 | kfree(radio); | ||
1814 | } | ||
1815 | mutex_unlock(&radio->disconnect_lock); | ||
1816 | } | ||
1817 | |||
1818 | |||
1819 | /* | ||
1820 | * si470x_usb_driver - usb driver interface | ||
1821 | */ | ||
1822 | static struct usb_driver si470x_usb_driver = { | ||
1823 | .name = DRIVER_NAME, | ||
1824 | .probe = si470x_usb_driver_probe, | ||
1825 | .disconnect = si470x_usb_driver_disconnect, | ||
1826 | .suspend = si470x_usb_driver_suspend, | ||
1827 | .resume = si470x_usb_driver_resume, | ||
1828 | .id_table = si470x_usb_driver_id_table, | ||
1829 | .supports_autosuspend = 1, | ||
1830 | }; | ||
1831 | |||
1832 | |||
1833 | |||
1834 | /************************************************************************** | ||
1835 | * Module Interface | ||
1836 | **************************************************************************/ | ||
1837 | |||
1838 | /* | ||
1839 | * si470x_module_init - module init | ||
1840 | */ | ||
1841 | static int __init si470x_module_init(void) | ||
1842 | { | ||
1843 | printk(KERN_INFO DRIVER_DESC ", Version " DRIVER_VERSION "\n"); | ||
1844 | return usb_register(&si470x_usb_driver); | ||
1845 | } | ||
1846 | |||
1847 | |||
1848 | /* | ||
1849 | * si470x_module_exit - module exit | ||
1850 | */ | ||
1851 | static void __exit si470x_module_exit(void) | ||
1852 | { | ||
1853 | usb_deregister(&si470x_usb_driver); | ||
1854 | } | ||
1855 | |||
1856 | |||
1857 | module_init(si470x_module_init); | ||
1858 | module_exit(si470x_module_exit); | ||
1859 | |||
1860 | MODULE_LICENSE("GPL"); | ||
1861 | MODULE_AUTHOR(DRIVER_AUTHOR); | ||
1862 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
1863 | MODULE_VERSION(DRIVER_VERSION); | ||