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

dice.c (11007B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * TC Applied Technologies Digital Interface Communications Engine driver
      4 *
      5 * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
      6 */
      7
      8#include "dice.h"
      9
     10MODULE_DESCRIPTION("DICE driver");
     11MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
     12MODULE_LICENSE("GPL v2");
     13
     14#define OUI_WEISS		0x001c6a
     15#define OUI_LOUD		0x000ff2
     16#define OUI_FOCUSRITE		0x00130e
     17#define OUI_TCELECTRONIC	0x000166
     18#define OUI_ALESIS		0x000595
     19#define OUI_MAUDIO		0x000d6c
     20#define OUI_MYTEK		0x001ee8
     21#define OUI_SSL			0x0050c2	// Actually ID reserved by IEEE.
     22#define OUI_PRESONUS		0x000a92
     23#define OUI_HARMAN		0x000fd7
     24#define OUI_AVID		0x00a07e
     25
     26#define DICE_CATEGORY_ID	0x04
     27#define WEISS_CATEGORY_ID	0x00
     28#define LOUD_CATEGORY_ID	0x10
     29#define HARMAN_CATEGORY_ID	0x20
     30
     31#define MODEL_ALESIS_IO_BOTH	0x000001
     32
     33static int check_dice_category(struct fw_unit *unit)
     34{
     35	struct fw_device *device = fw_parent_device(unit);
     36	struct fw_csr_iterator it;
     37	int key, val, vendor = -1, model = -1;
     38	unsigned int category;
     39
     40	/*
     41	 * Check that GUID and unit directory are constructed according to DICE
     42	 * rules, i.e., that the specifier ID is the GUID's OUI, and that the
     43	 * GUID chip ID consists of the 8-bit category ID, the 10-bit product
     44	 * ID, and a 22-bit serial number.
     45	 */
     46	fw_csr_iterator_init(&it, unit->directory);
     47	while (fw_csr_iterator_next(&it, &key, &val)) {
     48		switch (key) {
     49		case CSR_SPECIFIER_ID:
     50			vendor = val;
     51			break;
     52		case CSR_MODEL:
     53			model = val;
     54			break;
     55		}
     56	}
     57
     58	if (vendor == OUI_WEISS)
     59		category = WEISS_CATEGORY_ID;
     60	else if (vendor == OUI_LOUD)
     61		category = LOUD_CATEGORY_ID;
     62	else if (vendor == OUI_HARMAN)
     63		category = HARMAN_CATEGORY_ID;
     64	else
     65		category = DICE_CATEGORY_ID;
     66	if (device->config_rom[3] != ((vendor << 8) | category) ||
     67	    device->config_rom[4] >> 22 != model)
     68		return -ENODEV;
     69
     70	return 0;
     71}
     72
     73static int check_clock_caps(struct snd_dice *dice)
     74{
     75	__be32 value;
     76	int err;
     77
     78	/* some very old firmwares don't tell about their clock support */
     79	if (dice->clock_caps > 0) {
     80		err = snd_dice_transaction_read_global(dice,
     81						GLOBAL_CLOCK_CAPABILITIES,
     82						&value, 4);
     83		if (err < 0)
     84			return err;
     85		dice->clock_caps = be32_to_cpu(value);
     86	} else {
     87		/* this should be supported by any device */
     88		dice->clock_caps = CLOCK_CAP_RATE_44100 |
     89				   CLOCK_CAP_RATE_48000 |
     90				   CLOCK_CAP_SOURCE_ARX1 |
     91				   CLOCK_CAP_SOURCE_INTERNAL;
     92	}
     93
     94	return 0;
     95}
     96
     97static void dice_card_strings(struct snd_dice *dice)
     98{
     99	struct snd_card *card = dice->card;
    100	struct fw_device *dev = fw_parent_device(dice->unit);
    101	char vendor[32], model[32];
    102	unsigned int i;
    103	int err;
    104
    105	strcpy(card->driver, "DICE");
    106
    107	strcpy(card->shortname, "DICE");
    108	BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
    109	err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
    110					       card->shortname,
    111					       sizeof(card->shortname));
    112	if (err >= 0) {
    113		/* DICE strings are returned in "always-wrong" endianness */
    114		BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
    115		for (i = 0; i < sizeof(card->shortname); i += 4)
    116			swab32s((u32 *)&card->shortname[i]);
    117		card->shortname[sizeof(card->shortname) - 1] = '\0';
    118	}
    119
    120	strcpy(vendor, "?");
    121	fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
    122	strcpy(model, "?");
    123	fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
    124	snprintf(card->longname, sizeof(card->longname),
    125		 "%s %s (serial %u) at %s, S%d",
    126		 vendor, model, dev->config_rom[4] & 0x3fffff,
    127		 dev_name(&dice->unit->device), 100 << dev->max_speed);
    128
    129	strcpy(card->mixername, "DICE");
    130}
    131
    132static void dice_card_free(struct snd_card *card)
    133{
    134	struct snd_dice *dice = card->private_data;
    135
    136	snd_dice_stream_destroy_duplex(dice);
    137	snd_dice_transaction_destroy(dice);
    138
    139	mutex_destroy(&dice->mutex);
    140	fw_unit_put(dice->unit);
    141}
    142
    143static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
    144{
    145	struct snd_card *card;
    146	struct snd_dice *dice;
    147	snd_dice_detect_formats_t detect_formats;
    148	int err;
    149
    150	if (!entry->driver_data && entry->vendor_id != OUI_SSL) {
    151		err = check_dice_category(unit);
    152		if (err < 0)
    153			return -ENODEV;
    154	}
    155
    156	err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE, sizeof(*dice), &card);
    157	if (err < 0)
    158		return err;
    159	card->private_free = dice_card_free;
    160
    161	dice = card->private_data;
    162	dice->unit = fw_unit_get(unit);
    163	dev_set_drvdata(&unit->device, dice);
    164	dice->card = card;
    165
    166	if (!entry->driver_data)
    167		detect_formats = snd_dice_stream_detect_current_formats;
    168	else
    169		detect_formats = (snd_dice_detect_formats_t)entry->driver_data;
    170
    171	// Below models are compliant to IEC 61883-1/6 and have no quirk at high sampling transfer
    172	// frequency.
    173	// * Avid M-Box 3 Pro
    174	// * M-Audio Profire 610
    175	// * M-Audio Profire 2626
    176	if (entry->vendor_id == OUI_MAUDIO || entry->vendor_id == OUI_AVID)
    177		dice->disable_double_pcm_frames = true;
    178
    179	spin_lock_init(&dice->lock);
    180	mutex_init(&dice->mutex);
    181	init_completion(&dice->clock_accepted);
    182	init_waitqueue_head(&dice->hwdep_wait);
    183
    184	err = snd_dice_transaction_init(dice);
    185	if (err < 0)
    186		goto error;
    187
    188	err = check_clock_caps(dice);
    189	if (err < 0)
    190		goto error;
    191
    192	dice_card_strings(dice);
    193
    194	err = detect_formats(dice);
    195	if (err < 0)
    196		goto error;
    197
    198	err = snd_dice_stream_init_duplex(dice);
    199	if (err < 0)
    200		goto error;
    201
    202	snd_dice_create_proc(dice);
    203
    204	err = snd_dice_create_pcm(dice);
    205	if (err < 0)
    206		goto error;
    207
    208	err = snd_dice_create_midi(dice);
    209	if (err < 0)
    210		goto error;
    211
    212	err = snd_dice_create_hwdep(dice);
    213	if (err < 0)
    214		goto error;
    215
    216	err = snd_card_register(card);
    217	if (err < 0)
    218		goto error;
    219
    220	return 0;
    221error:
    222	snd_card_free(card);
    223	return err;
    224}
    225
    226static void dice_remove(struct fw_unit *unit)
    227{
    228	struct snd_dice *dice = dev_get_drvdata(&unit->device);
    229
    230	// Block till all of ALSA character devices are released.
    231	snd_card_free(dice->card);
    232}
    233
    234static void dice_bus_reset(struct fw_unit *unit)
    235{
    236	struct snd_dice *dice = dev_get_drvdata(&unit->device);
    237
    238	/* The handler address register becomes initialized. */
    239	snd_dice_transaction_reinit(dice);
    240
    241	mutex_lock(&dice->mutex);
    242	snd_dice_stream_update_duplex(dice);
    243	mutex_unlock(&dice->mutex);
    244}
    245
    246#define DICE_INTERFACE	0x000001
    247
    248#define DICE_DEV_ENTRY_TYPICAL(vendor, model, data) \
    249	{ \
    250		.match_flags	= IEEE1394_MATCH_VENDOR_ID | \
    251				  IEEE1394_MATCH_MODEL_ID | \
    252				  IEEE1394_MATCH_SPECIFIER_ID | \
    253				  IEEE1394_MATCH_VERSION, \
    254		.vendor_id	= (vendor), \
    255		.model_id	= (model), \
    256		.specifier_id	= (vendor), \
    257		.version	= DICE_INTERFACE, \
    258		.driver_data = (kernel_ulong_t)(data), \
    259	}
    260
    261static const struct ieee1394_device_id dice_id_table[] = {
    262	// Avid M-Box 3 Pro. To match in probe function.
    263	DICE_DEV_ENTRY_TYPICAL(OUI_AVID, 0x000004, snd_dice_detect_extension_formats),
    264	/* M-Audio Profire 2626 has a different value in version field. */
    265	{
    266		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    267				  IEEE1394_MATCH_MODEL_ID,
    268		.vendor_id	= OUI_MAUDIO,
    269		.model_id	= 0x000010,
    270		.driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats,
    271	},
    272	/* M-Audio Profire 610 has a different value in version field. */
    273	{
    274		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    275				  IEEE1394_MATCH_MODEL_ID,
    276		.vendor_id	= OUI_MAUDIO,
    277		.model_id	= 0x000011,
    278		.driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats,
    279	},
    280	/* TC Electronic Konnekt 24D. */
    281	{
    282		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    283				  IEEE1394_MATCH_MODEL_ID,
    284		.vendor_id	= OUI_TCELECTRONIC,
    285		.model_id	= 0x000020,
    286		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    287	},
    288	/* TC Electronic Konnekt 8. */
    289	{
    290		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    291				  IEEE1394_MATCH_MODEL_ID,
    292		.vendor_id	= OUI_TCELECTRONIC,
    293		.model_id	= 0x000021,
    294		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    295	},
    296	/* TC Electronic Studio Konnekt 48. */
    297	{
    298		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    299				  IEEE1394_MATCH_MODEL_ID,
    300		.vendor_id	= OUI_TCELECTRONIC,
    301		.model_id	= 0x000022,
    302		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    303	},
    304	/* TC Electronic Konnekt Live. */
    305	{
    306		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    307				  IEEE1394_MATCH_MODEL_ID,
    308		.vendor_id	= OUI_TCELECTRONIC,
    309		.model_id	= 0x000023,
    310		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    311	},
    312	/* TC Electronic Desktop Konnekt 6. */
    313	{
    314		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    315				  IEEE1394_MATCH_MODEL_ID,
    316		.vendor_id	= OUI_TCELECTRONIC,
    317		.model_id	= 0x000024,
    318		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    319	},
    320	/* TC Electronic Impact Twin. */
    321	{
    322		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    323				  IEEE1394_MATCH_MODEL_ID,
    324		.vendor_id	= OUI_TCELECTRONIC,
    325		.model_id	= 0x000027,
    326		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    327	},
    328	/* TC Electronic Digital Konnekt x32. */
    329	{
    330		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    331				  IEEE1394_MATCH_MODEL_ID,
    332		.vendor_id	= OUI_TCELECTRONIC,
    333		.model_id	= 0x000030,
    334		.driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats,
    335	},
    336	/* Alesis iO14/iO26. */
    337	{
    338		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    339				  IEEE1394_MATCH_MODEL_ID,
    340		.vendor_id	= OUI_ALESIS,
    341		.model_id	= MODEL_ALESIS_IO_BOTH,
    342		.driver_data = (kernel_ulong_t)snd_dice_detect_alesis_formats,
    343	},
    344	// Alesis MasterControl.
    345	{
    346		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    347				  IEEE1394_MATCH_MODEL_ID,
    348		.vendor_id	= OUI_ALESIS,
    349		.model_id	= 0x000002,
    350		.driver_data = (kernel_ulong_t)snd_dice_detect_alesis_mastercontrol_formats,
    351	},
    352	/* Mytek Stereo 192 DSD-DAC. */
    353	{
    354		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    355				  IEEE1394_MATCH_MODEL_ID,
    356		.vendor_id	= OUI_MYTEK,
    357		.model_id	= 0x000002,
    358		.driver_data = (kernel_ulong_t)snd_dice_detect_mytek_formats,
    359	},
    360	// Solid State Logic, Duende Classic and Mini.
    361	// NOTE: each field of GUID in config ROM is not compliant to standard
    362	// DICE scheme.
    363	{
    364		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    365				  IEEE1394_MATCH_MODEL_ID,
    366		.vendor_id	= OUI_SSL,
    367		.model_id	= 0x000070,
    368	},
    369	// Presonus FireStudio.
    370	{
    371		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    372				  IEEE1394_MATCH_MODEL_ID,
    373		.vendor_id	= OUI_PRESONUS,
    374		.model_id	= 0x000008,
    375		.driver_data	= (kernel_ulong_t)snd_dice_detect_presonus_formats,
    376	},
    377	// Lexicon I-ONYX FW810S.
    378	{
    379		.match_flags	= IEEE1394_MATCH_VENDOR_ID |
    380				  IEEE1394_MATCH_MODEL_ID,
    381		.vendor_id	= OUI_HARMAN,
    382		.model_id	= 0x000001,
    383		.driver_data	= (kernel_ulong_t)snd_dice_detect_harman_formats,
    384	},
    385	{
    386		.match_flags = IEEE1394_MATCH_VERSION,
    387		.version     = DICE_INTERFACE,
    388	},
    389	{ }
    390};
    391MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
    392
    393static struct fw_driver dice_driver = {
    394	.driver   = {
    395		.owner	= THIS_MODULE,
    396		.name	= KBUILD_MODNAME,
    397		.bus	= &fw_bus_type,
    398	},
    399	.probe    = dice_probe,
    400	.update   = dice_bus_reset,
    401	.remove   = dice_remove,
    402	.id_table = dice_id_table,
    403};
    404
    405static int __init alsa_dice_init(void)
    406{
    407	return driver_register(&dice_driver.driver);
    408}
    409
    410static void __exit alsa_dice_exit(void)
    411{
    412	driver_unregister(&dice_driver.driver);
    413}
    414
    415module_init(alsa_dice_init);
    416module_exit(alsa_dice_exit);