Skip to content

Commit a91c3fb

Browse files
ao2tiwai
authored andcommitted
Add M2Tech hiFace USB-SPDIF driver
Add driver for M2Tech hiFace USB-SPDIF interface and compatible devices. M2Tech hiFace and compatible devices offer a Hi-End S/PDIF Output Interface, see http://www.m2tech.biz/hiface.html The supported products are: * M2Tech Young * M2Tech hiFace * M2Tech North Star * M2Tech W4S Young * M2Tech Corrson * M2Tech AUDIA * M2Tech SL Audio * M2Tech Empirical * M2Tech Rockna * M2Tech Pathos * M2Tech Metronome * M2Tech CAD * M2Tech Audio Esclusive * M2Tech Rotel * M2Tech Eeaudio * The Chord Company CHORD * AVA Group A/S Vitus Signed-off-by: Antonio Ospite <[email protected]> Signed-off-by: Takashi Iwai <[email protected]>
1 parent 04c9548 commit a91c3fb

File tree

7 files changed

+1006
-1
lines changed

7 files changed

+1006
-1
lines changed

sound/usb/Kconfig

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,5 +115,36 @@ config SND_USB_6FIRE
115115
and further help can be found at
116116
http://sixfireusb.sourceforge.net
117117

118+
config SND_USB_HIFACE
119+
tristate "M2Tech hiFace USB-SPDIF driver"
120+
select SND_PCM
121+
help
122+
Select this option to include support for M2Tech hiFace USB-SPDIF
123+
interface.
124+
125+
This driver supports the original M2Tech hiFace and some other
126+
compatible devices. The supported products are:
127+
128+
* M2Tech Young
129+
* M2Tech hiFace
130+
* M2Tech North Star
131+
* M2Tech W4S Young
132+
* M2Tech Corrson
133+
* M2Tech AUDIA
134+
* M2Tech SL Audio
135+
* M2Tech Empirical
136+
* M2Tech Rockna
137+
* M2Tech Pathos
138+
* M2Tech Metronome
139+
* M2Tech CAD
140+
* M2Tech Audio Esclusive
141+
* M2Tech Rotel
142+
* M2Tech Eeaudio
143+
* The Chord Company CHORD
144+
* AVA Group A/S Vitus
145+
146+
To compile this driver as a module, choose M here: the module
147+
will be called snd-usb-hiface.
148+
118149
endif # SND_USB
119150

sound/usb/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,4 @@ obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
2323
obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
2424
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
2525

26-
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/
26+
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/

sound/usb/hiface/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
snd-usb-hiface-objs := chip.o pcm.o
2+
obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o

sound/usb/hiface/chip.c

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

sound/usb/hiface/chip.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/*
2+
* Linux driver for M2Tech hiFace compatible devices
3+
*
4+
* Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V.
5+
*
6+
* Authors: Michael Trimarchi <[email protected]>
7+
* Antonio Ospite <[email protected]>
8+
*
9+
* The driver is based on the work done in TerraTec DMX 6Fire USB
10+
*
11+
* This program is free software; you can redistribute it and/or modify
12+
* it under the terms of the GNU General Public License as published by
13+
* the Free Software Foundation; either version 2 of the License, or
14+
* (at your option) any later version.
15+
*/
16+
17+
#ifndef HIFACE_CHIP_H
18+
#define HIFACE_CHIP_H
19+
20+
#include <linux/usb.h>
21+
#include <sound/core.h>
22+
23+
struct pcm_runtime;
24+
25+
struct hiface_chip {
26+
struct usb_device *dev;
27+
struct snd_card *card;
28+
struct pcm_runtime *pcm;
29+
};
30+
#endif /* HIFACE_CHIP_H */

0 commit comments

Comments
 (0)