-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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 <ao2@amarulasolutions.com> Signed-off-by: Takashi Iwai <tiwai@suse.de>
- Loading branch information
Antonio Ospite
authored and
Takashi Iwai
committed
Jun 24, 2013
1 parent
04c9548
commit a91c3fb
Showing
7 changed files
with
1,006 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
snd-usb-hiface-objs := chip.o pcm.o | ||
obj-$(CONFIG_SND_USB_HIFACE) += snd-usb-hiface.o |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,297 @@ | ||
/* | ||
* Linux driver for M2Tech hiFace compatible devices | ||
* | ||
* Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. | ||
* | ||
* Authors: Michael Trimarchi <michael@amarulasolutions.com> | ||
* Antonio Ospite <ao2@amarulasolutions.com> | ||
* | ||
* The driver is based on the work done in TerraTec DMX 6Fire USB | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
*/ | ||
|
||
#include <linux/module.h> | ||
#include <linux/slab.h> | ||
#include <sound/initval.h> | ||
|
||
#include "chip.h" | ||
#include "pcm.h" | ||
|
||
MODULE_AUTHOR("Michael Trimarchi <michael@amarulasolutions.com>"); | ||
MODULE_AUTHOR("Antonio Ospite <ao2@amarulasolutions.com>"); | ||
MODULE_DESCRIPTION("M2Tech hiFace USB-SPDIF audio driver"); | ||
MODULE_LICENSE("GPL v2"); | ||
MODULE_SUPPORTED_DEVICE("{{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}}"); | ||
|
||
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ | ||
static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for card */ | ||
static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ | ||
|
||
#define DRIVER_NAME "snd-usb-hiface" | ||
#define CARD_NAME "hiFace" | ||
|
||
module_param_array(index, int, NULL, 0444); | ||
MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | ||
module_param_array(id, charp, NULL, 0444); | ||
MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | ||
module_param_array(enable, bool, NULL, 0444); | ||
MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | ||
|
||
static DEFINE_MUTEX(register_mutex); | ||
|
||
struct hiface_vendor_quirk { | ||
const char *device_name; | ||
u8 extra_freq; | ||
}; | ||
|
||
static int hiface_chip_create(struct usb_device *device, int idx, | ||
const struct hiface_vendor_quirk *quirk, | ||
struct hiface_chip **rchip) | ||
{ | ||
struct snd_card *card = NULL; | ||
struct hiface_chip *chip; | ||
int ret; | ||
int len; | ||
|
||
*rchip = NULL; | ||
|
||
/* if we are here, card can be registered in alsa. */ | ||
ret = snd_card_create(index[idx], id[idx], THIS_MODULE, sizeof(*chip), &card); | ||
if (ret < 0) { | ||
dev_err(&device->dev, "cannot create alsa card.\n"); | ||
return ret; | ||
} | ||
|
||
strlcpy(card->driver, DRIVER_NAME, sizeof(card->driver)); | ||
|
||
if (quirk && quirk->device_name) | ||
strlcpy(card->shortname, quirk->device_name, sizeof(card->shortname)); | ||
else | ||
strlcpy(card->shortname, "M2Tech generic audio", sizeof(card->shortname)); | ||
|
||
strlcat(card->longname, card->shortname, sizeof(card->longname)); | ||
len = strlcat(card->longname, " at ", sizeof(card->longname)); | ||
if (len < sizeof(card->longname)) | ||
usb_make_path(device, card->longname + len, | ||
sizeof(card->longname) - len); | ||
|
||
chip = card->private_data; | ||
chip->dev = device; | ||
chip->card = card; | ||
|
||
*rchip = chip; | ||
return 0; | ||
} | ||
|
||
static int hiface_chip_probe(struct usb_interface *intf, | ||
const struct usb_device_id *usb_id) | ||
{ | ||
const struct hiface_vendor_quirk *quirk = (struct hiface_vendor_quirk *)usb_id->driver_info; | ||
int ret; | ||
int i; | ||
struct hiface_chip *chip; | ||
struct usb_device *device = interface_to_usbdev(intf); | ||
|
||
ret = usb_set_interface(device, 0, 0); | ||
if (ret != 0) { | ||
dev_err(&device->dev, "can't set first interface for " CARD_NAME " device.\n"); | ||
return -EIO; | ||
} | ||
|
||
/* check whether the card is already registered */ | ||
chip = NULL; | ||
mutex_lock(®ister_mutex); | ||
|
||
for (i = 0; i < SNDRV_CARDS; i++) | ||
if (enable[i]) | ||
break; | ||
|
||
if (i >= SNDRV_CARDS) { | ||
dev_err(&device->dev, "no available " CARD_NAME " audio device\n"); | ||
ret = -ENODEV; | ||
goto err; | ||
} | ||
|
||
ret = hiface_chip_create(device, i, quirk, &chip); | ||
if (ret < 0) | ||
goto err; | ||
|
||
snd_card_set_dev(chip->card, &intf->dev); | ||
|
||
ret = hiface_pcm_init(chip, quirk ? quirk->extra_freq : 0); | ||
if (ret < 0) | ||
goto err_chip_destroy; | ||
|
||
ret = snd_card_register(chip->card); | ||
if (ret < 0) { | ||
dev_err(&device->dev, "cannot register " CARD_NAME " card\n"); | ||
goto err_chip_destroy; | ||
} | ||
|
||
mutex_unlock(®ister_mutex); | ||
|
||
usb_set_intfdata(intf, chip); | ||
return 0; | ||
|
||
err_chip_destroy: | ||
snd_card_free(chip->card); | ||
err: | ||
mutex_unlock(®ister_mutex); | ||
return ret; | ||
} | ||
|
||
static void hiface_chip_disconnect(struct usb_interface *intf) | ||
{ | ||
struct hiface_chip *chip; | ||
struct snd_card *card; | ||
|
||
chip = usb_get_intfdata(intf); | ||
if (!chip) | ||
return; | ||
|
||
card = chip->card; | ||
|
||
/* Make sure that the userspace cannot create new request */ | ||
snd_card_disconnect(card); | ||
|
||
hiface_pcm_abort(chip); | ||
snd_card_free_when_closed(card); | ||
} | ||
|
||
static const struct usb_device_id device_table[] = { | ||
{ | ||
USB_DEVICE(0x04b4, 0x0384), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Young", | ||
.extra_freq = 1, | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x930b), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "hiFace", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x931b), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "North Star", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x931c), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "W4S Young", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x931d), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Corrson", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x931e), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "AUDIA", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x931f), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "SL Audio", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x9320), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Empirical", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x04b4, 0x9321), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Rockna", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x9001), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Pathos", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x9002), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Metronome", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x9006), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "CAD", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x9008), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Audio Esclusive", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x931c), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Rotel", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x249c, 0x932c), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Eeaudio", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x245f, 0x931c), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "CHORD", | ||
} | ||
}, | ||
{ | ||
USB_DEVICE(0x25c6, 0x9002), | ||
.driver_info = (unsigned long)&(const struct hiface_vendor_quirk) { | ||
.device_name = "Vitus", | ||
} | ||
}, | ||
{} | ||
}; | ||
|
||
MODULE_DEVICE_TABLE(usb, device_table); | ||
|
||
static struct usb_driver hiface_usb_driver = { | ||
.name = DRIVER_NAME, | ||
.probe = hiface_chip_probe, | ||
.disconnect = hiface_chip_disconnect, | ||
.id_table = device_table, | ||
}; | ||
|
||
module_usb_driver(hiface_usb_driver); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/* | ||
* Linux driver for M2Tech hiFace compatible devices | ||
* | ||
* Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. | ||
* | ||
* Authors: Michael Trimarchi <michael@amarulasolutions.com> | ||
* Antonio Ospite <ao2@amarulasolutions.com> | ||
* | ||
* The driver is based on the work done in TerraTec DMX 6Fire USB | ||
* | ||
* This program is free software; you can redistribute it and/or modify | ||
* it under the terms of the GNU General Public License as published by | ||
* the Free Software Foundation; either version 2 of the License, or | ||
* (at your option) any later version. | ||
*/ | ||
|
||
#ifndef HIFACE_CHIP_H | ||
#define HIFACE_CHIP_H | ||
|
||
#include <linux/usb.h> | ||
#include <sound/core.h> | ||
|
||
struct pcm_runtime; | ||
|
||
struct hiface_chip { | ||
struct usb_device *dev; | ||
struct snd_card *card; | ||
struct pcm_runtime *pcm; | ||
}; | ||
#endif /* HIFACE_CHIP_H */ |
Oops, something went wrong.