Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/hiface/chip.c
26424 views
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 <[email protected]>
8
* Antonio Ospite <[email protected]>
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 <[email protected]>");
21
MODULE_AUTHOR("Antonio Ospite <[email protected]>");
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
278