0001
0002
0003
0004
0005
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
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
0037 struct usb_line6 line6;
0038
0039
0040 unsigned char *buffer_activate;
0041
0042
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
0052
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
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
0080
0081
0082
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
0092 schedule_delayed_work(&line6->startup_work,
0093 msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
0094
0095 line6_version_request_async(line6);
0096 break;
0097 case VARIAX_STARTUP_ACTIVATE:
0098
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
0106 snd_card_register(variax->line6.card);
0107 break;
0108 }
0109 }
0110
0111
0112
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
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
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
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
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
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
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
0213 }
0214 };
0215
0216
0217
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");