2
2
* Line 6 Pod HD
3
3
*
4
4
* Copyright (C) 2011 Stefan Hajnoczi <[email protected] >
5
+ * Copyright (C) 2015 Andrej Krutak <[email protected] >
5
6
*
6
7
* This program is free software; you can redistribute it and/or
7
8
* modify it under the terms of the GNU General Public License as
18
19
#include "driver.h"
19
20
#include "pcm.h"
20
21
22
+ #define PODHD_STARTUP_DELAY 500
23
+
24
+ /*
25
+ * Stages of POD startup procedure
26
+ */
27
+ enum {
28
+ PODHD_STARTUP_INIT = 1 ,
29
+ PODHD_STARTUP_SCHEDULE_WORKQUEUE ,
30
+ PODHD_STARTUP_SETUP ,
31
+ PODHD_STARTUP_LAST = PODHD_STARTUP_SETUP - 1
32
+ };
33
+
21
34
enum {
22
35
LINE6_PODHD300 ,
23
36
LINE6_PODHD400 ,
24
37
LINE6_PODHD500_0 ,
25
38
LINE6_PODHD500_1 ,
39
+ LINE6_PODX3 ,
40
+ };
41
+
42
+ struct usb_line6_podhd {
43
+ /* Generic Line 6 USB data */
44
+ struct usb_line6 line6 ;
45
+
46
+ /* Timer for device initialization */
47
+ struct timer_list startup_timer ;
48
+
49
+ /* Work handler for device initialization */
50
+ struct work_struct startup_work ;
51
+
52
+ /* Current progress in startup procedure */
53
+ int startup_progress ;
54
+
55
+ /* Serial number of device */
56
+ u32 serial_number ;
57
+
58
+ /* Firmware version */
59
+ int firmware_version ;
26
60
};
27
61
28
62
static struct snd_ratden podhd_ratden = {
@@ -71,40 +105,249 @@ static struct line6_pcm_properties podhd_pcm_properties = {
71
105
.rates = {
72
106
.nrats = 1 ,
73
107
.rats = & podhd_ratden },
74
- .bytes_per_channel = 3 /* 24bit audio (stereo) */
108
+ .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
75
109
};
76
110
111
+ static struct line6_pcm_properties podx3_pcm_properties = {
112
+ .playback_hw = {
113
+ .info = (SNDRV_PCM_INFO_MMAP |
114
+ SNDRV_PCM_INFO_INTERLEAVED |
115
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
116
+ SNDRV_PCM_INFO_MMAP_VALID |
117
+ SNDRV_PCM_INFO_PAUSE |
118
+ SNDRV_PCM_INFO_SYNC_START ),
119
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE ,
120
+ .rates = SNDRV_PCM_RATE_48000 ,
121
+ .rate_min = 48000 ,
122
+ .rate_max = 48000 ,
123
+ .channels_min = 2 ,
124
+ .channels_max = 2 ,
125
+ .buffer_bytes_max = 60000 ,
126
+ .period_bytes_min = 64 ,
127
+ .period_bytes_max = 8192 ,
128
+ .periods_min = 1 ,
129
+ .periods_max = 1024 },
130
+ .capture_hw = {
131
+ .info = (SNDRV_PCM_INFO_MMAP |
132
+ SNDRV_PCM_INFO_INTERLEAVED |
133
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
134
+ SNDRV_PCM_INFO_MMAP_VALID |
135
+ SNDRV_PCM_INFO_SYNC_START ),
136
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE ,
137
+ .rates = SNDRV_PCM_RATE_48000 ,
138
+ .rate_min = 48000 ,
139
+ .rate_max = 48000 ,
140
+ /* 1+2: Main signal (out), 3+4: Tone 1,
141
+ * 5+6: Tone 2, 7+8: raw
142
+ */
143
+ .channels_min = 8 ,
144
+ .channels_max = 8 ,
145
+ .buffer_bytes_max = 60000 ,
146
+ .period_bytes_min = 64 ,
147
+ .period_bytes_max = 8192 ,
148
+ .periods_min = 1 ,
149
+ .periods_max = 1024 },
150
+ .rates = {
151
+ .nrats = 1 ,
152
+ .rats = & podhd_ratden },
153
+ .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
154
+ };
155
+
156
+ static void podhd_startup_start_workqueue (unsigned long data );
157
+ static void podhd_startup_workqueue (struct work_struct * work );
158
+ static int podhd_startup_finalize (struct usb_line6_podhd * pod );
159
+
160
+ static ssize_t serial_number_show (struct device * dev ,
161
+ struct device_attribute * attr , char * buf )
162
+ {
163
+ struct snd_card * card = dev_to_snd_card (dev );
164
+ struct usb_line6_podhd * pod = card -> private_data ;
165
+
166
+ return sprintf (buf , "%u\n" , pod -> serial_number );
167
+ }
168
+
169
+ static ssize_t firmware_version_show (struct device * dev ,
170
+ struct device_attribute * attr , char * buf )
171
+ {
172
+ struct snd_card * card = dev_to_snd_card (dev );
173
+ struct usb_line6_podhd * pod = card -> private_data ;
174
+
175
+ return sprintf (buf , "%06x\n" , pod -> firmware_version );
176
+ }
177
+
178
+ static DEVICE_ATTR_RO (firmware_version );
179
+ static DEVICE_ATTR_RO (serial_number );
180
+
181
+ static struct attribute * podhd_dev_attrs [] = {
182
+ & dev_attr_firmware_version .attr ,
183
+ & dev_attr_serial_number .attr ,
184
+ NULL
185
+ };
186
+
187
+ static const struct attribute_group podhd_dev_attr_group = {
188
+ .name = "podhd" ,
189
+ .attrs = podhd_dev_attrs ,
190
+ };
191
+
192
+ /*
193
+ * POD X3 startup procedure.
194
+ *
195
+ * May be compatible with other POD HD's, since it's also similar to the
196
+ * previous POD setup. In any case, it doesn't seem to be required for the
197
+ * audio nor bulk interfaces to work.
198
+ */
199
+
200
+ static void podhd_startup (struct usb_line6_podhd * pod )
201
+ {
202
+ CHECK_STARTUP_PROGRESS (pod -> startup_progress , PODHD_STARTUP_INIT );
203
+
204
+ /* delay startup procedure: */
205
+ line6_start_timer (& pod -> startup_timer , PODHD_STARTUP_DELAY ,
206
+ podhd_startup_start_workqueue , (unsigned long )pod );
207
+ }
208
+
209
+ static void podhd_startup_start_workqueue (unsigned long data )
210
+ {
211
+ struct usb_line6_podhd * pod = (struct usb_line6_podhd * )data ;
212
+
213
+ CHECK_STARTUP_PROGRESS (pod -> startup_progress ,
214
+ PODHD_STARTUP_SCHEDULE_WORKQUEUE );
215
+
216
+ /* schedule work for global work queue: */
217
+ schedule_work (& pod -> startup_work );
218
+ }
219
+
220
+ static int podhd_dev_start (struct usb_line6_podhd * pod )
221
+ {
222
+ int ret ;
223
+ u8 init_bytes [8 ];
224
+ int i ;
225
+ struct usb_device * usbdev = pod -> line6 .usbdev ;
226
+
227
+ ret = usb_control_msg (usbdev , usb_sndctrlpipe (usbdev , 0 ),
228
+ 0x67 , USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT ,
229
+ 0x11 , 0 ,
230
+ NULL , 0 , LINE6_TIMEOUT * HZ );
231
+ if (ret < 0 ) {
232
+ dev_err (pod -> line6 .ifcdev , "read request failed (error %d)\n" , ret );
233
+ return ret ;
234
+ }
235
+
236
+ /* NOTE: looks like some kind of ping message */
237
+ ret = usb_control_msg (usbdev , usb_rcvctrlpipe (usbdev , 0 ), 0x67 ,
238
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN ,
239
+ 0x11 , 0x0 ,
240
+ & init_bytes , 3 , LINE6_TIMEOUT * HZ );
241
+ if (ret < 0 ) {
242
+ dev_err (pod -> line6 .ifcdev ,
243
+ "receive length failed (error %d)\n" , ret );
244
+ return ret ;
245
+ }
246
+
247
+ pod -> firmware_version =
248
+ (init_bytes [0 ] << 16 ) | (init_bytes [1 ] << 8 ) | (init_bytes [2 ] << 0 );
249
+
250
+ for (i = 0 ; i <= 16 ; i ++ ) {
251
+ ret = line6_read_data (& pod -> line6 , 0xf000 + 0x08 * i , init_bytes , 8 );
252
+ if (ret < 0 )
253
+ return ret ;
254
+ }
255
+
256
+ ret = usb_control_msg (usbdev , usb_sndctrlpipe (usbdev , 0 ),
257
+ USB_REQ_SET_FEATURE ,
258
+ USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT ,
259
+ 1 , 0 ,
260
+ NULL , 0 , LINE6_TIMEOUT * HZ );
261
+ if (ret < 0 )
262
+ return ret ;
263
+
264
+ return 0 ;
265
+ }
266
+
267
+ static void podhd_startup_workqueue (struct work_struct * work )
268
+ {
269
+ struct usb_line6_podhd * pod =
270
+ container_of (work , struct usb_line6_podhd , startup_work );
271
+
272
+ CHECK_STARTUP_PROGRESS (pod -> startup_progress , PODHD_STARTUP_SETUP );
273
+
274
+ podhd_dev_start (pod );
275
+ line6_read_serial_number (& pod -> line6 , & pod -> serial_number );
276
+
277
+ podhd_startup_finalize (pod );
278
+ }
279
+
280
+ static int podhd_startup_finalize (struct usb_line6_podhd * pod )
281
+ {
282
+ struct usb_line6 * line6 = & pod -> line6 ;
283
+
284
+ /* ALSA audio interface: */
285
+ return snd_card_register (line6 -> card );
286
+ }
287
+
288
+ static void podhd_disconnect (struct usb_line6 * line6 )
289
+ {
290
+ struct usb_line6_podhd * pod = (struct usb_line6_podhd * )line6 ;
291
+
292
+ if (pod -> line6 .properties -> capabilities & LINE6_CAP_CONTROL ) {
293
+ del_timer_sync (& pod -> startup_timer );
294
+ cancel_work_sync (& pod -> startup_work );
295
+ }
296
+ }
297
+
77
298
/*
78
299
Try to init POD HD device.
79
300
*/
80
301
static int podhd_init (struct usb_line6 * line6 ,
81
302
const struct usb_device_id * id )
82
303
{
83
304
int err ;
305
+ struct usb_line6_podhd * pod = (struct usb_line6_podhd * ) line6 ;
306
+
307
+ line6 -> disconnect = podhd_disconnect ;
308
+
309
+ if (pod -> line6 .properties -> capabilities & LINE6_CAP_CONTROL ) {
310
+ /* create sysfs entries: */
311
+ err = snd_card_add_dev_attr (line6 -> card , & podhd_dev_attr_group );
312
+ if (err < 0 )
313
+ return err ;
314
+ }
84
315
85
316
/* initialize MIDI subsystem: */
86
317
err = line6_init_midi (line6 );
87
318
if (err < 0 )
88
319
return err ;
89
320
90
321
/* initialize PCM subsystem: */
91
- err = line6_init_pcm (line6 , & podhd_pcm_properties );
322
+ err = line6_init_pcm (line6 ,
323
+ (id -> driver_info == LINE6_PODX3 ) ? & podx3_pcm_properties :
324
+ & podhd_pcm_properties );
92
325
if (err < 0 )
93
326
return err ;
94
327
95
- /* register USB audio system: */
96
- return snd_card_register (line6 -> card );
328
+ if (!(pod -> line6 .properties -> capabilities & LINE6_CAP_CONTROL )) {
329
+ /* register USB audio system directly */
330
+ return podhd_startup_finalize (pod );
331
+ }
332
+
333
+ /* init device and delay registering */
334
+ init_timer (& pod -> startup_timer );
335
+ INIT_WORK (& pod -> startup_work , podhd_startup_workqueue );
336
+ podhd_startup (pod );
337
+ return 0 ;
97
338
}
98
339
99
340
#define LINE6_DEVICE (prod ) USB_DEVICE(0x0e41, prod)
100
341
#define LINE6_IF_NUM (prod , n ) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
101
342
102
343
/* table of devices that work with this driver */
103
344
static const struct usb_device_id podhd_id_table [] = {
345
+ /* TODO: no need to alloc data interfaces when only audio is used */
104
346
{ LINE6_DEVICE (0x5057 ), .driver_info = LINE6_PODHD300 },
105
347
{ LINE6_DEVICE (0x5058 ), .driver_info = LINE6_PODHD400 },
106
348
{ LINE6_IF_NUM (0x414D , 0 ), .driver_info = LINE6_PODHD500_0 },
107
349
{ LINE6_IF_NUM (0x414D , 1 ), .driver_info = LINE6_PODHD500_1 },
350
+ { LINE6_IF_NUM (0x414A , 0 ), .driver_info = LINE6_PODX3 },
108
351
{}
109
352
};
110
353
@@ -114,8 +357,7 @@ static const struct line6_properties podhd_properties_table[] = {
114
357
[LINE6_PODHD300 ] = {
115
358
.id = "PODHD300" ,
116
359
.name = "POD HD300" ,
117
- .capabilities = LINE6_CAP_CONTROL
118
- | LINE6_CAP_PCM
360
+ .capabilities = LINE6_CAP_PCM
119
361
| LINE6_CAP_HWMON ,
120
362
.altsetting = 5 ,
121
363
.ep_ctrl_r = 0x84 ,
@@ -126,8 +368,7 @@ static const struct line6_properties podhd_properties_table[] = {
126
368
[LINE6_PODHD400 ] = {
127
369
.id = "PODHD400" ,
128
370
.name = "POD HD400" ,
129
- .capabilities = LINE6_CAP_CONTROL
130
- | LINE6_CAP_PCM
371
+ .capabilities = LINE6_CAP_PCM
131
372
| LINE6_CAP_HWMON ,
132
373
.altsetting = 5 ,
133
374
.ep_ctrl_r = 0x84 ,
@@ -138,8 +379,7 @@ static const struct line6_properties podhd_properties_table[] = {
138
379
[LINE6_PODHD500_0 ] = {
139
380
.id = "PODHD500" ,
140
381
.name = "POD HD500" ,
141
- .capabilities = LINE6_CAP_CONTROL
142
- | LINE6_CAP_PCM
382
+ .capabilities = LINE6_CAP_PCM
143
383
| LINE6_CAP_HWMON ,
144
384
.altsetting = 1 ,
145
385
.ep_ctrl_r = 0x81 ,
@@ -150,15 +390,25 @@ static const struct line6_properties podhd_properties_table[] = {
150
390
[LINE6_PODHD500_1 ] = {
151
391
.id = "PODHD500" ,
152
392
.name = "POD HD500" ,
153
- .capabilities = LINE6_CAP_CONTROL
154
- | LINE6_CAP_PCM
393
+ .capabilities = LINE6_CAP_PCM
155
394
| LINE6_CAP_HWMON ,
156
395
.altsetting = 1 ,
157
396
.ep_ctrl_r = 0x81 ,
158
397
.ep_ctrl_w = 0x01 ,
159
398
.ep_audio_r = 0x86 ,
160
399
.ep_audio_w = 0x02 ,
161
400
},
401
+ [LINE6_PODX3 ] = {
402
+ .id = "PODX3" ,
403
+ .name = "POD X3" ,
404
+ .capabilities = LINE6_CAP_CONTROL
405
+ | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT ,
406
+ .altsetting = 1 ,
407
+ .ep_ctrl_r = 0x81 ,
408
+ .ep_ctrl_w = 0x01 ,
409
+ .ep_audio_r = 0x86 ,
410
+ .ep_audio_w = 0x02 ,
411
+ },
162
412
};
163
413
164
414
/*
@@ -169,7 +419,7 @@ static int podhd_probe(struct usb_interface *interface,
169
419
{
170
420
return line6_probe (interface , id , "Line6-PODHD" ,
171
421
& podhd_properties_table [id -> driver_info ],
172
- podhd_init , sizeof (struct usb_line6 ));
422
+ podhd_init , sizeof (struct usb_line6_podhd ));
173
423
}
174
424
175
425
static struct usb_driver podhd_driver = {
0 commit comments