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