Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/hiface/chip.c
29269 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
guard(mutex)(&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
return -ENODEV;
113
}
114
115
ret = hiface_chip_create(intf, device, i, quirk, &chip);
116
if (ret < 0)
117
return ret;
118
119
ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0);
120
if (ret < 0)
121
goto err_chip_destroy;
122
123
ret = snd_card_register(chip->card);
124
if (ret < 0) {
125
dev_err(&device->dev, "cannot register " CARD_NAME " card\n");
126
goto err_chip_destroy;
127
}
128
129
usb_set_intfdata(intf, chip);
130
return 0;
131
132
err_chip_destroy:
133
snd_card_free(chip->card);
134
return ret;
135
}
136
137
static void hiface_chip_disconnect(struct usb_interface *intf)
138
{
139
struct hiface_chip *chip;
140
struct snd_card *card;
141
142
chip = usb_get_intfdata(intf);
143
if (!chip)
144
return;
145
146
card = chip->card;
147
148
/* Make sure that the userspace cannot create new request */
149
snd_card_disconnect(card);
150
151
hiface_pcm_abort(chip);
152
snd_card_free_when_closed(card);
153
}
154
155
static const struct usb_device_id device_table[] = {
156
{
157
USB_DEVICE(0x04b4, 0x0384),
158
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
159
.device_name = "Young",
160
.extra_freq = 1,
161
}
162
},
163
{
164
USB_DEVICE(0x04b4, 0x930b),
165
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
166
.device_name = "hiFace",
167
}
168
},
169
{
170
USB_DEVICE(0x04b4, 0x931b),
171
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
172
.device_name = "North Star",
173
}
174
},
175
{
176
USB_DEVICE(0x04b4, 0x931c),
177
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
178
.device_name = "W4S Young",
179
}
180
},
181
{
182
USB_DEVICE(0x04b4, 0x931d),
183
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
184
.device_name = "Corrson",
185
}
186
},
187
{
188
USB_DEVICE(0x04b4, 0x931e),
189
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
190
.device_name = "AUDIA",
191
}
192
},
193
{
194
USB_DEVICE(0x04b4, 0x931f),
195
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
196
.device_name = "SL Audio",
197
}
198
},
199
{
200
USB_DEVICE(0x04b4, 0x9320),
201
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
202
.device_name = "Empirical",
203
}
204
},
205
{
206
USB_DEVICE(0x04b4, 0x9321),
207
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
208
.device_name = "Rockna",
209
}
210
},
211
{
212
USB_DEVICE(0x249c, 0x9001),
213
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
214
.device_name = "Pathos",
215
}
216
},
217
{
218
USB_DEVICE(0x249c, 0x9002),
219
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
220
.device_name = "Metronome",
221
}
222
},
223
{
224
USB_DEVICE(0x249c, 0x9006),
225
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
226
.device_name = "CAD",
227
}
228
},
229
{
230
USB_DEVICE(0x249c, 0x9008),
231
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
232
.device_name = "Audio Esclusive",
233
}
234
},
235
{
236
USB_DEVICE(0x249c, 0x931c),
237
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
238
.device_name = "Rotel",
239
}
240
},
241
{
242
USB_DEVICE(0x249c, 0x932c),
243
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
244
.device_name = "Eeaudio",
245
}
246
},
247
{
248
USB_DEVICE(0x245f, 0x931c),
249
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
250
.device_name = "CHORD",
251
}
252
},
253
{
254
USB_DEVICE(0x25c6, 0x9002),
255
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) {
256
.device_name = "Vitus",
257
}
258
},
259
{}
260
};
261
262
MODULE_DEVICE_TABLE(usb, device_table);
263
264
static struct usb_driver hiface_usb_driver = {
265
.name = DRIVER_NAME,
266
.probe = hiface_chip_probe,
267
.disconnect = hiface_chip_disconnect,
268
.id_table = device_table,
269
};
270
271
module_usb_driver(hiface_usb_driver);
272
273