Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc3 453 lines 11 kB view raw
1/* 2 * Line6 Linux USB driver - 0.9.1beta 3 * 4 * 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 */ 11 12#include <linux/slab.h> 13#include <linux/wait.h> 14#include <sound/control.h> 15 16#include "audio.h" 17#include "capture.h" 18#include "driver.h" 19#include "playback.h" 20#include "pod.h" 21 22#define POD_SYSEX_CODE 3 23#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ 24 25/* *INDENT-OFF* */ 26 27enum { 28 POD_SYSEX_SAVE = 0x24, 29 POD_SYSEX_SYSTEM = 0x56, 30 POD_SYSEX_SYSTEMREQ = 0x57, 31 /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ 32 POD_SYSEX_STORE = 0x71, 33 POD_SYSEX_FINISH = 0x72, 34 POD_SYSEX_DUMPMEM = 0x73, 35 POD_SYSEX_DUMP = 0x74, 36 POD_SYSEX_DUMPREQ = 0x75 37 38 /* dumps entire internal memory of PODxt Pro */ 39 /* POD_SYSEX_DUMPMEM2 = 0x76 */ 40}; 41 42enum { 43 POD_MONITOR_LEVEL = 0x04, 44 POD_SYSTEM_INVALID = 0x10000 45}; 46 47/* *INDENT-ON* */ 48 49enum { 50 POD_DUMP_MEMORY = 2 51}; 52 53enum { 54 POD_BUSY_READ, 55 POD_BUSY_WRITE, 56 POD_CHANNEL_DIRTY, 57 POD_SAVE_PRESSED, 58 POD_BUSY_MIDISEND 59}; 60 61static struct snd_ratden pod_ratden = { 62 .num_min = 78125, 63 .num_max = 78125, 64 .num_step = 1, 65 .den = 2 66}; 67 68static struct line6_pcm_properties pod_pcm_properties = { 69 .snd_line6_playback_hw = { 70 .info = (SNDRV_PCM_INFO_MMAP | 71 SNDRV_PCM_INFO_INTERLEAVED | 72 SNDRV_PCM_INFO_BLOCK_TRANSFER | 73 SNDRV_PCM_INFO_MMAP_VALID | 74 SNDRV_PCM_INFO_PAUSE | 75#ifdef CONFIG_PM 76 SNDRV_PCM_INFO_RESUME | 77#endif 78 SNDRV_PCM_INFO_SYNC_START), 79 .formats = SNDRV_PCM_FMTBIT_S24_3LE, 80 .rates = SNDRV_PCM_RATE_KNOT, 81 .rate_min = 39062, 82 .rate_max = 39063, 83 .channels_min = 2, 84 .channels_max = 2, 85 .buffer_bytes_max = 60000, 86 .period_bytes_min = 64, 87 .period_bytes_max = 8192, 88 .periods_min = 1, 89 .periods_max = 1024}, 90 .snd_line6_capture_hw = { 91 .info = (SNDRV_PCM_INFO_MMAP | 92 SNDRV_PCM_INFO_INTERLEAVED | 93 SNDRV_PCM_INFO_BLOCK_TRANSFER | 94 SNDRV_PCM_INFO_MMAP_VALID | 95#ifdef CONFIG_PM 96 SNDRV_PCM_INFO_RESUME | 97#endif 98 SNDRV_PCM_INFO_SYNC_START), 99 .formats = SNDRV_PCM_FMTBIT_S24_3LE, 100 .rates = SNDRV_PCM_RATE_KNOT, 101 .rate_min = 39062, 102 .rate_max = 39063, 103 .channels_min = 2, 104 .channels_max = 2, 105 .buffer_bytes_max = 60000, 106 .period_bytes_min = 64, 107 .period_bytes_max = 8192, 108 .periods_min = 1, 109 .periods_max = 1024}, 110 .snd_line6_rates = { 111 .nrats = 1, 112 .rats = &pod_ratden}, 113 .bytes_per_frame = POD_BYTES_PER_FRAME 114}; 115 116static const char pod_version_header[] = { 117 0xf2, 0x7e, 0x7f, 0x06, 0x02 118}; 119 120/* forward declarations: */ 121static void pod_startup2(unsigned long data); 122static void pod_startup3(struct usb_line6_pod *pod); 123 124static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, 125 int size) 126{ 127 return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, 128 size); 129} 130 131/* 132 Process a completely received message. 133*/ 134void line6_pod_process_message(struct usb_line6_pod *pod) 135{ 136 const unsigned char *buf = pod->line6.buffer_message; 137 138 if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { 139 pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; 140 pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | 141 (int) buf[10]; 142 pod_startup3(pod); 143 return; 144 } 145 146 /* Only look for sysex messages from this device */ 147 if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && 148 buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { 149 return; 150 } 151 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0) 152 return; 153 154 if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { 155 short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | 156 ((int)buf[9] << 4) | (int)buf[10]; 157 pod->monitor_level = value; 158 } 159} 160 161/* 162 Transmit PODxt Pro control parameter. 163*/ 164void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param, 165 u8 value) 166{ 167 line6_transmit_parameter(&pod->line6, param, value); 168} 169 170/* 171 Send system parameter (from integer). 172*/ 173static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, 174 int code) 175{ 176 char *sysex; 177 static const int size = 5; 178 179 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); 180 if (!sysex) 181 return -ENOMEM; 182 sysex[SYSEX_DATA_OFS] = code; 183 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; 184 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; 185 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; 186 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; 187 line6_send_sysex_message(&pod->line6, sysex, size); 188 kfree(sysex); 189 return 0; 190} 191 192/* 193 "read" request on "serial_number" special file. 194*/ 195static ssize_t serial_number_show(struct device *dev, 196 struct device_attribute *attr, char *buf) 197{ 198 struct usb_interface *interface = to_usb_interface(dev); 199 struct usb_line6_pod *pod = usb_get_intfdata(interface); 200 return sprintf(buf, "%d\n", pod->serial_number); 201} 202 203/* 204 "read" request on "firmware_version" special file. 205*/ 206static ssize_t firmware_version_show(struct device *dev, 207 struct device_attribute *attr, char *buf) 208{ 209 struct usb_interface *interface = to_usb_interface(dev); 210 struct usb_line6_pod *pod = usb_get_intfdata(interface); 211 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, 212 pod->firmware_version % 100); 213} 214 215/* 216 "read" request on "device_id" special file. 217*/ 218static ssize_t device_id_show(struct device *dev, 219 struct device_attribute *attr, char *buf) 220{ 221 struct usb_interface *interface = to_usb_interface(dev); 222 struct usb_line6_pod *pod = usb_get_intfdata(interface); 223 return sprintf(buf, "%d\n", pod->device_id); 224} 225 226/* 227 POD startup procedure. 228 This is a sequence of functions with special requirements (e.g., must 229 not run immediately after initialization, must not run in interrupt 230 context). After the last one has finished, the device is ready to use. 231*/ 232 233static void pod_startup1(struct usb_line6_pod *pod) 234{ 235 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT); 236 237 /* delay startup procedure: */ 238 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, 239 (unsigned long)pod); 240} 241 242static void pod_startup2(unsigned long data) 243{ 244 struct usb_line6_pod *pod = (struct usb_line6_pod *)data; 245 struct usb_line6 *line6 = &pod->line6; 246 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ); 247 248 /* request firmware version: */ 249 line6_version_request_async(line6); 250} 251 252static void pod_startup3(struct usb_line6_pod *pod) 253{ 254 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE); 255 256 /* schedule work for global work queue: */ 257 schedule_work(&pod->startup_work); 258} 259 260static void pod_startup4(struct work_struct *work) 261{ 262 struct usb_line6_pod *pod = 263 container_of(work, struct usb_line6_pod, startup_work); 264 struct usb_line6 *line6 = &pod->line6; 265 266 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP); 267 268 /* serial number: */ 269 line6_read_serial_number(&pod->line6, &pod->serial_number); 270 271 /* ALSA audio interface: */ 272 line6_register_audio(line6); 273} 274 275/* POD special files: */ 276static DEVICE_ATTR_RO(device_id); 277static DEVICE_ATTR_RO(firmware_version); 278static DEVICE_ATTR_RO(serial_number); 279 280/* control info callback */ 281static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, 282 struct snd_ctl_elem_info *uinfo) 283{ 284 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 285 uinfo->count = 1; 286 uinfo->value.integer.min = 0; 287 uinfo->value.integer.max = 65535; 288 return 0; 289} 290 291/* control get callback */ 292static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, 293 struct snd_ctl_elem_value *ucontrol) 294{ 295 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 296 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; 297 ucontrol->value.integer.value[0] = pod->monitor_level; 298 return 0; 299} 300 301/* control put callback */ 302static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, 303 struct snd_ctl_elem_value *ucontrol) 304{ 305 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); 306 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; 307 308 if (ucontrol->value.integer.value[0] == pod->monitor_level) 309 return 0; 310 311 pod->monitor_level = ucontrol->value.integer.value[0]; 312 pod_set_system_param_int(pod, ucontrol->value.integer.value[0], 313 POD_MONITOR_LEVEL); 314 return 1; 315} 316 317/* control definition */ 318static struct snd_kcontrol_new pod_control_monitor = { 319 .iface = SNDRV_CTL_ELEM_IFACE_MIXER, 320 .name = "Monitor Playback Volume", 321 .index = 0, 322 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, 323 .info = snd_pod_control_monitor_info, 324 .get = snd_pod_control_monitor_get, 325 .put = snd_pod_control_monitor_put 326}; 327 328/* 329 POD destructor. 330*/ 331static void pod_destruct(struct usb_interface *interface) 332{ 333 struct usb_line6_pod *pod = usb_get_intfdata(interface); 334 335 if (pod == NULL) 336 return; 337 line6_cleanup_audio(&pod->line6); 338 339 del_timer(&pod->startup_timer); 340 cancel_work_sync(&pod->startup_work); 341} 342 343/* 344 Create sysfs entries. 345*/ 346static int pod_create_files2(struct device *dev) 347{ 348 int err; 349 350 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); 351 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); 352 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); 353 return 0; 354} 355 356/* 357 Try to init POD device. 358*/ 359static int pod_try_init(struct usb_interface *interface, 360 struct usb_line6_pod *pod) 361{ 362 int err; 363 struct usb_line6 *line6 = &pod->line6; 364 365 init_timer(&pod->startup_timer); 366 INIT_WORK(&pod->startup_work, pod_startup4); 367 368 if ((interface == NULL) || (pod == NULL)) 369 return -ENODEV; 370 371 /* create sysfs entries: */ 372 err = pod_create_files2(&interface->dev); 373 if (err < 0) 374 return err; 375 376 /* initialize audio system: */ 377 err = line6_init_audio(line6); 378 if (err < 0) 379 return err; 380 381 /* initialize MIDI subsystem: */ 382 err = line6_init_midi(line6); 383 if (err < 0) 384 return err; 385 386 /* initialize PCM subsystem: */ 387 err = line6_init_pcm(line6, &pod_pcm_properties); 388 if (err < 0) 389 return err; 390 391 /* register monitor control: */ 392 err = snd_ctl_add(line6->card, 393 snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); 394 if (err < 0) 395 return err; 396 397 /* 398 When the sound card is registered at this point, the PODxt Live 399 displays "Invalid Code Error 07", so we do it later in the event 400 handler. 401 */ 402 403 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) { 404 pod->monitor_level = POD_SYSTEM_INVALID; 405 406 /* initiate startup procedure: */ 407 pod_startup1(pod); 408 } 409 410 return 0; 411} 412 413/* 414 Init POD device (and clean up in case of failure). 415*/ 416int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod) 417{ 418 int err = pod_try_init(interface, pod); 419 420 if (err < 0) 421 pod_destruct(interface); 422 423 return err; 424} 425 426/* 427 POD device disconnected. 428*/ 429void line6_pod_disconnect(struct usb_interface *interface) 430{ 431 struct usb_line6_pod *pod; 432 433 if (interface == NULL) 434 return; 435 pod = usb_get_intfdata(interface); 436 437 if (pod != NULL) { 438 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; 439 struct device *dev = &interface->dev; 440 441 if (line6pcm != NULL) 442 line6_pcm_disconnect(line6pcm); 443 444 if (dev != NULL) { 445 /* remove sysfs entries: */ 446 device_remove_file(dev, &dev_attr_device_id); 447 device_remove_file(dev, &dev_attr_firmware_version); 448 device_remove_file(dev, &dev_attr_serial_number); 449 } 450 } 451 452 pod_destruct(interface); 453}