| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Line 6 Linux USB driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or |
|---|
| 7 | | - * modify it under the terms of the GNU General Public License as |
|---|
| 8 | | - * published by the Free Software Foundation, version 2. |
|---|
| 9 | | - * |
|---|
| 10 | 6 | */ |
|---|
| 11 | 7 | |
|---|
| 12 | 8 | #include <linux/slab.h> |
|---|
| .. | .. |
|---|
| 39 | 35 | Stages of POD startup procedure |
|---|
| 40 | 36 | */ |
|---|
| 41 | 37 | enum { |
|---|
| 42 | | - POD_STARTUP_INIT = 1, |
|---|
| 43 | 38 | POD_STARTUP_VERSIONREQ, |
|---|
| 44 | | - POD_STARTUP_WORKQUEUE, |
|---|
| 45 | 39 | POD_STARTUP_SETUP, |
|---|
| 46 | | - POD_STARTUP_LAST = POD_STARTUP_SETUP - 1 |
|---|
| 40 | + POD_STARTUP_DONE, |
|---|
| 47 | 41 | }; |
|---|
| 48 | 42 | |
|---|
| 49 | 43 | enum { |
|---|
| .. | .. |
|---|
| 63 | 57 | /* Instrument monitor level */ |
|---|
| 64 | 58 | int monitor_level; |
|---|
| 65 | 59 | |
|---|
| 66 | | - /* Timer for device initialization */ |
|---|
| 67 | | - struct timer_list startup_timer; |
|---|
| 68 | | - |
|---|
| 69 | | - /* Work handler for device initialization */ |
|---|
| 70 | | - struct work_struct startup_work; |
|---|
| 71 | | - |
|---|
| 72 | 60 | /* Current progress in startup procedure */ |
|---|
| 73 | 61 | int startup_progress; |
|---|
| 74 | 62 | |
|---|
| .. | .. |
|---|
| 81 | 69 | /* Device ID */ |
|---|
| 82 | 70 | int device_id; |
|---|
| 83 | 71 | }; |
|---|
| 72 | + |
|---|
| 73 | +#define line6_to_pod(x) container_of(x, struct usb_line6_pod, line6) |
|---|
| 84 | 74 | |
|---|
| 85 | 75 | #define POD_SYSEX_CODE 3 |
|---|
| 86 | 76 | |
|---|
| .. | .. |
|---|
| 120 | 110 | POD_BUSY_MIDISEND |
|---|
| 121 | 111 | }; |
|---|
| 122 | 112 | |
|---|
| 123 | | -static struct snd_ratden pod_ratden = { |
|---|
| 113 | +static const struct snd_ratden pod_ratden = { |
|---|
| 124 | 114 | .num_min = 78125, |
|---|
| 125 | 115 | .num_max = 78125, |
|---|
| 126 | 116 | .num_step = 1, |
|---|
| .. | .. |
|---|
| 169 | 159 | .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */ |
|---|
| 170 | 160 | }; |
|---|
| 171 | 161 | |
|---|
| 172 | | -static const char pod_version_header[] = { |
|---|
| 173 | | - 0xf2, 0x7e, 0x7f, 0x06, 0x02 |
|---|
| 174 | | -}; |
|---|
| 175 | 162 | |
|---|
| 176 | | -/* forward declarations: */ |
|---|
| 177 | | -static void pod_startup2(struct timer_list *t); |
|---|
| 178 | | -static void pod_startup3(struct usb_line6_pod *pod); |
|---|
| 163 | +static const char pod_version_header[] = { |
|---|
| 164 | + 0xf0, 0x7e, 0x7f, 0x06, 0x02 |
|---|
| 165 | +}; |
|---|
| 179 | 166 | |
|---|
| 180 | 167 | static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, |
|---|
| 181 | 168 | int size) |
|---|
| .. | .. |
|---|
| 189 | 176 | */ |
|---|
| 190 | 177 | static void line6_pod_process_message(struct usb_line6 *line6) |
|---|
| 191 | 178 | { |
|---|
| 192 | | - struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; |
|---|
| 179 | + struct usb_line6_pod *pod = line6_to_pod(line6); |
|---|
| 193 | 180 | const unsigned char *buf = pod->line6.buffer_message; |
|---|
| 194 | 181 | |
|---|
| 195 | 182 | if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { |
|---|
| 196 | 183 | pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; |
|---|
| 197 | 184 | pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | |
|---|
| 198 | 185 | (int) buf[10]; |
|---|
| 199 | | - pod_startup3(pod); |
|---|
| 186 | + if (pod->startup_progress == POD_STARTUP_VERSIONREQ) { |
|---|
| 187 | + pod->startup_progress = POD_STARTUP_SETUP; |
|---|
| 188 | + schedule_delayed_work(&line6->startup_work, 0); |
|---|
| 189 | + } |
|---|
| 200 | 190 | return; |
|---|
| 201 | 191 | } |
|---|
| 202 | 192 | |
|---|
| .. | .. |
|---|
| 281 | 271 | context). After the last one has finished, the device is ready to use. |
|---|
| 282 | 272 | */ |
|---|
| 283 | 273 | |
|---|
| 284 | | -static void pod_startup1(struct usb_line6_pod *pod) |
|---|
| 274 | +static void pod_startup(struct usb_line6 *line6) |
|---|
| 285 | 275 | { |
|---|
| 286 | | - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); |
|---|
| 276 | + struct usb_line6_pod *pod = line6_to_pod(line6); |
|---|
| 287 | 277 | |
|---|
| 288 | | - /* delay startup procedure: */ |
|---|
| 289 | | - line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2); |
|---|
| 290 | | -} |
|---|
| 278 | + switch (pod->startup_progress) { |
|---|
| 279 | + case POD_STARTUP_VERSIONREQ: |
|---|
| 280 | + /* request firmware version: */ |
|---|
| 281 | + line6_version_request_async(line6); |
|---|
| 282 | + break; |
|---|
| 283 | + case POD_STARTUP_SETUP: |
|---|
| 284 | + /* serial number: */ |
|---|
| 285 | + line6_read_serial_number(&pod->line6, &pod->serial_number); |
|---|
| 291 | 286 | |
|---|
| 292 | | -static void pod_startup2(struct timer_list *t) |
|---|
| 293 | | -{ |
|---|
| 294 | | - struct usb_line6_pod *pod = from_timer(pod, t, startup_timer); |
|---|
| 295 | | - struct usb_line6 *line6 = &pod->line6; |
|---|
| 296 | | - |
|---|
| 297 | | - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); |
|---|
| 298 | | - |
|---|
| 299 | | - /* request firmware version: */ |
|---|
| 300 | | - line6_version_request_async(line6); |
|---|
| 301 | | -} |
|---|
| 302 | | - |
|---|
| 303 | | -static void pod_startup3(struct usb_line6_pod *pod) |
|---|
| 304 | | -{ |
|---|
| 305 | | - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); |
|---|
| 306 | | - |
|---|
| 307 | | - /* schedule work for global work queue: */ |
|---|
| 308 | | - schedule_work(&pod->startup_work); |
|---|
| 309 | | -} |
|---|
| 310 | | - |
|---|
| 311 | | -static void pod_startup4(struct work_struct *work) |
|---|
| 312 | | -{ |
|---|
| 313 | | - struct usb_line6_pod *pod = |
|---|
| 314 | | - container_of(work, struct usb_line6_pod, startup_work); |
|---|
| 315 | | - struct usb_line6 *line6 = &pod->line6; |
|---|
| 316 | | - |
|---|
| 317 | | - CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); |
|---|
| 318 | | - |
|---|
| 319 | | - /* serial number: */ |
|---|
| 320 | | - line6_read_serial_number(&pod->line6, &pod->serial_number); |
|---|
| 321 | | - |
|---|
| 322 | | - /* ALSA audio interface: */ |
|---|
| 323 | | - snd_card_register(line6->card); |
|---|
| 287 | + /* ALSA audio interface: */ |
|---|
| 288 | + if (snd_card_register(line6->card)) |
|---|
| 289 | + dev_err(line6->ifcdev, "Failed to register POD card.\n"); |
|---|
| 290 | + pod->startup_progress = POD_STARTUP_DONE; |
|---|
| 291 | + break; |
|---|
| 292 | + default: |
|---|
| 293 | + break; |
|---|
| 294 | + } |
|---|
| 324 | 295 | } |
|---|
| 325 | 296 | |
|---|
| 326 | 297 | /* POD special files: */ |
|---|
| .. | .. |
|---|
| 356 | 327 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 357 | 328 | { |
|---|
| 358 | 329 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
|---|
| 359 | | - struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; |
|---|
| 330 | + struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6); |
|---|
| 360 | 331 | |
|---|
| 361 | 332 | ucontrol->value.integer.value[0] = pod->monitor_level; |
|---|
| 362 | 333 | return 0; |
|---|
| .. | .. |
|---|
| 367 | 338 | struct snd_ctl_elem_value *ucontrol) |
|---|
| 368 | 339 | { |
|---|
| 369 | 340 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
|---|
| 370 | | - struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; |
|---|
| 341 | + struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6); |
|---|
| 371 | 342 | |
|---|
| 372 | 343 | if (ucontrol->value.integer.value[0] == pod->monitor_level) |
|---|
| 373 | 344 | return 0; |
|---|
| .. | .. |
|---|
| 390 | 361 | }; |
|---|
| 391 | 362 | |
|---|
| 392 | 363 | /* |
|---|
| 393 | | - POD device disconnected. |
|---|
| 394 | | -*/ |
|---|
| 395 | | -static void line6_pod_disconnect(struct usb_line6 *line6) |
|---|
| 396 | | -{ |
|---|
| 397 | | - struct usb_line6_pod *pod = (struct usb_line6_pod *)line6; |
|---|
| 398 | | - |
|---|
| 399 | | - del_timer_sync(&pod->startup_timer); |
|---|
| 400 | | - cancel_work_sync(&pod->startup_work); |
|---|
| 401 | | -} |
|---|
| 402 | | - |
|---|
| 403 | | -/* |
|---|
| 404 | 364 | Try to init POD device. |
|---|
| 405 | 365 | */ |
|---|
| 406 | 366 | static int pod_init(struct usb_line6 *line6, |
|---|
| 407 | 367 | const struct usb_device_id *id) |
|---|
| 408 | 368 | { |
|---|
| 409 | 369 | int err; |
|---|
| 410 | | - struct usb_line6_pod *pod = (struct usb_line6_pod *) line6; |
|---|
| 370 | + struct usb_line6_pod *pod = line6_to_pod(line6); |
|---|
| 411 | 371 | |
|---|
| 412 | 372 | line6->process_message = line6_pod_process_message; |
|---|
| 413 | | - line6->disconnect = line6_pod_disconnect; |
|---|
| 414 | | - |
|---|
| 415 | | - timer_setup(&pod->startup_timer, NULL, 0); |
|---|
| 416 | | - INIT_WORK(&pod->startup_work, pod_startup4); |
|---|
| 373 | + line6->startup = pod_startup; |
|---|
| 417 | 374 | |
|---|
| 418 | 375 | /* create sysfs entries: */ |
|---|
| 419 | 376 | err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group); |
|---|
| .. | .. |
|---|
| 441 | 398 | pod->monitor_level = POD_SYSTEM_INVALID; |
|---|
| 442 | 399 | |
|---|
| 443 | 400 | /* initiate startup procedure: */ |
|---|
| 444 | | - pod_startup1(pod); |
|---|
| 401 | + schedule_delayed_work(&line6->startup_work, |
|---|
| 402 | + msecs_to_jiffies(POD_STARTUP_DELAY)); |
|---|
| 445 | 403 | } |
|---|
| 446 | 404 | |
|---|
| 447 | 405 | return 0; |
|---|