xref: /linux/sound/usb/hiface/chip.c (revision af873fcecef567abf8a3468b06dd4e4aab46da6d)
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 
20 MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>");
21 MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>");
22 MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver");
23 MODULE_LICENSE("GPL v2");
24 MODULE_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 
42 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
43 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
44 static 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 
49 module_param_array(index, int, NULL, 0444);
50 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
51 module_param_array(id, charp, NULL, 0444);
52 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
53 module_param_array(enable, bool, NULL, 0444);
54 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
55 
56 static DEFINE_MUTEX(register_mutex);
57 
58 struct hiface_vendor_quirk {
59 	const char *device_name;
60 	u8 extra_freq;
61 };
62 
63 static 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 
104 static 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 
152 err_chip_destroy:
153 	snd_card_free(chip->card);
154 err:
155 	mutex_unlock(&register_mutex);
156 	return ret;
157 }
158 
159 static 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 
177 static 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 
284 MODULE_DEVICE_TABLE(usb, device_table);
285 
286 static 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 
293 module_usb_driver(hiface_usb_driver);
294