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

toneport.c (14499B)


      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 *                         Emil Myhrman (emil.myhrman@gmail.com)
      7 */
      8
      9#include <linux/wait.h>
     10#include <linux/usb.h>
     11#include <linux/slab.h>
     12#include <linux/module.h>
     13#include <linux/leds.h>
     14#include <sound/core.h>
     15#include <sound/control.h>
     16
     17#include "capture.h"
     18#include "driver.h"
     19#include "playback.h"
     20
     21enum line6_device_type {
     22	LINE6_GUITARPORT,
     23	LINE6_PODSTUDIO_GX,
     24	LINE6_PODSTUDIO_UX1,
     25	LINE6_PODSTUDIO_UX2,
     26	LINE6_TONEPORT_GX,
     27	LINE6_TONEPORT_UX1,
     28	LINE6_TONEPORT_UX2,
     29};
     30
     31struct usb_line6_toneport;
     32
     33struct toneport_led {
     34	struct led_classdev dev;
     35	char name[64];
     36	struct usb_line6_toneport *toneport;
     37	bool registered;
     38};
     39
     40struct usb_line6_toneport {
     41	/* Generic Line 6 USB data */
     42	struct usb_line6 line6;
     43
     44	/* Source selector */
     45	int source;
     46
     47	/* Serial number of device */
     48	u32 serial_number;
     49
     50	/* Firmware version (x 100) */
     51	u8 firmware_version;
     52
     53	/* Device type */
     54	enum line6_device_type type;
     55
     56	/* LED instances */
     57	struct toneport_led leds[2];
     58};
     59
     60#define line6_to_toneport(x) container_of(x, struct usb_line6_toneport, line6)
     61
     62static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
     63
     64#define TONEPORT_PCM_DELAY 1
     65
     66static const struct snd_ratden toneport_ratden = {
     67	.num_min = 44100,
     68	.num_max = 44100,
     69	.num_step = 1,
     70	.den = 1
     71};
     72
     73static struct line6_pcm_properties toneport_pcm_properties = {
     74	.playback_hw = {
     75				  .info = (SNDRV_PCM_INFO_MMAP |
     76					   SNDRV_PCM_INFO_INTERLEAVED |
     77					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
     78					   SNDRV_PCM_INFO_MMAP_VALID |
     79					   SNDRV_PCM_INFO_PAUSE |
     80					   SNDRV_PCM_INFO_SYNC_START),
     81				  .formats = SNDRV_PCM_FMTBIT_S16_LE,
     82				  .rates = SNDRV_PCM_RATE_KNOT,
     83				  .rate_min = 44100,
     84				  .rate_max = 44100,
     85				  .channels_min = 2,
     86				  .channels_max = 2,
     87				  .buffer_bytes_max = 60000,
     88				  .period_bytes_min = 64,
     89				  .period_bytes_max = 8192,
     90				  .periods_min = 1,
     91				  .periods_max = 1024},
     92	.capture_hw = {
     93				 .info = (SNDRV_PCM_INFO_MMAP |
     94					  SNDRV_PCM_INFO_INTERLEAVED |
     95					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
     96					  SNDRV_PCM_INFO_MMAP_VALID |
     97					  SNDRV_PCM_INFO_SYNC_START),
     98				 .formats = SNDRV_PCM_FMTBIT_S16_LE,
     99				 .rates = SNDRV_PCM_RATE_KNOT,
    100				 .rate_min = 44100,
    101				 .rate_max = 44100,
    102				 .channels_min = 2,
    103				 .channels_max = 2,
    104				 .buffer_bytes_max = 60000,
    105				 .period_bytes_min = 64,
    106				 .period_bytes_max = 8192,
    107				 .periods_min = 1,
    108				 .periods_max = 1024},
    109	.rates = {
    110			    .nrats = 1,
    111			    .rats = &toneport_ratden},
    112	.bytes_per_channel = 2
    113};
    114
    115static const struct {
    116	const char *name;
    117	int code;
    118} toneport_source_info[] = {
    119	{"Microphone", 0x0a01},
    120	{"Line", 0x0801},
    121	{"Instrument", 0x0b01},
    122	{"Inst & Mic", 0x0901}
    123};
    124
    125static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
    126{
    127	int ret;
    128
    129	ret = usb_control_msg_send(usbdev, 0, 0x67,
    130				   USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
    131				   cmd1, cmd2, NULL, 0, LINE6_TIMEOUT,
    132				   GFP_KERNEL);
    133
    134	if (ret) {
    135		dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
    136		return ret;
    137	}
    138
    139	return 0;
    140}
    141
    142/* monitor info callback */
    143static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
    144				     struct snd_ctl_elem_info *uinfo)
    145{
    146	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    147	uinfo->count = 1;
    148	uinfo->value.integer.min = 0;
    149	uinfo->value.integer.max = 256;
    150	return 0;
    151}
    152
    153/* monitor get callback */
    154static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
    155				    struct snd_ctl_elem_value *ucontrol)
    156{
    157	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
    158
    159	ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
    160	return 0;
    161}
    162
    163/* monitor put callback */
    164static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
    165				    struct snd_ctl_elem_value *ucontrol)
    166{
    167	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
    168	int err;
    169
    170	if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
    171		return 0;
    172
    173	line6pcm->volume_monitor = ucontrol->value.integer.value[0];
    174
    175	if (line6pcm->volume_monitor > 0) {
    176		err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR, true);
    177		if (err < 0) {
    178			line6pcm->volume_monitor = 0;
    179			line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
    180			return err;
    181		}
    182	} else {
    183		line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
    184	}
    185
    186	return 1;
    187}
    188
    189/* source info callback */
    190static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
    191				    struct snd_ctl_elem_info *uinfo)
    192{
    193	const int size = ARRAY_SIZE(toneport_source_info);
    194
    195	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
    196	uinfo->count = 1;
    197	uinfo->value.enumerated.items = size;
    198
    199	if (uinfo->value.enumerated.item >= size)
    200		uinfo->value.enumerated.item = size - 1;
    201
    202	strcpy(uinfo->value.enumerated.name,
    203	       toneport_source_info[uinfo->value.enumerated.item].name);
    204
    205	return 0;
    206}
    207
    208/* source get callback */
    209static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
    210				   struct snd_ctl_elem_value *ucontrol)
    211{
    212	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
    213	struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
    214
    215	ucontrol->value.enumerated.item[0] = toneport->source;
    216	return 0;
    217}
    218
    219/* source put callback */
    220static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
    221				   struct snd_ctl_elem_value *ucontrol)
    222{
    223	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
    224	struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
    225	unsigned int source;
    226
    227	source = ucontrol->value.enumerated.item[0];
    228	if (source >= ARRAY_SIZE(toneport_source_info))
    229		return -EINVAL;
    230	if (source == toneport->source)
    231		return 0;
    232
    233	toneport->source = source;
    234	toneport_send_cmd(toneport->line6.usbdev,
    235			  toneport_source_info[source].code, 0x0000);
    236	return 1;
    237}
    238
    239static void toneport_startup(struct usb_line6 *line6)
    240{
    241	line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
    242}
    243
    244/* control definition */
    245static const struct snd_kcontrol_new toneport_control_monitor = {
    246	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    247	.name = "Monitor Playback Volume",
    248	.index = 0,
    249	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    250	.info = snd_toneport_monitor_info,
    251	.get = snd_toneport_monitor_get,
    252	.put = snd_toneport_monitor_put
    253};
    254
    255/* source selector definition */
    256static const struct snd_kcontrol_new toneport_control_source = {
    257	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
    258	.name = "PCM Capture Source",
    259	.index = 0,
    260	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
    261	.info = snd_toneport_source_info,
    262	.get = snd_toneport_source_get,
    263	.put = snd_toneport_source_put
    264};
    265
    266/*
    267	For the led on Guitarport.
    268	Brightness goes from 0x00 to 0x26. Set a value above this to have led
    269	blink.
    270	(void cmd_0x02(byte red, byte green)
    271*/
    272
    273static bool toneport_has_led(struct usb_line6_toneport *toneport)
    274{
    275	switch (toneport->type) {
    276	case LINE6_GUITARPORT:
    277	case LINE6_TONEPORT_GX:
    278	/* add your device here if you are missing support for the LEDs */
    279		return true;
    280
    281	default:
    282		return false;
    283	}
    284}
    285
    286static const char * const toneport_led_colors[2] = { "red", "green" };
    287static const int toneport_led_init_vals[2] = { 0x00, 0x26 };
    288
    289static void toneport_update_led(struct usb_line6_toneport *toneport)
    290{
    291	toneport_send_cmd(toneport->line6.usbdev,
    292			  (toneport->leds[0].dev.brightness << 8) | 0x0002,
    293			  toneport->leds[1].dev.brightness);
    294}
    295
    296static void toneport_led_brightness_set(struct led_classdev *led_cdev,
    297					enum led_brightness brightness)
    298{
    299	struct toneport_led *leds =
    300		container_of(led_cdev, struct toneport_led, dev);
    301	toneport_update_led(leds->toneport);
    302}
    303
    304static int toneport_init_leds(struct usb_line6_toneport *toneport)
    305{
    306	struct device *dev = &toneport->line6.usbdev->dev;
    307	int i, err;
    308
    309	for (i = 0; i < 2; i++) {
    310		struct toneport_led *led = &toneport->leds[i];
    311		struct led_classdev *leddev = &led->dev;
    312
    313		led->toneport = toneport;
    314		snprintf(led->name, sizeof(led->name), "%s::%s",
    315			 dev_name(dev), toneport_led_colors[i]);
    316		leddev->name = led->name;
    317		leddev->brightness = toneport_led_init_vals[i];
    318		leddev->max_brightness = 0x26;
    319		leddev->brightness_set = toneport_led_brightness_set;
    320		err = led_classdev_register(dev, leddev);
    321		if (err)
    322			return err;
    323		led->registered = true;
    324	}
    325
    326	return 0;
    327}
    328
    329static void toneport_remove_leds(struct usb_line6_toneport *toneport)
    330{
    331	struct toneport_led *led;
    332	int i;
    333
    334	for (i = 0; i < 2; i++) {
    335		led = &toneport->leds[i];
    336		if (!led->registered)
    337			break;
    338		led_classdev_unregister(&led->dev);
    339		led->registered = false;
    340	}
    341}
    342
    343static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
    344{
    345	switch (toneport->type) {
    346	case LINE6_TONEPORT_UX1:
    347	case LINE6_TONEPORT_UX2:
    348	case LINE6_PODSTUDIO_UX1:
    349	case LINE6_PODSTUDIO_UX2:
    350		return true;
    351
    352	default:
    353		return false;
    354	}
    355}
    356
    357/*
    358	Setup Toneport device.
    359*/
    360static int toneport_setup(struct usb_line6_toneport *toneport)
    361{
    362	u32 *ticks;
    363	struct usb_line6 *line6 = &toneport->line6;
    364	struct usb_device *usbdev = line6->usbdev;
    365
    366	ticks = kmalloc(sizeof(*ticks), GFP_KERNEL);
    367	if (!ticks)
    368		return -ENOMEM;
    369
    370	/* sync time on device with host: */
    371	/* note: 32-bit timestamps overflow in year 2106 */
    372	*ticks = (u32)ktime_get_real_seconds();
    373	line6_write_data(line6, 0x80c6, ticks, 4);
    374	kfree(ticks);
    375
    376	/* enable device: */
    377	toneport_send_cmd(usbdev, 0x0301, 0x0000);
    378
    379	/* initialize source select: */
    380	if (toneport_has_source_select(toneport))
    381		toneport_send_cmd(usbdev,
    382				  toneport_source_info[toneport->source].code,
    383				  0x0000);
    384
    385	if (toneport_has_led(toneport))
    386		toneport_update_led(toneport);
    387
    388	schedule_delayed_work(&toneport->line6.startup_work,
    389			      msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
    390	return 0;
    391}
    392
    393/*
    394	Toneport device disconnected.
    395*/
    396static void line6_toneport_disconnect(struct usb_line6 *line6)
    397{
    398	struct usb_line6_toneport *toneport = line6_to_toneport(line6);
    399
    400	if (toneport_has_led(toneport))
    401		toneport_remove_leds(toneport);
    402}
    403
    404
    405/*
    406	 Try to init Toneport device.
    407*/
    408static int toneport_init(struct usb_line6 *line6,
    409			 const struct usb_device_id *id)
    410{
    411	int err;
    412	struct usb_line6_toneport *toneport = line6_to_toneport(line6);
    413
    414	toneport->type = id->driver_info;
    415
    416	line6->disconnect = line6_toneport_disconnect;
    417	line6->startup = toneport_startup;
    418
    419	/* initialize PCM subsystem: */
    420	err = line6_init_pcm(line6, &toneport_pcm_properties);
    421	if (err < 0)
    422		return err;
    423
    424	/* register monitor control: */
    425	err = snd_ctl_add(line6->card,
    426			  snd_ctl_new1(&toneport_control_monitor,
    427				       line6->line6pcm));
    428	if (err < 0)
    429		return err;
    430
    431	/* register source select control: */
    432	if (toneport_has_source_select(toneport)) {
    433		err =
    434		    snd_ctl_add(line6->card,
    435				snd_ctl_new1(&toneport_control_source,
    436					     line6->line6pcm));
    437		if (err < 0)
    438			return err;
    439	}
    440
    441	line6_read_serial_number(line6, &toneport->serial_number);
    442	line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
    443
    444	if (toneport_has_led(toneport)) {
    445		err = toneport_init_leds(toneport);
    446		if (err < 0)
    447			return err;
    448	}
    449
    450	err = toneport_setup(toneport);
    451	if (err)
    452		return err;
    453
    454	/* register audio system: */
    455	return snd_card_register(line6->card);
    456}
    457
    458#ifdef CONFIG_PM
    459/*
    460	Resume Toneport device after reset.
    461*/
    462static int toneport_reset_resume(struct usb_interface *interface)
    463{
    464	int err;
    465
    466	err = toneport_setup(usb_get_intfdata(interface));
    467	if (err)
    468		return err;
    469	return line6_resume(interface);
    470}
    471#endif
    472
    473#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
    474#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
    475
    476/* table of devices that work with this driver */
    477static const struct usb_device_id toneport_id_table[] = {
    478	{ LINE6_DEVICE(0x4750),    .driver_info = LINE6_GUITARPORT },
    479	{ LINE6_DEVICE(0x4153),    .driver_info = LINE6_PODSTUDIO_GX },
    480	{ LINE6_DEVICE(0x4150),    .driver_info = LINE6_PODSTUDIO_UX1 },
    481	{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
    482	{ LINE6_DEVICE(0x4147),    .driver_info = LINE6_TONEPORT_GX },
    483	{ LINE6_DEVICE(0x4141),    .driver_info = LINE6_TONEPORT_UX1 },
    484	{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
    485	{}
    486};
    487
    488MODULE_DEVICE_TABLE(usb, toneport_id_table);
    489
    490static const struct line6_properties toneport_properties_table[] = {
    491	[LINE6_GUITARPORT] = {
    492		.id = "GuitarPort",
    493		.name = "GuitarPort",
    494		.capabilities	= LINE6_CAP_PCM,
    495		.altsetting = 2,  /* 1..4 seem to be ok */
    496		/* no control channel */
    497		.ep_audio_r = 0x82,
    498		.ep_audio_w = 0x01,
    499	},
    500	[LINE6_PODSTUDIO_GX] = {
    501		.id = "PODStudioGX",
    502		.name = "POD Studio GX",
    503		.capabilities	= LINE6_CAP_PCM,
    504		.altsetting = 2,  /* 1..4 seem to be ok */
    505		/* no control channel */
    506		.ep_audio_r = 0x82,
    507		.ep_audio_w = 0x01,
    508	},
    509	[LINE6_PODSTUDIO_UX1] = {
    510		.id = "PODStudioUX1",
    511		.name = "POD Studio UX1",
    512		.capabilities	= LINE6_CAP_PCM,
    513		.altsetting = 2,  /* 1..4 seem to be ok */
    514		/* no control channel */
    515		.ep_audio_r = 0x82,
    516		.ep_audio_w = 0x01,
    517	},
    518	[LINE6_PODSTUDIO_UX2] = {
    519		.id = "PODStudioUX2",
    520		.name = "POD Studio UX2",
    521		.capabilities	= LINE6_CAP_PCM,
    522		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
    523		/* no control channel */
    524		.ep_audio_r = 0x82,
    525		.ep_audio_w = 0x01,
    526	},
    527	[LINE6_TONEPORT_GX] = {
    528		.id = "TonePortGX",
    529		.name = "TonePort GX",
    530		.capabilities	= LINE6_CAP_PCM,
    531		.altsetting = 2,  /* 1..4 seem to be ok */
    532		/* no control channel */
    533		.ep_audio_r = 0x82,
    534		.ep_audio_w = 0x01,
    535	},
    536	[LINE6_TONEPORT_UX1] = {
    537		.id = "TonePortUX1",
    538		.name = "TonePort UX1",
    539		.capabilities	= LINE6_CAP_PCM,
    540		.altsetting = 2,  /* 1..4 seem to be ok */
    541		/* no control channel */
    542		.ep_audio_r = 0x82,
    543		.ep_audio_w = 0x01,
    544	},
    545	[LINE6_TONEPORT_UX2] = {
    546		.id = "TonePortUX2",
    547		.name = "TonePort UX2",
    548		.capabilities	= LINE6_CAP_PCM,
    549		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
    550		/* no control channel */
    551		.ep_audio_r = 0x82,
    552		.ep_audio_w = 0x01,
    553	},
    554};
    555
    556/*
    557	Probe USB device.
    558*/
    559static int toneport_probe(struct usb_interface *interface,
    560			  const struct usb_device_id *id)
    561{
    562	return line6_probe(interface, id, "Line6-TonePort",
    563			   &toneport_properties_table[id->driver_info],
    564			   toneport_init, sizeof(struct usb_line6_toneport));
    565}
    566
    567static struct usb_driver toneport_driver = {
    568	.name = KBUILD_MODNAME,
    569	.probe = toneport_probe,
    570	.disconnect = line6_disconnect,
    571#ifdef CONFIG_PM
    572	.suspend = line6_suspend,
    573	.resume = line6_resume,
    574	.reset_resume = toneport_reset_resume,
    575#endif
    576	.id_table = toneport_id_table,
    577};
    578
    579module_usb_driver(toneport_driver);
    580
    581MODULE_DESCRIPTION("TonePort USB driver");
    582MODULE_LICENSE("GPL");