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