Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Line 6 Pod HD
0004  *
0005  * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
0006  * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
0007  * Copyright (C) 2017 Hans P. Moller <hmoller@uc.cl>
0008  */
0009 
0010 #include <linux/usb.h>
0011 #include <linux/slab.h>
0012 #include <linux/module.h>
0013 #include <sound/core.h>
0014 #include <sound/control.h>
0015 #include <sound/pcm.h>
0016 
0017 #include "driver.h"
0018 #include "pcm.h"
0019 
0020 #define PODHD_STARTUP_DELAY 500
0021 
0022 enum {
0023     LINE6_PODHD300,
0024     LINE6_PODHD400,
0025     LINE6_PODHD500,
0026     LINE6_PODX3,
0027     LINE6_PODX3LIVE,
0028     LINE6_PODHD500X,
0029     LINE6_PODHDDESKTOP
0030 };
0031 
0032 struct usb_line6_podhd {
0033     /* Generic Line 6 USB data */
0034     struct usb_line6 line6;
0035 
0036     /* Serial number of device */
0037     u32 serial_number;
0038 
0039     /* Firmware version */
0040     int firmware_version;
0041 
0042     /* Monitor level */
0043     int monitor_level;
0044 };
0045 
0046 #define line6_to_podhd(x)   container_of(x, struct usb_line6_podhd, line6)
0047 
0048 static const struct snd_ratden podhd_ratden = {
0049     .num_min = 48000,
0050     .num_max = 48000,
0051     .num_step = 1,
0052     .den = 1,
0053 };
0054 
0055 static struct line6_pcm_properties podhd_pcm_properties = {
0056     .playback_hw = {
0057                   .info = (SNDRV_PCM_INFO_MMAP |
0058                        SNDRV_PCM_INFO_INTERLEAVED |
0059                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
0060                        SNDRV_PCM_INFO_MMAP_VALID |
0061                        SNDRV_PCM_INFO_PAUSE |
0062                        SNDRV_PCM_INFO_SYNC_START),
0063                   .formats = SNDRV_PCM_FMTBIT_S24_3LE,
0064                   .rates = SNDRV_PCM_RATE_48000,
0065                   .rate_min = 48000,
0066                   .rate_max = 48000,
0067                   .channels_min = 2,
0068                   .channels_max = 2,
0069                   .buffer_bytes_max = 60000,
0070                   .period_bytes_min = 64,
0071                   .period_bytes_max = 8192,
0072                   .periods_min = 1,
0073                   .periods_max = 1024},
0074     .capture_hw = {
0075                  .info = (SNDRV_PCM_INFO_MMAP |
0076                       SNDRV_PCM_INFO_INTERLEAVED |
0077                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
0078                       SNDRV_PCM_INFO_MMAP_VALID |
0079                       SNDRV_PCM_INFO_SYNC_START),
0080                  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
0081                  .rates = SNDRV_PCM_RATE_48000,
0082                  .rate_min = 48000,
0083                  .rate_max = 48000,
0084                  .channels_min = 2,
0085                  .channels_max = 2,
0086                  .buffer_bytes_max = 60000,
0087                  .period_bytes_min = 64,
0088                  .period_bytes_max = 8192,
0089                  .periods_min = 1,
0090                  .periods_max = 1024},
0091     .rates = {
0092                 .nrats = 1,
0093                 .rats = &podhd_ratden},
0094     .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
0095 };
0096 
0097 static struct line6_pcm_properties podx3_pcm_properties = {
0098     .playback_hw = {
0099                   .info = (SNDRV_PCM_INFO_MMAP |
0100                        SNDRV_PCM_INFO_INTERLEAVED |
0101                        SNDRV_PCM_INFO_BLOCK_TRANSFER |
0102                        SNDRV_PCM_INFO_MMAP_VALID |
0103                        SNDRV_PCM_INFO_PAUSE |
0104                        SNDRV_PCM_INFO_SYNC_START),
0105                   .formats = SNDRV_PCM_FMTBIT_S24_3LE,
0106                   .rates = SNDRV_PCM_RATE_48000,
0107                   .rate_min = 48000,
0108                   .rate_max = 48000,
0109                   .channels_min = 2,
0110                   .channels_max = 2,
0111                   .buffer_bytes_max = 60000,
0112                   .period_bytes_min = 64,
0113                   .period_bytes_max = 8192,
0114                   .periods_min = 1,
0115                   .periods_max = 1024},
0116     .capture_hw = {
0117                  .info = (SNDRV_PCM_INFO_MMAP |
0118                       SNDRV_PCM_INFO_INTERLEAVED |
0119                       SNDRV_PCM_INFO_BLOCK_TRANSFER |
0120                       SNDRV_PCM_INFO_MMAP_VALID |
0121                       SNDRV_PCM_INFO_SYNC_START),
0122                  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
0123                  .rates = SNDRV_PCM_RATE_48000,
0124                  .rate_min = 48000,
0125                  .rate_max = 48000,
0126                  /* 1+2: Main signal (out), 3+4: Tone 1,
0127                   * 5+6: Tone 2, 7+8: raw
0128                   */
0129                  .channels_min = 8,
0130                  .channels_max = 8,
0131                  .buffer_bytes_max = 60000,
0132                  .period_bytes_min = 64,
0133                  .period_bytes_max = 8192,
0134                  .periods_min = 1,
0135                  .periods_max = 1024},
0136     .rates = {
0137                 .nrats = 1,
0138                 .rats = &podhd_ratden},
0139     .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
0140 };
0141 static struct usb_driver podhd_driver;
0142 
0143 static ssize_t serial_number_show(struct device *dev,
0144                   struct device_attribute *attr, char *buf)
0145 {
0146     struct snd_card *card = dev_to_snd_card(dev);
0147     struct usb_line6_podhd *pod = card->private_data;
0148 
0149     return sysfs_emit(buf, "%u\n", pod->serial_number);
0150 }
0151 
0152 static ssize_t firmware_version_show(struct device *dev,
0153                      struct device_attribute *attr, char *buf)
0154 {
0155     struct snd_card *card = dev_to_snd_card(dev);
0156     struct usb_line6_podhd *pod = card->private_data;
0157 
0158     return sysfs_emit(buf, "%06x\n", pod->firmware_version);
0159 }
0160 
0161 static DEVICE_ATTR_RO(firmware_version);
0162 static DEVICE_ATTR_RO(serial_number);
0163 
0164 static struct attribute *podhd_dev_attrs[] = {
0165     &dev_attr_firmware_version.attr,
0166     &dev_attr_serial_number.attr,
0167     NULL
0168 };
0169 
0170 static const struct attribute_group podhd_dev_attr_group = {
0171     .name = "podhd",
0172     .attrs = podhd_dev_attrs,
0173 };
0174 
0175 /*
0176  * POD X3 startup procedure.
0177  *
0178  * May be compatible with other POD HD's, since it's also similar to the
0179  * previous POD setup. In any case, it doesn't seem to be required for the
0180  * audio nor bulk interfaces to work.
0181  */
0182 
0183 static int podhd_dev_start(struct usb_line6_podhd *pod)
0184 {
0185     int ret;
0186     u8 init_bytes[8];
0187     int i;
0188     struct usb_device *usbdev = pod->line6.usbdev;
0189 
0190     ret = usb_control_msg_send(usbdev, 0,
0191                     0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
0192                     0x11, 0,
0193                     NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
0194     if (ret) {
0195         dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
0196         goto exit;
0197     }
0198 
0199     /* NOTE: looks like some kind of ping message */
0200     ret = usb_control_msg_recv(usbdev, 0, 0x67,
0201                     USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
0202                     0x11, 0x0,
0203                     init_bytes, 3, LINE6_TIMEOUT, GFP_KERNEL);
0204     if (ret) {
0205         dev_err(pod->line6.ifcdev,
0206             "receive length failed (error %d)\n", ret);
0207         goto exit;
0208     }
0209 
0210     pod->firmware_version =
0211         (init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
0212 
0213     for (i = 0; i <= 16; i++) {
0214         ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
0215         if (ret < 0)
0216             goto exit;
0217     }
0218 
0219     ret = usb_control_msg_send(usbdev, 0,
0220                     USB_REQ_SET_FEATURE,
0221                     USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
0222                     1, 0,
0223                     NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
0224 exit:
0225     return ret;
0226 }
0227 
0228 static void podhd_startup(struct usb_line6 *line6)
0229 {
0230     struct usb_line6_podhd *pod = line6_to_podhd(line6);
0231 
0232     podhd_dev_start(pod);
0233     line6_read_serial_number(&pod->line6, &pod->serial_number);
0234     if (snd_card_register(line6->card))
0235         dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
0236 }
0237 
0238 static void podhd_disconnect(struct usb_line6 *line6)
0239 {
0240     struct usb_line6_podhd *pod = line6_to_podhd(line6);
0241 
0242     if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
0243         struct usb_interface *intf;
0244 
0245         intf = usb_ifnum_to_if(line6->usbdev,
0246                     pod->line6.properties->ctrl_if);
0247         if (intf)
0248             usb_driver_release_interface(&podhd_driver, intf);
0249     }
0250 }
0251 
0252 static const unsigned int float_zero_to_one_lookup[] = {
0253 0x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
0254 0x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
0255 0x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
0256 0x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
0257 0x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
0258 0x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
0259 0x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
0260 0x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
0261 0x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
0262 0x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
0263 0x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
0264 0x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
0265 0x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
0266 0x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
0267 0x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
0268 0x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
0269 0x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
0270 };
0271 
0272 static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
0273 {
0274     unsigned int fl;
0275     static const unsigned char msg[16] = {
0276         /* Chunk is 0xc bytes (without first word) */
0277         0x0c, 0x00,
0278         /* First chunk in the message */
0279         0x01, 0x00,
0280         /* Message size is 2 4-byte words */
0281         0x02, 0x00,
0282         /* Unknown */
0283         0x04, 0x41,
0284         /* Unknown */
0285         0x04, 0x00, 0x13, 0x00,
0286         /* Volume, LE float32, 0.0 - 1.0 */
0287         0x00, 0x00, 0x00, 0x00
0288     };
0289     unsigned char *buf;
0290 
0291     buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
0292     if (!buf)
0293         return;
0294 
0295     if (value < 0)
0296         value = 0;
0297 
0298     if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
0299         value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
0300 
0301     fl = float_zero_to_one_lookup[value];
0302 
0303     buf[12] = (fl >> 0) & 0xff;
0304     buf[13] = (fl >> 8) & 0xff;
0305     buf[14] = (fl >> 16) & 0xff;
0306     buf[15] = (fl >> 24) & 0xff;
0307 
0308     line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
0309     kfree(buf);
0310 
0311     podhd->monitor_level = value;
0312 }
0313 
0314 /* control info callback */
0315 static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
0316                     struct snd_ctl_elem_info *uinfo)
0317 {
0318     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
0319     uinfo->count = 1;
0320     uinfo->value.integer.min = 0;
0321     uinfo->value.integer.max = 100;
0322     uinfo->value.integer.step = 1;
0323     return 0;
0324 }
0325 
0326 /* control get callback */
0327 static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
0328                        struct snd_ctl_elem_value *ucontrol)
0329 {
0330     struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
0331     struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
0332 
0333     ucontrol->value.integer.value[0] = podhd->monitor_level;
0334     return 0;
0335 }
0336 
0337 /* control put callback */
0338 static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
0339                        struct snd_ctl_elem_value *ucontrol)
0340 {
0341     struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
0342     struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
0343 
0344     if (ucontrol->value.integer.value[0] == podhd->monitor_level)
0345         return 0;
0346 
0347     podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
0348     return 1;
0349 }
0350 
0351 /* control definition */
0352 static const struct snd_kcontrol_new podhd_control_monitor = {
0353     .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
0354     .name = "Monitor Playback Volume",
0355     .index = 0,
0356     .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
0357     .info = snd_podhd_control_monitor_info,
0358     .get = snd_podhd_control_monitor_get,
0359     .put = snd_podhd_control_monitor_put
0360 };
0361 
0362 /*
0363     Try to init POD HD device.
0364 */
0365 static int podhd_init(struct usb_line6 *line6,
0366               const struct usb_device_id *id)
0367 {
0368     int err;
0369     struct usb_line6_podhd *pod = line6_to_podhd(line6);
0370     struct usb_interface *intf;
0371 
0372     line6->disconnect = podhd_disconnect;
0373     line6->startup = podhd_startup;
0374 
0375     if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
0376         /* claim the data interface */
0377         intf = usb_ifnum_to_if(line6->usbdev,
0378                     pod->line6.properties->ctrl_if);
0379         if (!intf) {
0380             dev_err(pod->line6.ifcdev, "interface %d not found\n",
0381                 pod->line6.properties->ctrl_if);
0382             return -ENODEV;
0383         }
0384 
0385         err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
0386         if (err != 0) {
0387             dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
0388                 pod->line6.properties->ctrl_if, err);
0389             return err;
0390         }
0391     }
0392 
0393     if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
0394         /* create sysfs entries: */
0395         err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
0396         if (err < 0)
0397             return err;
0398     }
0399 
0400     if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
0401         /* initialize PCM subsystem: */
0402         err = line6_init_pcm(line6,
0403             (id->driver_info == LINE6_PODX3 ||
0404             id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
0405             &podhd_pcm_properties);
0406         if (err < 0)
0407             return err;
0408     }
0409 
0410     if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
0411         podhd_set_monitor_level(pod, 100);
0412         err = snd_ctl_add(line6->card,
0413                   snd_ctl_new1(&podhd_control_monitor,
0414                            line6->line6pcm));
0415         if (err < 0)
0416             return err;
0417     }
0418 
0419     if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
0420         /* register USB audio system directly */
0421         return snd_card_register(line6->card);
0422     }
0423 
0424     /* init device and delay registering */
0425     schedule_delayed_work(&line6->startup_work,
0426                   msecs_to_jiffies(PODHD_STARTUP_DELAY));
0427     return 0;
0428 }
0429 
0430 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
0431 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
0432 
0433 /* table of devices that work with this driver */
0434 static const struct usb_device_id podhd_id_table[] = {
0435     /* TODO: no need to alloc data interfaces when only audio is used */
0436     { LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
0437     { LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
0438     { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
0439     { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
0440     { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
0441     { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
0442     { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
0443     {}
0444 };
0445 
0446 MODULE_DEVICE_TABLE(usb, podhd_id_table);
0447 
0448 static const struct line6_properties podhd_properties_table[] = {
0449     [LINE6_PODHD300] = {
0450         .id = "PODHD300",
0451         .name = "POD HD300",
0452         .capabilities   = LINE6_CAP_PCM
0453                 | LINE6_CAP_HWMON,
0454         .altsetting = 5,
0455         .ep_ctrl_r = 0x84,
0456         .ep_ctrl_w = 0x03,
0457         .ep_audio_r = 0x82,
0458         .ep_audio_w = 0x01,
0459     },
0460     [LINE6_PODHD400] = {
0461         .id = "PODHD400",
0462         .name = "POD HD400",
0463         .capabilities   = LINE6_CAP_PCM
0464                 | LINE6_CAP_HWMON,
0465         .altsetting = 5,
0466         .ep_ctrl_r = 0x84,
0467         .ep_ctrl_w = 0x03,
0468         .ep_audio_r = 0x82,
0469         .ep_audio_w = 0x01,
0470     },
0471     [LINE6_PODHD500] = {
0472         .id = "PODHD500",
0473         .name = "POD HD500",
0474         .capabilities   = LINE6_CAP_PCM | LINE6_CAP_CONTROL
0475                 | LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
0476         .altsetting = 1,
0477         .ctrl_if = 1,
0478         .ep_ctrl_r = 0x81,
0479         .ep_ctrl_w = 0x01,
0480         .ep_audio_r = 0x86,
0481         .ep_audio_w = 0x02,
0482     },
0483     [LINE6_PODX3] = {
0484         .id = "PODX3",
0485         .name = "POD X3",
0486         .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
0487                 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
0488         .altsetting = 1,
0489         .ep_ctrl_r = 0x81,
0490         .ep_ctrl_w = 0x01,
0491         .ctrl_if = 1,
0492         .ep_audio_r = 0x86,
0493         .ep_audio_w = 0x02,
0494     },
0495     [LINE6_PODX3LIVE] = {
0496         .id = "PODX3LIVE",
0497         .name = "POD X3 LIVE",
0498         .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
0499                 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
0500         .altsetting = 1,
0501         .ep_ctrl_r = 0x81,
0502         .ep_ctrl_w = 0x01,
0503         .ctrl_if = 1,
0504         .ep_audio_r = 0x86,
0505         .ep_audio_w = 0x02,
0506     },
0507     [LINE6_PODHD500X] = {
0508         .id = "PODHD500X",
0509         .name = "POD HD500X",
0510         .capabilities   = LINE6_CAP_CONTROL
0511                 | LINE6_CAP_PCM | LINE6_CAP_HWMON,
0512         .altsetting = 1,
0513         .ep_ctrl_r = 0x81,
0514         .ep_ctrl_w = 0x01,
0515         .ctrl_if = 1,
0516         .ep_audio_r = 0x86,
0517         .ep_audio_w = 0x02,
0518     },
0519     [LINE6_PODHDDESKTOP] = {
0520         .id = "PODHDDESKTOP",
0521         .name = "POD HDDESKTOP",
0522         .capabilities    = LINE6_CAP_CONTROL
0523             | LINE6_CAP_PCM | LINE6_CAP_HWMON,
0524         .altsetting = 1,
0525         .ep_ctrl_r = 0x81,
0526         .ep_ctrl_w = 0x01,
0527         .ctrl_if = 1,
0528         .ep_audio_r = 0x86,
0529         .ep_audio_w = 0x02,
0530     },
0531 };
0532 
0533 /*
0534     Probe USB device.
0535 */
0536 static int podhd_probe(struct usb_interface *interface,
0537                const struct usb_device_id *id)
0538 {
0539     return line6_probe(interface, id, "Line6-PODHD",
0540                &podhd_properties_table[id->driver_info],
0541                podhd_init, sizeof(struct usb_line6_podhd));
0542 }
0543 
0544 static struct usb_driver podhd_driver = {
0545     .name = KBUILD_MODNAME,
0546     .probe = podhd_probe,
0547     .disconnect = line6_disconnect,
0548 #ifdef CONFIG_PM
0549     .suspend = line6_suspend,
0550     .resume = line6_resume,
0551     .reset_resume = line6_resume,
0552 #endif
0553     .id_table = podhd_id_table,
0554 };
0555 
0556 module_usb_driver(podhd_driver);
0557 
0558 MODULE_DESCRIPTION("Line 6 PODHD USB driver");
0559 MODULE_LICENSE("GPL");