18e2ce73eSHans de Goede /* 28e2ce73eSHans de Goede * Linux V4L2 radio driver for the Griffin radioSHARK USB radio receiver 38e2ce73eSHans de Goede * 48e2ce73eSHans de Goede * Note the radioSHARK offers the audio through a regular USB audio device, 58e2ce73eSHans de Goede * this driver only handles the tuning. 68e2ce73eSHans de Goede * 78e2ce73eSHans de Goede * The info necessary to drive the shark was taken from the small userspace 88e2ce73eSHans de Goede * shark.c program by Michael Rolig, which he kindly placed in the Public 98e2ce73eSHans de Goede * Domain. 108e2ce73eSHans de Goede * 118e2ce73eSHans de Goede * Copyright (c) 2012 Hans de Goede <hdegoede@redhat.com> 128e2ce73eSHans de Goede * 138e2ce73eSHans de Goede * This program is free software; you can redistribute it and/or modify 148e2ce73eSHans de Goede * it under the terms of the GNU General Public License as published by 158e2ce73eSHans de Goede * the Free Software Foundation; either version 2 of the License, or 168e2ce73eSHans de Goede * (at your option) any later version. 178e2ce73eSHans de Goede * 188e2ce73eSHans de Goede * This program is distributed in the hope that it will be useful, 198e2ce73eSHans de Goede * but WITHOUT ANY WARRANTY; without even the implied warranty of 208e2ce73eSHans de Goede * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 218e2ce73eSHans de Goede * GNU General Public License for more details. 228e2ce73eSHans de Goede * 238e2ce73eSHans de Goede * You should have received a copy of the GNU General Public License 248e2ce73eSHans de Goede * along with this program; if not, write to the Free Software 258e2ce73eSHans de Goede * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 268e2ce73eSHans de Goede */ 278e2ce73eSHans de Goede 288e2ce73eSHans de Goede #include <linux/init.h> 298e2ce73eSHans de Goede #include <linux/kernel.h> 308e2ce73eSHans de Goede #include <linux/leds.h> 318e2ce73eSHans de Goede #include <linux/module.h> 328e2ce73eSHans de Goede #include <linux/slab.h> 338e2ce73eSHans de Goede #include <linux/usb.h> 348e2ce73eSHans de Goede #include <linux/workqueue.h> 358e2ce73eSHans de Goede #include <media/v4l2-device.h> 368e2ce73eSHans de Goede #include <sound/tea575x-tuner.h> 378e2ce73eSHans de Goede 383e3b92caSHans de Goede #if defined(CONFIG_LEDS_CLASS) || \ 393e3b92caSHans de Goede (defined(CONFIG_LEDS_CLASS_MODULE) && defined(CONFIG_RADIO_SHARK_MODULE)) 403e3b92caSHans de Goede #define SHARK_USE_LEDS 1 413e3b92caSHans de Goede #endif 423e3b92caSHans de Goede 438e2ce73eSHans de Goede /* 448e2ce73eSHans de Goede * Version Information 458e2ce73eSHans de Goede */ 468e2ce73eSHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 478e2ce73eSHans de Goede MODULE_DESCRIPTION("Griffin radioSHARK, USB radio receiver driver"); 488e2ce73eSHans de Goede MODULE_LICENSE("GPL"); 498e2ce73eSHans de Goede 508e2ce73eSHans de Goede #define SHARK_IN_EP 0x83 518e2ce73eSHans de Goede #define SHARK_OUT_EP 0x05 528e2ce73eSHans de Goede 538e2ce73eSHans de Goede #define TEA575X_BIT_MONO (1<<22) /* 0 = stereo, 1 = mono */ 548e2ce73eSHans de Goede #define TEA575X_BIT_BAND_MASK (3<<20) 558e2ce73eSHans de Goede #define TEA575X_BIT_BAND_FM (0<<20) 568e2ce73eSHans de Goede 578e2ce73eSHans de Goede #define TB_LEN 6 588e2ce73eSHans de Goede #define DRV_NAME "radioshark" 598e2ce73eSHans de Goede 608e2ce73eSHans de Goede #define v4l2_dev_to_shark(d) container_of(d, struct shark_device, v4l2_dev) 618e2ce73eSHans de Goede 628e2ce73eSHans de Goede enum { BLUE_LED, BLUE_PULSE_LED, RED_LED, NO_LEDS }; 638e2ce73eSHans de Goede 648e2ce73eSHans de Goede struct shark_device { 658e2ce73eSHans de Goede struct usb_device *usbdev; 668e2ce73eSHans de Goede struct v4l2_device v4l2_dev; 678e2ce73eSHans de Goede struct snd_tea575x tea; 688e2ce73eSHans de Goede 693e3b92caSHans de Goede #ifdef SHARK_USE_LEDS 708e2ce73eSHans de Goede struct work_struct led_work; 718e2ce73eSHans de Goede struct led_classdev leds[NO_LEDS]; 728e2ce73eSHans de Goede char led_names[NO_LEDS][32]; 738e2ce73eSHans de Goede atomic_t brightness[NO_LEDS]; 748e2ce73eSHans de Goede unsigned long brightness_new; 753e3b92caSHans de Goede #endif 768e2ce73eSHans de Goede 778e2ce73eSHans de Goede u8 *transfer_buffer; 788e2ce73eSHans de Goede u32 last_val; 798e2ce73eSHans de Goede }; 808e2ce73eSHans de Goede 818e2ce73eSHans de Goede static atomic_t shark_instance = ATOMIC_INIT(0); 828e2ce73eSHans de Goede 838e2ce73eSHans de Goede static void shark_write_val(struct snd_tea575x *tea, u32 val) 848e2ce73eSHans de Goede { 858e2ce73eSHans de Goede struct shark_device *shark = tea->private_data; 868e2ce73eSHans de Goede int i, res, actual_len; 878e2ce73eSHans de Goede 888e2ce73eSHans de Goede /* Avoid unnecessary (slow) USB transfers */ 898e2ce73eSHans de Goede if (shark->last_val == val) 908e2ce73eSHans de Goede return; 918e2ce73eSHans de Goede 928e2ce73eSHans de Goede memset(shark->transfer_buffer, 0, TB_LEN); 938e2ce73eSHans de Goede shark->transfer_buffer[0] = 0xc0; /* Write shift register command */ 948e2ce73eSHans de Goede for (i = 0; i < 4; i++) 958e2ce73eSHans de Goede shark->transfer_buffer[i] |= (val >> (24 - i * 8)) & 0xff; 968e2ce73eSHans de Goede 978e2ce73eSHans de Goede res = usb_interrupt_msg(shark->usbdev, 988e2ce73eSHans de Goede usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), 998e2ce73eSHans de Goede shark->transfer_buffer, TB_LEN, 1008e2ce73eSHans de Goede &actual_len, 1000); 1018e2ce73eSHans de Goede if (res >= 0) 1028e2ce73eSHans de Goede shark->last_val = val; 1038e2ce73eSHans de Goede else 1048e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "set-freq error: %d\n", res); 1058e2ce73eSHans de Goede } 1068e2ce73eSHans de Goede 1078e2ce73eSHans de Goede static u32 shark_read_val(struct snd_tea575x *tea) 1088e2ce73eSHans de Goede { 1098e2ce73eSHans de Goede struct shark_device *shark = tea->private_data; 1108e2ce73eSHans de Goede int i, res, actual_len; 1118e2ce73eSHans de Goede u32 val = 0; 1128e2ce73eSHans de Goede 1138e2ce73eSHans de Goede memset(shark->transfer_buffer, 0, TB_LEN); 1148e2ce73eSHans de Goede shark->transfer_buffer[0] = 0x80; 1158e2ce73eSHans de Goede res = usb_interrupt_msg(shark->usbdev, 1168e2ce73eSHans de Goede usb_sndintpipe(shark->usbdev, SHARK_OUT_EP), 1178e2ce73eSHans de Goede shark->transfer_buffer, TB_LEN, 1188e2ce73eSHans de Goede &actual_len, 1000); 1198e2ce73eSHans de Goede if (res < 0) { 1208e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "request-status error: %d\n", res); 1218e2ce73eSHans de Goede return shark->last_val; 1228e2ce73eSHans de Goede } 1238e2ce73eSHans de Goede 1248e2ce73eSHans de Goede res = usb_interrupt_msg(shark->usbdev, 1258e2ce73eSHans de Goede usb_rcvintpipe(shark->usbdev, SHARK_IN_EP), 1268e2ce73eSHans de Goede shark->transfer_buffer, TB_LEN, 1278e2ce73eSHans de Goede &actual_len, 1000); 1288e2ce73eSHans de Goede if (res < 0) { 1298e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "get-status error: %d\n", res); 1308e2ce73eSHans de Goede return shark->last_val; 1318e2ce73eSHans de Goede } 1328e2ce73eSHans de Goede 1338e2ce73eSHans de Goede for (i = 0; i < 4; i++) 1348e2ce73eSHans de Goede val |= shark->transfer_buffer[i] << (24 - i * 8); 1358e2ce73eSHans de Goede 1368e2ce73eSHans de Goede shark->last_val = val; 1378e2ce73eSHans de Goede 1388e2ce73eSHans de Goede /* 1398e2ce73eSHans de Goede * The shark does not allow actually reading the stereo / mono pin :( 1408e2ce73eSHans de Goede * So assume that when we're tuned to an FM station and mono has not 1418e2ce73eSHans de Goede * been requested, that we're receiving stereo. 1428e2ce73eSHans de Goede */ 1438e2ce73eSHans de Goede if (((val & TEA575X_BIT_BAND_MASK) == TEA575X_BIT_BAND_FM) && 1448e2ce73eSHans de Goede !(val & TEA575X_BIT_MONO)) 1458e2ce73eSHans de Goede shark->tea.stereo = true; 1468e2ce73eSHans de Goede else 1478e2ce73eSHans de Goede shark->tea.stereo = false; 1488e2ce73eSHans de Goede 1498e2ce73eSHans de Goede return val; 1508e2ce73eSHans de Goede } 1518e2ce73eSHans de Goede 1528e2ce73eSHans de Goede static struct snd_tea575x_ops shark_tea_ops = { 1538e2ce73eSHans de Goede .write_val = shark_write_val, 1548e2ce73eSHans de Goede .read_val = shark_read_val, 1558e2ce73eSHans de Goede }; 1568e2ce73eSHans de Goede 1573e3b92caSHans de Goede #ifdef SHARK_USE_LEDS 1588e2ce73eSHans de Goede static void shark_led_work(struct work_struct *work) 1598e2ce73eSHans de Goede { 1608e2ce73eSHans de Goede struct shark_device *shark = 1618e2ce73eSHans de Goede container_of(work, struct shark_device, led_work); 1628e2ce73eSHans de Goede int i, res, brightness, actual_len; 1638e2ce73eSHans de Goede 1648e2ce73eSHans de Goede for (i = 0; i < 3; i++) { 1658e2ce73eSHans de Goede if (!test_and_clear_bit(i, &shark->brightness_new)) 1668e2ce73eSHans de Goede continue; 1678e2ce73eSHans de Goede 1688e2ce73eSHans de Goede brightness = atomic_read(&shark->brightness[i]); 1698e2ce73eSHans de Goede memset(shark->transfer_buffer, 0, TB_LEN); 1708e2ce73eSHans de Goede if (i != RED_LED) { 1718e2ce73eSHans de Goede shark->transfer_buffer[0] = 0xA0 + i; 1728e2ce73eSHans de Goede shark->transfer_buffer[1] = brightness; 1738e2ce73eSHans de Goede } else 1748e2ce73eSHans de Goede shark->transfer_buffer[0] = brightness ? 0xA9 : 0xA8; 1758e2ce73eSHans de Goede res = usb_interrupt_msg(shark->usbdev, 1768e2ce73eSHans de Goede usb_sndintpipe(shark->usbdev, 0x05), 1778e2ce73eSHans de Goede shark->transfer_buffer, TB_LEN, 1788e2ce73eSHans de Goede &actual_len, 1000); 1798e2ce73eSHans de Goede if (res < 0) 1808e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "set LED %s error: %d\n", 1818e2ce73eSHans de Goede shark->led_names[i], res); 1828e2ce73eSHans de Goede } 1838e2ce73eSHans de Goede } 1848e2ce73eSHans de Goede 1858e2ce73eSHans de Goede static void shark_led_set_blue(struct led_classdev *led_cdev, 1868e2ce73eSHans de Goede enum led_brightness value) 1878e2ce73eSHans de Goede { 1888e2ce73eSHans de Goede struct shark_device *shark = 1898e2ce73eSHans de Goede container_of(led_cdev, struct shark_device, leds[BLUE_LED]); 1908e2ce73eSHans de Goede 1918e2ce73eSHans de Goede atomic_set(&shark->brightness[BLUE_LED], value); 1928e2ce73eSHans de Goede set_bit(BLUE_LED, &shark->brightness_new); 1938e2ce73eSHans de Goede schedule_work(&shark->led_work); 1948e2ce73eSHans de Goede } 1958e2ce73eSHans de Goede 1968e2ce73eSHans de Goede static void shark_led_set_blue_pulse(struct led_classdev *led_cdev, 1978e2ce73eSHans de Goede enum led_brightness value) 1988e2ce73eSHans de Goede { 1998e2ce73eSHans de Goede struct shark_device *shark = container_of(led_cdev, 2008e2ce73eSHans de Goede struct shark_device, leds[BLUE_PULSE_LED]); 2018e2ce73eSHans de Goede 2028e2ce73eSHans de Goede atomic_set(&shark->brightness[BLUE_PULSE_LED], 256 - value); 2038e2ce73eSHans de Goede set_bit(BLUE_PULSE_LED, &shark->brightness_new); 2048e2ce73eSHans de Goede schedule_work(&shark->led_work); 2058e2ce73eSHans de Goede } 2068e2ce73eSHans de Goede 2078e2ce73eSHans de Goede static void shark_led_set_red(struct led_classdev *led_cdev, 2088e2ce73eSHans de Goede enum led_brightness value) 2098e2ce73eSHans de Goede { 2108e2ce73eSHans de Goede struct shark_device *shark = 2118e2ce73eSHans de Goede container_of(led_cdev, struct shark_device, leds[RED_LED]); 2128e2ce73eSHans de Goede 2138e2ce73eSHans de Goede atomic_set(&shark->brightness[RED_LED], value); 2148e2ce73eSHans de Goede set_bit(RED_LED, &shark->brightness_new); 2158e2ce73eSHans de Goede schedule_work(&shark->led_work); 2168e2ce73eSHans de Goede } 2178e2ce73eSHans de Goede 2183e3b92caSHans de Goede static const struct led_classdev shark_led_templates[NO_LEDS] = { 2193e3b92caSHans de Goede [BLUE_LED] = { 2203e3b92caSHans de Goede .name = "%s:blue:", 2213e3b92caSHans de Goede .brightness = LED_OFF, 2223e3b92caSHans de Goede .max_brightness = 127, 2233e3b92caSHans de Goede .brightness_set = shark_led_set_blue, 2243e3b92caSHans de Goede }, 2253e3b92caSHans de Goede [BLUE_PULSE_LED] = { 2263e3b92caSHans de Goede .name = "%s:blue-pulse:", 2273e3b92caSHans de Goede .brightness = LED_OFF, 2283e3b92caSHans de Goede .max_brightness = 255, 2293e3b92caSHans de Goede .brightness_set = shark_led_set_blue_pulse, 2303e3b92caSHans de Goede }, 2313e3b92caSHans de Goede [RED_LED] = { 2323e3b92caSHans de Goede .name = "%s:red:", 2333e3b92caSHans de Goede .brightness = LED_OFF, 2343e3b92caSHans de Goede .max_brightness = 1, 2353e3b92caSHans de Goede .brightness_set = shark_led_set_red, 2363e3b92caSHans de Goede }, 2373e3b92caSHans de Goede }; 2383e3b92caSHans de Goede 2393e3b92caSHans de Goede static int shark_register_leds(struct shark_device *shark, struct device *dev) 2403e3b92caSHans de Goede { 2413e3b92caSHans de Goede int i, retval; 2423e3b92caSHans de Goede 2433e3b92caSHans de Goede INIT_WORK(&shark->led_work, shark_led_work); 2443e3b92caSHans de Goede for (i = 0; i < NO_LEDS; i++) { 2453e3b92caSHans de Goede shark->leds[i] = shark_led_templates[i]; 2463e3b92caSHans de Goede snprintf(shark->led_names[i], sizeof(shark->led_names[0]), 2473e3b92caSHans de Goede shark->leds[i].name, shark->v4l2_dev.name); 2483e3b92caSHans de Goede shark->leds[i].name = shark->led_names[i]; 2493e3b92caSHans de Goede retval = led_classdev_register(dev, &shark->leds[i]); 2503e3b92caSHans de Goede if (retval) { 2513e3b92caSHans de Goede v4l2_err(&shark->v4l2_dev, 2523e3b92caSHans de Goede "couldn't register led: %s\n", 2533e3b92caSHans de Goede shark->led_names[i]); 2543e3b92caSHans de Goede return retval; 2553e3b92caSHans de Goede } 2563e3b92caSHans de Goede } 2573e3b92caSHans de Goede return 0; 2583e3b92caSHans de Goede } 2593e3b92caSHans de Goede 2603e3b92caSHans de Goede static void shark_unregister_leds(struct shark_device *shark) 2613e3b92caSHans de Goede { 2623e3b92caSHans de Goede int i; 2633e3b92caSHans de Goede 2643e3b92caSHans de Goede for (i = 0; i < NO_LEDS; i++) 2653e3b92caSHans de Goede led_classdev_unregister(&shark->leds[i]); 2663e3b92caSHans de Goede 2673e3b92caSHans de Goede cancel_work_sync(&shark->led_work); 2683e3b92caSHans de Goede } 2693e3b92caSHans de Goede #else 2703e3b92caSHans de Goede static int shark_register_leds(struct shark_device *shark, struct device *dev) 2713e3b92caSHans de Goede { 2723e3b92caSHans de Goede v4l2_warn(&shark->v4l2_dev, 2733e3b92caSHans de Goede "CONFIG_LED_CLASS not enabled, LED support disabled\n"); 2743e3b92caSHans de Goede return 0; 2753e3b92caSHans de Goede } 2763e3b92caSHans de Goede static inline void shark_unregister_leds(struct shark_device *shark) { } 2773e3b92caSHans de Goede #endif 2783e3b92caSHans de Goede 2798e2ce73eSHans de Goede static void usb_shark_disconnect(struct usb_interface *intf) 2808e2ce73eSHans de Goede { 2818e2ce73eSHans de Goede struct v4l2_device *v4l2_dev = usb_get_intfdata(intf); 2828e2ce73eSHans de Goede struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); 2838e2ce73eSHans de Goede 2848e2ce73eSHans de Goede mutex_lock(&shark->tea.mutex); 2858e2ce73eSHans de Goede v4l2_device_disconnect(&shark->v4l2_dev); 2868e2ce73eSHans de Goede snd_tea575x_exit(&shark->tea); 2878e2ce73eSHans de Goede mutex_unlock(&shark->tea.mutex); 2888e2ce73eSHans de Goede 2893e3b92caSHans de Goede shark_unregister_leds(shark); 290cfc1b2a0SHans de Goede 2918e2ce73eSHans de Goede v4l2_device_put(&shark->v4l2_dev); 2928e2ce73eSHans de Goede } 2938e2ce73eSHans de Goede 2948e2ce73eSHans de Goede static void usb_shark_release(struct v4l2_device *v4l2_dev) 2958e2ce73eSHans de Goede { 2968e2ce73eSHans de Goede struct shark_device *shark = v4l2_dev_to_shark(v4l2_dev); 2978e2ce73eSHans de Goede 2988e2ce73eSHans de Goede v4l2_device_unregister(&shark->v4l2_dev); 2998e2ce73eSHans de Goede kfree(shark->transfer_buffer); 3008e2ce73eSHans de Goede kfree(shark); 3018e2ce73eSHans de Goede } 3028e2ce73eSHans de Goede 3038e2ce73eSHans de Goede static int usb_shark_probe(struct usb_interface *intf, 3048e2ce73eSHans de Goede const struct usb_device_id *id) 3058e2ce73eSHans de Goede { 3068e2ce73eSHans de Goede struct shark_device *shark; 3073e3b92caSHans de Goede int retval = -ENOMEM; 3088e2ce73eSHans de Goede 3098e2ce73eSHans de Goede shark = kzalloc(sizeof(struct shark_device), GFP_KERNEL); 3108e2ce73eSHans de Goede if (!shark) 3118e2ce73eSHans de Goede return retval; 3128e2ce73eSHans de Goede 3138e2ce73eSHans de Goede shark->transfer_buffer = kmalloc(TB_LEN, GFP_KERNEL); 3148e2ce73eSHans de Goede if (!shark->transfer_buffer) 3158e2ce73eSHans de Goede goto err_alloc_buffer; 3168e2ce73eSHans de Goede 3178e2ce73eSHans de Goede v4l2_device_set_name(&shark->v4l2_dev, DRV_NAME, &shark_instance); 3183e3b92caSHans de Goede 3193e3b92caSHans de Goede retval = shark_register_leds(shark, &intf->dev); 3203e3b92caSHans de Goede if (retval) 3213e3b92caSHans de Goede goto err_reg_leds; 3223e3b92caSHans de Goede 3233e3b92caSHans de Goede shark->v4l2_dev.release = usb_shark_release; 3248e2ce73eSHans de Goede retval = v4l2_device_register(&intf->dev, &shark->v4l2_dev); 3258e2ce73eSHans de Goede if (retval) { 3268e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "couldn't register v4l2_device\n"); 3278e2ce73eSHans de Goede goto err_reg_dev; 3288e2ce73eSHans de Goede } 3298e2ce73eSHans de Goede 3308e2ce73eSHans de Goede shark->usbdev = interface_to_usbdev(intf); 3318e2ce73eSHans de Goede shark->tea.v4l2_dev = &shark->v4l2_dev; 3328e2ce73eSHans de Goede shark->tea.private_data = shark; 3338e2ce73eSHans de Goede shark->tea.radio_nr = -1; 3348e2ce73eSHans de Goede shark->tea.ops = &shark_tea_ops; 3358e2ce73eSHans de Goede shark->tea.cannot_mute = true; 336fc488517SHans de Goede shark->tea.has_am = true; 3378e2ce73eSHans de Goede strlcpy(shark->tea.card, "Griffin radioSHARK", 3388e2ce73eSHans de Goede sizeof(shark->tea.card)); 3398e2ce73eSHans de Goede usb_make_path(shark->usbdev, shark->tea.bus_info, 3408e2ce73eSHans de Goede sizeof(shark->tea.bus_info)); 3418e2ce73eSHans de Goede 3428e2ce73eSHans de Goede retval = snd_tea575x_init(&shark->tea, THIS_MODULE); 3438e2ce73eSHans de Goede if (retval) { 3448e2ce73eSHans de Goede v4l2_err(&shark->v4l2_dev, "couldn't init tea5757\n"); 3458e2ce73eSHans de Goede goto err_init_tea; 3468e2ce73eSHans de Goede } 3478e2ce73eSHans de Goede 3488e2ce73eSHans de Goede return 0; 3498e2ce73eSHans de Goede 3508e2ce73eSHans de Goede err_init_tea: 3518e2ce73eSHans de Goede v4l2_device_unregister(&shark->v4l2_dev); 3528e2ce73eSHans de Goede err_reg_dev: 3533e3b92caSHans de Goede shark_unregister_leds(shark); 3543e3b92caSHans de Goede err_reg_leds: 3558e2ce73eSHans de Goede kfree(shark->transfer_buffer); 3568e2ce73eSHans de Goede err_alloc_buffer: 3578e2ce73eSHans de Goede kfree(shark); 3588e2ce73eSHans de Goede 3598e2ce73eSHans de Goede return retval; 3608e2ce73eSHans de Goede } 3618e2ce73eSHans de Goede 3628e2ce73eSHans de Goede /* Specify the bcdDevice value, as the radioSHARK and radioSHARK2 share ids */ 3638e2ce73eSHans de Goede static struct usb_device_id usb_shark_device_table[] = { 3648e2ce73eSHans de Goede { .match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION | 3658e2ce73eSHans de Goede USB_DEVICE_ID_MATCH_INT_CLASS, 3668e2ce73eSHans de Goede .idVendor = 0x077d, 3678e2ce73eSHans de Goede .idProduct = 0x627a, 3688e2ce73eSHans de Goede .bcdDevice_lo = 0x0001, 3698e2ce73eSHans de Goede .bcdDevice_hi = 0x0001, 3708e2ce73eSHans de Goede .bInterfaceClass = 3, 3718e2ce73eSHans de Goede }, 3728e2ce73eSHans de Goede { } 3738e2ce73eSHans de Goede }; 3748e2ce73eSHans de Goede MODULE_DEVICE_TABLE(usb, usb_shark_device_table); 3758e2ce73eSHans de Goede 3768e2ce73eSHans de Goede static struct usb_driver usb_shark_driver = { 3778e2ce73eSHans de Goede .name = DRV_NAME, 3788e2ce73eSHans de Goede .probe = usb_shark_probe, 3798e2ce73eSHans de Goede .disconnect = usb_shark_disconnect, 3808e2ce73eSHans de Goede .id_table = usb_shark_device_table, 3818e2ce73eSHans de Goede }; 3828e2ce73eSHans de Goede module_usb_driver(usb_shark_driver); 383