aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/si470x/radio-si470x-usb.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/radio/si470x/radio-si470x-usb.c')
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index d6d4d60261d5..07ef40595efd 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -137,6 +137,8 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
137/* interrupt out endpoint 2 every 1 millisecond */ 137/* interrupt out endpoint 2 every 1 millisecond */
138#define UNUSED_REPORT 23 138#define UNUSED_REPORT 23
139 139
140#define MAX_REPORT_SIZE 64
141
140 142
141 143
142/************************************************************************** 144/**************************************************************************
@@ -208,7 +210,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
208 */ 210 */
209static int si470x_get_report(struct si470x_device *radio, void *buf, int size) 211static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
210{ 212{
211 unsigned char *report = (unsigned char *) buf; 213 unsigned char *report = buf;
212 int retval; 214 int retval;
213 215
214 retval = usb_control_msg(radio->usbdev, 216 retval = usb_control_msg(radio->usbdev,
@@ -231,7 +233,7 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
231 */ 233 */
232static int si470x_set_report(struct si470x_device *radio, void *buf, int size) 234static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
233{ 235{
234 unsigned char *report = (unsigned char *) buf; 236 unsigned char *report = buf;
235 int retval; 237 int retval;
236 238
237 retval = usb_control_msg(radio->usbdev, 239 retval = usb_control_msg(radio->usbdev,
@@ -254,15 +256,14 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
254 */ 256 */
255int si470x_get_register(struct si470x_device *radio, int regnr) 257int si470x_get_register(struct si470x_device *radio, int regnr)
256{ 258{
257 unsigned char buf[REGISTER_REPORT_SIZE];
258 int retval; 259 int retval;
259 260
260 buf[0] = REGISTER_REPORT(regnr); 261 radio->usb_buf[0] = REGISTER_REPORT(regnr);
261 262
262 retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); 263 retval = si470x_get_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE);
263 264
264 if (retval >= 0) 265 if (retval >= 0)
265 radio->registers[regnr] = get_unaligned_be16(&buf[1]); 266 radio->registers[regnr] = get_unaligned_be16(&radio->usb_buf[1]);
266 267
267 return (retval < 0) ? -EINVAL : 0; 268 return (retval < 0) ? -EINVAL : 0;
268} 269}
@@ -273,13 +274,12 @@ int si470x_get_register(struct si470x_device *radio, int regnr)
273 */ 274 */
274int si470x_set_register(struct si470x_device *radio, int regnr) 275int si470x_set_register(struct si470x_device *radio, int regnr)
275{ 276{
276 unsigned char buf[REGISTER_REPORT_SIZE];
277 int retval; 277 int retval;
278 278
279 buf[0] = REGISTER_REPORT(regnr); 279 radio->usb_buf[0] = REGISTER_REPORT(regnr);
280 put_unaligned_be16(radio->registers[regnr], &buf[1]); 280 put_unaligned_be16(radio->registers[regnr], &radio->usb_buf[1]);
281 281
282 retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); 282 retval = si470x_set_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE);
283 283
284 return (retval < 0) ? -EINVAL : 0; 284 return (retval < 0) ? -EINVAL : 0;
285} 285}
@@ -295,18 +295,17 @@ int si470x_set_register(struct si470x_device *radio, int regnr)
295 */ 295 */
296static int si470x_get_all_registers(struct si470x_device *radio) 296static int si470x_get_all_registers(struct si470x_device *radio)
297{ 297{
298 unsigned char buf[ENTIRE_REPORT_SIZE];
299 int retval; 298 int retval;
300 unsigned char regnr; 299 unsigned char regnr;
301 300
302 buf[0] = ENTIRE_REPORT; 301 radio->usb_buf[0] = ENTIRE_REPORT;
303 302
304 retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); 303 retval = si470x_get_report(radio, radio->usb_buf, ENTIRE_REPORT_SIZE);
305 304
306 if (retval >= 0) 305 if (retval >= 0)
307 for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) 306 for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
308 radio->registers[regnr] = get_unaligned_be16( 307 radio->registers[regnr] = get_unaligned_be16(
309 &buf[regnr * RADIO_REGISTER_SIZE + 1]); 308 &radio->usb_buf[regnr * RADIO_REGISTER_SIZE + 1]);
310 309
311 return (retval < 0) ? -EINVAL : 0; 310 return (retval < 0) ? -EINVAL : 0;
312} 311}
@@ -323,14 +322,13 @@ static int si470x_get_all_registers(struct si470x_device *radio)
323static int si470x_set_led_state(struct si470x_device *radio, 322static int si470x_set_led_state(struct si470x_device *radio,
324 unsigned char led_state) 323 unsigned char led_state)
325{ 324{
326 unsigned char buf[LED_REPORT_SIZE];
327 int retval; 325 int retval;
328 326
329 buf[0] = LED_REPORT; 327 radio->usb_buf[0] = LED_REPORT;
330 buf[1] = LED_COMMAND; 328 radio->usb_buf[1] = LED_COMMAND;
331 buf[2] = led_state; 329 radio->usb_buf[2] = led_state;
332 330
333 retval = si470x_set_report(radio, (void *) &buf, sizeof(buf)); 331 retval = si470x_set_report(radio, radio->usb_buf, LED_REPORT_SIZE);
334 332
335 return (retval < 0) ? -EINVAL : 0; 333 return (retval < 0) ? -EINVAL : 0;
336} 334}
@@ -346,19 +344,18 @@ static int si470x_set_led_state(struct si470x_device *radio,
346 */ 344 */
347static int si470x_get_scratch_page_versions(struct si470x_device *radio) 345static int si470x_get_scratch_page_versions(struct si470x_device *radio)
348{ 346{
349 unsigned char buf[SCRATCH_REPORT_SIZE];
350 int retval; 347 int retval;
351 348
352 buf[0] = SCRATCH_REPORT; 349 radio->usb_buf[0] = SCRATCH_REPORT;
353 350
354 retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); 351 retval = si470x_get_report(radio, radio->usb_buf, SCRATCH_REPORT_SIZE);
355 352
356 if (retval < 0) 353 if (retval < 0)
357 dev_warn(&radio->intf->dev, "si470x_get_scratch: " 354 dev_warn(&radio->intf->dev, "si470x_get_scratch: "
358 "si470x_get_report returned %d\n", retval); 355 "si470x_get_report returned %d\n", retval);
359 else { 356 else {
360 radio->software_version = buf[1]; 357 radio->software_version = radio->usb_buf[1];
361 radio->hardware_version = buf[2]; 358 radio->hardware_version = radio->usb_buf[2];
362 } 359 }
363 360
364 return (retval < 0) ? -EINVAL : 0; 361 return (retval < 0) ? -EINVAL : 0;
@@ -509,6 +506,7 @@ static void si470x_usb_release(struct v4l2_device *v4l2_dev)
509 v4l2_device_unregister(&radio->v4l2_dev); 506 v4l2_device_unregister(&radio->v4l2_dev);
510 kfree(radio->int_in_buffer); 507 kfree(radio->int_in_buffer);
511 kfree(radio->buffer); 508 kfree(radio->buffer);
509 kfree(radio->usb_buf);
512 kfree(radio); 510 kfree(radio);
513} 511}
514 512
@@ -593,6 +591,11 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
593 retval = -ENOMEM; 591 retval = -ENOMEM;
594 goto err_initial; 592 goto err_initial;
595 } 593 }
594 radio->usb_buf = kmalloc(MAX_REPORT_SIZE, GFP_KERNEL);
595 if (radio->usb_buf == NULL) {
596 retval = -ENOMEM;
597 goto err_radio;
598 }
596 radio->usbdev = interface_to_usbdev(intf); 599 radio->usbdev = interface_to_usbdev(intf);
597 radio->intf = intf; 600 radio->intf = intf;
598 radio->band = 1; /* Default to 76 - 108 MHz */ 601 radio->band = 1; /* Default to 76 - 108 MHz */
@@ -612,7 +615,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
612 if (!radio->int_in_endpoint) { 615 if (!radio->int_in_endpoint) {
613 dev_info(&intf->dev, "could not find interrupt in endpoint\n"); 616 dev_info(&intf->dev, "could not find interrupt in endpoint\n");
614 retval = -EIO; 617 retval = -EIO;
615 goto err_radio; 618 goto err_usbbuf;
616 } 619 }
617 620
618 int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize); 621 int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize);
@@ -621,7 +624,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
621 if (!radio->int_in_buffer) { 624 if (!radio->int_in_buffer) {
622 dev_info(&intf->dev, "could not allocate int_in_buffer"); 625 dev_info(&intf->dev, "could not allocate int_in_buffer");
623 retval = -ENOMEM; 626 retval = -ENOMEM;
624 goto err_radio; 627 goto err_usbbuf;
625 } 628 }
626 629
627 radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL); 630 radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -632,6 +635,30 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
632 } 635 }
633 636
634 radio->v4l2_dev.release = si470x_usb_release; 637 radio->v4l2_dev.release = si470x_usb_release;
638
639 /*
640 * The si470x SiLabs reference design uses the same USB IDs as
641 * 'Thanko's Raremono' si4734 based receiver. So check here which we
642 * have: attempt to read the device ID from the si470x: the lower 12
643 * bits should be 0x0242 for the si470x.
644 *
645 * We use this check to determine which device we are dealing with.
646 */
647 if (id->idVendor == 0x10c4 && id->idProduct == 0x818a) {
648 retval = usb_control_msg(radio->usbdev,
649 usb_rcvctrlpipe(radio->usbdev, 0),
650 HID_REQ_GET_REPORT,
651 USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
652 1, 2,
653 radio->usb_buf, 3, 500);
654 if (retval != 3 ||
655 (get_unaligned_be16(&radio->usb_buf[1]) & 0xfff) != 0x0242) {
656 dev_info(&intf->dev, "this is not a si470x device.\n");
657 retval = -ENODEV;
658 goto err_urb;
659 }
660 }
661
635 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev); 662 retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
636 if (retval < 0) { 663 if (retval < 0) {
637 dev_err(&intf->dev, "couldn't register v4l2_device\n"); 664 dev_err(&intf->dev, "couldn't register v4l2_device\n");
@@ -743,6 +770,8 @@ err_urb:
743 usb_free_urb(radio->int_in_urb); 770 usb_free_urb(radio->int_in_urb);
744err_intbuffer: 771err_intbuffer:
745 kfree(radio->int_in_buffer); 772 kfree(radio->int_in_buffer);
773err_usbbuf:
774 kfree(radio->usb_buf);
746err_radio: 775err_radio:
747 kfree(radio); 776 kfree(radio);
748err_initial: 777err_initial: