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

bcd2000.c (11456B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Behringer BCD2000 driver
      4 *
      5 *   Copyright (C) 2014 Mario Kicherer (dev@kicherer.org)
      6 */
      7
      8#include <linux/kernel.h>
      9#include <linux/errno.h>
     10#include <linux/init.h>
     11#include <linux/slab.h>
     12#include <linux/module.h>
     13#include <linux/bitmap.h>
     14#include <linux/usb.h>
     15#include <linux/usb/audio.h>
     16#include <sound/core.h>
     17#include <sound/initval.h>
     18#include <sound/rawmidi.h>
     19
     20#define PREFIX "snd-bcd2000: "
     21#define BUFSIZE 64
     22
     23static const struct usb_device_id id_table[] = {
     24	{ USB_DEVICE(0x1397, 0x00bd) },
     25	{ },
     26};
     27
     28static const unsigned char device_cmd_prefix[] = {0x03, 0x00};
     29
     30static const unsigned char bcd2000_init_sequence[] = {
     31	0x07, 0x00, 0x00, 0x00, 0x78, 0x48, 0x1c, 0x81,
     32	0xc4, 0x00, 0x00, 0x00, 0x5e, 0x53, 0x4a, 0xf7,
     33	0x18, 0xfa, 0x11, 0xff, 0x6c, 0xf3, 0x90, 0xff,
     34	0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
     35	0x18, 0xfa, 0x11, 0xff, 0x14, 0x00, 0x00, 0x00,
     36	0x00, 0x00, 0x00, 0x00, 0xf2, 0x34, 0x4a, 0xf7,
     37	0x18, 0xfa, 0x11, 0xff
     38};
     39
     40struct bcd2000 {
     41	struct usb_device *dev;
     42	struct snd_card *card;
     43	struct usb_interface *intf;
     44	int card_index;
     45
     46	int midi_out_active;
     47	struct snd_rawmidi *rmidi;
     48	struct snd_rawmidi_substream *midi_receive_substream;
     49	struct snd_rawmidi_substream *midi_out_substream;
     50
     51	unsigned char midi_in_buf[BUFSIZE];
     52	unsigned char midi_out_buf[BUFSIZE];
     53
     54	struct urb *midi_out_urb;
     55	struct urb *midi_in_urb;
     56
     57	struct usb_anchor anchor;
     58};
     59
     60static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
     61static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
     62
     63static DEFINE_MUTEX(devices_mutex);
     64static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
     65static struct usb_driver bcd2000_driver;
     66
     67#ifdef CONFIG_SND_DEBUG
     68static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len)
     69{
     70	print_hex_dump(KERN_DEBUG, prefix,
     71			DUMP_PREFIX_NONE, 16, 1,
     72			buf, len, false);
     73}
     74#else
     75static void bcd2000_dump_buffer(const char *prefix, const char *buf, int len) {}
     76#endif
     77
     78static int bcd2000_midi_input_open(struct snd_rawmidi_substream *substream)
     79{
     80	return 0;
     81}
     82
     83static int bcd2000_midi_input_close(struct snd_rawmidi_substream *substream)
     84{
     85	return 0;
     86}
     87
     88/* (de)register midi substream from client */
     89static void bcd2000_midi_input_trigger(struct snd_rawmidi_substream *substream,
     90						int up)
     91{
     92	struct bcd2000 *bcd2k = substream->rmidi->private_data;
     93	bcd2k->midi_receive_substream = up ? substream : NULL;
     94}
     95
     96static void bcd2000_midi_handle_input(struct bcd2000 *bcd2k,
     97				const unsigned char *buf, unsigned int buf_len)
     98{
     99	unsigned int payload_length, tocopy;
    100	struct snd_rawmidi_substream *midi_receive_substream;
    101
    102	midi_receive_substream = READ_ONCE(bcd2k->midi_receive_substream);
    103	if (!midi_receive_substream)
    104		return;
    105
    106	bcd2000_dump_buffer(PREFIX "received from device: ", buf, buf_len);
    107
    108	if (buf_len < 2)
    109		return;
    110
    111	payload_length = buf[0];
    112
    113	/* ignore packets without payload */
    114	if (payload_length == 0)
    115		return;
    116
    117	tocopy = min(payload_length, buf_len-1);
    118
    119	bcd2000_dump_buffer(PREFIX "sending to userspace: ",
    120					&buf[1], tocopy);
    121
    122	snd_rawmidi_receive(midi_receive_substream,
    123					&buf[1], tocopy);
    124}
    125
    126static void bcd2000_midi_send(struct bcd2000 *bcd2k)
    127{
    128	int len, ret;
    129	struct snd_rawmidi_substream *midi_out_substream;
    130
    131	BUILD_BUG_ON(sizeof(device_cmd_prefix) >= BUFSIZE);
    132
    133	midi_out_substream = READ_ONCE(bcd2k->midi_out_substream);
    134	if (!midi_out_substream)
    135		return;
    136
    137	/* copy command prefix bytes */
    138	memcpy(bcd2k->midi_out_buf, device_cmd_prefix,
    139		sizeof(device_cmd_prefix));
    140
    141	/*
    142	 * get MIDI packet and leave space for command prefix
    143	 * and payload length
    144	 */
    145	len = snd_rawmidi_transmit(midi_out_substream,
    146				bcd2k->midi_out_buf + 3, BUFSIZE - 3);
    147
    148	if (len < 0)
    149		dev_err(&bcd2k->dev->dev, "%s: snd_rawmidi_transmit error %d\n",
    150				__func__, len);
    151
    152	if (len <= 0)
    153		return;
    154
    155	/* set payload length */
    156	bcd2k->midi_out_buf[2] = len;
    157	bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE;
    158
    159	bcd2000_dump_buffer(PREFIX "sending to device: ",
    160			bcd2k->midi_out_buf, len+3);
    161
    162	/* send packet to the BCD2000 */
    163	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC);
    164	if (ret < 0)
    165		dev_err(&bcd2k->dev->dev, PREFIX
    166			"%s (%p): usb_submit_urb() failed, ret=%d, len=%d\n",
    167			__func__, midi_out_substream, ret, len);
    168	else
    169		bcd2k->midi_out_active = 1;
    170}
    171
    172static int bcd2000_midi_output_open(struct snd_rawmidi_substream *substream)
    173{
    174	return 0;
    175}
    176
    177static int bcd2000_midi_output_close(struct snd_rawmidi_substream *substream)
    178{
    179	struct bcd2000 *bcd2k = substream->rmidi->private_data;
    180
    181	if (bcd2k->midi_out_active) {
    182		usb_kill_urb(bcd2k->midi_out_urb);
    183		bcd2k->midi_out_active = 0;
    184	}
    185
    186	return 0;
    187}
    188
    189/* (de)register midi substream from client */
    190static void bcd2000_midi_output_trigger(struct snd_rawmidi_substream *substream,
    191						int up)
    192{
    193	struct bcd2000 *bcd2k = substream->rmidi->private_data;
    194
    195	if (up) {
    196		bcd2k->midi_out_substream = substream;
    197		/* check if there is data userspace wants to send */
    198		if (!bcd2k->midi_out_active)
    199			bcd2000_midi_send(bcd2k);
    200	} else {
    201		bcd2k->midi_out_substream = NULL;
    202	}
    203}
    204
    205static void bcd2000_output_complete(struct urb *urb)
    206{
    207	struct bcd2000 *bcd2k = urb->context;
    208
    209	bcd2k->midi_out_active = 0;
    210
    211	if (urb->status)
    212		dev_warn(&urb->dev->dev,
    213			PREFIX "output urb->status: %d\n", urb->status);
    214
    215	if (urb->status == -ESHUTDOWN)
    216		return;
    217
    218	/* check if there is more data userspace wants to send */
    219	bcd2000_midi_send(bcd2k);
    220}
    221
    222static void bcd2000_input_complete(struct urb *urb)
    223{
    224	int ret;
    225	struct bcd2000 *bcd2k = urb->context;
    226
    227	if (urb->status)
    228		dev_warn(&urb->dev->dev,
    229			PREFIX "input urb->status: %i\n", urb->status);
    230
    231	if (!bcd2k || urb->status == -ESHUTDOWN)
    232		return;
    233
    234	if (urb->actual_length > 0)
    235		bcd2000_midi_handle_input(bcd2k, urb->transfer_buffer,
    236					urb->actual_length);
    237
    238	/* return URB to device */
    239	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_ATOMIC);
    240	if (ret < 0)
    241		dev_err(&bcd2k->dev->dev, PREFIX
    242			"%s: usb_submit_urb() failed, ret=%d\n",
    243			__func__, ret);
    244}
    245
    246static const struct snd_rawmidi_ops bcd2000_midi_output = {
    247	.open =    bcd2000_midi_output_open,
    248	.close =   bcd2000_midi_output_close,
    249	.trigger = bcd2000_midi_output_trigger,
    250};
    251
    252static const struct snd_rawmidi_ops bcd2000_midi_input = {
    253	.open =    bcd2000_midi_input_open,
    254	.close =   bcd2000_midi_input_close,
    255	.trigger = bcd2000_midi_input_trigger,
    256};
    257
    258static void bcd2000_init_device(struct bcd2000 *bcd2k)
    259{
    260	int ret;
    261
    262	init_usb_anchor(&bcd2k->anchor);
    263	usb_anchor_urb(bcd2k->midi_out_urb, &bcd2k->anchor);
    264	usb_anchor_urb(bcd2k->midi_in_urb, &bcd2k->anchor);
    265
    266	/* copy init sequence into buffer */
    267	memcpy(bcd2k->midi_out_buf, bcd2000_init_sequence, 52);
    268	bcd2k->midi_out_urb->transfer_buffer_length = 52;
    269
    270	/* submit sequence */
    271	ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_KERNEL);
    272	if (ret < 0)
    273		dev_err(&bcd2k->dev->dev, PREFIX
    274			"%s: usb_submit_urb() out failed, ret=%d: ",
    275			__func__, ret);
    276	else
    277		bcd2k->midi_out_active = 1;
    278
    279	/* pass URB to device to enable button and controller events */
    280	ret = usb_submit_urb(bcd2k->midi_in_urb, GFP_KERNEL);
    281	if (ret < 0)
    282		dev_err(&bcd2k->dev->dev, PREFIX
    283			"%s: usb_submit_urb() in failed, ret=%d: ",
    284			__func__, ret);
    285
    286	/* ensure initialization is finished */
    287	usb_wait_anchor_empty_timeout(&bcd2k->anchor, 1000);
    288}
    289
    290static int bcd2000_init_midi(struct bcd2000 *bcd2k)
    291{
    292	int ret;
    293	struct snd_rawmidi *rmidi;
    294
    295	ret = snd_rawmidi_new(bcd2k->card, bcd2k->card->shortname, 0,
    296					1, /* output */
    297					1, /* input */
    298					&rmidi);
    299
    300	if (ret < 0)
    301		return ret;
    302
    303	strscpy(rmidi->name, bcd2k->card->shortname, sizeof(rmidi->name));
    304
    305	rmidi->info_flags = SNDRV_RAWMIDI_INFO_DUPLEX;
    306	rmidi->private_data = bcd2k;
    307
    308	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
    309	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
    310					&bcd2000_midi_output);
    311
    312	rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
    313	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
    314					&bcd2000_midi_input);
    315
    316	bcd2k->rmidi = rmidi;
    317
    318	bcd2k->midi_in_urb = usb_alloc_urb(0, GFP_KERNEL);
    319	bcd2k->midi_out_urb = usb_alloc_urb(0, GFP_KERNEL);
    320
    321	if (!bcd2k->midi_in_urb || !bcd2k->midi_out_urb) {
    322		dev_err(&bcd2k->dev->dev, PREFIX "usb_alloc_urb failed\n");
    323		return -ENOMEM;
    324	}
    325
    326	usb_fill_int_urb(bcd2k->midi_in_urb, bcd2k->dev,
    327				usb_rcvintpipe(bcd2k->dev, 0x81),
    328				bcd2k->midi_in_buf, BUFSIZE,
    329				bcd2000_input_complete, bcd2k, 1);
    330
    331	usb_fill_int_urb(bcd2k->midi_out_urb, bcd2k->dev,
    332				usb_sndintpipe(bcd2k->dev, 0x1),
    333				bcd2k->midi_out_buf, BUFSIZE,
    334				bcd2000_output_complete, bcd2k, 1);
    335
    336	/* sanity checks of EPs before actually submitting */
    337	if (usb_urb_ep_type_check(bcd2k->midi_in_urb) ||
    338	    usb_urb_ep_type_check(bcd2k->midi_out_urb)) {
    339		dev_err(&bcd2k->dev->dev, "invalid MIDI EP\n");
    340		return -EINVAL;
    341	}
    342
    343	bcd2000_init_device(bcd2k);
    344
    345	return 0;
    346}
    347
    348static void bcd2000_free_usb_related_resources(struct bcd2000 *bcd2k,
    349						struct usb_interface *interface)
    350{
    351	/* usb_kill_urb not necessary, urb is aborted automatically */
    352
    353	usb_free_urb(bcd2k->midi_out_urb);
    354	usb_free_urb(bcd2k->midi_in_urb);
    355
    356	if (bcd2k->intf) {
    357		usb_set_intfdata(bcd2k->intf, NULL);
    358		bcd2k->intf = NULL;
    359	}
    360}
    361
    362static int bcd2000_probe(struct usb_interface *interface,
    363				const struct usb_device_id *usb_id)
    364{
    365	struct snd_card *card;
    366	struct bcd2000 *bcd2k;
    367	unsigned int card_index;
    368	char usb_path[32];
    369	int err;
    370
    371	mutex_lock(&devices_mutex);
    372
    373	for (card_index = 0; card_index < SNDRV_CARDS; ++card_index)
    374		if (!test_bit(card_index, devices_used))
    375			break;
    376
    377	if (card_index >= SNDRV_CARDS) {
    378		mutex_unlock(&devices_mutex);
    379		return -ENOENT;
    380	}
    381
    382	err = snd_card_new(&interface->dev, index[card_index], id[card_index],
    383			THIS_MODULE, sizeof(*bcd2k), &card);
    384	if (err < 0) {
    385		mutex_unlock(&devices_mutex);
    386		return err;
    387	}
    388
    389	bcd2k = card->private_data;
    390	bcd2k->dev = interface_to_usbdev(interface);
    391	bcd2k->card = card;
    392	bcd2k->card_index = card_index;
    393	bcd2k->intf = interface;
    394
    395	snd_card_set_dev(card, &interface->dev);
    396
    397	strncpy(card->driver, "snd-bcd2000", sizeof(card->driver));
    398	strncpy(card->shortname, "BCD2000", sizeof(card->shortname));
    399	usb_make_path(bcd2k->dev, usb_path, sizeof(usb_path));
    400	snprintf(bcd2k->card->longname, sizeof(bcd2k->card->longname),
    401		    "Behringer BCD2000 at %s",
    402			usb_path);
    403
    404	err = bcd2000_init_midi(bcd2k);
    405	if (err < 0)
    406		goto probe_error;
    407
    408	err = snd_card_register(card);
    409	if (err < 0)
    410		goto probe_error;
    411
    412	usb_set_intfdata(interface, bcd2k);
    413	set_bit(card_index, devices_used);
    414
    415	mutex_unlock(&devices_mutex);
    416	return 0;
    417
    418probe_error:
    419	dev_info(&bcd2k->dev->dev, PREFIX "error during probing");
    420	bcd2000_free_usb_related_resources(bcd2k, interface);
    421	snd_card_free(card);
    422	mutex_unlock(&devices_mutex);
    423	return err;
    424}
    425
    426static void bcd2000_disconnect(struct usb_interface *interface)
    427{
    428	struct bcd2000 *bcd2k = usb_get_intfdata(interface);
    429
    430	if (!bcd2k)
    431		return;
    432
    433	mutex_lock(&devices_mutex);
    434
    435	/* make sure that userspace cannot create new requests */
    436	snd_card_disconnect(bcd2k->card);
    437
    438	bcd2000_free_usb_related_resources(bcd2k, interface);
    439
    440	clear_bit(bcd2k->card_index, devices_used);
    441
    442	snd_card_free_when_closed(bcd2k->card);
    443
    444	mutex_unlock(&devices_mutex);
    445}
    446
    447static struct usb_driver bcd2000_driver = {
    448	.name =		"snd-bcd2000",
    449	.probe =	bcd2000_probe,
    450	.disconnect =	bcd2000_disconnect,
    451	.id_table =	id_table,
    452};
    453
    454module_usb_driver(bcd2000_driver);
    455
    456MODULE_DEVICE_TABLE(usb, id_table);
    457MODULE_AUTHOR("Mario Kicherer, dev@kicherer.org");
    458MODULE_DESCRIPTION("Behringer BCD2000 driver");
    459MODULE_LICENSE("GPL");