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

chip.c (6860B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Linux driver for M2Tech hiFace compatible devices
      4 *
      5 * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
      6 *
      7 * Authors:  Michael Trimarchi <michael@amarulasolutions.com>
      8 *           Antonio Ospite <ao2@amarulasolutions.com>
      9 *
     10 * The driver is based on the work done in TerraTec DMX 6Fire USB
     11 */
     12
     13#include <linux/module.h>
     14#include <linux/slab.h>
     15#include <sound/initval.h>
     16
     17#include "chip.h"
     18#include "pcm.h"
     19
     20MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
     21MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
     22MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
     23MODULE_LICENSE("GPL v2");
     24
     25static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
     26static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
     27static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */
     28
     29#define DRIVER_NAME "snd-usb-hiface"
     30#define CARD_NAME "hiFace"
     31
     32module_param_array(index, int, NULL, 0444);
     33MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
     34module_param_array(id, charp, NULL, 0444);
     35MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
     36module_param_array(enable, bool, NULL, 0444);
     37MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
     38
     39static DEFINE_MUTEX(register_mutex);
     40
     41struct hiface_vendor_quirk {
     42	const char *device_name;
     43	u8 extra_freq;
     44};
     45
     46static int hiface_chip_create(struct usb_interface *intf,
     47			      struct usb_device *device, int idx,
     48			      const struct hiface_vendor_quirk *quirk,
     49			      struct hiface_chip **rchip)
     50{
     51	struct snd_card *card = NULL;
     52	struct hiface_chip *chip;
     53	int ret;
     54	int len;
     55
     56	*rchip = NULL;
     57
     58	/* if we are here, card can be registered in alsa. */
     59	ret = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE,
     60			   sizeof(*chip), &card);
     61	if (ret < 0) {
     62		dev_err(&device->dev, "cannot create alsa card.\n");
     63		return ret;
     64	}
     65
     66	strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
     67
     68	if (quirk && quirk->device_name)
     69		strscpy(card->shortname, quirk->device_name, sizeof(card->shortname));
     70	else
     71		strscpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
     72
     73	strlcat(card->longname, card->shortname, sizeof(card->longname));
     74	len = strlcat(card->longname, " at ", sizeof(card->longname));
     75	if (len < sizeof(card->longname))
     76		usb_make_path(device, card->longname + len,
     77			      sizeof(card->longname) - len);
     78
     79	chip = card->private_data;
     80	chip->dev = device;
     81	chip->card = card;
     82
     83	*rchip = chip;
     84	return 0;
     85}
     86
     87static int hiface_chip_probe(struct usb_interface *intf,
     88			     const struct usb_device_id *usb_id)
     89{
     90	const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
     91	int ret;
     92	int i;
     93	struct hiface_chip *chip;
     94	struct usb_device *device = interface_to_usbdev(intf);
     95
     96	ret = usb_set_interface(device, 0, 0);
     97	if (ret != 0) {
     98		dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
     99		return -EIO;
    100	}
    101
    102	/* check whether the card is already registered */
    103	chip = NULL;
    104	mutex_lock(&register_mutex);
    105
    106	for (i = 0; i < SNDRV_CARDS; i++)
    107		if (enable[i])
    108			break;
    109
    110	if (i >= SNDRV_CARDS) {
    111		dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
    112		ret = -ENODEV;
    113		goto err;
    114	}
    115
    116	ret = hiface_chip_create(intf, device, i, quirk, &chip);
    117	if (ret < 0)
    118		goto err;
    119
    120	ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
    121	if (ret < 0)
    122		goto err_chip_destroy;
    123
    124	ret = snd_card_register(chip->card);
    125	if (ret < 0) {
    126		dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
    127		goto err_chip_destroy;
    128	}
    129
    130	mutex_unlock(&register_mutex);
    131
    132	usb_set_intfdata(intf, chip);
    133	return 0;
    134
    135err_chip_destroy:
    136	snd_card_free(chip->card);
    137err:
    138	mutex_unlock(&register_mutex);
    139	return ret;
    140}
    141
    142static void hiface_chip_disconnect(struct usb_interface *intf)
    143{
    144	struct hiface_chip *chip;
    145	struct snd_card *card;
    146
    147	chip = usb_get_intfdata(intf);
    148	if (!chip)
    149		return;
    150
    151	card = chip->card;
    152
    153	/* Make sure that the userspace cannot create new request */
    154	snd_card_disconnect(card);
    155
    156	hiface_pcm_abort(chip);
    157	snd_card_free_when_closed(card);
    158}
    159
    160static const struct usb_device_id device_table[] = {
    161	{
    162		USB_DEVICE(0x04b4, 0x0384),
    163		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    164			.device_name = "Young",
    165			.extra_freq = 1,
    166		}
    167	},
    168	{
    169		USB_DEVICE(0x04b4, 0x930b),
    170		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    171			.device_name = "hiFace",
    172		}
    173	},
    174	{
    175		USB_DEVICE(0x04b4, 0x931b),
    176		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    177			.device_name = "North Star",
    178		}
    179	},
    180	{
    181		USB_DEVICE(0x04b4, 0x931c),
    182		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    183			.device_name = "W4S Young",
    184		}
    185	},
    186	{
    187		USB_DEVICE(0x04b4, 0x931d),
    188		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    189			.device_name = "Corrson",
    190		}
    191	},
    192	{
    193		USB_DEVICE(0x04b4, 0x931e),
    194		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    195			.device_name = "AUDIA",
    196		}
    197	},
    198	{
    199		USB_DEVICE(0x04b4, 0x931f),
    200		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    201			.device_name = "SL Audio",
    202		}
    203	},
    204	{
    205		USB_DEVICE(0x04b4, 0x9320),
    206		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    207			.device_name = "Empirical",
    208		}
    209	},
    210	{
    211		USB_DEVICE(0x04b4, 0x9321),
    212		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    213			.device_name = "Rockna",
    214		}
    215	},
    216	{
    217		USB_DEVICE(0x249c, 0x9001),
    218		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    219			.device_name = "Pathos",
    220		}
    221	},
    222	{
    223		USB_DEVICE(0x249c, 0x9002),
    224		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    225			.device_name = "Metronome",
    226		}
    227	},
    228	{
    229		USB_DEVICE(0x249c, 0x9006),
    230		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    231			.device_name = "CAD",
    232		}
    233	},
    234	{
    235		USB_DEVICE(0x249c, 0x9008),
    236		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    237			.device_name = "Audio Esclusive",
    238		}
    239	},
    240	{
    241		USB_DEVICE(0x249c, 0x931c),
    242		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    243			.device_name = "Rotel",
    244		}
    245	},
    246	{
    247		USB_DEVICE(0x249c, 0x932c),
    248		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    249			.device_name = "Eeaudio",
    250		}
    251	},
    252	{
    253		USB_DEVICE(0x245f, 0x931c),
    254		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    255			.device_name = "CHORD",
    256		}
    257	},
    258	{
    259		USB_DEVICE(0x25c6, 0x9002),
    260		.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
    261			.device_name = "Vitus",
    262		}
    263	},
    264	{}
    265};
    266
    267MODULE_DEVICE_TABLE(usb, device_table);
    268
    269static struct usb_driver hiface_usb_driver = {
    270	.name = DRIVER_NAME,
    271	.probe = hiface_chip_probe,
    272	.disconnect = hiface_chip_disconnect,
    273	.id_table = device_table,
    274};
    275
    276module_usb_driver(hiface_usb_driver);