staging: line6: drop variax bank sysfs attr
[cascardo/linux.git] / drivers / staging / line6 / variax.c
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 "control.h"
16 #include "driver.h"
17 #include "variax.h"
18
19 #define VARIAX_SYSEX_CODE 7
20 #define VARIAX_SYSEX_PARAM 0x3b
21 #define VARIAX_SYSEX_ACTIVATE 0x2a
22 #define VARIAX_MODEL_HEADER_LENGTH 7
23 #define VARIAX_MODEL_MESSAGE_LENGTH 199
24 #define VARIAX_OFFSET_ACTIVATE 7
25
26 /*
27         This message is sent by the device during initialization and identifies
28         the connected guitar model.
29 */
30 static const char variax_init_model[] = {
31         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x69, 0x02,
32         0x00
33 };
34
35 /*
36         This message is sent by the device during initialization and identifies
37         the connected guitar version.
38 */
39 static const char variax_init_version[] = {
40         0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
41         0x07, 0x00, 0x00, 0x00
42 };
43
44 /*
45         This message is the last one sent by the device during initialization.
46 */
47 static const char variax_init_done[] = {
48         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
49 };
50
51 static const char variax_activate[] = {
52         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
53         0xf7
54 };
55
56 static const char variax_request_bank[] = {
57         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
58 };
59
60 static const char variax_request_model1[] = {
61         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
62         0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03,
63         0x00, 0x00, 0x00, 0xf7
64 };
65
66 static const char variax_request_model2[] = {
67         0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
68         0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03,
69         0x00, 0x00, 0x00, 0xf7
70 };
71
72 /* forward declarations: */
73 static int variax_create_files2(struct device *dev);
74 static void variax_startup2(unsigned long data);
75 static void variax_startup4(unsigned long data);
76 static void variax_startup5(unsigned long data);
77
78 /*
79         Decode data transmitted by workbench.
80 */
81 static void variax_decode(const unsigned char *raw_data, unsigned char *data,
82                           int raw_size)
83 {
84         for (; raw_size > 0; raw_size -= 6) {
85                 data[2] = raw_data[0] | (raw_data[1] << 4);
86                 data[1] = raw_data[2] | (raw_data[3] << 4);
87                 data[0] = raw_data[4] | (raw_data[5] << 4);
88                 raw_data += 6;
89                 data += 3;
90         }
91 }
92
93 static void variax_activate_async(struct usb_line6_variax *variax, int a)
94 {
95         variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
96         line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
97                                      sizeof(variax_activate));
98 }
99
100 /*
101         Variax startup procedure.
102         This is a sequence of functions with special requirements (e.g., must
103         not run immediately after initialization, must not run in interrupt
104         context). After the last one has finished, the device is ready to use.
105 */
106
107 static void variax_startup1(struct usb_line6_variax *variax)
108 {
109         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
110
111         /* delay startup procedure: */
112         line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
113                           variax_startup2, (unsigned long)variax);
114 }
115
116 static void variax_startup2(unsigned long data)
117 {
118         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
119         struct usb_line6 *line6 = &variax->line6;
120
121         /* schedule another startup procedure until startup is complete: */
122         if (variax->startup_progress >= VARIAX_STARTUP_LAST)
123                 return;
124
125         variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
126         line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
127                           variax_startup2, (unsigned long)variax);
128
129         /* request firmware version: */
130         line6_version_request_async(line6);
131 }
132
133 static void variax_startup3(struct usb_line6_variax *variax)
134 {
135         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
136
137         /* delay startup procedure: */
138         line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
139                           variax_startup4, (unsigned long)variax);
140 }
141
142 static void variax_startup4(unsigned long data)
143 {
144         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
145         CHECK_STARTUP_PROGRESS(variax->startup_progress,
146                                VARIAX_STARTUP_ACTIVATE);
147
148         /* activate device: */
149         variax_activate_async(variax, 1);
150         line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
151                           variax_startup5, (unsigned long)variax);
152 }
153
154 static void variax_startup5(unsigned long data)
155 {
156         struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
157         CHECK_STARTUP_PROGRESS(variax->startup_progress,
158                                VARIAX_STARTUP_DUMPREQ);
159
160         /* current model dump: */
161         line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
162                                  VARIAX_DUMP_PASS1);
163         /* passes 2 and 3 are performed implicitly before entering
164          * variax_startup6.
165          */
166 }
167
168 static void variax_startup6(struct usb_line6_variax *variax)
169 {
170         CHECK_STARTUP_PROGRESS(variax->startup_progress,
171                                VARIAX_STARTUP_WORKQUEUE);
172
173         /* schedule work for global work queue: */
174         schedule_work(&variax->startup_work);
175 }
176
177 static void variax_startup7(struct work_struct *work)
178 {
179         struct usb_line6_variax *variax =
180             container_of(work, struct usb_line6_variax, startup_work);
181         struct usb_line6 *line6 = &variax->line6;
182
183         CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
184
185         /* ALSA audio interface: */
186         line6_register_audio(&variax->line6);
187
188         /* device files: */
189         line6_variax_create_files(0, 0, line6->ifcdev);
190         variax_create_files2(line6->ifcdev);
191 }
192
193 /*
194         Process a completely received message.
195 */
196 void line6_variax_process_message(struct usb_line6_variax *variax)
197 {
198         const unsigned char *buf = variax->line6.buffer_message;
199
200         switch (buf[0]) {
201         case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
202                 break;
203
204         case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
205         case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
206                 line6_dump_request_async(&variax->dumpreq, &variax->line6, 0,
207                                          VARIAX_DUMP_PASS1);
208                 break;
209
210         case LINE6_RESET:
211                 dev_info(variax->line6.ifcdev, "VARIAX reset\n");
212                 break;
213
214         case LINE6_SYSEX_BEGIN:
215                 if (memcmp(buf + 1, variax_request_model1 + 1,
216                            VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
217                         if (variax->line6.message_length ==
218                             VARIAX_MODEL_MESSAGE_LENGTH) {
219                                 switch (variax->dumpreq.in_progress) {
220                                 case VARIAX_DUMP_PASS1:
221                                         line6_dump_request_async
222                                             (&variax->dumpreq, &variax->line6,
223                                              1, VARIAX_DUMP_PASS2);
224                                         break;
225
226                                 case VARIAX_DUMP_PASS2:
227                                         /* model name is transmitted twice, so skip it here: */
228                                         variax_decode(buf +
229                                                       VARIAX_MODEL_HEADER_LENGTH,
230                                                       (unsigned char *)
231                                                       &variax->
232                                                       model_data.control +
233                                                       sizeof(variax->model_data.
234                                                              control)
235                                                       / 2,
236                                                       sizeof(variax->model_data.
237                                                              control)
238                                                       / 2 * 2);
239                                         line6_dump_request_async
240                                             (&variax->dumpreq, &variax->line6,
241                                              2, VARIAX_DUMP_PASS3);
242                                 }
243                         } else {
244                                 dev_dbg(variax->line6.ifcdev,
245                                         "illegal length %d of model data\n",
246                                         variax->line6.message_length);
247                                 line6_dump_finished(&variax->dumpreq);
248                         }
249                 } else if (memcmp(buf + 1, variax_request_bank + 1,
250                                   sizeof(variax_request_bank) - 2) == 0) {
251                         line6_dump_finished(&variax->dumpreq);
252                         variax_startup6(variax);
253                 } else if (memcmp(buf + 1, variax_init_model + 1,
254                                   sizeof(variax_init_model) - 1) == 0) {
255                         memcpy(variax->guitar,
256                                buf + sizeof(variax_init_model),
257                                sizeof(variax->guitar));
258                 } else if (memcmp(buf + 1, variax_init_version + 1,
259                                   sizeof(variax_init_version) - 1) == 0) {
260                         variax_startup3(variax);
261                 } else if (memcmp(buf + 1, variax_init_done + 1,
262                                   sizeof(variax_init_done) - 1) == 0) {
263                         /* notify of complete initialization: */
264                         variax_startup4((unsigned long)variax);
265                 }
266
267                 break;
268
269         case LINE6_SYSEX_END:
270                 break;
271
272         default:
273                 dev_dbg(variax->line6.ifcdev,
274                         "Variax: unknown message %02X\n", buf[0]);
275         }
276 }
277
278 /*
279         "read" request on "active" special file.
280 */
281 static ssize_t variax_get_active(struct device *dev,
282                                  struct device_attribute *attr, char *buf)
283 {
284         struct usb_line6_variax *variax =
285             usb_get_intfdata(to_usb_interface(dev));
286         return sprintf(buf, "%d\n",
287                        variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
288 }
289
290 /*
291         "write" request on "active" special file.
292 */
293 static ssize_t variax_set_active(struct device *dev,
294                                  struct device_attribute *attr,
295                                  const char *buf, size_t count)
296 {
297         struct usb_line6_variax *variax =
298             usb_get_intfdata(to_usb_interface(dev));
299         u8 value;
300         int ret;
301
302         ret = kstrtou8(buf, 10, &value);
303         if (ret)
304                 return ret;
305
306         variax_activate_async(variax, value ? 1 : 0);
307         return count;
308 }
309
310 /*
311         "read" request on "dump" special file.
312 */
313 static ssize_t variax_get_dump(struct device *dev,
314                                struct device_attribute *attr, char *buf)
315 {
316         struct usb_line6_variax *variax =
317             usb_get_intfdata(to_usb_interface(dev));
318         int retval;
319         retval = line6_dump_wait_interruptible(&variax->dumpreq);
320         if (retval < 0)
321                 return retval;
322         memcpy(buf, &variax->model_data.control,
323                sizeof(variax->model_data.control));
324         return sizeof(variax->model_data.control);
325 }
326
327 /*
328         "read" request on "guitar" special file.
329 */
330 static ssize_t variax_get_guitar(struct device *dev,
331                                  struct device_attribute *attr, char *buf)
332 {
333         struct usb_line6_variax *variax =
334             usb_get_intfdata(to_usb_interface(dev));
335         return sprintf(buf, "%s\n", variax->guitar);
336 }
337
338 #ifdef CONFIG_LINE6_USB_RAW
339
340 static char *variax_alloc_sysex_buffer(struct usb_line6_variax *variax,
341                                        int code, int size)
342 {
343         return line6_alloc_sysex_buffer(&variax->line6, VARIAX_SYSEX_CODE, code,
344                                         size);
345 }
346
347 /*
348         "write" request on "raw" special file.
349 */
350 static ssize_t variax_set_raw2(struct device *dev,
351                                struct device_attribute *attr,
352                                const char *buf, size_t count)
353 {
354         struct usb_line6_variax *variax =
355             usb_get_intfdata(to_usb_interface(dev));
356         int size;
357         int i;
358         char *sysex;
359
360         count -= count % 3;
361         size = count * 2;
362         sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
363
364         if (!sysex)
365                 return 0;
366
367         for (i = 0; i < count; i += 3) {
368                 const unsigned char *p1 = buf + i;
369                 char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
370                 p2[0] = p1[2] & 0x0f;
371                 p2[1] = p1[2] >> 4;
372                 p2[2] = p1[1] & 0x0f;
373                 p2[3] = p1[1] >> 4;
374                 p2[4] = p1[0] & 0x0f;
375                 p2[5] = p1[0] >> 4;
376         }
377
378         line6_send_sysex_message(&variax->line6, sysex, size);
379         kfree(sysex);
380         return count;
381 }
382
383 #endif
384
385 /* Variax workbench special files: */
386 static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
387 static DEVICE_ATTR(active, S_IWUSR | S_IRUGO, variax_get_active,
388                    variax_set_active);
389 static DEVICE_ATTR(guitar, S_IRUGO, variax_get_guitar, line6_nop_write);
390
391 #ifdef CONFIG_LINE6_USB_RAW
392 static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
393 static DEVICE_ATTR(raw2, S_IWUSR, line6_nop_read, variax_set_raw2);
394 #endif
395
396 /*
397         Variax destructor.
398 */
399 static void variax_destruct(struct usb_interface *interface)
400 {
401         struct usb_line6_variax *variax = usb_get_intfdata(interface);
402
403         if (variax == NULL)
404                 return;
405         line6_cleanup_audio(&variax->line6);
406
407         del_timer(&variax->startup_timer1);
408         del_timer(&variax->startup_timer2);
409         cancel_work_sync(&variax->startup_work);
410
411         /* free dump request data: */
412         line6_dumpreq_destructbuf(&variax->dumpreq, 2);
413         line6_dumpreq_destructbuf(&variax->dumpreq, 1);
414         line6_dumpreq_destruct(&variax->dumpreq);
415
416         kfree(variax->buffer_activate);
417 }
418
419 /*
420         Create sysfs entries.
421 */
422 static int variax_create_files2(struct device *dev)
423 {
424         int err;
425         CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
426         CHECK_RETURN(device_create_file(dev, &dev_attr_active));
427         CHECK_RETURN(device_create_file(dev, &dev_attr_guitar));
428 #ifdef CONFIG_LINE6_USB_RAW
429         CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
430         CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
431 #endif
432         return 0;
433 }
434
435 /*
436          Try to init workbench device.
437 */
438 static int variax_try_init(struct usb_interface *interface,
439                            struct usb_line6_variax *variax)
440 {
441         int err;
442
443         init_timer(&variax->startup_timer1);
444         init_timer(&variax->startup_timer2);
445         INIT_WORK(&variax->startup_work, variax_startup7);
446
447         if ((interface == NULL) || (variax == NULL))
448                 return -ENODEV;
449
450         /* initialize USB buffers: */
451         err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
452                                  sizeof(variax_request_model1));
453
454         if (err < 0) {
455                 dev_err(&interface->dev, "Out of memory\n");
456                 return err;
457         }
458
459         err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
460                                     sizeof(variax_request_model2), 1);
461
462         if (err < 0) {
463                 dev_err(&interface->dev, "Out of memory\n");
464                 return err;
465         }
466
467         err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
468                                     sizeof(variax_request_bank), 2);
469
470         if (err < 0) {
471                 dev_err(&interface->dev, "Out of memory\n");
472                 return err;
473         }
474
475         variax->buffer_activate = kmemdup(variax_activate,
476                                           sizeof(variax_activate), GFP_KERNEL);
477
478         if (variax->buffer_activate == NULL) {
479                 dev_err(&interface->dev, "Out of memory\n");
480                 return -ENOMEM;
481         }
482
483         /* initialize audio system: */
484         err = line6_init_audio(&variax->line6);
485         if (err < 0)
486                 return err;
487
488         /* initialize MIDI subsystem: */
489         err = line6_init_midi(&variax->line6);
490         if (err < 0)
491                 return err;
492
493         /* initiate startup procedure: */
494         variax_startup1(variax);
495         return 0;
496 }
497
498 /*
499          Init workbench device (and clean up in case of failure).
500 */
501 int line6_variax_init(struct usb_interface *interface,
502                       struct usb_line6_variax *variax)
503 {
504         int err = variax_try_init(interface, variax);
505
506         if (err < 0)
507                 variax_destruct(interface);
508
509         return err;
510 }
511
512 /*
513         Workbench device disconnected.
514 */
515 void line6_variax_disconnect(struct usb_interface *interface)
516 {
517         struct device *dev;
518
519         if (interface == NULL)
520                 return;
521         dev = &interface->dev;
522
523         if (dev != NULL) {
524                 /* remove sysfs entries: */
525                 line6_variax_remove_files(0, 0, dev);
526                 device_remove_file(dev, &dev_attr_dump);
527                 device_remove_file(dev, &dev_attr_active);
528                 device_remove_file(dev, &dev_attr_guitar);
529 #ifdef CONFIG_LINE6_USB_RAW
530                 device_remove_file(dev, &dev_attr_raw);
531                 device_remove_file(dev, &dev_attr_raw2);
532 #endif
533         }
534
535         variax_destruct(interface);
536 }