// SPDX-License-Identifier: GPL-2.0-or-later /* * drivers/media/radio/si470x/radio-si470x-usb.c * * USB driver for radios with Silicon Labs Si470x FM Radio Receivers * * Copyright (c) 2009 Tobias Lorenz <[email protected]> */ /* * ToDo: * - add firmware download/update support */ /* driver definitions */ #define DRIVER_AUTHOR … #define DRIVER_CARD … #define DRIVER_DESC … #define DRIVER_VERSION … /* kernel includes */ #include <linux/usb.h> #include <linux/hid.h> #include <linux/slab.h> #include "radio-si470x.h" /* USB Device ID List */ static const struct usb_device_id si470x_usb_driver_id_table[] = …; MODULE_DEVICE_TABLE(usb, si470x_usb_driver_id_table); /************************************************************************** * Module Parameters **************************************************************************/ /* Radio Nr */ static int radio_nr = …; module_param(radio_nr, int, 0444); MODULE_PARM_DESC(…) …; /* USB timeout */ static unsigned int usb_timeout = …; module_param(usb_timeout, uint, 0644); MODULE_PARM_DESC(…) …; /* RDS buffer blocks */ static unsigned int rds_buf = …; module_param(rds_buf, uint, 0444); MODULE_PARM_DESC(…) …; /* RDS maximum block errors */ static unsigned short max_rds_errors = …; /* 0 means 0 errors requiring correction */ /* 1 means 1-2 errors requiring correction (used by original USBRadio.exe) */ /* 2 means 3-5 errors requiring correction */ /* 3 means 6+ errors or errors in checkword, correction not possible */ module_param(max_rds_errors, ushort, 0644); MODULE_PARM_DESC(…) …; /************************************************************************** * USB HID Reports **************************************************************************/ /* Reports 1-16 give direct read/write access to the 16 Si470x registers */ /* with the (REPORT_ID - 1) corresponding to the register address across USB */ /* endpoint 0 using GET_REPORT and SET_REPORT */ #define REGISTER_REPORT_SIZE … #define REGISTER_REPORT(reg) … /* Report 17 gives direct read/write access to the entire Si470x register */ /* map across endpoint 0 using GET_REPORT and SET_REPORT */ #define ENTIRE_REPORT_SIZE … #define ENTIRE_REPORT … /* Report 18 is used to send the lowest 6 Si470x registers up the HID */ /* interrupt endpoint 1 to Windows every 20 milliseconds for status */ #define RDS_REPORT_SIZE … #define RDS_REPORT … /* Report 19: LED state */ #define LED_REPORT_SIZE … #define LED_REPORT … /* Report 19: stream */ #define STREAM_REPORT_SIZE … #define STREAM_REPORT … /* Report 20: scratch */ #define SCRATCH_PAGE_SIZE … #define SCRATCH_REPORT_SIZE … #define SCRATCH_REPORT … /* Reports 19-22: flash upgrade of the C8051F321 */ #define WRITE_REPORT_SIZE … #define WRITE_REPORT … #define FLASH_REPORT_SIZE … #define FLASH_REPORT … #define CRC_REPORT_SIZE … #define CRC_REPORT … #define RESPONSE_REPORT_SIZE … #define RESPONSE_REPORT … /* Report 23: currently unused, but can accept 60 byte reports on the HID */ /* interrupt out endpoint 2 every 1 millisecond */ #define UNUSED_REPORT … #define MAX_REPORT_SIZE … /************************************************************************** * Software/Hardware Versions from Scratch Page **************************************************************************/ #define RADIO_HW_VERSION … /************************************************************************** * LED State Definitions **************************************************************************/ #define LED_COMMAND … #define NO_CHANGE_LED … #define ALL_COLOR_LED … #define BLINK_GREEN_LED … #define BLINK_RED_LED … #define BLINK_ORANGE_LED … #define SOLID_GREEN_LED … #define SOLID_RED_LED … #define SOLID_ORANGE_LED … /************************************************************************** * Stream State Definitions **************************************************************************/ #define STREAM_COMMAND … #define STREAM_VIDPID … #define STREAM_AUDIO … /************************************************************************** * Bootloader / Flash Commands **************************************************************************/ /* unique id sent to bootloader and required to put into a bootload state */ #define UNIQUE_BL_ID … /* mask for the flash data */ #define FLASH_DATA_MASK … /* bootloader commands */ #define GET_SW_VERSION_COMMAND … #define SET_PAGE_COMMAND … #define ERASE_PAGE_COMMAND … #define WRITE_PAGE_COMMAND … #define CRC_ON_PAGE_COMMAND … #define READ_FLASH_BYTE_COMMAND … #define RESET_DEVICE_COMMAND … #define GET_HW_VERSION_COMMAND … #define BLANK … /* bootloader command responses */ #define COMMAND_OK … #define COMMAND_FAILED … #define COMMAND_PENDING … /************************************************************************** * General Driver Functions - REGISTER_REPORTs **************************************************************************/ /* * si470x_get_report - receive a HID report */ static int si470x_get_report(struct si470x_device *radio, void *buf, int size) { … } /* * si470x_set_report - send a HID report */ static int si470x_set_report(struct si470x_device *radio, void *buf, int size) { … } /* * si470x_get_register - read register */ static int si470x_get_register(struct si470x_device *radio, int regnr) { … } /* * si470x_set_register - write register */ static int si470x_set_register(struct si470x_device *radio, int regnr) { … } /************************************************************************** * General Driver Functions - ENTIRE_REPORT **************************************************************************/ /* * si470x_get_all_registers - read entire registers */ static int si470x_get_all_registers(struct si470x_device *radio) { … } /************************************************************************** * General Driver Functions - LED_REPORT **************************************************************************/ /* * si470x_set_led_state - sets the led state */ static int si470x_set_led_state(struct si470x_device *radio, unsigned char led_state) { … } /************************************************************************** * General Driver Functions - SCRATCH_REPORT **************************************************************************/ /* * si470x_get_scratch_versions - gets the scratch page and version infos */ static int si470x_get_scratch_page_versions(struct si470x_device *radio) { … } /************************************************************************** * RDS Driver Functions **************************************************************************/ /* * si470x_int_in_callback - rds callback and processing function * * TODO: do we need to use mutex locks in some sections? */ static void si470x_int_in_callback(struct urb *urb) { … } static int si470x_fops_open(struct file *file) { … } static int si470x_fops_release(struct file *file) { … } static void si470x_usb_release(struct v4l2_device *v4l2_dev) { … } /************************************************************************** * Video4Linux Interface **************************************************************************/ /* * si470x_vidioc_querycap - query device capabilities */ static int si470x_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { … } static int si470x_start_usb(struct si470x_device *radio) { … } /************************************************************************** * USB Interface **************************************************************************/ /* * si470x_usb_driver_probe - probe for the device */ static int si470x_usb_driver_probe(struct usb_interface *intf, const struct usb_device_id *id) { … } /* * si470x_usb_driver_suspend - suspend the device */ static int si470x_usb_driver_suspend(struct usb_interface *intf, pm_message_t message) { … } /* * si470x_usb_driver_resume - resume the device */ static int si470x_usb_driver_resume(struct usb_interface *intf) { … } /* * si470x_usb_driver_disconnect - disconnect the device */ static void si470x_usb_driver_disconnect(struct usb_interface *intf) { … } /* * si470x_usb_driver - usb driver interface * * A note on suspend/resume: this driver had only empty suspend/resume * functions, and when I tried to test suspend/resume it always disconnected * instead of resuming (using my ADS InstantFM stick). So I've decided to * remove these callbacks until someone else with better hardware can * implement and test this. */ static struct usb_driver si470x_usb_driver = …; module_usb_driver(…) …; MODULE_LICENSE(…) …; MODULE_AUTHOR(…); MODULE_DESCRIPTION(…); MODULE_VERSION(…);