brintos

brintos / linux-shallow public Read only

0
0
Text · 6.7 KiB · 95385e9 Raw
277 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux driver for M2Tech hiFace compatible devices4 *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 USB11 */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	else71		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);277