cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

variax.c (6186B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Line 6 Linux USB driver
      4 *
      5 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
      6 */
      7
      8#include <linux/slab.h>
      9#include <linux/spinlock.h>
     10#include <linux/usb.h>
     11#include <linux/wait.h>
     12#include <linux/module.h>
     13#include <sound/core.h>
     14
     15#include "driver.h"
     16
     17#define VARIAX_STARTUP_DELAY1 1000
     18#define VARIAX_STARTUP_DELAY3 100
     19#define VARIAX_STARTUP_DELAY4 100
     20
     21/*
     22	Stages of Variax startup procedure
     23*/
     24enum {
     25	VARIAX_STARTUP_VERSIONREQ,
     26	VARIAX_STARTUP_ACTIVATE,
     27	VARIAX_STARTUP_SETUP,
     28};
     29
     30enum {
     31	LINE6_PODXTLIVE_VARIAX,
     32	LINE6_VARIAX
     33};
     34
     35struct usb_line6_variax {
     36	/* Generic Line 6 USB data */
     37	struct usb_line6 line6;
     38
     39	/* Buffer for activation code */
     40	unsigned char *buffer_activate;
     41
     42	/* Current progress in startup procedure */
     43	int startup_progress;
     44};
     45
     46#define line6_to_variax(x)	container_of(x, struct usb_line6_variax, line6)
     47
     48#define VARIAX_OFFSET_ACTIVATE 7
     49
     50/*
     51	This message is sent by the device during initialization and identifies
     52	the connected guitar version.
     53*/
     54static const char variax_init_version[] = {
     55	0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
     56	0x07, 0x00, 0x00, 0x00
     57};
     58
     59/*
     60	This message is the last one sent by the device during initialization.
     61*/
     62static const char variax_init_done[] = {
     63	0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
     64};
     65
     66static const char variax_activate[] = {
     67	0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
     68	0xf7
     69};
     70
     71static void variax_activate_async(struct usb_line6_variax *variax, int a)
     72{
     73	variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
     74	line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
     75				     sizeof(variax_activate));
     76}
     77
     78/*
     79	Variax startup procedure.
     80	This is a sequence of functions with special requirements (e.g., must
     81	not run immediately after initialization, must not run in interrupt
     82	context). After the last one has finished, the device is ready to use.
     83*/
     84
     85static void variax_startup(struct usb_line6 *line6)
     86{
     87	struct usb_line6_variax *variax = line6_to_variax(line6);
     88
     89	switch (variax->startup_progress) {
     90	case VARIAX_STARTUP_VERSIONREQ:
     91		/* repeat request until getting the response */
     92		schedule_delayed_work(&line6->startup_work,
     93				      msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
     94		/* request firmware version: */
     95		line6_version_request_async(line6);
     96		break;
     97	case VARIAX_STARTUP_ACTIVATE:
     98		/* activate device: */
     99		variax_activate_async(variax, 1);
    100		variax->startup_progress = VARIAX_STARTUP_SETUP;
    101		schedule_delayed_work(&line6->startup_work,
    102				      msecs_to_jiffies(VARIAX_STARTUP_DELAY4));
    103		break;
    104	case VARIAX_STARTUP_SETUP:
    105		/* ALSA audio interface: */
    106		snd_card_register(variax->line6.card);
    107		break;
    108	}
    109}
    110
    111/*
    112	Process a completely received message.
    113*/
    114static void line6_variax_process_message(struct usb_line6 *line6)
    115{
    116	struct usb_line6_variax *variax = line6_to_variax(line6);
    117	const unsigned char *buf = variax->line6.buffer_message;
    118
    119	switch (buf[0]) {
    120	case LINE6_RESET:
    121		dev_info(variax->line6.ifcdev, "VARIAX reset\n");
    122		break;
    123
    124	case LINE6_SYSEX_BEGIN:
    125		if (memcmp(buf + 1, variax_init_version + 1,
    126			   sizeof(variax_init_version) - 1) == 0) {
    127			if (variax->startup_progress >= VARIAX_STARTUP_ACTIVATE)
    128				break;
    129			variax->startup_progress = VARIAX_STARTUP_ACTIVATE;
    130			cancel_delayed_work(&line6->startup_work);
    131			schedule_delayed_work(&line6->startup_work,
    132					      msecs_to_jiffies(VARIAX_STARTUP_DELAY3));
    133		} else if (memcmp(buf + 1, variax_init_done + 1,
    134				  sizeof(variax_init_done) - 1) == 0) {
    135			/* notify of complete initialization: */
    136			if (variax->startup_progress >= VARIAX_STARTUP_SETUP)
    137				break;
    138			cancel_delayed_work(&line6->startup_work);
    139			schedule_delayed_work(&line6->startup_work, 0);
    140		}
    141		break;
    142	}
    143}
    144
    145/*
    146	Variax destructor.
    147*/
    148static void line6_variax_disconnect(struct usb_line6 *line6)
    149{
    150	struct usb_line6_variax *variax = line6_to_variax(line6);
    151
    152	kfree(variax->buffer_activate);
    153}
    154
    155/*
    156	 Try to init workbench device.
    157*/
    158static int variax_init(struct usb_line6 *line6,
    159		       const struct usb_device_id *id)
    160{
    161	struct usb_line6_variax *variax = line6_to_variax(line6);
    162
    163	line6->process_message = line6_variax_process_message;
    164	line6->disconnect = line6_variax_disconnect;
    165	line6->startup = variax_startup;
    166
    167	/* initialize USB buffers: */
    168	variax->buffer_activate = kmemdup(variax_activate,
    169					  sizeof(variax_activate), GFP_KERNEL);
    170
    171	if (variax->buffer_activate == NULL)
    172		return -ENOMEM;
    173
    174	/* initiate startup procedure: */
    175	schedule_delayed_work(&line6->startup_work,
    176			      msecs_to_jiffies(VARIAX_STARTUP_DELAY1));
    177	return 0;
    178}
    179
    180#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
    181#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
    182
    183/* table of devices that work with this driver */
    184static const struct usb_device_id variax_id_table[] = {
    185	{ LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
    186	{ LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
    187	{}
    188};
    189
    190MODULE_DEVICE_TABLE(usb, variax_id_table);
    191
    192static const struct line6_properties variax_properties_table[] = {
    193	[LINE6_PODXTLIVE_VARIAX] = {
    194		.id = "PODxtLive",
    195		.name = "PODxt Live",
    196		.capabilities	= LINE6_CAP_CONTROL
    197				| LINE6_CAP_CONTROL_MIDI,
    198		.altsetting = 1,
    199		.ep_ctrl_r = 0x86,
    200		.ep_ctrl_w = 0x05,
    201		.ep_audio_r = 0x82,
    202		.ep_audio_w = 0x01,
    203	},
    204	[LINE6_VARIAX] = {
    205		.id = "Variax",
    206		.name = "Variax Workbench",
    207		.capabilities	= LINE6_CAP_CONTROL
    208				| LINE6_CAP_CONTROL_MIDI,
    209		.altsetting = 1,
    210		.ep_ctrl_r = 0x82,
    211		.ep_ctrl_w = 0x01,
    212		/* no audio channel */
    213	}
    214};
    215
    216/*
    217	Probe USB device.
    218*/
    219static int variax_probe(struct usb_interface *interface,
    220			const struct usb_device_id *id)
    221{
    222	return line6_probe(interface, id, "Line6-Variax",
    223			   &variax_properties_table[id->driver_info],
    224			   variax_init, sizeof(struct usb_line6_variax));
    225}
    226
    227static struct usb_driver variax_driver = {
    228	.name = KBUILD_MODNAME,
    229	.probe = variax_probe,
    230	.disconnect = line6_disconnect,
    231#ifdef CONFIG_PM
    232	.suspend = line6_suspend,
    233	.resume = line6_resume,
    234	.reset_resume = line6_resume,
    235#endif
    236	.id_table = variax_id_table,
    237};
    238
    239module_usb_driver(variax_driver);
    240
    241MODULE_DESCRIPTION("Variax Workbench USB driver");
    242MODULE_LICENSE("GPL");