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.11 233 lines 6.0 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 14#include "audio.h" 15#include "driver.h" 16#include "variax.h" 17 18#define VARIAX_OFFSET_ACTIVATE 7 19 20/* 21 This message is sent by the device during initialization and identifies 22 the connected guitar version. 23*/ 24static const char variax_init_version[] = { 25 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c, 26 0x07, 0x00, 0x00, 0x00 27}; 28 29/* 30 This message is the last one sent by the device during initialization. 31*/ 32static const char variax_init_done[] = { 33 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b 34}; 35 36static const char variax_activate[] = { 37 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01, 38 0xf7 39}; 40 41/* forward declarations: */ 42static void variax_startup2(unsigned long data); 43static void variax_startup4(unsigned long data); 44static void variax_startup5(unsigned long data); 45 46static void variax_activate_async(struct usb_line6_variax *variax, int a) 47{ 48 variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a; 49 line6_send_raw_message_async(&variax->line6, variax->buffer_activate, 50 sizeof(variax_activate)); 51} 52 53/* 54 Variax startup procedure. 55 This is a sequence of functions with special requirements (e.g., must 56 not run immediately after initialization, must not run in interrupt 57 context). After the last one has finished, the device is ready to use. 58*/ 59 60static void variax_startup1(struct usb_line6_variax *variax) 61{ 62 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT); 63 64 /* delay startup procedure: */ 65 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, 66 variax_startup2, (unsigned long)variax); 67} 68 69static void variax_startup2(unsigned long data) 70{ 71 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 72 struct usb_line6 *line6 = &variax->line6; 73 74 /* schedule another startup procedure until startup is complete: */ 75 if (variax->startup_progress >= VARIAX_STARTUP_LAST) 76 return; 77 78 variax->startup_progress = VARIAX_STARTUP_VERSIONREQ; 79 line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1, 80 variax_startup2, (unsigned long)variax); 81 82 /* request firmware version: */ 83 line6_version_request_async(line6); 84} 85 86static void variax_startup3(struct usb_line6_variax *variax) 87{ 88 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT); 89 90 /* delay startup procedure: */ 91 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3, 92 variax_startup4, (unsigned long)variax); 93} 94 95static void variax_startup4(unsigned long data) 96{ 97 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 98 CHECK_STARTUP_PROGRESS(variax->startup_progress, 99 VARIAX_STARTUP_ACTIVATE); 100 101 /* activate device: */ 102 variax_activate_async(variax, 1); 103 line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4, 104 variax_startup5, (unsigned long)variax); 105} 106 107static void variax_startup5(unsigned long data) 108{ 109 struct usb_line6_variax *variax = (struct usb_line6_variax *)data; 110 CHECK_STARTUP_PROGRESS(variax->startup_progress, 111 VARIAX_STARTUP_WORKQUEUE); 112 113 /* schedule work for global work queue: */ 114 schedule_work(&variax->startup_work); 115} 116 117static void variax_startup6(struct work_struct *work) 118{ 119 struct usb_line6_variax *variax = 120 container_of(work, struct usb_line6_variax, startup_work); 121 122 CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); 123 124 /* ALSA audio interface: */ 125 line6_register_audio(&variax->line6); 126} 127 128/* 129 Process a completely received message. 130*/ 131void line6_variax_process_message(struct usb_line6_variax *variax) 132{ 133 const unsigned char *buf = variax->line6.buffer_message; 134 135 switch (buf[0]) { 136 case LINE6_RESET: 137 dev_info(variax->line6.ifcdev, "VARIAX reset\n"); 138 break; 139 140 case LINE6_SYSEX_BEGIN: 141 if (memcmp(buf + 1, variax_init_version + 1, 142 sizeof(variax_init_version) - 1) == 0) { 143 variax_startup3(variax); 144 } else if (memcmp(buf + 1, variax_init_done + 1, 145 sizeof(variax_init_done) - 1) == 0) { 146 /* notify of complete initialization: */ 147 variax_startup4((unsigned long)variax); 148 } 149 break; 150 } 151} 152 153/* 154 Variax destructor. 155*/ 156static void variax_destruct(struct usb_interface *interface) 157{ 158 struct usb_line6_variax *variax = usb_get_intfdata(interface); 159 160 if (variax == NULL) 161 return; 162 line6_cleanup_audio(&variax->line6); 163 164 del_timer(&variax->startup_timer1); 165 del_timer(&variax->startup_timer2); 166 cancel_work_sync(&variax->startup_work); 167 168 kfree(variax->buffer_activate); 169} 170 171/* 172 Try to init workbench device. 173*/ 174static int variax_try_init(struct usb_interface *interface, 175 struct usb_line6_variax *variax) 176{ 177 int err; 178 179 init_timer(&variax->startup_timer1); 180 init_timer(&variax->startup_timer2); 181 INIT_WORK(&variax->startup_work, variax_startup6); 182 183 if ((interface == NULL) || (variax == NULL)) 184 return -ENODEV; 185 186 /* initialize USB buffers: */ 187 variax->buffer_activate = kmemdup(variax_activate, 188 sizeof(variax_activate), GFP_KERNEL); 189 190 if (variax->buffer_activate == NULL) { 191 dev_err(&interface->dev, "Out of memory\n"); 192 return -ENOMEM; 193 } 194 195 /* initialize audio system: */ 196 err = line6_init_audio(&variax->line6); 197 if (err < 0) 198 return err; 199 200 /* initialize MIDI subsystem: */ 201 err = line6_init_midi(&variax->line6); 202 if (err < 0) 203 return err; 204 205 /* initiate startup procedure: */ 206 variax_startup1(variax); 207 return 0; 208} 209 210/* 211 Init workbench device (and clean up in case of failure). 212*/ 213int line6_variax_init(struct usb_interface *interface, 214 struct usb_line6_variax *variax) 215{ 216 int err = variax_try_init(interface, variax); 217 218 if (err < 0) 219 variax_destruct(interface); 220 221 return err; 222} 223 224/* 225 Workbench device disconnected. 226*/ 227void line6_variax_disconnect(struct usb_interface *interface) 228{ 229 if (interface == NULL) 230 return; 231 232 variax_destruct(interface); 233}