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