Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Line 6 Linux USB driver
0004  *
0005  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
0006  */
0007 
0008 #include <linux/slab.h>
0009 #include <linux/spinlock.h>
0010 #include <linux/usb.h>
0011 #include <linux/wait.h>
0012 #include <linux/module.h>
0013 #include <sound/core.h>
0014 
0015 #include "driver.h"
0016 
0017 #define VARIAX_STARTUP_DELAY1 1000
0018 #define VARIAX_STARTUP_DELAY3 100
0019 #define VARIAX_STARTUP_DELAY4 100
0020 
0021 /*
0022     Stages of Variax startup procedure
0023 */
0024 enum {
0025     VARIAX_STARTUP_VERSIONREQ,
0026     VARIAX_STARTUP_ACTIVATE,
0027     VARIAX_STARTUP_SETUP,
0028 };
0029 
0030 enum {
0031     LINE6_PODXTLIVE_VARIAX,
0032     LINE6_VARIAX
0033 };
0034 
0035 struct usb_line6_variax {
0036     /* Generic Line 6 USB data */
0037     struct usb_line6 line6;
0038 
0039     /* Buffer for activation code */
0040     unsigned char *buffer_activate;
0041 
0042     /* Current progress in startup procedure */
0043     int startup_progress;
0044 };
0045 
0046 #define line6_to_variax(x)  container_of(x, struct usb_line6_variax, line6)
0047 
0048 #define VARIAX_OFFSET_ACTIVATE 7
0049 
0050 /*
0051     This message is sent by the device during initialization and identifies
0052     the connected guitar version.
0053 */
0054 static const char variax_init_version[] = {
0055     0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
0056     0x07, 0x00, 0x00, 0x00
0057 };
0058 
0059 /*
0060     This message is the last one sent by the device during initialization.
0061 */
0062 static const char variax_init_done[] = {
0063     0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
0064 };
0065 
0066 static const char variax_activate[] = {
0067     0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
0068     0xf7
0069 };
0070 
0071 static void variax_activate_async(struct usb_line6_variax *variax, int a)
0072 {
0073     variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
0074     line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
0075                      sizeof(variax_activate));
0076 }
0077 
0078 /*
0079     Variax startup procedure.
0080     This is a sequence of functions with special requirements (e.g., must
0081     not run immediately after initialization, must not run in interrupt
0082     context). After the last one has finished, the device is ready to use.
0083 */
0084 
0085 static void variax_startup(struct usb_line6 *line6)
0086 {
0087     struct usb_line6_variax *variax = line6_to_variax(line6);
0088 
0089     switch (variax->startup_progress) {
0090     case VARIAX_STARTUP_VERSIONREQ:
0091         /* repeat request until getting the response */
0092         schedule_delayed_work(&line6->startup_work,
0093                       msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
0094         /* request firmware version: */
0095         line6_version_request_async(line6);
0096         break;
0097     case VARIAX_STARTUP_ACTIVATE:
0098         /* activate device: */
0099         variax_activate_async(variax, 1);
0100         variax->startup_progress = VARIAX_STARTUP_SETUP;
0101         schedule_delayed_work(&line6->startup_work,
0102                       msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
0103         break;
0104     case VARIAX_STARTUP_SETUP:
0105         /* ALSA audio interface: */
0106         snd_card_register(variax->line6.card);
0107         break;
0108     }
0109 }
0110 
0111 /*
0112     Process a completely received message.
0113 */
0114 static void line6_variax_process_message(struct usb_line6 *line6)
0115 {
0116     struct usb_line6_variax *variax = line6_to_variax(line6);
0117     const unsigned char *buf = variax->line6.buffer_message;
0118 
0119     switch (buf[0]) {
0120     case LINE6_RESET:
0121         dev_info(variax->line6.ifcdev, "VARIAX reset\n");
0122         break;
0123 
0124     case LINE6_SYSEX_BEGIN:
0125         if (memcmp(buf + 1, variax_init_version + 1,
0126                sizeof(variax_init_version) - 1) == 0) {
0127             if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
0128                 break;
0129             variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
0130             cancel_delayed_work(&line6->startup_work);
0131             schedule_delayed_work(&line6->startup_work,
0132                           msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
0133         } else if (memcmp(buf + 1, variax_init_done + 1,
0134                   sizeof(variax_init_done) - 1) == 0) {
0135             /* notify of complete initialization: */
0136             if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
0137                 break;
0138             cancel_delayed_work(&line6->startup_work);
0139             schedule_delayed_work(&line6->startup_work, 0);
0140         }
0141         break;
0142     }
0143 }
0144 
0145 /*
0146     Variax destructor.
0147 */
0148 static void line6_variax_disconnect(struct usb_line6 *line6)
0149 {
0150     struct usb_line6_variax *variax = line6_to_variax(line6);
0151 
0152     kfree(variax->buffer_activate);
0153 }
0154 
0155 /*
0156      Try to init workbench device.
0157 */
0158 static int variax_init(struct usb_line6 *line6,
0159                const struct usb_device_id *id)
0160 {
0161     struct usb_line6_variax *variax = line6_to_variax(line6);
0162 
0163     line6->process_message = line6_variax_process_message;
0164     line6->disconnect = line6_variax_disconnect;
0165     line6->startup = variax_startup;
0166 
0167     /* initialize USB buffers: */
0168     variax->buffer_activate = kmemdup(variax_activate,
0169                       sizeof(variax_activate), GFP_KERNEL);
0170 
0171     if (variax->buffer_activate == NULL)
0172         return -ENOMEM;
0173 
0174     /* initiate startup procedure: */
0175     schedule_delayed_work(&line6->startup_work,
0176                   msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
0177     return 0;
0178 }
0179 
0180 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
0181 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
0182 
0183 /* table of devices that work with this driver */
0184 static const struct usb_device_id variax_id_table[] = {
0185     { LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
0186     { LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
0187     {}
0188 };
0189 
0190 MODULE_DEVICE_TABLE(usb, variax_id_table);
0191 
0192 static const struct line6_properties variax_properties_table[] = {
0193     [LINE6_PODXTLIVE_VARIAX] = {
0194         .id = "PODxtLive",
0195         .name = "PODxt Live",
0196         .capabilities   = LINE6_CAP_CONTROL
0197                 | LINE6_CAP_CONTROL_MIDI,
0198         .altsetting = 1,
0199         .ep_ctrl_r = 0x86,
0200         .ep_ctrl_w = 0x05,
0201         .ep_audio_r = 0x82,
0202         .ep_audio_w = 0x01,
0203     },
0204     [LINE6_VARIAX] = {
0205         .id = "Variax",
0206         .name = "Variax Workbench",
0207         .capabilities   = LINE6_CAP_CONTROL
0208                 | LINE6_CAP_CONTROL_MIDI,
0209         .altsetting = 1,
0210         .ep_ctrl_r = 0x82,
0211         .ep_ctrl_w = 0x01,
0212         /* no audio channel */
0213     }
0214 };
0215 
0216 /*
0217     Probe USB device.
0218 */
0219 static int variax_probe(struct usb_interface *interface,
0220             const struct usb_device_id *id)
0221 {
0222     return line6_probe(interface, id, "Line6-Variax",
0223                &variax_properties_table[id->driver_info],
0224                variax_init, sizeof(struct usb_line6_variax));
0225 }
0226 
0227 static struct usb_driver variax_driver = {
0228     .name = KBUILD_MODNAME,
0229     .probe = variax_probe,
0230     .disconnect = line6_disconnect,
0231 #ifdef CONFIG_PM
0232     .suspend = line6_suspend,
0233     .resume = line6_resume,
0234     .reset_resume = line6_resume,
0235 #endif
0236     .id_table = variax_id_table,
0237 };
0238 
0239 module_usb_driver(variax_driver);
0240 
0241 MODULE_DESCRIPTION("Variax Workbench USB driver");
0242 MODULE_LICENSE("GPL");