diff options
author | Tobias Lorenz <tobias.lorenz@gmx.net> | 2008-01-25 02:19:48 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-01-25 16:05:13 -0500 |
commit | 8bf5e5ca394441e56f68300dc4e7b26b79ddfe0b (patch) | |
tree | f3485964f862781caadf646bebada258116d2d86 | |
parent | ed086314f4e41eb90a9107c7fb2737230686f668 (diff) |
V4L/DVB (7061): radio-si470x: Some cleanups
- code reordered to avoid function prototypes
- switch/case defaults are now more user-friendly
- unified comment style
- applied all checkpatch.pl v1.12 suggestions
except the warning about the too long lines with bit comments
- renamed FMRADIO to RADIO to cut line length (checkpatch.pl)
Signed-off-by: Tobias Lorenz <tobias.lorenz@gmx.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 843 |
1 files changed, 407 insertions, 436 deletions
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index ccb167a1acdc..d54fe6405351 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c | |||
@@ -5,7 +5,7 @@ | |||
5 | * - Silicon Labs USB FM Radio Reference Design | 5 | * - Silicon Labs USB FM Radio Reference Design |
6 | * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) | 6 | * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) |
7 | * | 7 | * |
8 | * Copyright (c) 2007 Tobias Lorenz <tobias.lorenz@gmx.net> | 8 | * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net> |
9 | * | 9 | * |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -29,7 +29,7 @@ | |||
29 | * Version 1.0.0 | 29 | * Version 1.0.0 |
30 | * - First working version | 30 | * - First working version |
31 | * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> | 31 | * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> |
32 | * Version 1.0.1 | 32 | * Version 1.0.1 |
33 | * - Improved error handling, every function now returns errno | 33 | * - Improved error handling, every function now returns errno |
34 | * - Improved multi user access (start/mute/stop) | 34 | * - Improved multi user access (start/mute/stop) |
35 | * - Channel doesn't get lost anymore after start/mute/stop | 35 | * - Channel doesn't get lost anymore after start/mute/stop |
@@ -47,6 +47,14 @@ | |||
47 | * - check for firmware version 15 | 47 | * - check for firmware version 15 |
48 | * - code order and prototypes still remain the same | 48 | * - code order and prototypes still remain the same |
49 | * - spacing and bottom of band codes remain the same | 49 | * - spacing and bottom of band codes remain the same |
50 | * 2008-01-16 Tobias Lorenz <tobias.lorenz@gmx.net> | ||
51 | * Version 1.0.3 | ||
52 | * - code reordered to avoid function prototypes | ||
53 | * - switch/case defaults are now more user-friendly | ||
54 | * - unified comment style | ||
55 | * - applied all checkpatch.pl v1.12 suggestions | ||
56 | * except the warning about the too long lines with bit comments | ||
57 | * - renamed FMRADIO to RADIO to cut line length (checkpatch.pl) | ||
50 | * | 58 | * |
51 | * ToDo: | 59 | * ToDo: |
52 | * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver | 60 | * - check USB Vendor/Product ID for ADS/Tech FM Radio Receiver |
@@ -55,13 +63,14 @@ | |||
55 | * - add firmware download/update support | 63 | * - add firmware download/update support |
56 | * - add possibility to switch off RDS | 64 | * - add possibility to switch off RDS |
57 | * - RDS support: interrupt mode, instead of polling | 65 | * - RDS support: interrupt mode, instead of polling |
58 | * - add LED status output | 66 | * - add LED status output (check if that's not already done in firmware) |
59 | */ | 67 | */ |
60 | 68 | ||
69 | |||
61 | /* driver definitions */ | 70 | /* driver definitions */ |
62 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" | 71 | #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" |
63 | #define DRIVER_NAME "radio-si470x" | 72 | #define DRIVER_NAME "radio-si470x" |
64 | #define DRIVER_VERSION KERNEL_VERSION(1, 0, 2) | 73 | #define DRIVER_VERSION KERNEL_VERSION(1, 0, 3) |
65 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" | 74 | #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" |
66 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" | 75 | #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" |
67 | 76 | ||
@@ -80,6 +89,21 @@ | |||
80 | #include <media/rds.h> | 89 | #include <media/rds.h> |
81 | 90 | ||
82 | 91 | ||
92 | /* USB Device ID List */ | ||
93 | static struct usb_device_id si470x_usb_driver_id_table[] = { | ||
94 | /* Silicon Labs USB FM Radio Reference Design */ | ||
95 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, | ||
96 | /* Terminating entry */ | ||
97 | { } | ||
98 | }; | ||
99 | MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); | ||
100 | |||
101 | |||
102 | |||
103 | /************************************************************************** | ||
104 | * Module Parameters | ||
105 | **************************************************************************/ | ||
106 | |||
83 | /* Radio Nr */ | 107 | /* Radio Nr */ |
84 | static int radio_nr = -1; | 108 | static int radio_nr = -1; |
85 | module_param(radio_nr, int, 0); | 109 | module_param(radio_nr, int, 0); |
@@ -145,8 +169,8 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
145 | /************************************************************************** | 169 | /************************************************************************** |
146 | * Register Definitions | 170 | * Register Definitions |
147 | **************************************************************************/ | 171 | **************************************************************************/ |
148 | #define FMRADIO_REGISTER_SIZE 2 /* 16 register bit width */ | 172 | #define RADIO_REGISTER_SIZE 2 /* 16 register bit width */ |
149 | #define FMRADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ | 173 | #define RADIO_REGISTER_NUM 16 /* DEVICEID ... RDSD */ |
150 | #define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ | 174 | #define RDS_REGISTER_NUM 6 /* STATUSRSSI ... RDSD */ |
151 | 175 | ||
152 | #define DEVICEID 0 /* Device ID */ | 176 | #define DEVICEID 0 /* Device ID */ |
@@ -236,23 +260,23 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
236 | 260 | ||
237 | 261 | ||
238 | /************************************************************************** | 262 | /************************************************************************** |
239 | * USB HID reports | 263 | * USB HID Reports |
240 | **************************************************************************/ | 264 | **************************************************************************/ |
241 | 265 | ||
242 | /* Reports 1-16 give direct read/write access to the 16 Si470x registers */ | 266 | /* Reports 1-16 give direct read/write access to the 16 Si470x registers */ |
243 | /* with the (REPORT_ID - 1) corresponding to the register address across USB */ | 267 | /* with the (REPORT_ID - 1) corresponding to the register address across USB */ |
244 | /* endpoint 0 using GET_REPORT and SET_REPORT */ | 268 | /* endpoint 0 using GET_REPORT and SET_REPORT */ |
245 | #define REGISTER_REPORT_SIZE (FMRADIO_REGISTER_SIZE + 1) | 269 | #define REGISTER_REPORT_SIZE (RADIO_REGISTER_SIZE + 1) |
246 | #define REGISTER_REPORT(reg) ((reg) + 1) | 270 | #define REGISTER_REPORT(reg) ((reg) + 1) |
247 | 271 | ||
248 | /* Report 17 gives direct read/write access to the entire Si470x register */ | 272 | /* Report 17 gives direct read/write access to the entire Si470x register */ |
249 | /* map across endpoint 0 using GET_REPORT and SET_REPORT */ | 273 | /* map across endpoint 0 using GET_REPORT and SET_REPORT */ |
250 | #define ENTIRE_REPORT_SIZE (FMRADIO_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) | 274 | #define ENTIRE_REPORT_SIZE (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) |
251 | #define ENTIRE_REPORT 17 | 275 | #define ENTIRE_REPORT 17 |
252 | 276 | ||
253 | /* Report 18 is used to send the lowest 6 Si470x registers up the HID */ | 277 | /* Report 18 is used to send the lowest 6 Si470x registers up the HID */ |
254 | /* interrupt endpoint 1 to Windows every 20 milliseconds for status */ | 278 | /* interrupt endpoint 1 to Windows every 20 milliseconds for status */ |
255 | #define RDS_REPORT_SIZE (RDS_REGISTER_NUM * FMRADIO_REGISTER_SIZE + 1) | 279 | #define RDS_REPORT_SIZE (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) |
256 | #define RDS_REPORT 18 | 280 | #define RDS_REPORT 18 |
257 | 281 | ||
258 | /* Report 19: LED state */ | 282 | /* Report 19: LED state */ |
@@ -281,12 +305,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
281 | 305 | ||
282 | 306 | ||
283 | /************************************************************************** | 307 | /************************************************************************** |
284 | * software/hardware versions | 308 | * Software/Hardware Versions |
285 | **************************************************************************/ | 309 | **************************************************************************/ |
286 | #define FMRADIO_SW_VERSION_NOT_BOOTLOADABLE 6 | 310 | #define RADIO_SW_VERSION_NOT_BOOTLOADABLE 6 |
287 | #define FMRADIO_SW_VERSION 7 | 311 | #define RADIO_SW_VERSION 7 |
288 | #define FMRADIO_SW_VERSION_CURRENT 15 | 312 | #define RADIO_SW_VERSION_CURRENT 15 |
289 | #define FMRADIO_HW_VERSION 1 | 313 | #define RADIO_HW_VERSION 1 |
290 | 314 | ||
291 | #define SCRATCH_PAGE_SW_VERSION 1 | 315 | #define SCRATCH_PAGE_SW_VERSION 1 |
292 | #define SCRATCH_PAGE_HW_VERSION 2 | 316 | #define SCRATCH_PAGE_HW_VERSION 2 |
@@ -294,7 +318,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
294 | 318 | ||
295 | 319 | ||
296 | /************************************************************************** | 320 | /************************************************************************** |
297 | * LED State definitions | 321 | * LED State Definitions |
298 | **************************************************************************/ | 322 | **************************************************************************/ |
299 | #define LED_COMMAND 0x35 | 323 | #define LED_COMMAND 0x35 |
300 | 324 | ||
@@ -310,7 +334,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
310 | 334 | ||
311 | 335 | ||
312 | /************************************************************************** | 336 | /************************************************************************** |
313 | * Stream State definitions | 337 | * Stream State Definitions |
314 | **************************************************************************/ | 338 | **************************************************************************/ |
315 | #define STREAM_COMMAND 0x36 | 339 | #define STREAM_COMMAND 0x36 |
316 | #define STREAM_VIDPID 0x00 | 340 | #define STREAM_VIDPID 0x00 |
@@ -319,16 +343,16 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
319 | 343 | ||
320 | 344 | ||
321 | /************************************************************************** | 345 | /************************************************************************** |
322 | * bootloader / flash commands | 346 | * Bootloader / Flash Commands |
323 | **************************************************************************/ | 347 | **************************************************************************/ |
324 | 348 | ||
325 | /* Unique ID sent to bootloader and required to put into a bootload state */ | 349 | /* unique id sent to bootloader and required to put into a bootload state */ |
326 | #define UNIQUE_BL_ID 0x34 | 350 | #define UNIQUE_BL_ID 0x34 |
327 | 351 | ||
328 | /* Mask for the flash data */ | 352 | /* mask for the flash data */ |
329 | #define FLASH_DATA_MASK 0x55 | 353 | #define FLASH_DATA_MASK 0x55 |
330 | 354 | ||
331 | /* Bootloader commands */ | 355 | /* bootloader commands */ |
332 | #define GET_SW_VERSION_COMMAND 0x00 | 356 | #define GET_SW_VERSION_COMMAND 0x00 |
333 | #define SET_PAGE_COMMAND 0x01 | 357 | #define SET_PAGE_COMMAND 0x01 |
334 | #define ERASE_PAGE_COMMAND 0x02 | 358 | #define ERASE_PAGE_COMMAND 0x02 |
@@ -339,12 +363,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
339 | #define GET_HW_VERSION_COMMAND 0x07 | 363 | #define GET_HW_VERSION_COMMAND 0x07 |
340 | #define BLANK 0xff | 364 | #define BLANK 0xff |
341 | 365 | ||
342 | /* Bootloader command responses */ | 366 | /* bootloader command responses */ |
343 | #define COMMAND_OK 0x01 | 367 | #define COMMAND_OK 0x01 |
344 | #define COMMAND_FAILED 0x02 | 368 | #define COMMAND_FAILED 0x02 |
345 | #define COMMAND_PENDING 0x03 | 369 | #define COMMAND_PENDING 0x03 |
346 | 370 | ||
347 | /* Buffer sizes */ | 371 | /* buffer sizes */ |
348 | #define COMMAND_BUFFER_SIZE 4 | 372 | #define COMMAND_BUFFER_SIZE 4 |
349 | #define RESPONSE_BUFFER_SIZE 2 | 373 | #define RESPONSE_BUFFER_SIZE 2 |
350 | #define FLASH_BUFFER_SIZE 64 | 374 | #define FLASH_BUFFER_SIZE 64 |
@@ -353,10 +377,12 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); | |||
353 | 377 | ||
354 | 378 | ||
355 | /************************************************************************** | 379 | /************************************************************************** |
356 | * Driver private definitions | 380 | * General Driver Definitions |
357 | **************************************************************************/ | 381 | **************************************************************************/ |
358 | 382 | ||
359 | /* private data */ | 383 | /* |
384 | * si470x_device - private data | ||
385 | */ | ||
360 | struct si470x_device { | 386 | struct si470x_device { |
361 | /* reference to USB and video device */ | 387 | /* reference to USB and video device */ |
362 | struct usb_device *usbdev; | 388 | struct usb_device *usbdev; |
@@ -369,12 +395,12 @@ struct si470x_device { | |||
369 | unsigned char buf[64]; | 395 | unsigned char buf[64]; |
370 | 396 | ||
371 | /* Silabs internal registers (0..15) */ | 397 | /* Silabs internal registers (0..15) */ |
372 | unsigned short registers[FMRADIO_REGISTER_NUM]; | 398 | unsigned short registers[RADIO_REGISTER_NUM]; |
373 | 399 | ||
374 | /* RDS receive buffer */ | 400 | /* RDS receive buffer */ |
375 | struct work_struct work; | 401 | struct work_struct work; |
376 | struct timer_list timer; | 402 | struct timer_list timer; |
377 | spinlock_t lock; | 403 | spinlock_t lock; /* buffer locking */ |
378 | unsigned char *buffer; | 404 | unsigned char *buffer; |
379 | unsigned int buf_size; | 405 | unsigned int buf_size; |
380 | unsigned int rd_index; | 406 | unsigned int rd_index; |
@@ -385,177 +411,20 @@ struct si470x_device { | |||
385 | int data_available_for_read; | 411 | int data_available_for_read; |
386 | }; | 412 | }; |
387 | 413 | ||
388 | /* register acccess functions */ | ||
389 | static int si470x_get_report(struct si470x_device *radio, int size); | ||
390 | static int si470x_set_report(struct si470x_device *radio, int size); | ||
391 | static int si470x_get_register(struct si470x_device *radio, int regnr); | ||
392 | static int si470x_set_register(struct si470x_device *radio, int regnr); | ||
393 | static int si470x_get_all_registers(struct si470x_device *radio); | ||
394 | static int si470x_get_rds_registers(struct si470x_device *radio); | ||
395 | |||
396 | /* high-level functions */ | ||
397 | static int si470x_start(struct si470x_device *radio); | ||
398 | static int si470x_stop(struct si470x_device *radio); | ||
399 | static int si470x_set_chan(struct si470x_device *radio, int chan); | ||
400 | static int si470x_get_freq(struct si470x_device *radio); | ||
401 | static int si470x_set_freq(struct si470x_device *radio, int freq); | ||
402 | |||
403 | /* RDS functions */ | ||
404 | static void si470x_rds(struct si470x_device *radio); | ||
405 | static void si470x_timer(unsigned long data); | ||
406 | static void si470x_work(struct work_struct *work); | ||
407 | |||
408 | |||
409 | |||
410 | /************************************************************************** | ||
411 | * USB interface definitions | ||
412 | **************************************************************************/ | ||
413 | |||
414 | /* USB device ID list (Vendor, Product, Class, SubClass, Protocol) */ | ||
415 | static struct usb_device_id si470x_usb_driver_id_table[] = { | ||
416 | /* Silicon Labs USB FM Radio Reference Design */ | ||
417 | { USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) }, | ||
418 | /* Terminating entry */ | ||
419 | { } | ||
420 | }; | ||
421 | MODULE_DEVICE_TABLE (usb, si470x_usb_driver_id_table); | ||
422 | |||
423 | /* USB driver functions */ | ||
424 | static int si470x_usb_driver_probe(struct usb_interface *intf, | ||
425 | const struct usb_device_id *id); | ||
426 | static void si470x_usb_driver_disconnect(struct usb_interface *intf); | ||
427 | |||
428 | /* USB driver interface */ | ||
429 | static struct usb_driver si470x_usb_driver = { | ||
430 | .name = DRIVER_NAME, | ||
431 | .probe = si470x_usb_driver_probe, | ||
432 | .disconnect = si470x_usb_driver_disconnect, | ||
433 | .id_table = si470x_usb_driver_id_table, | ||
434 | }; | ||
435 | |||
436 | |||
437 | 414 | ||
438 | /************************************************************************** | 415 | /* |
439 | * Video4Linux interface definitions | 416 | * The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, |
440 | **************************************************************************/ | 417 | * 62.5 kHz otherwise. |
441 | 418 | * The tuner is able to have a channel spacing of 50, 100 or 200 kHz. | |
442 | /* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW, */ | 419 | * tuner->capability is therefore set to V4L2_TUNER_CAP_LOW |
443 | /* 62.5 kHz otherwise. */ | 420 | * The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 |
444 | /* The tuner is able to have a channel spacing of 50, 100 or 200 kHz. */ | 421 | */ |
445 | /* tuner->capability is therefore set to V4L2_TUNER_CAP_LOW */ | ||
446 | /* The FREQ_MUL is then: 1 MHz / 62.5 Hz = 16000 */ | ||
447 | #define FREQ_MUL (1000000 / 62.5) | 422 | #define FREQ_MUL (1000000 / 62.5) |
448 | 423 | ||
449 | /* File operations functions */ | ||
450 | static ssize_t si470x_fops_read(struct file *file, char __user *buf, | ||
451 | size_t count, loff_t *ppos); | ||
452 | static unsigned int si470x_fops_poll(struct file *file, | ||
453 | struct poll_table_struct *pts); | ||
454 | static int si470x_fops_open(struct inode *inode, struct file *file); | ||
455 | static int si470x_fops_release(struct inode *inode, struct file *file); | ||
456 | |||
457 | /* File operations interface */ | ||
458 | static const struct file_operations si470x_fops = { | ||
459 | .owner = THIS_MODULE, | ||
460 | .llseek = no_llseek, | ||
461 | .read = si470x_fops_read, | ||
462 | .poll = si470x_fops_poll, | ||
463 | .ioctl = video_ioctl2, | ||
464 | .compat_ioctl = v4l_compat_ioctl32, | ||
465 | .open = si470x_fops_open, | ||
466 | .release = si470x_fops_release, | ||
467 | }; | ||
468 | |||
469 | /* Video device functions */ | ||
470 | static int si470x_vidioc_querycap(struct file *file, void *priv, | ||
471 | struct v4l2_capability *capability); | ||
472 | static int si470x_vidioc_g_input(struct file *file, void *priv, | ||
473 | unsigned int *i); | ||
474 | static int si470x_vidioc_s_input(struct file *file, void *priv, | ||
475 | unsigned int i); | ||
476 | static int si470x_vidioc_queryctrl(struct file *file, void *priv, | ||
477 | struct v4l2_queryctrl *qc); | ||
478 | static int si470x_vidioc_g_ctrl(struct file *file, void *priv, | ||
479 | struct v4l2_control *ctrl); | ||
480 | static int si470x_vidioc_s_ctrl(struct file *file, void *priv, | ||
481 | struct v4l2_control *ctrl); | ||
482 | static int si470x_vidioc_g_audio(struct file *file, void *priv, | ||
483 | struct v4l2_audio *audio); | ||
484 | static int si470x_vidioc_s_audio(struct file *file, void *priv, | ||
485 | struct v4l2_audio *audio); | ||
486 | static int si470x_vidioc_g_tuner(struct file *file, void *priv, | ||
487 | struct v4l2_tuner *tuner); | ||
488 | static int si470x_vidioc_s_tuner(struct file *file, void *priv, | ||
489 | struct v4l2_tuner *tuner); | ||
490 | static int si470x_vidioc_g_frequency(struct file *file, void *priv, | ||
491 | struct v4l2_frequency *freq); | ||
492 | static int si470x_vidioc_s_frequency(struct file *file, void *priv, | ||
493 | struct v4l2_frequency *freq); | ||
494 | |||
495 | /* Video device interface */ | ||
496 | static struct video_device si470x_viddev_template = { | ||
497 | .fops = &si470x_fops, | ||
498 | .name = DRIVER_NAME, | ||
499 | .type = VID_TYPE_TUNER, | ||
500 | .release = video_device_release, | ||
501 | .vidioc_querycap = si470x_vidioc_querycap, | ||
502 | .vidioc_g_input = si470x_vidioc_g_input, | ||
503 | .vidioc_s_input = si470x_vidioc_s_input, | ||
504 | .vidioc_queryctrl = si470x_vidioc_queryctrl, | ||
505 | .vidioc_g_ctrl = si470x_vidioc_g_ctrl, | ||
506 | .vidioc_s_ctrl = si470x_vidioc_s_ctrl, | ||
507 | .vidioc_g_audio = si470x_vidioc_g_audio, | ||
508 | .vidioc_s_audio = si470x_vidioc_s_audio, | ||
509 | .vidioc_g_tuner = si470x_vidioc_g_tuner, | ||
510 | .vidioc_s_tuner = si470x_vidioc_s_tuner, | ||
511 | .vidioc_g_frequency = si470x_vidioc_g_frequency, | ||
512 | .vidioc_s_frequency = si470x_vidioc_s_frequency, | ||
513 | .owner = THIS_MODULE, | ||
514 | }; | ||
515 | |||
516 | /* Query control */ | ||
517 | static struct v4l2_queryctrl radio_queryctrl[] = { | ||
518 | /* HINT: the disabled controls are only here to satify kradio and such apps */ | ||
519 | { | ||
520 | .id = V4L2_CID_AUDIO_VOLUME, | ||
521 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
522 | .name = "Volume", | ||
523 | .minimum = 0, | ||
524 | .maximum = 15, | ||
525 | .step = 1, | ||
526 | .default_value = 15, | ||
527 | }, | ||
528 | { | ||
529 | .id = V4L2_CID_AUDIO_BALANCE, | ||
530 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
531 | }, | ||
532 | { | ||
533 | .id = V4L2_CID_AUDIO_BASS, | ||
534 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
535 | }, | ||
536 | { | ||
537 | .id = V4L2_CID_AUDIO_TREBLE, | ||
538 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
539 | }, | ||
540 | { | ||
541 | .id = V4L2_CID_AUDIO_MUTE, | ||
542 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
543 | .name = "Mute", | ||
544 | .minimum = 0, | ||
545 | .maximum = 1, | ||
546 | .step = 1, | ||
547 | .default_value = 1, | ||
548 | }, | ||
549 | { | ||
550 | .id = V4L2_CID_AUDIO_LOUDNESS, | ||
551 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
552 | }, | ||
553 | }; | ||
554 | |||
555 | 424 | ||
556 | 425 | ||
557 | /************************************************************************** | 426 | /************************************************************************** |
558 | * Driver private functions | 427 | * General Driver Functions |
559 | **************************************************************************/ | 428 | **************************************************************************/ |
560 | 429 | ||
561 | /* | 430 | /* |
@@ -633,10 +502,10 @@ static int si470x_get_all_registers(struct si470x_device *radio) | |||
633 | retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); | 502 | retval = si470x_get_report(radio, ENTIRE_REPORT_SIZE); |
634 | 503 | ||
635 | if (retval >= 0) | 504 | if (retval >= 0) |
636 | for (regnr = 0; regnr < FMRADIO_REGISTER_NUM; regnr++) | 505 | for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) |
637 | radio->registers[regnr] = | 506 | radio->registers[regnr] = |
638 | (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | | 507 | (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | |
639 | radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; | 508 | radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; |
640 | 509 | ||
641 | return (retval < 0) ? -EINVAL : 0; | 510 | return (retval < 0) ? -EINVAL : 0; |
642 | } | 511 | } |
@@ -657,65 +526,13 @@ static int si470x_get_rds_registers(struct si470x_device *radio) | |||
657 | usb_rcvctrlpipe(radio->usbdev, 1), | 526 | usb_rcvctrlpipe(radio->usbdev, 1), |
658 | radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); | 527 | radio->buf, RDS_REPORT_SIZE, &size, usb_timeout); |
659 | 528 | ||
660 | if (retval >= 0) { | 529 | if (retval >= 0) |
661 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) { | 530 | for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) |
662 | radio->registers[STATUSRSSI + regnr] = | 531 | radio->registers[STATUSRSSI + regnr] = |
663 | (radio->buf[regnr * FMRADIO_REGISTER_SIZE + 1] << 8) | | 532 | (radio->buf[regnr * RADIO_REGISTER_SIZE + 1] << 8) | |
664 | radio->buf[regnr * FMRADIO_REGISTER_SIZE + 2]; | 533 | radio->buf[regnr * RADIO_REGISTER_SIZE + 2]; |
665 | } | ||
666 | } | ||
667 | |||
668 | return (retval < 0) ? - EINVAL : 0; | ||
669 | } | ||
670 | |||
671 | 534 | ||
672 | /* | 535 | return (retval < 0) ? -EINVAL : 0; |
673 | * si470x_start - switch on radio | ||
674 | */ | ||
675 | static int si470x_start(struct si470x_device *radio) | ||
676 | { | ||
677 | int retval; | ||
678 | |||
679 | /* powercfg */ | ||
680 | radio->registers[POWERCFG] = | ||
681 | POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; | ||
682 | retval = si470x_set_register(radio, POWERCFG); | ||
683 | if (retval < 0) | ||
684 | return retval; | ||
685 | |||
686 | /* sysconfig 1 */ | ||
687 | radio->registers[SYSCONFIG1] = | ||
688 | SYSCONFIG1_DE | SYSCONFIG1_RDS; | ||
689 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
690 | if (retval < 0) | ||
691 | return retval; | ||
692 | |||
693 | /* sysconfig 2 */ | ||
694 | radio->registers[SYSCONFIG2] = | ||
695 | (0x3f << 8) | /* SEEKTH */ | ||
696 | (band << 6) | /* BAND */ | ||
697 | (space << 4) | /* SPACE */ | ||
698 | 15; /* VOLUME (max) */ | ||
699 | retval = si470x_set_register(radio, SYSCONFIG2); | ||
700 | if (retval < 0) | ||
701 | return retval; | ||
702 | |||
703 | /* reset last channel */ | ||
704 | return si470x_set_chan(radio, | ||
705 | radio->registers[CHANNEL] & CHANNEL_CHAN); | ||
706 | } | ||
707 | |||
708 | |||
709 | /* | ||
710 | * si470x_stop - switch off radio | ||
711 | */ | ||
712 | static int si470x_stop(struct si470x_device *radio) | ||
713 | { | ||
714 | /* powercfg */ | ||
715 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | ||
716 | /* POWERCFG_ENABLE has to automatically go low */ | ||
717 | radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; | ||
718 | return si470x_set_register(radio, POWERCFG); | ||
719 | } | 536 | } |
720 | 537 | ||
721 | 538 | ||
@@ -761,22 +578,22 @@ static int si470x_get_freq(struct si470x_device *radio) | |||
761 | 578 | ||
762 | /* Spacing (kHz) */ | 579 | /* Spacing (kHz) */ |
763 | switch (space) { | 580 | switch (space) { |
764 | /* 0: 200 kHz (USA, Australia) */ | 581 | /* 0: 200 kHz (USA, Australia) */ |
765 | default: spacing = 0.200 * FREQ_MUL; break; | 582 | case 0 : spacing = 0.200 * FREQ_MUL; break; |
766 | /* 1: 100 kHz (Europe, Japan) */ | 583 | /* 1: 100 kHz (Europe, Japan) */ |
767 | case 1 : spacing = 0.100 * FREQ_MUL; break; | 584 | case 1 : spacing = 0.100 * FREQ_MUL; break; |
768 | /* 2: 50 kHz */ | 585 | /* 2: 50 kHz */ |
769 | case 2 : spacing = 0.050 * FREQ_MUL; break; | 586 | default: spacing = 0.050 * FREQ_MUL; break; |
770 | }; | 587 | }; |
771 | 588 | ||
772 | /* Bottom of Band (MHz) */ | 589 | /* Bottom of Band (MHz) */ |
773 | switch (band) { | 590 | switch (band) { |
774 | /* 0: 87.5 - 108 MHz (USA, Europe) */ | 591 | /* 0: 87.5 - 108 MHz (USA, Europe) */ |
775 | default: band_bottom = 87.5 * FREQ_MUL; break; | 592 | case 0 : band_bottom = 87.5 * FREQ_MUL; break; |
776 | /* 1: 76 - 108 MHz (Japan wide band) */ | 593 | /* 1: 76 - 108 MHz (Japan wide band) */ |
777 | case 1 : band_bottom = 76 * FREQ_MUL; break; | 594 | default: band_bottom = 76 * FREQ_MUL; break; |
778 | /* 2: 76 - 90 MHz (Japan) */ | 595 | /* 2: 76 - 90 MHz (Japan) */ |
779 | case 2 : band_bottom = 76 * FREQ_MUL; break; | 596 | case 2 : band_bottom = 76 * FREQ_MUL; break; |
780 | }; | 597 | }; |
781 | 598 | ||
782 | /* read channel */ | 599 | /* read channel */ |
@@ -801,22 +618,22 @@ static int si470x_set_freq(struct si470x_device *radio, int freq) | |||
801 | 618 | ||
802 | /* Spacing (kHz) */ | 619 | /* Spacing (kHz) */ |
803 | switch (space) { | 620 | switch (space) { |
804 | /* 0: 200 kHz (USA, Australia) */ | 621 | /* 0: 200 kHz (USA, Australia) */ |
805 | default: spacing = 0.200 * FREQ_MUL; break; | 622 | case 0 : spacing = 0.200 * FREQ_MUL; break; |
806 | /* 1: 100 kHz (Europe, Japan) */ | 623 | /* 1: 100 kHz (Europe, Japan) */ |
807 | case 1 : spacing = 0.100 * FREQ_MUL; break; | 624 | case 1 : spacing = 0.100 * FREQ_MUL; break; |
808 | /* 2: 50 kHz */ | 625 | /* 2: 50 kHz */ |
809 | case 2 : spacing = 0.050 * FREQ_MUL; break; | 626 | default: spacing = 0.050 * FREQ_MUL; break; |
810 | }; | 627 | }; |
811 | 628 | ||
812 | /* Bottom of Band (MHz) */ | 629 | /* Bottom of Band (MHz) */ |
813 | switch (band) { | 630 | switch (band) { |
814 | /* 0: 87.5 - 108 MHz (USA, Europe) */ | 631 | /* 0: 87.5 - 108 MHz (USA, Europe) */ |
815 | default: band_bottom = 87.5 * FREQ_MUL; break; | 632 | case 0 : band_bottom = 87.5 * FREQ_MUL; break; |
816 | /* 1: 76 - 108 MHz (Japan wide band) */ | 633 | /* 1: 76 - 108 MHz (Japan wide band) */ |
817 | case 1 : band_bottom = 76 * FREQ_MUL; break; | 634 | default: band_bottom = 76 * FREQ_MUL; break; |
818 | /* 2: 76 - 90 MHz (Japan) */ | 635 | /* 2: 76 - 90 MHz (Japan) */ |
819 | case 2 : band_bottom = 76 * FREQ_MUL; break; | 636 | case 2 : band_bottom = 76 * FREQ_MUL; break; |
820 | }; | 637 | }; |
821 | 638 | ||
822 | /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ | 639 | /* Chan = [ Freq (Mhz) - Bottom of Band (MHz) ] / Spacing (kHz) */ |
@@ -826,6 +643,60 @@ static int si470x_set_freq(struct si470x_device *radio, int freq) | |||
826 | } | 643 | } |
827 | 644 | ||
828 | 645 | ||
646 | /* | ||
647 | * si470x_start - switch on radio | ||
648 | */ | ||
649 | static int si470x_start(struct si470x_device *radio) | ||
650 | { | ||
651 | int retval; | ||
652 | |||
653 | /* powercfg */ | ||
654 | radio->registers[POWERCFG] = | ||
655 | POWERCFG_DMUTE | POWERCFG_ENABLE | POWERCFG_RDSM; | ||
656 | retval = si470x_set_register(radio, POWERCFG); | ||
657 | if (retval < 0) | ||
658 | return retval; | ||
659 | |||
660 | /* sysconfig 1 */ | ||
661 | radio->registers[SYSCONFIG1] = | ||
662 | SYSCONFIG1_DE | SYSCONFIG1_RDS; | ||
663 | retval = si470x_set_register(radio, SYSCONFIG1); | ||
664 | if (retval < 0) | ||
665 | return retval; | ||
666 | |||
667 | /* sysconfig 2 */ | ||
668 | radio->registers[SYSCONFIG2] = | ||
669 | (0x3f << 8) | /* SEEKTH */ | ||
670 | (band << 6) | /* BAND */ | ||
671 | (space << 4) | /* SPACE */ | ||
672 | 15; /* VOLUME (max) */ | ||
673 | retval = si470x_set_register(radio, SYSCONFIG2); | ||
674 | if (retval < 0) | ||
675 | return retval; | ||
676 | |||
677 | /* reset last channel */ | ||
678 | return si470x_set_chan(radio, | ||
679 | radio->registers[CHANNEL] & CHANNEL_CHAN); | ||
680 | } | ||
681 | |||
682 | |||
683 | /* | ||
684 | * si470x_stop - switch off radio | ||
685 | */ | ||
686 | static int si470x_stop(struct si470x_device *radio) | ||
687 | { | ||
688 | /* powercfg */ | ||
689 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | ||
690 | /* POWERCFG_ENABLE has to automatically go low */ | ||
691 | radio->registers[POWERCFG] |= POWERCFG_ENABLE | POWERCFG_DISABLE; | ||
692 | return si470x_set_register(radio, POWERCFG); | ||
693 | } | ||
694 | |||
695 | |||
696 | |||
697 | /************************************************************************** | ||
698 | * RDS Driver Functions | ||
699 | **************************************************************************/ | ||
829 | 700 | ||
830 | /* | 701 | /* |
831 | * si470x_rds - rds processing function | 702 | * si470x_rds - rds processing function |
@@ -854,26 +725,26 @@ static void si470x_rds(struct si470x_device *radio) | |||
854 | 725 | ||
855 | for (blocknum = 0; blocknum < 4; blocknum++) { | 726 | for (blocknum = 0; blocknum < 4; blocknum++) { |
856 | switch (blocknum) { | 727 | switch (blocknum) { |
857 | default: | 728 | default: |
858 | bler = (radio->registers[STATUSRSSI] & | 729 | bler = (radio->registers[STATUSRSSI] & |
859 | STATUSRSSI_BLERA) >> 9; | 730 | STATUSRSSI_BLERA) >> 9; |
860 | rds = radio->registers[RDSA]; | 731 | rds = radio->registers[RDSA]; |
861 | break; | 732 | break; |
862 | case 1: | 733 | case 1: |
863 | bler = (radio->registers[READCHAN] & | 734 | bler = (radio->registers[READCHAN] & |
864 | READCHAN_BLERB) >> 14; | 735 | READCHAN_BLERB) >> 14; |
865 | rds = radio->registers[RDSB]; | 736 | rds = radio->registers[RDSB]; |
866 | break; | 737 | break; |
867 | case 2: | 738 | case 2: |
868 | bler = (radio->registers[READCHAN] & | 739 | bler = (radio->registers[READCHAN] & |
869 | READCHAN_BLERC) >> 12; | 740 | READCHAN_BLERC) >> 12; |
870 | rds = radio->registers[RDSC]; | 741 | rds = radio->registers[RDSC]; |
871 | break; | 742 | break; |
872 | case 3: | 743 | case 3: |
873 | bler = (radio->registers[READCHAN] & | 744 | bler = (radio->registers[READCHAN] & |
874 | READCHAN_BLERD) >> 10; | 745 | READCHAN_BLERD) >> 10; |
875 | rds = radio->registers[RDSD]; | 746 | rds = radio->registers[RDSD]; |
876 | break; | 747 | break; |
877 | }; | 748 | }; |
878 | 749 | ||
879 | /* Fill the V4L2 RDS buffer */ | 750 | /* Fill the V4L2 RDS buffer */ |
@@ -941,107 +812,7 @@ static void si470x_work(struct work_struct *work) | |||
941 | 812 | ||
942 | 813 | ||
943 | /************************************************************************** | 814 | /************************************************************************** |
944 | * USB interface functions | 815 | * File Operations Interface |
945 | **************************************************************************/ | ||
946 | |||
947 | /* | ||
948 | * si470x_usb_driver_probe - probe for the device | ||
949 | */ | ||
950 | static int si470x_usb_driver_probe(struct usb_interface *intf, | ||
951 | const struct usb_device_id *id) | ||
952 | { | ||
953 | struct si470x_device *radio; | ||
954 | |||
955 | if (!(radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL))) | ||
956 | return -ENOMEM; | ||
957 | if (!(radio->videodev = video_device_alloc())) { | ||
958 | kfree(radio); | ||
959 | return -ENOMEM; | ||
960 | } | ||
961 | memcpy(radio->videodev, &si470x_viddev_template, | ||
962 | sizeof(si470x_viddev_template)); | ||
963 | radio->users = 0; | ||
964 | radio->usbdev = interface_to_usbdev(intf); | ||
965 | video_set_drvdata(radio->videodev, radio); | ||
966 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { | ||
967 | printk(KERN_WARNING DRIVER_NAME | ||
968 | ": Could not register video device\n"); | ||
969 | video_device_release(radio->videodev); | ||
970 | kfree(radio); | ||
971 | return -EIO; | ||
972 | } | ||
973 | usb_set_intfdata(intf, radio); | ||
974 | |||
975 | /* show some infos about the specific device */ | ||
976 | if (si470x_get_all_registers(radio) < 0) { | ||
977 | video_device_release(radio->videodev); | ||
978 | kfree(radio); | ||
979 | return -EIO; | ||
980 | } | ||
981 | printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", | ||
982 | radio->registers[DEVICEID], radio->registers[CHIPID]); | ||
983 | |||
984 | /* check if firmware is current */ | ||
985 | if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) | ||
986 | < FMRADIO_SW_VERSION_CURRENT) { | ||
987 | printk(KERN_WARNING DRIVER_NAME | ||
988 | ": This driver is known to work with chip version %d, " | ||
989 | "but the device has firmware %d. If you have some " | ||
990 | "trouble using this driver, please report to V4L ML " | ||
991 | "at video4linux-list@redhat.com\n", | ||
992 | radio->registers[CHIPID] & CHIPID_FIRMWARE, | ||
993 | FMRADIO_SW_VERSION_CURRENT); | ||
994 | } | ||
995 | |||
996 | /* set initial frequency */ | ||
997 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | ||
998 | |||
999 | /* rds initialization */ | ||
1000 | radio->buf_size = rds_buf * 3; | ||
1001 | if (NULL == (radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL))) { | ||
1002 | video_device_release(radio->videodev); | ||
1003 | kfree(radio); | ||
1004 | return -ENOMEM; | ||
1005 | } | ||
1006 | radio->block_count = 0; | ||
1007 | radio->wr_index = 0; | ||
1008 | radio->rd_index = 0; | ||
1009 | radio->last_blocknum = 0xff; | ||
1010 | init_waitqueue_head(&radio->read_queue); | ||
1011 | radio->data_available_for_read = 0; | ||
1012 | |||
1013 | /* prepare polling via eventd */ | ||
1014 | INIT_WORK(&radio->work, si470x_work); | ||
1015 | init_timer(&radio->timer); | ||
1016 | radio->timer.function = si470x_timer; | ||
1017 | radio->timer.data = (unsigned long) radio; | ||
1018 | |||
1019 | return 0; | ||
1020 | } | ||
1021 | |||
1022 | |||
1023 | /* | ||
1024 | * si470x_usb_driver_disconnect - disconnect the device | ||
1025 | */ | ||
1026 | static void si470x_usb_driver_disconnect(struct usb_interface *intf) | ||
1027 | { | ||
1028 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1029 | |||
1030 | del_timer_sync(&radio->timer); | ||
1031 | flush_scheduled_work(); | ||
1032 | |||
1033 | usb_set_intfdata(intf, NULL); | ||
1034 | if (radio) { | ||
1035 | video_unregister_device(radio->videodev); | ||
1036 | kfree(radio->buffer); | ||
1037 | kfree(radio); | ||
1038 | } | ||
1039 | } | ||
1040 | |||
1041 | |||
1042 | |||
1043 | /************************************************************************** | ||
1044 | * Video4Linux interface functions | ||
1045 | **************************************************************************/ | 816 | **************************************************************************/ |
1046 | 817 | ||
1047 | /* | 818 | /* |
@@ -1166,6 +937,68 @@ static int si470x_fops_release(struct inode *inode, struct file *file) | |||
1166 | 937 | ||
1167 | 938 | ||
1168 | /* | 939 | /* |
940 | * si470x_fops - file operations interface | ||
941 | */ | ||
942 | static const struct file_operations si470x_fops = { | ||
943 | .owner = THIS_MODULE, | ||
944 | .llseek = no_llseek, | ||
945 | .read = si470x_fops_read, | ||
946 | .poll = si470x_fops_poll, | ||
947 | .ioctl = video_ioctl2, | ||
948 | .compat_ioctl = v4l_compat_ioctl32, | ||
949 | .open = si470x_fops_open, | ||
950 | .release = si470x_fops_release, | ||
951 | }; | ||
952 | |||
953 | |||
954 | |||
955 | /************************************************************************** | ||
956 | * Video4Linux Interface | ||
957 | **************************************************************************/ | ||
958 | |||
959 | /* | ||
960 | * si470x_v4l2_queryctrl - query control | ||
961 | */ | ||
962 | static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { | ||
963 | /* HINT: the disabled controls are only here to satify kradio and such apps */ | ||
964 | { | ||
965 | .id = V4L2_CID_AUDIO_VOLUME, | ||
966 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
967 | .name = "Volume", | ||
968 | .minimum = 0, | ||
969 | .maximum = 15, | ||
970 | .step = 1, | ||
971 | .default_value = 15, | ||
972 | }, | ||
973 | { | ||
974 | .id = V4L2_CID_AUDIO_BALANCE, | ||
975 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
976 | }, | ||
977 | { | ||
978 | .id = V4L2_CID_AUDIO_BASS, | ||
979 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
980 | }, | ||
981 | { | ||
982 | .id = V4L2_CID_AUDIO_TREBLE, | ||
983 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
984 | }, | ||
985 | { | ||
986 | .id = V4L2_CID_AUDIO_MUTE, | ||
987 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
988 | .name = "Mute", | ||
989 | .minimum = 0, | ||
990 | .maximum = 1, | ||
991 | .step = 1, | ||
992 | .default_value = 1, | ||
993 | }, | ||
994 | { | ||
995 | .id = V4L2_CID_AUDIO_LOUDNESS, | ||
996 | .flags = V4L2_CTRL_FLAG_DISABLED, | ||
997 | }, | ||
998 | }; | ||
999 | |||
1000 | |||
1001 | /* | ||
1169 | * si470x_vidioc_querycap - query device capabilities | 1002 | * si470x_vidioc_querycap - query device capabilities |
1170 | */ | 1003 | */ |
1171 | static int si470x_vidioc_querycap(struct file *file, void *priv, | 1004 | static int si470x_vidioc_querycap(struct file *file, void *priv, |
@@ -1213,9 +1046,9 @@ static int si470x_vidioc_queryctrl(struct file *file, void *priv, | |||
1213 | { | 1046 | { |
1214 | int i; | 1047 | int i; |
1215 | 1048 | ||
1216 | for (i = 0; i < ARRAY_SIZE(radio_queryctrl); i++) { | 1049 | for (i = 0; i < ARRAY_SIZE(si470x_v4l2_queryctrl); i++) { |
1217 | if (qc->id && qc->id == radio_queryctrl[i].id) { | 1050 | if (qc->id && qc->id == si470x_v4l2_queryctrl[i].id) { |
1218 | memcpy(qc, &(radio_queryctrl[i]), sizeof(*qc)); | 1051 | memcpy(qc, &(si470x_v4l2_queryctrl[i]), sizeof(*qc)); |
1219 | return 0; | 1052 | return 0; |
1220 | } | 1053 | } |
1221 | } | 1054 | } |
@@ -1233,14 +1066,14 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv, | |||
1233 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 1066 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
1234 | 1067 | ||
1235 | switch (ctrl->id) { | 1068 | switch (ctrl->id) { |
1236 | case V4L2_CID_AUDIO_VOLUME: | 1069 | case V4L2_CID_AUDIO_VOLUME: |
1237 | ctrl->value = radio->registers[SYSCONFIG2] & | 1070 | ctrl->value = radio->registers[SYSCONFIG2] & |
1238 | SYSCONFIG2_VOLUME; | 1071 | SYSCONFIG2_VOLUME; |
1239 | break; | 1072 | break; |
1240 | case V4L2_CID_AUDIO_MUTE: | 1073 | case V4L2_CID_AUDIO_MUTE: |
1241 | ctrl->value = ((radio->registers[POWERCFG] & | 1074 | ctrl->value = ((radio->registers[POWERCFG] & |
1242 | POWERCFG_DMUTE) == 0) ? 1 : 0; | 1075 | POWERCFG_DMUTE) == 0) ? 1 : 0; |
1243 | break; | 1076 | break; |
1244 | } | 1077 | } |
1245 | 1078 | ||
1246 | return 0; | 1079 | return 0; |
@@ -1256,16 +1089,16 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv, | |||
1256 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); | 1089 | struct si470x_device *radio = video_get_drvdata(video_devdata(file)); |
1257 | 1090 | ||
1258 | switch (ctrl->id) { | 1091 | switch (ctrl->id) { |
1259 | case V4L2_CID_AUDIO_VOLUME: | 1092 | case V4L2_CID_AUDIO_VOLUME: |
1260 | radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; | 1093 | radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME; |
1261 | radio->registers[SYSCONFIG2] |= ctrl->value; | 1094 | radio->registers[SYSCONFIG2] |= ctrl->value; |
1262 | return si470x_set_register(radio, SYSCONFIG2); | 1095 | return si470x_set_register(radio, SYSCONFIG2); |
1263 | case V4L2_CID_AUDIO_MUTE: | 1096 | case V4L2_CID_AUDIO_MUTE: |
1264 | if (ctrl->value == 1) | 1097 | if (ctrl->value == 1) |
1265 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; | 1098 | radio->registers[POWERCFG] &= ~POWERCFG_DMUTE; |
1266 | else | 1099 | else |
1267 | radio->registers[POWERCFG] |= POWERCFG_DMUTE; | 1100 | radio->registers[POWERCFG] |= POWERCFG_DMUTE; |
1268 | return si470x_set_register(radio, POWERCFG); | 1101 | return si470x_set_register(radio, POWERCFG); |
1269 | } | 1102 | } |
1270 | 1103 | ||
1271 | return -EINVAL; | 1104 | return -EINVAL; |
@@ -1320,22 +1153,22 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv, | |||
1320 | 1153 | ||
1321 | strcpy(tuner->name, "FM"); | 1154 | strcpy(tuner->name, "FM"); |
1322 | tuner->type = V4L2_TUNER_RADIO; | 1155 | tuner->type = V4L2_TUNER_RADIO; |
1323 | switch(band) { | 1156 | switch (band) { |
1324 | /* 0: 87.5 - 108 MHz (USA, Europe, default) */ | 1157 | /* 0: 87.5 - 108 MHz (USA, Europe, default) */ |
1325 | default: | 1158 | default: |
1326 | tuner->rangelow = 87.5 * FREQ_MUL; | 1159 | tuner->rangelow = 87.5 * FREQ_MUL; |
1327 | tuner->rangehigh = 108 * FREQ_MUL; | 1160 | tuner->rangehigh = 108 * FREQ_MUL; |
1328 | break; | 1161 | break; |
1329 | /* 1: 76 - 108 MHz (Japan wide band) */ | 1162 | /* 1: 76 - 108 MHz (Japan wide band) */ |
1330 | case 1 : | 1163 | case 1 : |
1331 | tuner->rangelow = 76 * FREQ_MUL; | 1164 | tuner->rangelow = 76 * FREQ_MUL; |
1332 | tuner->rangehigh = 108 * FREQ_MUL; | 1165 | tuner->rangehigh = 108 * FREQ_MUL; |
1333 | break; | 1166 | break; |
1334 | /* 2: 76 - 90 MHz (Japan) */ | 1167 | /* 2: 76 - 90 MHz (Japan) */ |
1335 | case 2 : | 1168 | case 2 : |
1336 | tuner->rangelow = 76 * FREQ_MUL; | 1169 | tuner->rangelow = 76 * FREQ_MUL; |
1337 | tuner->rangehigh = 90 * FREQ_MUL; | 1170 | tuner->rangehigh = 90 * FREQ_MUL; |
1338 | break; | 1171 | break; |
1339 | }; | 1172 | }; |
1340 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; | 1173 | tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; |
1341 | tuner->capability = V4L2_TUNER_CAP_LOW; | 1174 | tuner->capability = V4L2_TUNER_CAP_LOW; |
@@ -1407,9 +1240,147 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv, | |||
1407 | } | 1240 | } |
1408 | 1241 | ||
1409 | 1242 | ||
1243 | /* | ||
1244 | * si470x_viddev_tamples - video device interface | ||
1245 | */ | ||
1246 | static struct video_device si470x_viddev_template = { | ||
1247 | .fops = &si470x_fops, | ||
1248 | .name = DRIVER_NAME, | ||
1249 | .type = VID_TYPE_TUNER, | ||
1250 | .release = video_device_release, | ||
1251 | .vidioc_querycap = si470x_vidioc_querycap, | ||
1252 | .vidioc_g_input = si470x_vidioc_g_input, | ||
1253 | .vidioc_s_input = si470x_vidioc_s_input, | ||
1254 | .vidioc_queryctrl = si470x_vidioc_queryctrl, | ||
1255 | .vidioc_g_ctrl = si470x_vidioc_g_ctrl, | ||
1256 | .vidioc_s_ctrl = si470x_vidioc_s_ctrl, | ||
1257 | .vidioc_g_audio = si470x_vidioc_g_audio, | ||
1258 | .vidioc_s_audio = si470x_vidioc_s_audio, | ||
1259 | .vidioc_g_tuner = si470x_vidioc_g_tuner, | ||
1260 | .vidioc_s_tuner = si470x_vidioc_s_tuner, | ||
1261 | .vidioc_g_frequency = si470x_vidioc_g_frequency, | ||
1262 | .vidioc_s_frequency = si470x_vidioc_s_frequency, | ||
1263 | .owner = THIS_MODULE, | ||
1264 | }; | ||
1265 | |||
1266 | |||
1267 | |||
1268 | /************************************************************************** | ||
1269 | * USB Interface | ||
1270 | **************************************************************************/ | ||
1271 | |||
1272 | /* | ||
1273 | * si470x_usb_driver_probe - probe for the device | ||
1274 | */ | ||
1275 | static int si470x_usb_driver_probe(struct usb_interface *intf, | ||
1276 | const struct usb_device_id *id) | ||
1277 | { | ||
1278 | struct si470x_device *radio; | ||
1279 | |||
1280 | /* memory and interface allocations */ | ||
1281 | radio = kmalloc(sizeof(struct si470x_device), GFP_KERNEL); | ||
1282 | if (!radio) | ||
1283 | return -ENOMEM; | ||
1284 | radio->videodev = video_device_alloc(); | ||
1285 | if (!radio->videodev) { | ||
1286 | kfree(radio); | ||
1287 | return -ENOMEM; | ||
1288 | } | ||
1289 | memcpy(radio->videodev, &si470x_viddev_template, | ||
1290 | sizeof(si470x_viddev_template)); | ||
1291 | radio->users = 0; | ||
1292 | radio->usbdev = interface_to_usbdev(intf); | ||
1293 | video_set_drvdata(radio->videodev, radio); | ||
1294 | if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { | ||
1295 | printk(KERN_WARNING DRIVER_NAME | ||
1296 | ": Could not register video device\n"); | ||
1297 | video_device_release(radio->videodev); | ||
1298 | kfree(radio); | ||
1299 | return -EIO; | ||
1300 | } | ||
1301 | usb_set_intfdata(intf, radio); | ||
1302 | |||
1303 | /* show some infos about the specific device */ | ||
1304 | if (si470x_get_all_registers(radio) < 0) { | ||
1305 | video_device_release(radio->videodev); | ||
1306 | kfree(radio); | ||
1307 | return -EIO; | ||
1308 | } | ||
1309 | printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4x ChipID=0x%4.4x\n", | ||
1310 | radio->registers[DEVICEID], radio->registers[CHIPID]); | ||
1311 | |||
1312 | /* check if firmware is current */ | ||
1313 | if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) | ||
1314 | < RADIO_SW_VERSION_CURRENT) | ||
1315 | printk(KERN_WARNING DRIVER_NAME | ||
1316 | ": This driver is known to work with chip version %d, " | ||
1317 | "but the device has firmware %d. If you have some " | ||
1318 | "trouble using this driver, please report to V4L ML " | ||
1319 | "at video4linux-list@redhat.com\n", | ||
1320 | radio->registers[CHIPID] & CHIPID_FIRMWARE, | ||
1321 | RADIO_SW_VERSION_CURRENT); | ||
1322 | |||
1323 | /* set initial frequency */ | ||
1324 | si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */ | ||
1325 | |||
1326 | /* rds initialization */ | ||
1327 | radio->buf_size = rds_buf * 3; | ||
1328 | radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); | ||
1329 | if (!radio->buffer) { | ||
1330 | video_device_release(radio->videodev); | ||
1331 | kfree(radio); | ||
1332 | return -ENOMEM; | ||
1333 | } | ||
1334 | radio->block_count = 0; | ||
1335 | radio->wr_index = 0; | ||
1336 | radio->rd_index = 0; | ||
1337 | radio->last_blocknum = 0xff; | ||
1338 | init_waitqueue_head(&radio->read_queue); | ||
1339 | radio->data_available_for_read = 0; | ||
1340 | |||
1341 | /* prepare polling via eventd */ | ||
1342 | INIT_WORK(&radio->work, si470x_work); | ||
1343 | init_timer(&radio->timer); | ||
1344 | radio->timer.function = si470x_timer; | ||
1345 | radio->timer.data = (unsigned long) radio; | ||
1346 | |||
1347 | return 0; | ||
1348 | } | ||
1349 | |||
1350 | |||
1351 | /* | ||
1352 | * si470x_usb_driver_disconnect - disconnect the device | ||
1353 | */ | ||
1354 | static void si470x_usb_driver_disconnect(struct usb_interface *intf) | ||
1355 | { | ||
1356 | struct si470x_device *radio = usb_get_intfdata(intf); | ||
1357 | |||
1358 | del_timer_sync(&radio->timer); | ||
1359 | flush_scheduled_work(); | ||
1360 | |||
1361 | usb_set_intfdata(intf, NULL); | ||
1362 | if (radio) { | ||
1363 | video_unregister_device(radio->videodev); | ||
1364 | kfree(radio->buffer); | ||
1365 | kfree(radio); | ||
1366 | } | ||
1367 | } | ||
1368 | |||
1369 | |||
1370 | /* | ||
1371 | * si470x_usb_driver - usb driver interface | ||
1372 | */ | ||
1373 | static struct usb_driver si470x_usb_driver = { | ||
1374 | .name = DRIVER_NAME, | ||
1375 | .probe = si470x_usb_driver_probe, | ||
1376 | .disconnect = si470x_usb_driver_disconnect, | ||
1377 | .id_table = si470x_usb_driver_id_table, | ||
1378 | }; | ||
1379 | |||
1380 | |||
1410 | 1381 | ||
1411 | /************************************************************************** | 1382 | /************************************************************************** |
1412 | * Module interface definitions and functions | 1383 | * Module Interface |
1413 | **************************************************************************/ | 1384 | **************************************************************************/ |
1414 | 1385 | ||
1415 | /* | 1386 | /* |
@@ -1437,4 +1408,4 @@ module_exit(si470x_module_exit); | |||
1437 | MODULE_LICENSE("GPL"); | 1408 | MODULE_LICENSE("GPL"); |
1438 | MODULE_AUTHOR(DRIVER_AUTHOR); | 1409 | MODULE_AUTHOR(DRIVER_AUTHOR); |
1439 | MODULE_DESCRIPTION(DRIVER_DESC); | 1410 | MODULE_DESCRIPTION(DRIVER_DESC); |
1440 | MODULE_VERSION("1.0.2"); | 1411 | MODULE_VERSION("1.0.3"); |