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);
277