linux/sound/usb/line6/podhd.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Line 6 Pod HD
   4 *
   5 * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
   6 * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
   7 * Copyright (C) 2017 Hans P. Moller <hmoller@uc.cl>
   8 */
   9
  10#include <linux/usb.h>
  11#include <linux/slab.h>
  12#include <linux/module.h>
  13#include <sound/core.h>
  14#include <sound/control.h>
  15#include <sound/pcm.h>
  16
  17#include "driver.h"
  18#include "pcm.h"
  19
  20#define PODHD_STARTUP_DELAY 500
  21
  22enum {
  23        LINE6_PODHD300,
  24        LINE6_PODHD400,
  25        LINE6_PODHD500,
  26        LINE6_PODX3,
  27        LINE6_PODX3LIVE,
  28        LINE6_PODHD500X,
  29        LINE6_PODHDDESKTOP
  30};
  31
  32struct usb_line6_podhd {
  33        /* Generic Line 6 USB data */
  34        struct usb_line6 line6;
  35
  36        /* Serial number of device */
  37        u32 serial_number;
  38
  39        /* Firmware version */
  40        int firmware_version;
  41
  42        /* Monitor level */
  43        int monitor_level;
  44};
  45
  46#define line6_to_podhd(x)       container_of(x, struct usb_line6_podhd, line6)
  47
  48static const struct snd_ratden podhd_ratden = {
  49        .num_min = 48000,
  50        .num_max = 48000,
  51        .num_step = 1,
  52        .den = 1,
  53};
  54
  55static struct line6_pcm_properties podhd_pcm_properties = {
  56        .playback_hw = {
  57                                  .info = (SNDRV_PCM_INFO_MMAP |
  58                                           SNDRV_PCM_INFO_INTERLEAVED |
  59                                           SNDRV_PCM_INFO_BLOCK_TRANSFER |
  60                                           SNDRV_PCM_INFO_MMAP_VALID |
  61                                           SNDRV_PCM_INFO_PAUSE |
  62                                           SNDRV_PCM_INFO_SYNC_START),
  63                                  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  64                                  .rates = SNDRV_PCM_RATE_48000,
  65                                  .rate_min = 48000,
  66                                  .rate_max = 48000,
  67                                  .channels_min = 2,
  68                                  .channels_max = 2,
  69                                  .buffer_bytes_max = 60000,
  70                                  .period_bytes_min = 64,
  71                                  .period_bytes_max = 8192,
  72                                  .periods_min = 1,
  73                                  .periods_max = 1024},
  74        .capture_hw = {
  75                                 .info = (SNDRV_PCM_INFO_MMAP |
  76                                          SNDRV_PCM_INFO_INTERLEAVED |
  77                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
  78                                          SNDRV_PCM_INFO_MMAP_VALID |
  79                                          SNDRV_PCM_INFO_SYNC_START),
  80                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  81                                 .rates = SNDRV_PCM_RATE_48000,
  82                                 .rate_min = 48000,
  83                                 .rate_max = 48000,
  84                                 .channels_min = 2,
  85                                 .channels_max = 2,
  86                                 .buffer_bytes_max = 60000,
  87                                 .period_bytes_min = 64,
  88                                 .period_bytes_max = 8192,
  89                                 .periods_min = 1,
  90                                 .periods_max = 1024},
  91        .rates = {
  92                            .nrats = 1,
  93                            .rats = &podhd_ratden},
  94        .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
  95};
  96
  97static struct line6_pcm_properties podx3_pcm_properties = {
  98        .playback_hw = {
  99                                  .info = (SNDRV_PCM_INFO_MMAP |
 100                                           SNDRV_PCM_INFO_INTERLEAVED |
 101                                           SNDRV_PCM_INFO_BLOCK_TRANSFER |
 102                                           SNDRV_PCM_INFO_MMAP_VALID |
 103                                           SNDRV_PCM_INFO_PAUSE |
 104                                           SNDRV_PCM_INFO_SYNC_START),
 105                                  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 106                                  .rates = SNDRV_PCM_RATE_48000,
 107                                  .rate_min = 48000,
 108                                  .rate_max = 48000,
 109                                  .channels_min = 2,
 110                                  .channels_max = 2,
 111                                  .buffer_bytes_max = 60000,
 112                                  .period_bytes_min = 64,
 113                                  .period_bytes_max = 8192,
 114                                  .periods_min = 1,
 115                                  .periods_max = 1024},
 116        .capture_hw = {
 117                                 .info = (SNDRV_PCM_INFO_MMAP |
 118                                          SNDRV_PCM_INFO_INTERLEAVED |
 119                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
 120                                          SNDRV_PCM_INFO_MMAP_VALID |
 121                                          SNDRV_PCM_INFO_SYNC_START),
 122                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 123                                 .rates = SNDRV_PCM_RATE_48000,
 124                                 .rate_min = 48000,
 125                                 .rate_max = 48000,
 126                                 /* 1+2: Main signal (out), 3+4: Tone 1,
 127                                  * 5+6: Tone 2, 7+8: raw
 128                                  */
 129                                 .channels_min = 8,
 130                                 .channels_max = 8,
 131                                 .buffer_bytes_max = 60000,
 132                                 .period_bytes_min = 64,
 133                                 .period_bytes_max = 8192,
 134                                 .periods_min = 1,
 135                                 .periods_max = 1024},
 136        .rates = {
 137                            .nrats = 1,
 138                            .rats = &podhd_ratden},
 139        .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
 140};
 141static struct usb_driver podhd_driver;
 142
 143static ssize_t serial_number_show(struct device *dev,
 144                                  struct device_attribute *attr, char *buf)
 145{
 146        struct snd_card *card = dev_to_snd_card(dev);
 147        struct usb_line6_podhd *pod = card->private_data;
 148
 149        return sprintf(buf, "%u\n", pod->serial_number);
 150}
 151
 152static ssize_t firmware_version_show(struct device *dev,
 153                                     struct device_attribute *attr, char *buf)
 154{
 155        struct snd_card *card = dev_to_snd_card(dev);
 156        struct usb_line6_podhd *pod = card->private_data;
 157
 158        return sprintf(buf, "%06x\n", pod->firmware_version);
 159}
 160
 161static DEVICE_ATTR_RO(firmware_version);
 162static DEVICE_ATTR_RO(serial_number);
 163
 164static struct attribute *podhd_dev_attrs[] = {
 165        &dev_attr_firmware_version.attr,
 166        &dev_attr_serial_number.attr,
 167        NULL
 168};
 169
 170static const struct attribute_group podhd_dev_attr_group = {
 171        .name = "podhd",
 172        .attrs = podhd_dev_attrs,
 173};
 174
 175/*
 176 * POD X3 startup procedure.
 177 *
 178 * May be compatible with other POD HD's, since it's also similar to the
 179 * previous POD setup. In any case, it doesn't seem to be required for the
 180 * audio nor bulk interfaces to work.
 181 */
 182
 183static int podhd_dev_start(struct usb_line6_podhd *pod)
 184{
 185        int ret;
 186        u8 *init_bytes;
 187        int i;
 188        struct usb_device *usbdev = pod->line6.usbdev;
 189
 190        init_bytes = kmalloc(8, GFP_KERNEL);
 191        if (!init_bytes)
 192                return -ENOMEM;
 193
 194        ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
 195                                        0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
 196                                        0x11, 0,
 197                                        NULL, 0, LINE6_TIMEOUT * HZ);
 198        if (ret < 0) {
 199                dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
 200                goto exit;
 201        }
 202
 203        /* NOTE: looks like some kind of ping message */
 204        ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
 205                                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
 206                                        0x11, 0x0,
 207                                        init_bytes, 3, LINE6_TIMEOUT * HZ);
 208        if (ret < 0) {
 209                dev_err(pod->line6.ifcdev,
 210                        "receive length failed (error %d)\n", ret);
 211                goto exit;
 212        }
 213
 214        pod->firmware_version =
 215                (init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
 216
 217        for (i = 0; i <= 16; i++) {
 218                ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
 219                if (ret < 0)
 220                        goto exit;
 221        }
 222
 223        ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
 224                                        USB_REQ_SET_FEATURE,
 225                                        USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
 226                                        1, 0,
 227                                        NULL, 0, LINE6_TIMEOUT * HZ);
 228exit:
 229        kfree(init_bytes);
 230        return ret;
 231}
 232
 233static void podhd_startup(struct usb_line6 *line6)
 234{
 235        struct usb_line6_podhd *pod = line6_to_podhd(line6);
 236
 237        podhd_dev_start(pod);
 238        line6_read_serial_number(&pod->line6, &pod->serial_number);
 239        if (snd_card_register(line6->card))
 240                dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
 241}
 242
 243static void podhd_disconnect(struct usb_line6 *line6)
 244{
 245        struct usb_line6_podhd *pod = line6_to_podhd(line6);
 246
 247        if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
 248                struct usb_interface *intf;
 249
 250                intf = usb_ifnum_to_if(line6->usbdev,
 251                                        pod->line6.properties->ctrl_if);
 252                if (intf)
 253                        usb_driver_release_interface(&podhd_driver, intf);
 254        }
 255}
 256
 257static const unsigned int float_zero_to_one_lookup[] = {
 2580x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
 2590x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
 2600x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
 2610x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
 2620x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
 2630x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
 2640x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
 2650x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
 2660x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
 2670x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
 2680x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
 2690x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
 2700x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
 2710x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
 2720x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
 2730x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
 2740x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
 275};
 276
 277static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
 278{
 279        unsigned int fl;
 280        static const unsigned char msg[16] = {
 281                /* Chunk is 0xc bytes (without first word) */
 282                0x0c, 0x00,
 283                /* First chunk in the message */
 284                0x01, 0x00,
 285                /* Message size is 2 4-byte words */
 286                0x02, 0x00,
 287                /* Unknown */
 288                0x04, 0x41,
 289                /* Unknown */
 290                0x04, 0x00, 0x13, 0x00,
 291                /* Volume, LE float32, 0.0 - 1.0 */
 292                0x00, 0x00, 0x00, 0x00
 293        };
 294        unsigned char *buf;
 295
 296        buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
 297        if (!buf)
 298                return;
 299
 300        if (value < 0)
 301                value = 0;
 302
 303        if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
 304                value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
 305
 306        fl = float_zero_to_one_lookup[value];
 307
 308        buf[12] = (fl >> 0) & 0xff;
 309        buf[13] = (fl >> 8) & 0xff;
 310        buf[14] = (fl >> 16) & 0xff;
 311        buf[15] = (fl >> 24) & 0xff;
 312
 313        line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
 314        kfree(buf);
 315
 316        podhd->monitor_level = value;
 317}
 318
 319/* control info callback */
 320static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
 321                                        struct snd_ctl_elem_info *uinfo)
 322{
 323        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
 324        uinfo->count = 1;
 325        uinfo->value.integer.min = 0;
 326        uinfo->value.integer.max = 100;
 327        uinfo->value.integer.step = 1;
 328        return 0;
 329}
 330
 331/* control get callback */
 332static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
 333                                       struct snd_ctl_elem_value *ucontrol)
 334{
 335        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 336        struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
 337
 338        ucontrol->value.integer.value[0] = podhd->monitor_level;
 339        return 0;
 340}
 341
 342/* control put callback */
 343static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
 344                                       struct snd_ctl_elem_value *ucontrol)
 345{
 346        struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 347        struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
 348
 349        if (ucontrol->value.integer.value[0] == podhd->monitor_level)
 350                return 0;
 351
 352        podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
 353        return 1;
 354}
 355
 356/* control definition */
 357static const struct snd_kcontrol_new podhd_control_monitor = {
 358        .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
 359        .name = "Monitor Playback Volume",
 360        .index = 0,
 361        .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
 362        .info = snd_podhd_control_monitor_info,
 363        .get = snd_podhd_control_monitor_get,
 364        .put = snd_podhd_control_monitor_put
 365};
 366
 367/*
 368        Try to init POD HD device.
 369*/
 370static int podhd_init(struct usb_line6 *line6,
 371                      const struct usb_device_id *id)
 372{
 373        int err;
 374        struct usb_line6_podhd *pod = line6_to_podhd(line6);
 375        struct usb_interface *intf;
 376
 377        line6->disconnect = podhd_disconnect;
 378        line6->startup = podhd_startup;
 379
 380        if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
 381                /* claim the data interface */
 382                intf = usb_ifnum_to_if(line6->usbdev,
 383                                        pod->line6.properties->ctrl_if);
 384                if (!intf) {
 385                        dev_err(pod->line6.ifcdev, "interface %d not found\n",
 386                                pod->line6.properties->ctrl_if);
 387                        return -ENODEV;
 388                }
 389
 390                err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
 391                if (err != 0) {
 392                        dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
 393                                pod->line6.properties->ctrl_if, err);
 394                        return err;
 395                }
 396        }
 397
 398        if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
 399                /* create sysfs entries: */
 400                err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
 401                if (err < 0)
 402                        return err;
 403        }
 404
 405        if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
 406                /* initialize PCM subsystem: */
 407                err = line6_init_pcm(line6,
 408                        (id->driver_info == LINE6_PODX3 ||
 409                        id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
 410                        &podhd_pcm_properties);
 411                if (err < 0)
 412                        return err;
 413        }
 414
 415        if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
 416                podhd_set_monitor_level(pod, 100);
 417                err = snd_ctl_add(line6->card,
 418                                  snd_ctl_new1(&podhd_control_monitor,
 419                                               line6->line6pcm));
 420                if (err < 0)
 421                        return err;
 422        }
 423
 424        if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
 425                /* register USB audio system directly */
 426                return snd_card_register(line6->card);
 427        }
 428
 429        /* init device and delay registering */
 430        schedule_delayed_work(&line6->startup_work,
 431                              msecs_to_jiffies(PODHD_STARTUP_DELAY));
 432        return 0;
 433}
 434
 435#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
 436#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
 437
 438/* table of devices that work with this driver */
 439static const struct usb_device_id podhd_id_table[] = {
 440        /* TODO: no need to alloc data interfaces when only audio is used */
 441        { LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
 442        { LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
 443        { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
 444        { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
 445        { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
 446        { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
 447        { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
 448        {}
 449};
 450
 451MODULE_DEVICE_TABLE(usb, podhd_id_table);
 452
 453static const struct line6_properties podhd_properties_table[] = {
 454        [LINE6_PODHD300] = {
 455                .id = "PODHD300",
 456                .name = "POD HD300",
 457                .capabilities   = LINE6_CAP_PCM
 458                                | LINE6_CAP_HWMON,
 459                .altsetting = 5,
 460                .ep_ctrl_r = 0x84,
 461                .ep_ctrl_w = 0x03,
 462                .ep_audio_r = 0x82,
 463                .ep_audio_w = 0x01,
 464        },
 465        [LINE6_PODHD400] = {
 466                .id = "PODHD400",
 467                .name = "POD HD400",
 468                .capabilities   = LINE6_CAP_PCM
 469                                | LINE6_CAP_HWMON,
 470                .altsetting = 5,
 471                .ep_ctrl_r = 0x84,
 472                .ep_ctrl_w = 0x03,
 473                .ep_audio_r = 0x82,
 474                .ep_audio_w = 0x01,
 475        },
 476        [LINE6_PODHD500] = {
 477                .id = "PODHD500",
 478                .name = "POD HD500",
 479                .capabilities   = LINE6_CAP_PCM | LINE6_CAP_CONTROL
 480                                | LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
 481                .altsetting = 1,
 482                .ctrl_if = 1,
 483                .ep_ctrl_r = 0x81,
 484                .ep_ctrl_w = 0x01,
 485                .ep_audio_r = 0x86,
 486                .ep_audio_w = 0x02,
 487        },
 488        [LINE6_PODX3] = {
 489                .id = "PODX3",
 490                .name = "POD X3",
 491                .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
 492                                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
 493                .altsetting = 1,
 494                .ep_ctrl_r = 0x81,
 495                .ep_ctrl_w = 0x01,
 496                .ctrl_if = 1,
 497                .ep_audio_r = 0x86,
 498                .ep_audio_w = 0x02,
 499        },
 500        [LINE6_PODX3LIVE] = {
 501                .id = "PODX3LIVE",
 502                .name = "POD X3 LIVE",
 503                .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
 504                                | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
 505                .altsetting = 1,
 506                .ep_ctrl_r = 0x81,
 507                .ep_ctrl_w = 0x01,
 508                .ctrl_if = 1,
 509                .ep_audio_r = 0x86,
 510                .ep_audio_w = 0x02,
 511        },
 512        [LINE6_PODHD500X] = {
 513                .id = "PODHD500X",
 514                .name = "POD HD500X",
 515                .capabilities   = LINE6_CAP_CONTROL
 516                                | LINE6_CAP_PCM | LINE6_CAP_HWMON,
 517                .altsetting = 1,
 518                .ep_ctrl_r = 0x81,
 519                .ep_ctrl_w = 0x01,
 520                .ctrl_if = 1,
 521                .ep_audio_r = 0x86,
 522                .ep_audio_w = 0x02,
 523        },
 524        [LINE6_PODHDDESKTOP] = {
 525                .id = "PODHDDESKTOP",
 526                .name = "POD HDDESKTOP",
 527                .capabilities    = LINE6_CAP_CONTROL
 528                        | LINE6_CAP_PCM | LINE6_CAP_HWMON,
 529                .altsetting = 1,
 530                .ep_ctrl_r = 0x81,
 531                .ep_ctrl_w = 0x01,
 532                .ctrl_if = 1,
 533                .ep_audio_r = 0x86,
 534                .ep_audio_w = 0x02,
 535        },
 536};
 537
 538/*
 539        Probe USB device.
 540*/
 541static int podhd_probe(struct usb_interface *interface,
 542                       const struct usb_device_id *id)
 543{
 544        return line6_probe(interface, id, "Line6-PODHD",
 545                           &podhd_properties_table[id->driver_info],
 546                           podhd_init, sizeof(struct usb_line6_podhd));
 547}
 548
 549static struct usb_driver podhd_driver = {
 550        .name = KBUILD_MODNAME,
 551        .probe = podhd_probe,
 552        .disconnect = line6_disconnect,
 553#ifdef CONFIG_PM
 554        .suspend = line6_suspend,
 555        .resume = line6_resume,
 556        .reset_resume = line6_resume,
 557#endif
 558        .id_table = podhd_id_table,
 559};
 560
 561module_usb_driver(podhd_driver);
 562
 563MODULE_DESCRIPTION("Line 6 PODHD USB driver");
 564MODULE_LICENSE("GPL");
 565