linux/drivers/media/radio/radio-mr800.c
<<
>>
Prefs
   1/*
   2 * A driver for the AverMedia MR 800 USB FM radio. This device plugs
   3 * into both the USB and an analog audio input, so this thing
   4 * only deals with initialization and frequency setting, the
   5 * audio data has to be handled by a sound driver.
   6 *
   7 * Copyright (c) 2008 Alexey Klimov <klimov.linux@gmail.com>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or
  12 * (at your option) any later version.
  13 *
  14 * This program is distributed in the hope that it will be useful,
  15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17 * GNU General Public License for more details.
  18 */
  19
  20/*
  21 * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c
  22 *
  23 * When work was looked pretty good, i discover this:
  24 * http://av-usbradio.sourceforge.net/index.php
  25 * http://sourceforge.net/projects/av-usbradio/
  26 * Latest release of theirs project was in 2005.
  27 * Probably, this driver could be improved through using their
  28 * achievements (specifications given).
  29 * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio
  30 * in 2007. He allowed to use his driver to improve current mr800 radio driver.
  31 * http://www.spinics.net/lists/linux-usb-devel/msg10109.html
  32 *
  33 * Version 0.01:        First working version.
  34 *                      It's required to blacklist AverMedia USB Radio
  35 *                      in usbhid/hid-quirks.c
  36 * Version 0.10:        A lot of cleanups and fixes: unpluging the device,
  37 *                      few mutex locks were added, codinstyle issues, etc.
  38 *                      Added stereo support. Thanks to
  39 *                      Douglas Schilling Landgraf <dougsland@gmail.com> and
  40 *                      David Ellingsworth <david@identd.dyndns.org>
  41 *                      for discussion, help and support.
  42 * Version 0.11:        Converted to v4l2_device.
  43 *
  44 * Many things to do:
  45 *      - Correct power management of device (suspend & resume)
  46 *      - Add code for scanning and smooth tuning
  47 *      - Add code for sensitivity value
  48 *      - Correct mistakes
  49 *      - In Japan another FREQ_MIN and FREQ_MAX
  50 */
  51
  52/* kernel includes */
  53#include <linux/kernel.h>
  54#include <linux/module.h>
  55#include <linux/init.h>
  56#include <linux/slab.h>
  57#include <linux/input.h>
  58#include <linux/videodev2.h>
  59#include <media/v4l2-device.h>
  60#include <media/v4l2-ioctl.h>
  61#include <media/v4l2-ctrls.h>
  62#include <media/v4l2-event.h>
  63#include <linux/usb.h>
  64#include <linux/mutex.h>
  65
  66/* driver and module definitions */
  67#define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>"
  68#define DRIVER_DESC "AverMedia MR 800 USB FM radio driver"
  69#define DRIVER_VERSION "0.1.2"
  70
  71MODULE_AUTHOR(DRIVER_AUTHOR);
  72MODULE_DESCRIPTION(DRIVER_DESC);
  73MODULE_LICENSE("GPL");
  74MODULE_VERSION(DRIVER_VERSION);
  75
  76#define USB_AMRADIO_VENDOR 0x07ca
  77#define USB_AMRADIO_PRODUCT 0xb800
  78
  79/* dev_warn macro with driver name */
  80#define MR800_DRIVER_NAME "radio-mr800"
  81#define amradio_dev_warn(dev, fmt, arg...)                              \
  82                dev_warn(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
  83
  84#define amradio_dev_err(dev, fmt, arg...) \
  85                dev_err(dev, MR800_DRIVER_NAME " - " fmt, ##arg)
  86
  87/* Probably USB_TIMEOUT should be modified in module parameter */
  88#define BUFFER_LENGTH 8
  89#define USB_TIMEOUT 500
  90
  91/* Frequency limits in MHz -- these are European values.  For Japanese
  92devices, that would be 76 and 91.  */
  93#define FREQ_MIN  87.5
  94#define FREQ_MAX 108.0
  95#define FREQ_MUL 16000
  96
  97/*
  98 * Commands that device should understand
  99 * List isn't full and will be updated with implementation of new functions
 100 */
 101#define AMRADIO_SET_FREQ        0xa4
 102#define AMRADIO_GET_READY_FLAG  0xa5
 103#define AMRADIO_GET_SIGNAL      0xa7
 104#define AMRADIO_GET_FREQ        0xa8
 105#define AMRADIO_SET_SEARCH_UP   0xa9
 106#define AMRADIO_SET_SEARCH_DOWN 0xaa
 107#define AMRADIO_SET_MUTE        0xab
 108#define AMRADIO_SET_RIGHT_MUTE  0xac
 109#define AMRADIO_SET_LEFT_MUTE   0xad
 110#define AMRADIO_SET_MONO        0xae
 111#define AMRADIO_SET_SEARCH_LVL  0xb0
 112#define AMRADIO_STOP_SEARCH     0xb1
 113
 114/* Comfortable defines for amradio_set_stereo */
 115#define WANT_STEREO             0x00
 116#define WANT_MONO               0x01
 117
 118/* module parameter */
 119static int radio_nr = -1;
 120module_param(radio_nr, int, 0);
 121MODULE_PARM_DESC(radio_nr, "Radio Nr");
 122
 123/* Data for one (physical) device */
 124struct amradio_device {
 125        /* reference to USB and video device */
 126        struct usb_device *usbdev;
 127        struct usb_interface *intf;
 128        struct video_device vdev;
 129        struct v4l2_device v4l2_dev;
 130        struct v4l2_ctrl_handler hdl;
 131
 132        u8 *buffer;
 133        struct mutex lock;      /* buffer locking */
 134        int curfreq;
 135        int stereo;
 136        int muted;
 137};
 138
 139static inline struct amradio_device *to_amradio_dev(struct v4l2_device *v4l2_dev)
 140{
 141        return container_of(v4l2_dev, struct amradio_device, v4l2_dev);
 142}
 143
 144static int amradio_send_cmd(struct amradio_device *radio, u8 cmd, u8 arg,
 145                u8 *extra, u8 extralen, bool reply)
 146{
 147        int retval;
 148        int size;
 149
 150        radio->buffer[0] = 0x00;
 151        radio->buffer[1] = 0x55;
 152        radio->buffer[2] = 0xaa;
 153        radio->buffer[3] = extralen;
 154        radio->buffer[4] = cmd;
 155        radio->buffer[5] = arg;
 156        radio->buffer[6] = 0x00;
 157        radio->buffer[7] = extra || reply ? 8 : 0;
 158
 159        retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
 160                radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
 161
 162        if (retval < 0 || size != BUFFER_LENGTH) {
 163                if (video_is_registered(&radio->vdev))
 164                        amradio_dev_warn(&radio->vdev.dev,
 165                                        "cmd %02x failed\n", cmd);
 166                return retval ? retval : -EIO;
 167        }
 168        if (!extra && !reply)
 169                return 0;
 170
 171        if (extra) {
 172                memcpy(radio->buffer, extra, extralen);
 173                memset(radio->buffer + extralen, 0, 8 - extralen);
 174                retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2),
 175                        radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
 176        } else {
 177                memset(radio->buffer, 0, 8);
 178                retval = usb_bulk_msg(radio->usbdev, usb_rcvbulkpipe(radio->usbdev, 0x81),
 179                        radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
 180        }
 181        if (retval == 0 && size == BUFFER_LENGTH)
 182                return 0;
 183        if (video_is_registered(&radio->vdev) && cmd != AMRADIO_GET_READY_FLAG)
 184                amradio_dev_warn(&radio->vdev.dev, "follow-up to cmd %02x failed\n", cmd);
 185        return retval ? retval : -EIO;
 186}
 187
 188/* switch on/off the radio. Send 8 bytes to device */
 189static int amradio_set_mute(struct amradio_device *radio, bool mute)
 190{
 191        int ret = amradio_send_cmd(radio,
 192                        AMRADIO_SET_MUTE, mute, NULL, 0, false);
 193
 194        if (!ret)
 195                radio->muted = mute;
 196        return ret;
 197}
 198
 199/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
 200static int amradio_set_freq(struct amradio_device *radio, int freq)
 201{
 202        unsigned short freq_send;
 203        u8 buf[3];
 204        int retval;
 205
 206        /* we need to be sure that frequency isn't out of range */
 207        freq = clamp_t(unsigned, freq, FREQ_MIN * FREQ_MUL, FREQ_MAX * FREQ_MUL);
 208        freq_send = 0x10 + (freq >> 3) / 25;
 209
 210        /* frequency is calculated from freq_send and placed in first 2 bytes */
 211        buf[0] = (freq_send >> 8) & 0xff;
 212        buf[1] = freq_send & 0xff;
 213        buf[2] = 0x01;
 214
 215        retval = amradio_send_cmd(radio, AMRADIO_SET_FREQ, 0, buf, 3, false);
 216        if (retval)
 217                return retval;
 218        radio->curfreq = freq;
 219        msleep(40);
 220        return 0;
 221}
 222
 223static int amradio_set_stereo(struct amradio_device *radio, bool stereo)
 224{
 225        int ret = amradio_send_cmd(radio,
 226                        AMRADIO_SET_MONO, !stereo, NULL, 0, false);
 227
 228        if (!ret)
 229                radio->stereo = stereo;
 230        return ret;
 231}
 232
 233static int amradio_get_stat(struct amradio_device *radio, bool *is_stereo, u32 *signal)
 234{
 235        int ret = amradio_send_cmd(radio,
 236                        AMRADIO_GET_SIGNAL, 0, NULL, 0, true);
 237
 238        if (ret)
 239                return ret;
 240        *is_stereo = radio->buffer[2] >> 7;
 241        *signal = (radio->buffer[3] & 0xf0) << 8;
 242        return 0;
 243}
 244
 245/* Handle unplugging the device.
 246 * We call video_unregister_device in any case.
 247 * The last function called in this procedure is
 248 * usb_amradio_device_release.
 249 */
 250static void usb_amradio_disconnect(struct usb_interface *intf)
 251{
 252        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 253
 254        mutex_lock(&radio->lock);
 255        video_unregister_device(&radio->vdev);
 256        amradio_set_mute(radio, true);
 257        usb_set_intfdata(intf, NULL);
 258        v4l2_device_disconnect(&radio->v4l2_dev);
 259        mutex_unlock(&radio->lock);
 260        v4l2_device_put(&radio->v4l2_dev);
 261}
 262
 263/* vidioc_querycap - query device capabilities */
 264static int vidioc_querycap(struct file *file, void *priv,
 265                                        struct v4l2_capability *v)
 266{
 267        struct amradio_device *radio = video_drvdata(file);
 268
 269        strlcpy(v->driver, "radio-mr800", sizeof(v->driver));
 270        strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card));
 271        usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
 272        v->device_caps = V4L2_CAP_RADIO | V4L2_CAP_TUNER |
 273                                        V4L2_CAP_HW_FREQ_SEEK;
 274        v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 275        return 0;
 276}
 277
 278/* vidioc_g_tuner - get tuner attributes */
 279static int vidioc_g_tuner(struct file *file, void *priv,
 280                                struct v4l2_tuner *v)
 281{
 282        struct amradio_device *radio = video_drvdata(file);
 283        bool is_stereo = false;
 284        int retval;
 285
 286        if (v->index > 0)
 287                return -EINVAL;
 288
 289        v->signal = 0;
 290        retval = amradio_get_stat(radio, &is_stereo, &v->signal);
 291        if (retval)
 292                return retval;
 293
 294        strcpy(v->name, "FM");
 295        v->type = V4L2_TUNER_RADIO;
 296        v->rangelow = FREQ_MIN * FREQ_MUL;
 297        v->rangehigh = FREQ_MAX * FREQ_MUL;
 298        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
 299                V4L2_TUNER_CAP_HWSEEK_WRAP;
 300        v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
 301        v->audmode = radio->stereo ?
 302                V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
 303        return 0;
 304}
 305
 306/* vidioc_s_tuner - set tuner attributes */
 307static int vidioc_s_tuner(struct file *file, void *priv,
 308                                const struct v4l2_tuner *v)
 309{
 310        struct amradio_device *radio = video_drvdata(file);
 311
 312        if (v->index > 0)
 313                return -EINVAL;
 314
 315        /* mono/stereo selector */
 316        switch (v->audmode) {
 317        case V4L2_TUNER_MODE_MONO:
 318                return amradio_set_stereo(radio, WANT_MONO);
 319        default:
 320                return amradio_set_stereo(radio, WANT_STEREO);
 321        }
 322}
 323
 324/* vidioc_s_frequency - set tuner radio frequency */
 325static int vidioc_s_frequency(struct file *file, void *priv,
 326                                const struct v4l2_frequency *f)
 327{
 328        struct amradio_device *radio = video_drvdata(file);
 329
 330        if (f->tuner != 0)
 331                return -EINVAL;
 332        return amradio_set_freq(radio, f->frequency);
 333}
 334
 335/* vidioc_g_frequency - get tuner radio frequency */
 336static int vidioc_g_frequency(struct file *file, void *priv,
 337                                struct v4l2_frequency *f)
 338{
 339        struct amradio_device *radio = video_drvdata(file);
 340
 341        if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
 342                return -EINVAL;
 343        f->type = V4L2_TUNER_RADIO;
 344        f->frequency = radio->curfreq;
 345
 346        return 0;
 347}
 348
 349static int vidioc_s_hw_freq_seek(struct file *file, void *priv,
 350                const struct v4l2_hw_freq_seek *seek)
 351{
 352        static u8 buf[8] = {
 353                0x3d, 0x32, 0x0f, 0x08, 0x3d, 0x32, 0x0f, 0x08
 354        };
 355        struct amradio_device *radio = video_drvdata(file);
 356        unsigned long timeout;
 357        int retval;
 358
 359        if (seek->tuner != 0 || !seek->wrap_around)
 360                return -EINVAL;
 361
 362        if (file->f_flags & O_NONBLOCK)
 363                return -EWOULDBLOCK;
 364
 365        retval = amradio_send_cmd(radio,
 366                        AMRADIO_SET_SEARCH_LVL, 0, buf, 8, false);
 367        if (retval)
 368                return retval;
 369        amradio_set_freq(radio, radio->curfreq);
 370        retval = amradio_send_cmd(radio,
 371                seek->seek_upward ? AMRADIO_SET_SEARCH_UP : AMRADIO_SET_SEARCH_DOWN,
 372                0, NULL, 0, false);
 373        if (retval)
 374                return retval;
 375        timeout = jiffies + msecs_to_jiffies(30000);
 376        for (;;) {
 377                if (time_after(jiffies, timeout)) {
 378                        retval = -ENODATA;
 379                        break;
 380                }
 381                if (schedule_timeout_interruptible(msecs_to_jiffies(10))) {
 382                        retval = -ERESTARTSYS;
 383                        break;
 384                }
 385                retval = amradio_send_cmd(radio, AMRADIO_GET_READY_FLAG,
 386                                0, NULL, 0, true);
 387                if (retval)
 388                        continue;
 389                amradio_send_cmd(radio, AMRADIO_GET_FREQ, 0, NULL, 0, true);
 390                if (radio->buffer[1] || radio->buffer[2]) {
 391                        /* To check: sometimes radio->curfreq is set to out of range value */
 392                        radio->curfreq = (radio->buffer[1] << 8) | radio->buffer[2];
 393                        radio->curfreq = (radio->curfreq - 0x10) * 200;
 394                        amradio_send_cmd(radio, AMRADIO_STOP_SEARCH,
 395                                        0, NULL, 0, false);
 396                        amradio_set_freq(radio, radio->curfreq);
 397                        retval = 0;
 398                        break;
 399                }
 400        }
 401        amradio_send_cmd(radio, AMRADIO_STOP_SEARCH, 0, NULL, 0, false);
 402        amradio_set_freq(radio, radio->curfreq);
 403        return retval;
 404}
 405
 406static int usb_amradio_s_ctrl(struct v4l2_ctrl *ctrl)
 407{
 408        struct amradio_device *radio =
 409                container_of(ctrl->handler, struct amradio_device, hdl);
 410
 411        switch (ctrl->id) {
 412        case V4L2_CID_AUDIO_MUTE:
 413                return amradio_set_mute(radio, ctrl->val);
 414        }
 415
 416        return -EINVAL;
 417}
 418
 419static int usb_amradio_init(struct amradio_device *radio)
 420{
 421        int retval;
 422
 423        retval = amradio_set_mute(radio, true);
 424        if (retval)
 425                goto out_err;
 426        retval = amradio_set_stereo(radio, true);
 427        if (retval)
 428                goto out_err;
 429        retval = amradio_set_freq(radio, radio->curfreq);
 430        if (retval)
 431                goto out_err;
 432        return 0;
 433
 434out_err:
 435        amradio_dev_err(&radio->vdev.dev, "initialization failed\n");
 436        return retval;
 437}
 438
 439/* Suspend device - stop device. Need to be checked and fixed */
 440static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
 441{
 442        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 443
 444        mutex_lock(&radio->lock);
 445        if (!radio->muted) {
 446                amradio_set_mute(radio, true);
 447                radio->muted = false;
 448        }
 449        mutex_unlock(&radio->lock);
 450
 451        dev_info(&intf->dev, "going into suspend..\n");
 452        return 0;
 453}
 454
 455/* Resume device - start device. Need to be checked and fixed */
 456static int usb_amradio_resume(struct usb_interface *intf)
 457{
 458        struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
 459
 460        mutex_lock(&radio->lock);
 461        amradio_set_stereo(radio, radio->stereo);
 462        amradio_set_freq(radio, radio->curfreq);
 463
 464        if (!radio->muted)
 465                amradio_set_mute(radio, false);
 466
 467        mutex_unlock(&radio->lock);
 468
 469        dev_info(&intf->dev, "coming out of suspend..\n");
 470        return 0;
 471}
 472
 473static const struct v4l2_ctrl_ops usb_amradio_ctrl_ops = {
 474        .s_ctrl = usb_amradio_s_ctrl,
 475};
 476
 477/* File system interface */
 478static const struct v4l2_file_operations usb_amradio_fops = {
 479        .owner          = THIS_MODULE,
 480        .open           = v4l2_fh_open,
 481        .release        = v4l2_fh_release,
 482        .poll           = v4l2_ctrl_poll,
 483        .unlocked_ioctl = video_ioctl2,
 484};
 485
 486static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
 487        .vidioc_querycap    = vidioc_querycap,
 488        .vidioc_g_tuner     = vidioc_g_tuner,
 489        .vidioc_s_tuner     = vidioc_s_tuner,
 490        .vidioc_g_frequency = vidioc_g_frequency,
 491        .vidioc_s_frequency = vidioc_s_frequency,
 492        .vidioc_s_hw_freq_seek = vidioc_s_hw_freq_seek,
 493        .vidioc_log_status  = v4l2_ctrl_log_status,
 494        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
 495        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 496};
 497
 498static void usb_amradio_release(struct v4l2_device *v4l2_dev)
 499{
 500        struct amradio_device *radio = to_amradio_dev(v4l2_dev);
 501
 502        /* free rest memory */
 503        v4l2_ctrl_handler_free(&radio->hdl);
 504        v4l2_device_unregister(&radio->v4l2_dev);
 505        kfree(radio->buffer);
 506        kfree(radio);
 507}
 508
 509/* check if the device is present and register with v4l and usb if it is */
 510static int usb_amradio_probe(struct usb_interface *intf,
 511                                const struct usb_device_id *id)
 512{
 513        struct amradio_device *radio;
 514        int retval = 0;
 515
 516        radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL);
 517
 518        if (!radio) {
 519                dev_err(&intf->dev, "kmalloc for amradio_device failed\n");
 520                retval = -ENOMEM;
 521                goto err;
 522        }
 523
 524        radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
 525
 526        if (!radio->buffer) {
 527                dev_err(&intf->dev, "kmalloc for radio->buffer failed\n");
 528                retval = -ENOMEM;
 529                goto err_nobuf;
 530        }
 531
 532        retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
 533        if (retval < 0) {
 534                dev_err(&intf->dev, "couldn't register v4l2_device\n");
 535                goto err_v4l2;
 536        }
 537
 538        v4l2_ctrl_handler_init(&radio->hdl, 1);
 539        v4l2_ctrl_new_std(&radio->hdl, &usb_amradio_ctrl_ops,
 540                          V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
 541        if (radio->hdl.error) {
 542                retval = radio->hdl.error;
 543                dev_err(&intf->dev, "couldn't register control\n");
 544                goto err_ctrl;
 545        }
 546        mutex_init(&radio->lock);
 547
 548        radio->v4l2_dev.ctrl_handler = &radio->hdl;
 549        radio->v4l2_dev.release = usb_amradio_release;
 550        strlcpy(radio->vdev.name, radio->v4l2_dev.name,
 551                sizeof(radio->vdev.name));
 552        radio->vdev.v4l2_dev = &radio->v4l2_dev;
 553        radio->vdev.fops = &usb_amradio_fops;
 554        radio->vdev.ioctl_ops = &usb_amradio_ioctl_ops;
 555        radio->vdev.release = video_device_release_empty;
 556        radio->vdev.lock = &radio->lock;
 557
 558        radio->usbdev = interface_to_usbdev(intf);
 559        radio->intf = intf;
 560        usb_set_intfdata(intf, &radio->v4l2_dev);
 561        radio->curfreq = 95.16 * FREQ_MUL;
 562
 563        video_set_drvdata(&radio->vdev, radio);
 564        retval = usb_amradio_init(radio);
 565        if (retval)
 566                goto err_vdev;
 567
 568        retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO,
 569                                        radio_nr);
 570        if (retval < 0) {
 571                dev_err(&intf->dev, "could not register video device\n");
 572                goto err_vdev;
 573        }
 574
 575        return 0;
 576
 577err_vdev:
 578        v4l2_ctrl_handler_free(&radio->hdl);
 579err_ctrl:
 580        v4l2_device_unregister(&radio->v4l2_dev);
 581err_v4l2:
 582        kfree(radio->buffer);
 583err_nobuf:
 584        kfree(radio);
 585err:
 586        return retval;
 587}
 588
 589/* USB Device ID List */
 590static const struct usb_device_id usb_amradio_device_table[] = {
 591        { USB_DEVICE_AND_INTERFACE_INFO(USB_AMRADIO_VENDOR, USB_AMRADIO_PRODUCT,
 592                                                        USB_CLASS_HID, 0, 0) },
 593        { }                                             /* Terminating entry */
 594};
 595
 596MODULE_DEVICE_TABLE(usb, usb_amradio_device_table);
 597
 598/* USB subsystem interface */
 599static struct usb_driver usb_amradio_driver = {
 600        .name                   = MR800_DRIVER_NAME,
 601        .probe                  = usb_amradio_probe,
 602        .disconnect             = usb_amradio_disconnect,
 603        .suspend                = usb_amradio_suspend,
 604        .resume                 = usb_amradio_resume,
 605        .reset_resume           = usb_amradio_resume,
 606        .id_table               = usb_amradio_device_table,
 607};
 608
 609module_usb_driver(usb_amradio_driver);
 610