~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/usb/line6/podhd.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 22 enum {
 23         LINE6_PODHD300,
 24         LINE6_PODHD400,
 25         LINE6_PODHD500,
 26         LINE6_PODX3,
 27         LINE6_PODX3LIVE,
 28         LINE6_PODHD500X,
 29         LINE6_PODHDDESKTOP
 30 };
 31 
 32 struct 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 
 48 static const struct snd_ratden podhd_ratden = {
 49         .num_min = 48000,
 50         .num_max = 48000,
 51         .num_step = 1,
 52         .den = 1,
 53 };
 54 
 55 static 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 
 97 static 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 };
141 static struct usb_driver podhd_driver;
142 
143 static 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 sysfs_emit(buf, "%u\n", pod->serial_number);
150 }
151 
152 static 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 sysfs_emit(buf, "%06x\n", pod->firmware_version);
159 }
160 
161 static DEVICE_ATTR_RO(firmware_version);
162 static DEVICE_ATTR_RO(serial_number);
163 
164 static struct attribute *podhd_dev_attrs[] = {
165         &dev_attr_firmware_version.attr,
166         &dev_attr_serial_number.attr,
167         NULL
168 };
169 
170 static 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 
183 static int podhd_dev_start(struct usb_line6_podhd *pod)
184 {
185         int ret;
186         u8 init_bytes[8];
187         int i;
188         struct usb_device *usbdev = pod->line6.usbdev;
189 
190         ret = usb_control_msg_send(usbdev, 0,
191                                         0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
192                                         0x11, 0,
193                                         NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
194         if (ret) {
195                 dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
196                 goto exit;
197         }
198 
199         /* NOTE: looks like some kind of ping message */
200         ret = usb_control_msg_recv(usbdev, 0, 0x67,
201                                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
202                                         0x11, 0x0,
203                                         init_bytes, 3, LINE6_TIMEOUT, GFP_KERNEL);
204         if (ret) {
205                 dev_err(pod->line6.ifcdev,
206                         "receive length failed (error %d)\n", ret);
207                 goto exit;
208         }
209 
210         pod->firmware_version =
211                 (init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
212 
213         for (i = 0; i <= 16; i++) {
214                 ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
215                 if (ret < 0)
216                         goto exit;
217         }
218 
219         ret = usb_control_msg_send(usbdev, 0,
220                                         USB_REQ_SET_FEATURE,
221                                         USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
222                                         1, 0,
223                                         NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
224 exit:
225         return ret;
226 }
227 
228 static void podhd_startup(struct usb_line6 *line6)
229 {
230         struct usb_line6_podhd *pod = line6_to_podhd(line6);
231 
232         podhd_dev_start(pod);
233         line6_read_serial_number(&pod->line6, &pod->serial_number);
234         if (snd_card_register(line6->card))
235                 dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
236 }
237 
238 static void podhd_disconnect(struct usb_line6 *line6)
239 {
240         struct usb_line6_podhd *pod = line6_to_podhd(line6);
241 
242         if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
243                 struct usb_interface *intf;
244 
245                 intf = usb_ifnum_to_if(line6->usbdev,
246                                         pod->line6.properties->ctrl_if);
247                 if (intf)
248                         usb_driver_release_interface(&podhd_driver, intf);
249         }
250 }
251 
252 static const unsigned int float_zero_to_one_lookup[] = {
253 0x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
254 0x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
255 0x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
256 0x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
257 0x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
258 0x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
259 0x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
260 0x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
261 0x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
262 0x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
263 0x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
264 0x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
265 0x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
266 0x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
267 0x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
268 0x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
269 0x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
270 };
271 
272 static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
273 {
274         unsigned int fl;
275         static const unsigned char msg[16] = {
276                 /* Chunk is 0xc bytes (without first word) */
277                 0x0c, 0x00,
278                 /* First chunk in the message */
279                 0x01, 0x00,
280                 /* Message size is 2 4-byte words */
281                 0x02, 0x00,
282                 /* Unknown */
283                 0x04, 0x41,
284                 /* Unknown */
285                 0x04, 0x00, 0x13, 0x00,
286                 /* Volume, LE float32, 0.0 - 1.0 */
287                 0x00, 0x00, 0x00, 0x00
288         };
289         unsigned char *buf;
290 
291         buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
292         if (!buf)
293                 return;
294 
295         if (value < 0)
296                 value = 0;
297 
298         if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
299                 value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
300 
301         fl = float_zero_to_one_lookup[value];
302 
303         buf[12] = (fl >> 0) & 0xff;
304         buf[13] = (fl >> 8) & 0xff;
305         buf[14] = (fl >> 16) & 0xff;
306         buf[15] = (fl >> 24) & 0xff;
307 
308         line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
309         kfree(buf);
310 
311         podhd->monitor_level = value;
312 }
313 
314 /* control info callback */
315 static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
316                                         struct snd_ctl_elem_info *uinfo)
317 {
318         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
319         uinfo->count = 1;
320         uinfo->value.integer.min = 0;
321         uinfo->value.integer.max = 100;
322         uinfo->value.integer.step = 1;
323         return 0;
324 }
325 
326 /* control get callback */
327 static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
328                                        struct snd_ctl_elem_value *ucontrol)
329 {
330         struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
331         struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
332 
333         ucontrol->value.integer.value[0] = podhd->monitor_level;
334         return 0;
335 }
336 
337 /* control put callback */
338 static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
339                                        struct snd_ctl_elem_value *ucontrol)
340 {
341         struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
342         struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
343 
344         if (ucontrol->value.integer.value[0] == podhd->monitor_level)
345                 return 0;
346 
347         podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
348         return 1;
349 }
350 
351 /* control definition */
352 static const struct snd_kcontrol_new podhd_control_monitor = {
353         .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
354         .name = "Monitor Playback Volume",
355         .index = 0,
356         .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
357         .info = snd_podhd_control_monitor_info,
358         .get = snd_podhd_control_monitor_get,
359         .put = snd_podhd_control_monitor_put
360 };
361 
362 /*
363         Try to init POD HD device.
364 */
365 static int podhd_init(struct usb_line6 *line6,
366                       const struct usb_device_id *id)
367 {
368         int err;
369         struct usb_line6_podhd *pod = line6_to_podhd(line6);
370         struct usb_interface *intf;
371 
372         line6->disconnect = podhd_disconnect;
373         line6->startup = podhd_startup;
374 
375         if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
376                 /* claim the data interface */
377                 intf = usb_ifnum_to_if(line6->usbdev,
378                                         pod->line6.properties->ctrl_if);
379                 if (!intf) {
380                         dev_err(pod->line6.ifcdev, "interface %d not found\n",
381                                 pod->line6.properties->ctrl_if);
382                         return -ENODEV;
383                 }
384 
385                 err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
386                 if (err != 0) {
387                         dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
388                                 pod->line6.properties->ctrl_if, err);
389                         return err;
390                 }
391         }
392 
393         if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
394                 /* create sysfs entries: */
395                 err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
396                 if (err < 0)
397                         return err;
398         }
399 
400         if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
401                 /* initialize PCM subsystem: */
402                 err = line6_init_pcm(line6,
403                         (id->driver_info == LINE6_PODX3 ||
404                         id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
405                         &podhd_pcm_properties);
406                 if (err < 0)
407                         return err;
408         }
409 
410         if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
411                 podhd_set_monitor_level(pod, 100);
412                 err = snd_ctl_add(line6->card,
413                                   snd_ctl_new1(&podhd_control_monitor,
414                                                line6->line6pcm));
415                 if (err < 0)
416                         return err;
417         }
418 
419         if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
420                 /* register USB audio system directly */
421                 return snd_card_register(line6->card);
422         }
423 
424         /* init device and delay registering */
425         schedule_delayed_work(&line6->startup_work,
426                               msecs_to_jiffies(PODHD_STARTUP_DELAY));
427         return 0;
428 }
429 
430 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
431 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
432 
433 /* table of devices that work with this driver */
434 static const struct usb_device_id podhd_id_table[] = {
435         /* TODO: no need to alloc data interfaces when only audio is used */
436         { LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
437         { LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
438         { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
439         { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
440         { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
441         { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
442         { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
443         {}
444 };
445 
446 MODULE_DEVICE_TABLE(usb, podhd_id_table);
447 
448 static const struct line6_properties podhd_properties_table[] = {
449         [LINE6_PODHD300] = {
450                 .id = "PODHD300",
451                 .name = "POD HD300",
452                 .capabilities   = LINE6_CAP_PCM
453                                 | LINE6_CAP_HWMON,
454                 .altsetting = 5,
455                 .ep_ctrl_r = 0x84,
456                 .ep_ctrl_w = 0x03,
457                 .ep_audio_r = 0x82,
458                 .ep_audio_w = 0x01,
459         },
460         [LINE6_PODHD400] = {
461                 .id = "PODHD400",
462                 .name = "POD HD400",
463                 .capabilities   = LINE6_CAP_PCM
464                                 | LINE6_CAP_HWMON,
465                 .altsetting = 5,
466                 .ep_ctrl_r = 0x84,
467                 .ep_ctrl_w = 0x03,
468                 .ep_audio_r = 0x82,
469                 .ep_audio_w = 0x01,
470         },
471         [LINE6_PODHD500] = {
472                 .id = "PODHD500",
473                 .name = "POD HD500",
474                 .capabilities   = LINE6_CAP_PCM | LINE6_CAP_CONTROL
475                                 | LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
476                 .altsetting = 1,
477                 .ctrl_if = 1,
478                 .ep_ctrl_r = 0x81,
479                 .ep_ctrl_w = 0x01,
480                 .ep_audio_r = 0x86,
481                 .ep_audio_w = 0x02,
482         },
483         [LINE6_PODX3] = {
484                 .id = "PODX3",
485                 .name = "POD X3",
486                 .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
487                                 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
488                 .altsetting = 1,
489                 .ep_ctrl_r = 0x81,
490                 .ep_ctrl_w = 0x01,
491                 .ctrl_if = 1,
492                 .ep_audio_r = 0x86,
493                 .ep_audio_w = 0x02,
494         },
495         [LINE6_PODX3LIVE] = {
496                 .id = "PODX3LIVE",
497                 .name = "POD X3 LIVE",
498                 .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
499                                 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
500                 .altsetting = 1,
501                 .ep_ctrl_r = 0x81,
502                 .ep_ctrl_w = 0x01,
503                 .ctrl_if = 1,
504                 .ep_audio_r = 0x86,
505                 .ep_audio_w = 0x02,
506         },
507         [LINE6_PODHD500X] = {
508                 .id = "PODHD500X",
509                 .name = "POD HD500X",
510                 .capabilities   = LINE6_CAP_CONTROL | LINE6_CAP_HWMON_CTL
511                                 | LINE6_CAP_PCM | LINE6_CAP_HWMON,
512                 .altsetting = 1,
513                 .ep_ctrl_r = 0x81,
514                 .ep_ctrl_w = 0x01,
515                 .ctrl_if = 1,
516                 .ep_audio_r = 0x86,
517                 .ep_audio_w = 0x02,
518         },
519         [LINE6_PODHDDESKTOP] = {
520                 .id = "PODHDDESKTOP",
521                 .name = "POD HDDESKTOP",
522                 .capabilities    = LINE6_CAP_CONTROL
523                         | LINE6_CAP_PCM | LINE6_CAP_HWMON,
524                 .altsetting = 1,
525                 .ep_ctrl_r = 0x81,
526                 .ep_ctrl_w = 0x01,
527                 .ctrl_if = 1,
528                 .ep_audio_r = 0x86,
529                 .ep_audio_w = 0x02,
530         },
531 };
532 
533 /*
534         Probe USB device.
535 */
536 static int podhd_probe(struct usb_interface *interface,
537                        const struct usb_device_id *id)
538 {
539         return line6_probe(interface, id, "Line6-PODHD",
540                            &podhd_properties_table[id->driver_info],
541                            podhd_init, sizeof(struct usb_line6_podhd));
542 }
543 
544 static struct usb_driver podhd_driver = {
545         .name = KBUILD_MODNAME,
546         .probe = podhd_probe,
547         .disconnect = line6_disconnect,
548 #ifdef CONFIG_PM
549         .suspend = line6_suspend,
550         .resume = line6_resume,
551         .reset_resume = line6_resume,
552 #endif
553         .id_table = podhd_id_table,
554 };
555 
556 module_usb_driver(podhd_driver);
557 
558 MODULE_DESCRIPTION("Line 6 PODHD USB driver");
559 MODULE_LICENSE("GPL");
560 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php