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

usbusx2y.c (12968B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * usbusx2y.c - ALSA USB US-428 Driver
      4 *
      52005-04-14 Karsten Wiese
      6	Version 0.8.7.2:
      7	Call snd_card_free() instead of snd_card_free_in_thread() to prevent oops with dead keyboard symptom.
      8	Tested ok with kernel 2.6.12-rc2.
      9
     102004-12-14 Karsten Wiese
     11	Version 0.8.7.1:
     12	snd_pcm_open for rawusb pcm-devices now returns -EBUSY if called without rawusb's hwdep device being open.
     13
     142004-12-02 Karsten Wiese
     15	Version 0.8.7:
     16	Use macro usb_maxpacket() for portability.
     17
     182004-10-26 Karsten Wiese
     19	Version 0.8.6:
     20	wake_up() process waiting in usx2y_urbs_start() on error.
     21
     222004-10-21 Karsten Wiese
     23	Version 0.8.5:
     24	nrpacks is runtime or compiletime configurable now with tested values from 1 to 4.
     25
     262004-10-03 Karsten Wiese
     27	Version 0.8.2:
     28	Avoid any possible racing while in prepare callback.
     29
     302004-09-30 Karsten Wiese
     31	Version 0.8.0:
     32	Simplified things and made ohci work again.
     33
     342004-09-20 Karsten Wiese
     35	Version 0.7.3:
     36	Use usb_kill_urb() instead of deprecated (kernel 2.6.9) usb_unlink_urb().
     37
     382004-07-13 Karsten Wiese
     39	Version 0.7.1:
     40	Don't sleep in START/STOP callbacks anymore.
     41	us428 channels C/D not handled just for this version, sorry.
     42
     432004-06-21 Karsten Wiese
     44	Version 0.6.4:
     45	Temporarely suspend midi input
     46	to sanely call usb_set_interface() when setting format.
     47
     482004-06-12 Karsten Wiese
     49	Version 0.6.3:
     50	Made it thus the following rule is enforced:
     51	"All pcm substreams of one usx2y have to operate at the same rate & format."
     52
     532004-04-06 Karsten Wiese
     54	Version 0.6.0:
     55	Runs on 2.6.5 kernel without any "--with-debug=" things.
     56	us224 reported running.
     57
     582004-01-14 Karsten Wiese
     59	Version 0.5.1:
     60	Runs with 2.6.1 kernel.
     61
     622003-12-30 Karsten Wiese
     63	Version 0.4.1:
     64	Fix 24Bit 4Channel capturing for the us428.
     65
     662003-11-27 Karsten Wiese, Martin Langer
     67	Version 0.4:
     68	us122 support.
     69	us224 could be tested by uncommenting the sections containing USB_ID_US224
     70
     712003-11-03 Karsten Wiese
     72	Version 0.3:
     73	24Bit support.
     74	"arecord -D hw:1 -c 2 -r 48000 -M -f S24_3LE|aplay -D hw:1 -c 2 -r 48000 -M -f S24_3LE" works.
     75
     762003-08-22 Karsten Wiese
     77	Version 0.0.8:
     78	Removed EZUSB Firmware. First Stage Firmwaredownload is now done by tascam-firmware downloader.
     79	See:
     80	http://usb-midi-fw.sourceforge.net/tascam-firmware.tar.gz
     81
     822003-06-18 Karsten Wiese
     83	Version 0.0.5:
     84	changed to compile with kernel 2.4.21 and alsa 0.9.4
     85
     862002-10-16 Karsten Wiese
     87	Version 0.0.4:
     88	compiles again with alsa-current.
     89	USB_ISO_ASAP not used anymore (most of the time), instead
     90	urb->start_frame is calculated here now, some calls inside usb-driver don't need to happen anymore.
     91
     92	To get the best out of this:
     93	Disable APM-support in the kernel as APM-BIOS calls (once each second) hard disable interrupt for many precious milliseconds.
     94	This helped me much on my slowish PII 400 & PIII 500.
     95	ACPI yet untested but might cause the same bad behaviour.
     96	Use a kernel with lowlatency and preemptiv patches applied.
     97	To autoload snd-usb-midi append a line
     98		post-install snd-usb-us428 modprobe snd-usb-midi
     99	to /etc/modules.conf.
    100
    101	known problems:
    102	sliders, knobs, lights not yet handled except MASTER Volume slider.
    103	"pcm -c 2" doesn't work. "pcm -c 2 -m direct_interleaved" does.
    104	KDE3: "Enable full duplex operation" deadlocks.
    105
    1062002-08-31 Karsten Wiese
    107	Version 0.0.3: audio also simplex;
    108	simplifying: iso urbs only 1 packet, melted structs.
    109	ASYNC_UNLINK not used anymore: no more crashes so far.....
    110	for alsa 0.9 rc3.
    111
    1122002-08-09 Karsten Wiese
    113	Version 0.0.2: midi works with snd-usb-midi, audio (only fullduplex now) with i.e. bristol.
    114	The firmware has been sniffed from win2k us-428 driver 3.09.
    115
    116 *   Copyright (c) 2002 - 2004 Karsten Wiese
    117 */
    118
    119#include <linux/init.h>
    120#include <linux/module.h>
    121#include <linux/moduleparam.h>
    122#include <linux/slab.h>
    123#include <linux/interrupt.h>
    124#include <linux/usb.h>
    125#include <sound/core.h>
    126#include <sound/initval.h>
    127#include <sound/pcm.h>
    128
    129#include <sound/rawmidi.h>
    130#include "usx2y.h"
    131#include "usbusx2y.h"
    132#include "usX2Yhwdep.h"
    133
    134MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
    135MODULE_DESCRIPTION("TASCAM "NAME_ALLCAPS" Version 0.8.7.2");
    136MODULE_LICENSE("GPL");
    137
    138static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
    139static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
    140static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
    141
    142module_param_array(index, int, NULL, 0444);
    143MODULE_PARM_DESC(index, "Index value for "NAME_ALLCAPS".");
    144module_param_array(id, charp, NULL, 0444);
    145MODULE_PARM_DESC(id, "ID string for "NAME_ALLCAPS".");
    146module_param_array(enable, bool, NULL, 0444);
    147MODULE_PARM_DESC(enable, "Enable "NAME_ALLCAPS".");
    148
    149static int snd_usx2y_card_used[SNDRV_CARDS];
    150
    151static void snd_usx2y_card_private_free(struct snd_card *card);
    152static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s);
    153
    154/*
    155 * pipe 4 is used for switching the lamps, setting samplerate, volumes ....
    156 */
    157static void i_usx2y_out04_int(struct urb *urb)
    158{
    159#ifdef CONFIG_SND_DEBUG
    160	if (urb->status) {
    161		int i;
    162		struct usx2ydev *usx2y = urb->context;
    163
    164		for (i = 0; i < 10 && usx2y->as04.urb[i] != urb; i++)
    165			;
    166		snd_printdd("%s urb %i status=%i\n", __func__, i, urb->status);
    167	}
    168#endif
    169}
    170
    171static void i_usx2y_in04_int(struct urb *urb)
    172{
    173	int			err = 0;
    174	struct usx2ydev		*usx2y = urb->context;
    175	struct us428ctls_sharedmem	*us428ctls = usx2y->us428ctls_sharedmem;
    176	struct us428_p4out *p4out;
    177	int i, j, n, diff, send;
    178
    179	usx2y->in04_int_calls++;
    180
    181	if (urb->status) {
    182		snd_printdd("Interrupt Pipe 4 came back with status=%i\n", urb->status);
    183		return;
    184	}
    185
    186	//	printk("%i:0x%02X ", 8, (int)((unsigned char*)usx2y->in04_buf)[8]); Master volume shows 0 here if fader is at max during boot ?!?
    187	if (us428ctls) {
    188		diff = -1;
    189		if (us428ctls->ctl_snapshot_last == -2) {
    190			diff = 0;
    191			memcpy(usx2y->in04_last, usx2y->in04_buf, sizeof(usx2y->in04_last));
    192			us428ctls->ctl_snapshot_last = -1;
    193		} else {
    194			for (i = 0; i < 21; i++) {
    195				if (usx2y->in04_last[i] != ((char *)usx2y->in04_buf)[i]) {
    196					if (diff < 0)
    197						diff = i;
    198					usx2y->in04_last[i] = ((char *)usx2y->in04_buf)[i];
    199				}
    200			}
    201		}
    202		if (diff >= 0) {
    203			n = us428ctls->ctl_snapshot_last + 1;
    204			if (n >= N_US428_CTL_BUFS || n < 0)
    205				n = 0;
    206			memcpy(us428ctls->ctl_snapshot + n, usx2y->in04_buf, sizeof(us428ctls->ctl_snapshot[0]));
    207			us428ctls->ctl_snapshot_differs_at[n] = diff;
    208			us428ctls->ctl_snapshot_last = n;
    209			wake_up(&usx2y->us428ctls_wait_queue_head);
    210		}
    211	}
    212
    213	if (usx2y->us04) {
    214		if (!usx2y->us04->submitted) {
    215			do {
    216				err = usb_submit_urb(usx2y->us04->urb[usx2y->us04->submitted++], GFP_ATOMIC);
    217			} while (!err && usx2y->us04->submitted < usx2y->us04->len);
    218		}
    219	} else {
    220		if (us428ctls && us428ctls->p4out_last >= 0 && us428ctls->p4out_last < N_US428_P4OUT_BUFS) {
    221			if (us428ctls->p4out_last != us428ctls->p4out_sent) {
    222				send = us428ctls->p4out_sent + 1;
    223				if (send >= N_US428_P4OUT_BUFS)
    224					send = 0;
    225				for (j = 0; j < URBS_ASYNC_SEQ && !err; ++j) {
    226					if (!usx2y->as04.urb[j]->status) {
    227						p4out = us428ctls->p4out + send;	// FIXME if more than 1 p4out is new, 1 gets lost.
    228						usb_fill_bulk_urb(usx2y->as04.urb[j], usx2y->dev,
    229								  usb_sndbulkpipe(usx2y->dev, 0x04), &p4out->val.vol,
    230								  p4out->type == ELT_LIGHT ? sizeof(struct us428_lights) : 5,
    231								  i_usx2y_out04_int, usx2y);
    232						err = usb_submit_urb(usx2y->as04.urb[j], GFP_ATOMIC);
    233						us428ctls->p4out_sent = send;
    234						break;
    235					}
    236				}
    237			}
    238		}
    239	}
    240
    241	if (err)
    242		snd_printk(KERN_ERR "in04_int() usb_submit_urb err=%i\n", err);
    243
    244	urb->dev = usx2y->dev;
    245	usb_submit_urb(urb, GFP_ATOMIC);
    246}
    247
    248/*
    249 * Prepare some urbs
    250 */
    251int usx2y_async_seq04_init(struct usx2ydev *usx2y)
    252{
    253	int	err = 0, i;
    254
    255	if (WARN_ON(usx2y->as04.buffer))
    256		return -EBUSY;
    257
    258	usx2y->as04.buffer = kmalloc_array(URBS_ASYNC_SEQ,
    259					   URB_DATA_LEN_ASYNC_SEQ, GFP_KERNEL);
    260	if (!usx2y->as04.buffer) {
    261		err = -ENOMEM;
    262	} else {
    263		for (i = 0; i < URBS_ASYNC_SEQ; ++i) {
    264			usx2y->as04.urb[i] = usb_alloc_urb(0, GFP_KERNEL);
    265			if (!usx2y->as04.urb[i]) {
    266				err = -ENOMEM;
    267				break;
    268			}
    269			usb_fill_bulk_urb(usx2y->as04.urb[i], usx2y->dev,
    270					  usb_sndbulkpipe(usx2y->dev, 0x04),
    271					  usx2y->as04.buffer + URB_DATA_LEN_ASYNC_SEQ * i, 0,
    272					  i_usx2y_out04_int, usx2y);
    273			err = usb_urb_ep_type_check(usx2y->as04.urb[i]);
    274			if (err < 0)
    275				break;
    276		}
    277	}
    278	if (err)
    279		usx2y_unlinkseq(&usx2y->as04);
    280	return err;
    281}
    282
    283int usx2y_in04_init(struct usx2ydev *usx2y)
    284{
    285	int err;
    286
    287	if (WARN_ON(usx2y->in04_urb))
    288		return -EBUSY;
    289
    290	usx2y->in04_urb = usb_alloc_urb(0, GFP_KERNEL);
    291	if (!usx2y->in04_urb) {
    292		err = -ENOMEM;
    293		goto error;
    294	}
    295
    296	usx2y->in04_buf = kmalloc(21, GFP_KERNEL);
    297	if (!usx2y->in04_buf) {
    298		err = -ENOMEM;
    299		goto error;
    300	}
    301
    302	init_waitqueue_head(&usx2y->in04_wait_queue);
    303	usb_fill_int_urb(usx2y->in04_urb, usx2y->dev, usb_rcvintpipe(usx2y->dev, 0x4),
    304			 usx2y->in04_buf, 21,
    305			 i_usx2y_in04_int, usx2y,
    306			 10);
    307	if (usb_urb_ep_type_check(usx2y->in04_urb)) {
    308		err = -EINVAL;
    309		goto error;
    310	}
    311	return usb_submit_urb(usx2y->in04_urb, GFP_KERNEL);
    312
    313 error:
    314	kfree(usx2y->in04_buf);
    315	usb_free_urb(usx2y->in04_urb);
    316	usx2y->in04_buf = NULL;
    317	usx2y->in04_urb = NULL;
    318	return err;
    319}
    320
    321static void usx2y_unlinkseq(struct snd_usx2y_async_seq *s)
    322{
    323	int	i;
    324
    325	for (i = 0; i < URBS_ASYNC_SEQ; ++i) {
    326		if (!s->urb[i])
    327			continue;
    328		usb_kill_urb(s->urb[i]);
    329		usb_free_urb(s->urb[i]);
    330		s->urb[i] = NULL;
    331	}
    332	kfree(s->buffer);
    333	s->buffer = NULL;
    334}
    335
    336static const struct usb_device_id snd_usx2y_usb_id_table[] = {
    337	{
    338		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
    339		.idVendor =	0x1604,
    340		.idProduct =	USB_ID_US428
    341	},
    342	{
    343		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
    344		.idVendor =	0x1604,
    345		.idProduct =	USB_ID_US122
    346	},
    347	{
    348		.match_flags =	USB_DEVICE_ID_MATCH_DEVICE,
    349		.idVendor =	0x1604,
    350		.idProduct =	USB_ID_US224
    351	},
    352	{ /* terminator */ }
    353};
    354MODULE_DEVICE_TABLE(usb, snd_usx2y_usb_id_table);
    355
    356static int usx2y_create_card(struct usb_device *device,
    357			     struct usb_interface *intf,
    358			     struct snd_card **cardp)
    359{
    360	int		dev;
    361	struct snd_card *card;
    362	int err;
    363
    364	for (dev = 0; dev < SNDRV_CARDS; ++dev)
    365		if (enable[dev] && !snd_usx2y_card_used[dev])
    366			break;
    367	if (dev >= SNDRV_CARDS)
    368		return -ENODEV;
    369	err = snd_card_new(&intf->dev, index[dev], id[dev], THIS_MODULE,
    370			   sizeof(struct usx2ydev), &card);
    371	if (err < 0)
    372		return err;
    373	snd_usx2y_card_used[usx2y(card)->card_index = dev] = 1;
    374	card->private_free = snd_usx2y_card_private_free;
    375	usx2y(card)->dev = device;
    376	init_waitqueue_head(&usx2y(card)->prepare_wait_queue);
    377	init_waitqueue_head(&usx2y(card)->us428ctls_wait_queue_head);
    378	mutex_init(&usx2y(card)->pcm_mutex);
    379	INIT_LIST_HEAD(&usx2y(card)->midi_list);
    380	strcpy(card->driver, "USB "NAME_ALLCAPS"");
    381	sprintf(card->shortname, "TASCAM "NAME_ALLCAPS"");
    382	sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)",
    383		card->shortname,
    384		le16_to_cpu(device->descriptor.idVendor),
    385		le16_to_cpu(device->descriptor.idProduct),
    386		0,//us428(card)->usbmidi.ifnum,
    387		usx2y(card)->dev->bus->busnum, usx2y(card)->dev->devnum);
    388	*cardp = card;
    389	return 0;
    390}
    391
    392static void snd_usx2y_card_private_free(struct snd_card *card)
    393{
    394	struct usx2ydev *usx2y = usx2y(card);
    395
    396	kfree(usx2y->in04_buf);
    397	usb_free_urb(usx2y->in04_urb);
    398	if (usx2y->us428ctls_sharedmem)
    399		free_pages_exact(usx2y->us428ctls_sharedmem,
    400				 US428_SHAREDMEM_PAGES);
    401	if (usx2y->card_index >= 0 && usx2y->card_index < SNDRV_CARDS)
    402		snd_usx2y_card_used[usx2y->card_index] = 0;
    403}
    404
    405static void snd_usx2y_disconnect(struct usb_interface *intf)
    406{
    407	struct snd_card *card;
    408	struct usx2ydev *usx2y;
    409	struct list_head *p;
    410
    411	card = usb_get_intfdata(intf);
    412	if (!card)
    413		return;
    414	usx2y = usx2y(card);
    415	usx2y->chip_status = USX2Y_STAT_CHIP_HUP;
    416	usx2y_unlinkseq(&usx2y->as04);
    417	usb_kill_urb(usx2y->in04_urb);
    418	snd_card_disconnect(card);
    419
    420	/* release the midi resources */
    421	list_for_each(p, &usx2y->midi_list) {
    422		snd_usbmidi_disconnect(p);
    423	}
    424	if (usx2y->us428ctls_sharedmem)
    425		wake_up(&usx2y->us428ctls_wait_queue_head);
    426	snd_card_free(card);
    427}
    428
    429static int snd_usx2y_probe(struct usb_interface *intf,
    430			   const struct usb_device_id *id)
    431{
    432	struct usb_device *device = interface_to_usbdev(intf);
    433	struct snd_card *card;
    434	int err;
    435
    436	if (le16_to_cpu(device->descriptor.idVendor) != 0x1604 ||
    437	    (le16_to_cpu(device->descriptor.idProduct) != USB_ID_US122 &&
    438	     le16_to_cpu(device->descriptor.idProduct) != USB_ID_US224 &&
    439	     le16_to_cpu(device->descriptor.idProduct) != USB_ID_US428))
    440		return -EINVAL;
    441
    442	err = usx2y_create_card(device, intf, &card);
    443	if (err < 0)
    444		return err;
    445	err = usx2y_hwdep_new(card, device);
    446	if (err < 0)
    447		goto error;
    448	err = snd_card_register(card);
    449	if (err < 0)
    450		goto error;
    451
    452	dev_set_drvdata(&intf->dev, card);
    453	return 0;
    454
    455 error:
    456	snd_card_free(card);
    457	return err;
    458}
    459
    460static struct usb_driver snd_usx2y_usb_driver = {
    461	.name =		"snd-usb-usx2y",
    462	.probe =	snd_usx2y_probe,
    463	.disconnect =	snd_usx2y_disconnect,
    464	.id_table =	snd_usx2y_usb_id_table,
    465};
    466module_usb_driver(snd_usx2y_usb_driver);