/* RDS maximum block errors */ staticunsignedshort max_rds_errors = 1; /* 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(max_rds_errors, "RDS maximum block errors: *1*");
/************************************************************************** * 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 (RADIO_REGISTER_SIZE + 1) #define REGISTER_REPORT(reg) ((reg) + 1)
/* 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 (RADIO_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) #define ENTIRE_REPORT 17
/* 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 (RDS_REGISTER_NUM * RADIO_REGISTER_SIZE + 1) #define RDS_REPORT 18
/* Report 19: LED state */ #define LED_REPORT_SIZE 3 #define LED_REPORT 19
/* Report 23: currently unused, but can accept 60 byte reports on the HID */ /* interrupt out endpoint 2 every 1 millisecond */ #define UNUSED_REPORT 23
/************************************************************************** * LED State Definitions
**************************************************************************/ #define LED_COMMAND 0x35
#define NO_CHANGE_LED 0x00 #define ALL_COLOR_LED 0x01 /* streaming state */ #define BLINK_GREEN_LED 0x02 /* connect state */ #define BLINK_RED_LED 0x04 #define BLINK_ORANGE_LED 0x10 /* disconnect state */ #define SOLID_GREEN_LED 0x20 /* tuning/seeking state */ #define SOLID_RED_LED 0x40 /* bootload state */ #define SOLID_ORANGE_LED 0x80
/************************************************************************** * General Driver Functions - SCRATCH_REPORT
**************************************************************************/
/* * si470x_get_scratch_versions - gets the scratch page and version infos
*/ staticint si470x_get_scratch_page_versions(struct si470x_device *radio)
{ int retval;
/* * si470x_int_in_callback - rds callback and processing function * * TODO: do we need to use mutex locks in some sections?
*/ staticvoid si470x_int_in_callback(struct urb *urb)
{ struct si470x_device *radio = urb->context; int retval; unsignedchar regnr; unsignedchar blocknum; unsignedshort bler; /* rds block errors */ unsignedshort rds; unsignedchar tmpbuf[3];
if (urb->status) { if (urb->status == -ENOENT ||
urb->status == -ECONNRESET ||
urb->status == -ESHUTDOWN) { return;
} else {
dev_warn(&radio->intf->dev, "non-zero urb status (%d)\n", urb->status); goto resubmit; /* Maybe we can recover. */
}
}
/* Sometimes the device returns len 0 packets */ if (urb->actual_length != RDS_REPORT_SIZE) goto resubmit;
/* start radio */
retval = si470x_start(radio); if (retval < 0) return retval;
v4l2_ctrl_handler_setup(&radio->hdl);
return retval;
}
/************************************************************************** * USB Interface
**************************************************************************/
/* * si470x_usb_driver_probe - probe for the device
*/ staticint si470x_usb_driver_probe(struct usb_interface *intf, conststruct usb_device_id *id)
{ struct si470x_device *radio; struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; int i, int_end_size, retval; unsignedchar version_warning = 0;
/* private data allocation and initialization */
radio = kzalloc(sizeof(struct si470x_device), GFP_KERNEL); if (!radio) {
retval = -ENOMEM; goto err_initial;
}
radio->usb_buf = kmalloc(MAX_REPORT_SIZE, GFP_KERNEL); if (radio->usb_buf == NULL) {
retval = -ENOMEM; goto err_radio;
}
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
radio->band = 1; /* Default to 76 - 108 MHz */
mutex_init(&radio->lock);
init_completion(&radio->completion);
/* Set up interrupt endpoint information. */ for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
endpoint = &iface_desc->endpoint[i].desc; if (usb_endpoint_is_int_in(endpoint))
radio->int_in_endpoint = endpoint;
} if (!radio->int_in_endpoint) {
dev_info(&intf->dev, "could not find interrupt in endpoint\n");
retval = -EIO; goto err_usbbuf;
}
/* * The si470x SiLabs reference design uses the same USB IDs as * 'Thanko's Raremono' si4734 based receiver. So check here which we * have: attempt to read the device ID from the si470x: the lower 12 * bits should be 0x0242 for the si470x. * * We use this check to determine which device we are dealing with.
*/ if (id->idVendor == 0x10c4 && id->idProduct == 0x818a) {
retval = usb_control_msg(radio->usbdev,
usb_rcvctrlpipe(radio->usbdev, 0),
HID_REQ_GET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
1, 2,
radio->usb_buf, 3, 500); if (retval != 3 ||
(get_unaligned_be16(&radio->usb_buf[1]) & 0xfff) != 0x0242) {
dev_info(&intf->dev, "this is not a si470x device.\n");
retval = -ENODEV; goto err_urb;
}
}
/* get device and chip versions */ if (si470x_get_all_registers(radio) < 0) {
retval = -EIO; goto err_ctrl;
}
dev_info(&intf->dev, "DeviceID=0x%4.4hx ChipID=0x%4.4hx\n",
radio->registers[DEVICEID], radio->registers[SI_CHIPID]); if ((radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE) < RADIO_FW_VERSION) {
dev_warn(&intf->dev, "This driver is known to work with firmware version %u, but the device has firmware version %u.\n",
RADIO_FW_VERSION,
radio->registers[SI_CHIPID] & SI_CHIPID_FIRMWARE);
version_warning = 1;
}
/* get software and hardware versions */ if (si470x_get_scratch_page_versions(radio) < 0) {
retval = -EIO; goto err_ctrl;
}
dev_info(&intf->dev, "software version %d, hardware version %d\n",
radio->software_version, radio->hardware_version); if (radio->hardware_version < RADIO_HW_VERSION) {
dev_warn(&intf->dev, "This driver is known to work with hardware version %u, but the device has hardware version %u.\n",
RADIO_HW_VERSION,
radio->hardware_version);
version_warning = 1;
}
/* give out version warning */ if (version_warning == 1) {
dev_warn(&intf->dev, "If you have some trouble using this driver, please report to V4L ML at linux-media@vger.kernel.org\n");
}
/* set led to connect state */
si470x_set_led_state(radio, BLINK_GREEN_LED);
/* * 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.
*/ staticstruct usb_driver si470x_usb_driver = {
.name = DRIVER_NAME,
.probe = si470x_usb_driver_probe,
.disconnect = si470x_usb_driver_disconnect,
.suspend = si470x_usb_driver_suspend,
.resume = si470x_usb_driver_resume,
.reset_resume = si470x_usb_driver_resume,
.id_table = si470x_usb_driver_id_table,
};
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.