xref: /openbmc/linux/sound/usb/hiface/chip.c (revision 8dda2eac)
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 
25 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
26 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */
27 static 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 
32 module_param_array(index, int, NULL, 0444);
33 MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard.");
34 module_param_array(id, charp, NULL, 0444);
35 MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard.");
36 module_param_array(enable, bool, NULL, 0444);
37 MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard.");
38 
39 static DEFINE_MUTEX(register_mutex);
40 
41 struct hiface_vendor_quirk {
42 	const char *device_name;
43 	u8 extra_freq;
44 };
45 
46 static 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 
87 static 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 
135 err_chip_destroy:
136 	snd_card_free(chip->card);
137 err:
138 	mutex_unlock(&register_mutex);
139 	return ret;
140 }
141 
142 static 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 
160 static 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 
267 MODULE_DEVICE_TABLE(usb, device_table);
268 
269 static 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 
276 module_usb_driver(hiface_usb_driver);
277