1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Linux driver for M2Tech hiFace compatible devices
5 * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
7 * Authors: Michael Trimarchi <michael@amarulasolutions.com>
8 * Antonio Ospite <ao2@amarulasolutions.com>
10 * The driver is based on the work done in TerraTec DMX 6Fire USB
13 #include <linux/module.h>
14 #include <linux/slab.h>
15 #include <sound/initval.h>
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");
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 */
29 #define DRIVER_NAME "snd-usb-hiface"
30 #define CARD_NAME "hiFace"
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.");
39 static DEFINE_MUTEX(register_mutex);
41 struct hiface_vendor_quirk {
42 const char *device_name;
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)
51 struct snd_card *card = NULL;
52 struct hiface_chip *chip;
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);
62 dev_err(&device->dev, "cannot create alsa card.\n");
66 strscpy(card->driver, DRIVER_NAME, sizeof(card->driver));
68 if (quirk && quirk->device_name)
69 strscpy(card->shortname, quirk->device_name, sizeof(card->shortname));
71 strscpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname));
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);
79 chip = card->private_data;
87 static int hiface_chip_probe(struct usb_interface *intf,
88 const struct usb_device_id *usb_id)
90 const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info;
93 struct hiface_chip *chip;
94 struct usb_device *device = interface_to_usbdev(intf);
96 ret = usb_set_interface(device, 0, 0);
98 dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n");
102 /* check whether the card is already registered */
104 mutex_lock(®ister_mutex);
106 for (i = 0; i < SNDRV_CARDS; i++)
110 if (i >= SNDRV_CARDS) {
111 dev_err(&device->dev, "no available " CARD_NAME " audio device\n");
116 ret = hiface_chip_create(intf, device, i, quirk, &chip);
120 ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
122 goto err_chip_destroy;
124 ret = snd_card_register(chip->card);
126 dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
127 goto err_chip_destroy;
130 mutex_unlock(®ister_mutex);
132 usb_set_intfdata(intf, chip);
136 snd_card_free(chip->card);
138 mutex_unlock(®ister_mutex);
142 static void hiface_chip_disconnect(struct usb_interface *intf)
144 struct hiface_chip *chip;
145 struct snd_card *card;
147 chip = usb_get_intfdata(intf);
153 /* Make sure that the userspace cannot create new request */
154 snd_card_disconnect(card);
156 hiface_pcm_abort(chip);
157 snd_card_free_when_closed(card);
160 static const struct usb_device_id device_table[] = {
162 USB_DEVICE(0x04b4, 0x0384),
163 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
164 .device_name = "Young",
169 USB_DEVICE(0x04b4, 0x930b),
170 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
171 .device_name = "hiFace",
175 USB_DEVICE(0x04b4, 0x931b),
176 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
177 .device_name = "North Star",
181 USB_DEVICE(0x04b4, 0x931c),
182 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
183 .device_name = "W4S Young",
187 USB_DEVICE(0x04b4, 0x931d),
188 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
189 .device_name = "Corrson",
193 USB_DEVICE(0x04b4, 0x931e),
194 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
195 .device_name = "AUDIA",
199 USB_DEVICE(0x04b4, 0x931f),
200 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
201 .device_name = "SL Audio",
205 USB_DEVICE(0x04b4, 0x9320),
206 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
207 .device_name = "Empirical",
211 USB_DEVICE(0x04b4, 0x9321),
212 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
213 .device_name = "Rockna",
217 USB_DEVICE(0x249c, 0x9001),
218 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
219 .device_name = "Pathos",
223 USB_DEVICE(0x249c, 0x9002),
224 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
225 .device_name = "Metronome",
229 USB_DEVICE(0x249c, 0x9006),
230 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
231 .device_name = "CAD",
235 USB_DEVICE(0x249c, 0x9008),
236 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
237 .device_name = "Audio Esclusive",
241 USB_DEVICE(0x249c, 0x931c),
242 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
243 .device_name = "Rotel",
247 USB_DEVICE(0x249c, 0x932c),
248 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
249 .device_name = "Eeaudio",
253 USB_DEVICE(0x245f, 0x931c),
254 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
255 .device_name = "CHORD",
259 USB_DEVICE(0x25c6, 0x9002),
260 .driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
261 .device_name = "Vitus",
267 MODULE_DEVICE_TABLE(usb, device_table);
269 static struct usb_driver hiface_usb_driver = {
271 .probe = hiface_chip_probe,
272 .disconnect = hiface_chip_disconnect,
273 .id_table = device_table,
276 module_usb_driver(hiface_usb_driver);