diff options
Diffstat (limited to 'sound/usb/line6/toneport.c')
-rw-r--r-- | sound/usb/line6/toneport.c | 216 |
1 files changed, 113 insertions, 103 deletions
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c index c1f61cde52ab..819e06b3f3db 100644 --- a/sound/usb/line6/toneport.c +++ b/sound/usb/line6/toneport.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/usb.h> | 14 | #include <linux/usb.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/leds.h> | ||
17 | #include <sound/core.h> | 18 | #include <sound/core.h> |
18 | #include <sound/control.h> | 19 | #include <sound/control.h> |
19 | 20 | ||
@@ -32,6 +33,15 @@ enum line6_device_type { | |||
32 | LINE6_TONEPORT_UX2, | 33 | LINE6_TONEPORT_UX2, |
33 | }; | 34 | }; |
34 | 35 | ||
36 | struct usb_line6_toneport; | ||
37 | |||
38 | struct toneport_led { | ||
39 | struct led_classdev dev; | ||
40 | char name[64]; | ||
41 | struct usb_line6_toneport *toneport; | ||
42 | bool registered; | ||
43 | }; | ||
44 | |||
35 | struct usb_line6_toneport { | 45 | struct usb_line6_toneport { |
36 | /** | 46 | /** |
37 | Generic Line 6 USB data. | 47 | Generic Line 6 USB data. |
@@ -62,6 +72,9 @@ struct usb_line6_toneport { | |||
62 | Device type. | 72 | Device type. |
63 | */ | 73 | */ |
64 | enum line6_device_type type; | 74 | enum line6_device_type type; |
75 | |||
76 | /* LED instances */ | ||
77 | struct toneport_led leds[2]; | ||
65 | }; | 78 | }; |
66 | 79 | ||
67 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); | 80 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); |
@@ -117,15 +130,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { | |||
117 | .bytes_per_frame = 4 | 130 | .bytes_per_frame = 4 |
118 | }; | 131 | }; |
119 | 132 | ||
120 | /* | ||
121 | For the led on Guitarport. | ||
122 | Brightness goes from 0x00 to 0x26. Set a value above this to have led | ||
123 | blink. | ||
124 | (void cmd_0x02(byte red, byte green) | ||
125 | */ | ||
126 | static int led_red = 0x00; | ||
127 | static int led_green = 0x26; | ||
128 | |||
129 | static const struct { | 133 | static const struct { |
130 | const char *name; | 134 | const char *name; |
131 | int code; | 135 | int code; |
@@ -136,62 +140,6 @@ static const struct { | |||
136 | {"Inst & Mic", 0x0901} | 140 | {"Inst & Mic", 0x0901} |
137 | }; | 141 | }; |
138 | 142 | ||
139 | static bool toneport_has_led(enum line6_device_type type) | ||
140 | { | ||
141 | return | ||
142 | (type == LINE6_GUITARPORT) || | ||
143 | (type == LINE6_TONEPORT_GX); | ||
144 | /* add your device here if you are missing support for the LEDs */ | ||
145 | } | ||
146 | |||
147 | static void toneport_update_led(struct device *dev) | ||
148 | { | ||
149 | struct usb_interface *interface = to_usb_interface(dev); | ||
150 | struct usb_line6_toneport *tp = usb_get_intfdata(interface); | ||
151 | struct usb_line6 *line6; | ||
152 | |||
153 | if (!tp) | ||
154 | return; | ||
155 | |||
156 | line6 = &tp->line6; | ||
157 | if (line6) | ||
158 | toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, | ||
159 | led_green); | ||
160 | } | ||
161 | |||
162 | static ssize_t toneport_set_led_red(struct device *dev, | ||
163 | struct device_attribute *attr, | ||
164 | const char *buf, size_t count) | ||
165 | { | ||
166 | int retval; | ||
167 | |||
168 | retval = kstrtoint(buf, 10, &led_red); | ||
169 | if (retval) | ||
170 | return retval; | ||
171 | |||
172 | toneport_update_led(dev); | ||
173 | return count; | ||
174 | } | ||
175 | |||
176 | static ssize_t toneport_set_led_green(struct device *dev, | ||
177 | struct device_attribute *attr, | ||
178 | const char *buf, size_t count) | ||
179 | { | ||
180 | int retval; | ||
181 | |||
182 | retval = kstrtoint(buf, 10, &led_green); | ||
183 | if (retval) | ||
184 | return retval; | ||
185 | |||
186 | toneport_update_led(dev); | ||
187 | return count; | ||
188 | } | ||
189 | |||
190 | static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, | ||
191 | toneport_set_led_red); | ||
192 | static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, | ||
193 | toneport_set_led_green); | ||
194 | |||
195 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | 143 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) |
196 | { | 144 | { |
197 | int ret; | 145 | int ret; |
@@ -234,16 +182,23 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | |||
234 | struct snd_ctl_elem_value *ucontrol) | 182 | struct snd_ctl_elem_value *ucontrol) |
235 | { | 183 | { |
236 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | 184 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
185 | int err; | ||
237 | 186 | ||
238 | if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) | 187 | if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) |
239 | return 0; | 188 | return 0; |
240 | 189 | ||
241 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | 190 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; |
242 | 191 | ||
243 | if (line6pcm->volume_monitor > 0) | 192 | if (line6pcm->volume_monitor > 0) { |
244 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); | 193 | err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR); |
245 | else | 194 | if (err < 0) { |
246 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); | 195 | line6pcm->volume_monitor = 0; |
196 | line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); | ||
197 | return err; | ||
198 | } | ||
199 | } else { | ||
200 | line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR); | ||
201 | } | ||
247 | 202 | ||
248 | return 1; | 203 | return 1; |
249 | } | 204 | } |
@@ -304,7 +259,7 @@ static void toneport_start_pcm(unsigned long arg) | |||
304 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | 259 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; |
305 | struct usb_line6 *line6 = &toneport->line6; | 260 | struct usb_line6 *line6 = &toneport->line6; |
306 | 261 | ||
307 | line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); | 262 | line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR); |
308 | } | 263 | } |
309 | 264 | ||
310 | /* control definition */ | 265 | /* control definition */ |
@@ -330,6 +285,78 @@ static struct snd_kcontrol_new toneport_control_source = { | |||
330 | }; | 285 | }; |
331 | 286 | ||
332 | /* | 287 | /* |
288 | For the led on Guitarport. | ||
289 | Brightness goes from 0x00 to 0x26. Set a value above this to have led | ||
290 | blink. | ||
291 | (void cmd_0x02(byte red, byte green) | ||
292 | */ | ||
293 | |||
294 | static bool toneport_has_led(enum line6_device_type type) | ||
295 | { | ||
296 | return | ||
297 | (type == LINE6_GUITARPORT) || | ||
298 | (type == LINE6_TONEPORT_GX); | ||
299 | /* add your device here if you are missing support for the LEDs */ | ||
300 | } | ||
301 | |||
302 | static const char * const led_colors[2] = { "red", "green" }; | ||
303 | static const int led_init_vals[2] = { 0x00, 0x26 }; | ||
304 | |||
305 | static void toneport_update_led(struct usb_line6_toneport *toneport) | ||
306 | { | ||
307 | toneport_send_cmd(toneport->line6.usbdev, | ||
308 | (toneport->leds[0].dev.brightness << 8) | 0x0002, | ||
309 | toneport->leds[1].dev.brightness); | ||
310 | } | ||
311 | |||
312 | static void toneport_led_brightness_set(struct led_classdev *led_cdev, | ||
313 | enum led_brightness brightness) | ||
314 | { | ||
315 | struct toneport_led *leds = | ||
316 | container_of(led_cdev, struct toneport_led, dev); | ||
317 | toneport_update_led(leds->toneport); | ||
318 | } | ||
319 | |||
320 | static int toneport_init_leds(struct usb_line6_toneport *toneport) | ||
321 | { | ||
322 | struct device *dev = &toneport->line6.usbdev->dev; | ||
323 | int i, err; | ||
324 | |||
325 | for (i = 0; i < 2; i++) { | ||
326 | struct toneport_led *led = &toneport->leds[i]; | ||
327 | struct led_classdev *leddev = &led->dev; | ||
328 | |||
329 | led->toneport = toneport; | ||
330 | snprintf(led->name, sizeof(led->name), "%s::%s", | ||
331 | dev_name(dev), led_colors[i]); | ||
332 | leddev->name = led->name; | ||
333 | leddev->brightness = led_init_vals[i]; | ||
334 | leddev->max_brightness = 0x26; | ||
335 | leddev->brightness_set = toneport_led_brightness_set; | ||
336 | err = led_classdev_register(dev, leddev); | ||
337 | if (err) | ||
338 | return err; | ||
339 | led->registered = true; | ||
340 | } | ||
341 | |||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static void toneport_remove_leds(struct usb_line6_toneport *toneport) | ||
346 | { | ||
347 | struct toneport_led *led; | ||
348 | int i; | ||
349 | |||
350 | for (i = 0; i < 2; i++) { | ||
351 | led = &toneport->leds[i]; | ||
352 | if (!led->registered) | ||
353 | break; | ||
354 | led_classdev_unregister(&led->dev); | ||
355 | led->registered = false; | ||
356 | } | ||
357 | } | ||
358 | |||
359 | /* | ||
333 | Setup Toneport device. | 360 | Setup Toneport device. |
334 | */ | 361 | */ |
335 | static void toneport_setup(struct usb_line6_toneport *toneport) | 362 | static void toneport_setup(struct usb_line6_toneport *toneport) |
@@ -359,42 +386,38 @@ static void toneport_setup(struct usb_line6_toneport *toneport) | |||
359 | } | 386 | } |
360 | 387 | ||
361 | if (toneport_has_led(toneport->type)) | 388 | if (toneport_has_led(toneport->type)) |
362 | toneport_update_led(&usbdev->dev); | 389 | toneport_update_led(toneport); |
390 | |||
391 | mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); | ||
363 | } | 392 | } |
364 | 393 | ||
365 | /* | 394 | /* |
366 | Toneport device disconnected. | 395 | Toneport device disconnected. |
367 | */ | 396 | */ |
368 | static void line6_toneport_disconnect(struct usb_interface *interface) | 397 | static void line6_toneport_disconnect(struct usb_line6 *line6) |
369 | { | 398 | { |
370 | struct usb_line6_toneport *toneport; | 399 | struct usb_line6_toneport *toneport = |
371 | u16 idProduct; | 400 | (struct usb_line6_toneport *)line6; |
372 | |||
373 | if (interface == NULL) | ||
374 | return; | ||
375 | 401 | ||
376 | toneport = usb_get_intfdata(interface); | ||
377 | del_timer_sync(&toneport->timer); | 402 | del_timer_sync(&toneport->timer); |
378 | idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); | ||
379 | 403 | ||
380 | if (toneport_has_led(idProduct)) { | 404 | if (toneport_has_led(toneport->type)) |
381 | device_remove_file(&interface->dev, &dev_attr_led_red); | 405 | toneport_remove_leds(toneport); |
382 | device_remove_file(&interface->dev, &dev_attr_led_green); | ||
383 | } | ||
384 | } | 406 | } |
385 | 407 | ||
386 | 408 | ||
387 | /* | 409 | /* |
388 | Try to init Toneport device. | 410 | Try to init Toneport device. |
389 | */ | 411 | */ |
390 | static int toneport_init(struct usb_interface *interface, | 412 | static int toneport_init(struct usb_line6 *line6, |
391 | struct usb_line6 *line6) | 413 | const struct usb_device_id *id) |
392 | { | 414 | { |
393 | int err; | 415 | int err; |
394 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; | 416 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; |
395 | 417 | ||
396 | if ((interface == NULL) || (toneport == NULL)) | 418 | toneport->type = id->driver_info; |
397 | return -ENODEV; | 419 | setup_timer(&toneport->timer, toneport_start_pcm, |
420 | (unsigned long)toneport); | ||
398 | 421 | ||
399 | line6->disconnect = line6_toneport_disconnect; | 422 | line6->disconnect = line6_toneport_disconnect; |
400 | 423 | ||
@@ -431,20 +454,13 @@ static int toneport_init(struct usb_interface *interface, | |||
431 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); | 454 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); |
432 | 455 | ||
433 | if (toneport_has_led(toneport->type)) { | 456 | if (toneport_has_led(toneport->type)) { |
434 | err = device_create_file(&interface->dev, &dev_attr_led_red); | 457 | err = toneport_init_leds(toneport); |
435 | if (err < 0) | ||
436 | return err; | ||
437 | err = device_create_file(&interface->dev, &dev_attr_led_green); | ||
438 | if (err < 0) | 458 | if (err < 0) |
439 | return err; | 459 | return err; |
440 | } | 460 | } |
441 | 461 | ||
442 | toneport_setup(toneport); | 462 | toneport_setup(toneport); |
443 | 463 | ||
444 | setup_timer(&toneport->timer, toneport_start_pcm, | ||
445 | (unsigned long)toneport); | ||
446 | mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); | ||
447 | |||
448 | /* register audio system: */ | 464 | /* register audio system: */ |
449 | return snd_card_register(line6->card); | 465 | return snd_card_register(line6->card); |
450 | } | 466 | } |
@@ -549,15 +565,9 @@ static const struct line6_properties toneport_properties_table[] = { | |||
549 | static int toneport_probe(struct usb_interface *interface, | 565 | static int toneport_probe(struct usb_interface *interface, |
550 | const struct usb_device_id *id) | 566 | const struct usb_device_id *id) |
551 | { | 567 | { |
552 | struct usb_line6_toneport *toneport; | 568 | return line6_probe(interface, id, |
553 | |||
554 | toneport = kzalloc(sizeof(*toneport), GFP_KERNEL); | ||
555 | if (!toneport) | ||
556 | return -ENODEV; | ||
557 | toneport->type = id->driver_info; | ||
558 | return line6_probe(interface, &toneport->line6, | ||
559 | &toneport_properties_table[id->driver_info], | 569 | &toneport_properties_table[id->driver_info], |
560 | toneport_init); | 570 | toneport_init, sizeof(struct usb_line6_toneport)); |
561 | } | 571 | } |
562 | 572 | ||
563 | static struct usb_driver toneport_driver = { | 573 | static struct usb_driver toneport_driver = { |