diff options
author | Markus Grabner <grabner@icg.tugraz.at> | 2010-08-11 19:35:30 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-08-31 18:28:15 -0400 |
commit | 1027f476f507ef7ed9919cd3e3d32310f3985da1 (patch) | |
tree | 5f0da58a5bc15338c71e848693a5ae259b97a207 /drivers/staging/line6/toneport.c | |
parent | 4498dbcd2d85b67e9f46790bcfee5860d2dd1762 (diff) |
staging: line6: sync with upstream
Big upstream sync.
Signed-off-by: Markus Grabner <grabner@icg.tugraz.at>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/staging/line6/toneport.c')
-rw-r--r-- | drivers/staging/line6/toneport.c | 337 |
1 files changed, 268 insertions, 69 deletions
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c index e6770ea1793..0e7e871507c 100644 --- a/drivers/staging/line6/toneport.c +++ b/drivers/staging/line6/toneport.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * Line6 Linux USB driver - 0.8.0 | 2 | * Line6 Linux USB driver - 0.9.0 |
3 | * | 3 | * |
4 | * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at) | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
5 | * Emil Myhrman (emil.myhrman@gmail.com) | 5 | * Emil Myhrman (emil.myhrman@gmail.com) |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or | 7 | * This program is free software; you can redistribute it and/or |
@@ -10,15 +10,22 @@ | |||
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include "driver.h" | 13 | #include <linux/wait.h> |
14 | #include <sound/control.h> | ||
14 | 15 | ||
15 | #include "audio.h" | 16 | #include "audio.h" |
16 | #include "capture.h" | 17 | #include "capture.h" |
18 | #include "driver.h" | ||
17 | #include "playback.h" | 19 | #include "playback.h" |
18 | #include "toneport.h" | 20 | #include "toneport.h" |
19 | 21 | ||
22 | |||
20 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); | 23 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); |
21 | 24 | ||
25 | |||
26 | #define TONEPORT_PCM_DELAY 1 | ||
27 | |||
28 | |||
22 | static struct snd_ratden toneport_ratden = { | 29 | static struct snd_ratden toneport_ratden = { |
23 | .num_min = 44100, | 30 | .num_min = 44100, |
24 | .num_max = 44100, | 31 | .num_max = 44100, |
@@ -28,43 +35,52 @@ static struct snd_ratden toneport_ratden = { | |||
28 | 35 | ||
29 | static struct line6_pcm_properties toneport_pcm_properties = { | 36 | static struct line6_pcm_properties toneport_pcm_properties = { |
30 | .snd_line6_playback_hw = { | 37 | .snd_line6_playback_hw = { |
31 | .info = (SNDRV_PCM_INFO_MMAP | | 38 | .info = (SNDRV_PCM_INFO_MMAP | |
32 | SNDRV_PCM_INFO_INTERLEAVED | | 39 | SNDRV_PCM_INFO_INTERLEAVED | |
33 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 40 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
34 | SNDRV_PCM_INFO_MMAP_VALID | | 41 | SNDRV_PCM_INFO_MMAP_VALID | |
35 | SNDRV_PCM_INFO_PAUSE | | 42 | SNDRV_PCM_INFO_PAUSE | |
36 | SNDRV_PCM_INFO_SYNC_START), | 43 | #ifdef CONFIG_PM |
37 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 44 | SNDRV_PCM_INFO_RESUME | |
38 | .rates = SNDRV_PCM_RATE_KNOT, | 45 | #endif |
39 | .rate_min = 44100, | 46 | SNDRV_PCM_INFO_SYNC_START), |
40 | .rate_max = 44100, | 47 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
41 | .channels_min = 2, | 48 | .rates = SNDRV_PCM_RATE_KNOT, |
42 | .channels_max = 2, | 49 | .rate_min = 44100, |
43 | .buffer_bytes_max = 60000, | 50 | .rate_max = 44100, |
44 | .period_bytes_min = 180 * 4, | 51 | .channels_min = 2, |
45 | .period_bytes_max = 8192, | 52 | .channels_max = 2, |
46 | .periods_min = 1, | 53 | .buffer_bytes_max = 60000, |
47 | .periods_max = 1024}, | 54 | .period_bytes_min = 64, |
55 | .period_bytes_max = 8192, | ||
56 | .periods_min = 1, | ||
57 | .periods_max = 1024 | ||
58 | }, | ||
48 | .snd_line6_capture_hw = { | 59 | .snd_line6_capture_hw = { |
49 | .info = (SNDRV_PCM_INFO_MMAP | | 60 | .info = (SNDRV_PCM_INFO_MMAP | |
50 | SNDRV_PCM_INFO_INTERLEAVED | | 61 | SNDRV_PCM_INFO_INTERLEAVED | |
51 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 62 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
52 | SNDRV_PCM_INFO_MMAP_VALID | | 63 | SNDRV_PCM_INFO_MMAP_VALID | |
53 | SNDRV_PCM_INFO_SYNC_START), | 64 | #ifdef CONFIG_PM |
54 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 65 | SNDRV_PCM_INFO_RESUME | |
55 | .rates = SNDRV_PCM_RATE_KNOT, | 66 | #endif |
56 | .rate_min = 44100, | 67 | SNDRV_PCM_INFO_SYNC_START), |
57 | .rate_max = 44100, | 68 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
58 | .channels_min = 2, | 69 | .rates = SNDRV_PCM_RATE_KNOT, |
59 | .channels_max = 2, | 70 | .rate_min = 44100, |
60 | .buffer_bytes_max = 60000, | 71 | .rate_max = 44100, |
61 | .period_bytes_min = 188 * 4, | 72 | .channels_min = 2, |
62 | .period_bytes_max = 8192, | 73 | .channels_max = 2, |
63 | .periods_min = 1, | 74 | .buffer_bytes_max = 60000, |
64 | .periods_max = 1024}, | 75 | .period_bytes_min = 64, |
76 | .period_bytes_max = 8192, | ||
77 | .periods_min = 1, | ||
78 | .periods_max = 1024 | ||
79 | }, | ||
65 | .snd_line6_rates = { | 80 | .snd_line6_rates = { |
66 | .nrats = 1, | 81 | .nrats = 1, |
67 | .rats = &toneport_ratden}, | 82 | .rats = &toneport_ratden |
83 | }, | ||
68 | .bytes_per_frame = 4 | 84 | .bytes_per_frame = 4 |
69 | }; | 85 | }; |
70 | 86 | ||
@@ -77,6 +93,27 @@ static struct line6_pcm_properties toneport_pcm_properties = { | |||
77 | static int led_red = 0x00; | 93 | static int led_red = 0x00; |
78 | static int led_green = 0x26; | 94 | static int led_green = 0x26; |
79 | 95 | ||
96 | struct ToneportSourceInfo | ||
97 | { | ||
98 | const char *name; | ||
99 | int code; | ||
100 | }; | ||
101 | |||
102 | static const struct ToneportSourceInfo toneport_source_info[] = { | ||
103 | { "Microphone", 0x0a01 }, | ||
104 | { "Line" , 0x0801 }, | ||
105 | { "Instrument", 0x0b01 }, | ||
106 | { "Inst & Mic", 0x0901 } | ||
107 | }; | ||
108 | |||
109 | static bool toneport_has_led(short product) | ||
110 | { | ||
111 | return | ||
112 | (product == LINE6_DEVID_GUITARPORT) || | ||
113 | (product == LINE6_DEVID_TONEPORT_GX); | ||
114 | /* add your device here if you are missing support for the LEDs */ | ||
115 | } | ||
116 | |||
80 | static void toneport_update_led(struct device *dev) | 117 | static void toneport_update_led(struct device *dev) |
81 | { | 118 | { |
82 | struct usb_interface *interface = to_usb_interface(dev); | 119 | struct usb_interface *interface = to_usb_interface(dev); |
@@ -129,6 +166,7 @@ static DEVICE_ATTR(led_red, S_IWUGO | S_IRUGO, line6_nop_read, | |||
129 | static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read, | 166 | static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read, |
130 | toneport_set_led_green); | 167 | toneport_set_led_green); |
131 | 168 | ||
169 | |||
132 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | 170 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) |
133 | { | 171 | { |
134 | int ret; | 172 | int ret; |
@@ -145,6 +183,111 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | |||
145 | return 0; | 183 | return 0; |
146 | } | 184 | } |
147 | 185 | ||
186 | /* monitor info callback */ | ||
187 | static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, | ||
188 | struct snd_ctl_elem_info *uinfo) | ||
189 | { | ||
190 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
191 | uinfo->count = 1; | ||
192 | uinfo->value.integer.min = 0; | ||
193 | uinfo->value.integer.max = 256; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* monitor get callback */ | ||
198 | static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, | ||
199 | struct snd_ctl_elem_value *ucontrol) | ||
200 | { | ||
201 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
202 | ucontrol->value.integer.value[0] = line6pcm->volume_monitor; | ||
203 | return 0; | ||
204 | } | ||
205 | |||
206 | /* monitor put callback */ | ||
207 | static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | ||
208 | struct snd_ctl_elem_value *ucontrol) | ||
209 | { | ||
210 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
211 | |||
212 | if(ucontrol->value.integer.value[0] == line6pcm->volume_monitor) | ||
213 | return 0; | ||
214 | |||
215 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | ||
216 | return 1; | ||
217 | } | ||
218 | |||
219 | /* source info callback */ | ||
220 | static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, | ||
221 | struct snd_ctl_elem_info *uinfo) | ||
222 | { | ||
223 | const int size = ARRAY_SIZE(toneport_source_info); | ||
224 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
225 | uinfo->count = 1; | ||
226 | uinfo->value.enumerated.items = size; | ||
227 | |||
228 | if(uinfo->value.enumerated.item >= size) | ||
229 | uinfo->value.enumerated.item = size - 1; | ||
230 | |||
231 | strcpy(uinfo->value.enumerated.name, | ||
232 | toneport_source_info[uinfo->value.enumerated.item].name); | ||
233 | |||
234 | return 0; | ||
235 | } | ||
236 | |||
237 | /* source get callback */ | ||
238 | static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, | ||
239 | struct snd_ctl_elem_value *ucontrol) | ||
240 | { | ||
241 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
242 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)line6pcm->line6; | ||
243 | ucontrol->value.enumerated.item[0] = toneport->source; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | /* source put callback */ | ||
248 | static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, | ||
249 | struct snd_ctl_elem_value *ucontrol) | ||
250 | { | ||
251 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | ||
252 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)line6pcm->line6; | ||
253 | |||
254 | if(ucontrol->value.enumerated.item[0] == toneport->source) | ||
255 | return 0; | ||
256 | |||
257 | toneport->source = ucontrol->value.enumerated.item[0]; | ||
258 | toneport_send_cmd(toneport->line6.usbdev, toneport_source_info[toneport->source].code, 0x0000); | ||
259 | return 1; | ||
260 | } | ||
261 | |||
262 | static void toneport_start_pcm(unsigned long arg) | ||
263 | { | ||
264 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | ||
265 | struct usb_line6 *line6 = &toneport->line6; | ||
266 | line6_pcm_start(line6->line6pcm, MASK_PCM_MONITOR); | ||
267 | } | ||
268 | |||
269 | /* control definition */ | ||
270 | static struct snd_kcontrol_new toneport_control_monitor = { | ||
271 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
272 | .name = "Monitor Playback Volume", | ||
273 | .index = 0, | ||
274 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
275 | .info = snd_toneport_monitor_info, | ||
276 | .get = snd_toneport_monitor_get, | ||
277 | .put = snd_toneport_monitor_put | ||
278 | }; | ||
279 | |||
280 | /* source selector definition */ | ||
281 | static struct snd_kcontrol_new toneport_control_source = { | ||
282 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
283 | .name = "PCM Capture Source", | ||
284 | .index = 0, | ||
285 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
286 | .info = snd_toneport_source_info, | ||
287 | .get = snd_toneport_source_get, | ||
288 | .put = snd_toneport_source_put | ||
289 | }; | ||
290 | |||
148 | /* | 291 | /* |
149 | Toneport destructor. | 292 | Toneport destructor. |
150 | */ | 293 | */ |
@@ -162,14 +305,41 @@ static void toneport_destruct(struct usb_interface *interface) | |||
162 | } | 305 | } |
163 | 306 | ||
164 | /* | 307 | /* |
165 | Init Toneport device. | 308 | Setup Toneport device. |
166 | */ | 309 | */ |
167 | int toneport_init(struct usb_interface *interface, | 310 | static void toneport_setup(struct usb_line6_toneport *toneport) |
168 | struct usb_line6_toneport *toneport) | ||
169 | { | 311 | { |
170 | int err, ticks; | 312 | int ticks; |
171 | struct usb_line6 *line6 = &toneport->line6; | 313 | struct usb_line6 *line6 = &toneport->line6; |
172 | struct usb_device *usbdev; | 314 | struct usb_device *usbdev = line6->usbdev; |
315 | |||
316 | /* sync time on device with host: */ | ||
317 | ticks = (int)get_seconds(); | ||
318 | line6_write_data(line6, 0x80c6, &ticks, 4); | ||
319 | |||
320 | /* enable device: */ | ||
321 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | ||
322 | |||
323 | /* initialize source select: */ | ||
324 | switch(usbdev->descriptor.idProduct) { | ||
325 | case LINE6_DEVID_TONEPORT_UX1: | ||
326 | case LINE6_DEVID_PODSTUDIO_UX1: | ||
327 | toneport_send_cmd(usbdev, toneport_source_info[toneport->source].code, 0x0000); | ||
328 | } | ||
329 | |||
330 | if (toneport_has_led(usbdev->descriptor.idProduct)) | ||
331 | toneport_update_led(&usbdev->dev); | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | Try to init Toneport device. | ||
336 | */ | ||
337 | static int toneport_try_init(struct usb_interface *interface, | ||
338 | struct usb_line6_toneport *toneport) | ||
339 | { | ||
340 | int err; | ||
341 | struct usb_line6 *line6 = &toneport->line6; | ||
342 | struct usb_device *usbdev = line6->usbdev; | ||
173 | 343 | ||
174 | if ((interface == NULL) || (toneport == NULL)) | 344 | if ((interface == NULL) || (toneport == NULL)) |
175 | return -ENODEV; | 345 | return -ENODEV; |
@@ -177,64 +347,93 @@ int toneport_init(struct usb_interface *interface, | |||
177 | /* initialize audio system: */ | 347 | /* initialize audio system: */ |
178 | err = line6_init_audio(line6); | 348 | err = line6_init_audio(line6); |
179 | if (err < 0) { | 349 | if (err < 0) { |
180 | toneport_destruct(interface); | ||
181 | return err; | 350 | return err; |
182 | } | 351 | } |
183 | 352 | ||
184 | /* initialize PCM subsystem: */ | 353 | /* initialize PCM subsystem: */ |
185 | err = line6_init_pcm(line6, &toneport_pcm_properties); | 354 | err = line6_init_pcm(line6, &toneport_pcm_properties); |
186 | if (err < 0) { | 355 | if (err < 0) { |
187 | toneport_destruct(interface); | ||
188 | return err; | 356 | return err; |
189 | } | 357 | } |
190 | 358 | ||
359 | /* register monitor control: */ | ||
360 | err = snd_ctl_add(line6->card, snd_ctl_new1(&toneport_control_monitor, line6->line6pcm)); | ||
361 | if (err < 0) { | ||
362 | return err; | ||
363 | } | ||
364 | |||
365 | /* register source select control: */ | ||
366 | switch(usbdev->descriptor.idProduct) { | ||
367 | case LINE6_DEVID_TONEPORT_UX1: | ||
368 | case LINE6_DEVID_PODSTUDIO_UX1: | ||
369 | err = snd_ctl_add(line6->card, snd_ctl_new1(&toneport_control_source, line6->line6pcm)); | ||
370 | if (err < 0) { | ||
371 | return err; | ||
372 | } | ||
373 | } | ||
374 | |||
191 | /* register audio system: */ | 375 | /* register audio system: */ |
192 | err = line6_register_audio(line6); | 376 | err = line6_register_audio(line6); |
193 | if (err < 0) { | 377 | if (err < 0) { |
194 | toneport_destruct(interface); | ||
195 | return err; | 378 | return err; |
196 | } | 379 | } |
197 | 380 | ||
198 | usbdev = line6->usbdev; | ||
199 | line6_read_serial_number(line6, &toneport->serial_number); | 381 | line6_read_serial_number(line6, &toneport->serial_number); |
200 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); | 382 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); |
201 | 383 | ||
202 | /* sync time on device with host: */ | 384 | if (toneport_has_led(usbdev->descriptor.idProduct)) { |
203 | ticks = (int)get_seconds(); | 385 | CHECK_RETURN(device_create_file(&interface->dev, &dev_attr_led_red)); |
204 | line6_write_data(line6, 0x80c6, &ticks, 4); | 386 | CHECK_RETURN(device_create_file(&interface->dev, &dev_attr_led_green)); |
387 | } | ||
205 | 388 | ||
206 | /* | 389 | toneport_setup(toneport); |
207 | seems to work without the first two... | ||
208 | */ | ||
209 | /* toneport_send_cmd(usbdev, 0x0201, 0x0002); */ | ||
210 | /* toneport_send_cmd(usbdev, 0x0801, 0x0000); */ | ||
211 | /* only one that works for me; on GP, TP might be different? */ | ||
212 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | ||
213 | 390 | ||
214 | if (usbdev->descriptor.idProduct != LINE6_DEVID_GUITARPORT) { | 391 | init_timer(&toneport->timer); |
215 | CHECK_RETURN(device_create_file | 392 | toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; |
216 | (&interface->dev, &dev_attr_led_red)); | 393 | toneport->timer.function = toneport_start_pcm; |
217 | CHECK_RETURN(device_create_file | 394 | toneport->timer.data = (unsigned long)toneport; |
218 | (&interface->dev, &dev_attr_led_green)); | 395 | add_timer(&toneport->timer); |
219 | toneport_update_led(&usbdev->dev); | ||
220 | } | ||
221 | 396 | ||
222 | return 0; | 397 | return 0; |
223 | } | 398 | } |
224 | 399 | ||
225 | /* | 400 | /* |
401 | Init Toneport device (and clean up in case of failure). | ||
402 | */ | ||
403 | int line6_toneport_init(struct usb_interface *interface, | ||
404 | struct usb_line6_toneport *toneport) | ||
405 | { | ||
406 | int err = toneport_try_init(interface, toneport); | ||
407 | |||
408 | if (err < 0) { | ||
409 | toneport_destruct(interface); | ||
410 | } | ||
411 | |||
412 | return err; | ||
413 | } | ||
414 | |||
415 | /* | ||
416 | Resume Toneport device after reset. | ||
417 | */ | ||
418 | void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) | ||
419 | { | ||
420 | toneport_setup(toneport); | ||
421 | } | ||
422 | |||
423 | /* | ||
226 | Toneport device disconnected. | 424 | Toneport device disconnected. |
227 | */ | 425 | */ |
228 | void toneport_disconnect(struct usb_interface *interface) | 426 | void line6_toneport_disconnect(struct usb_interface *interface) |
229 | { | 427 | { |
230 | struct usb_line6_toneport *toneport; | 428 | struct usb_line6_toneport *toneport; |
231 | 429 | ||
232 | if (interface == NULL) | 430 | if (interface == NULL) |
233 | return; | 431 | return; |
432 | |||
234 | toneport = usb_get_intfdata(interface); | 433 | toneport = usb_get_intfdata(interface); |
434 | del_timer_sync(&toneport->timer); | ||
235 | 435 | ||
236 | if (toneport->line6.usbdev->descriptor.idProduct != | 436 | if (toneport_has_led(toneport->line6.usbdev->descriptor.idProduct)) { |
237 | LINE6_DEVID_GUITARPORT) { | ||
238 | device_remove_file(&interface->dev, &dev_attr_led_red); | 437 | device_remove_file(&interface->dev, &dev_attr_led_red); |
239 | device_remove_file(&interface->dev, &dev_attr_led_green); | 438 | device_remove_file(&interface->dev, &dev_attr_led_green); |
240 | } | 439 | } |
@@ -243,8 +442,8 @@ void toneport_disconnect(struct usb_interface *interface) | |||
243 | struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; | 442 | struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm; |
244 | 443 | ||
245 | if (line6pcm != NULL) { | 444 | if (line6pcm != NULL) { |
246 | unlink_wait_clear_audio_out_urbs(line6pcm); | 445 | line6_pcm_stop(line6pcm, MASK_PCM_MONITOR); |
247 | unlink_wait_clear_audio_in_urbs(line6pcm); | 446 | line6_pcm_disconnect(line6pcm); |
248 | } | 447 | } |
249 | } | 448 | } |
250 | 449 | ||