aboutsummaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorHans Petter Selasky <hselasky@FreeBSD.org>2017-03-14 15:25:49 +0000
committerHans Petter Selasky <hselasky@FreeBSD.org>2017-03-14 15:25:49 +0000
commit15f85b198f6ef0d83f4a86b31f6a60baed86e0ae (patch)
tree83a526e2feea190d1df2ca229c1ee6cf93109d23 /sys/dev
parent4e0fc3a0587974e0636075c84511a935914cbfbf (diff)
Notes
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/sound/usb/uaudio.c60
-rw-r--r--sys/dev/usb/quirk/usb_quirk.c2
-rw-r--r--sys/dev/usb/quirk/usb_quirk.h1
-rw-r--r--sys/dev/usb/usbdevs3
4 files changed, 66 insertions, 0 deletions
diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c
index 298f7f72e114..b4514fd9215e 100644
--- a/sys/dev/sound/usb/uaudio.c
+++ b/sys/dev/sound/usb/uaudio.c
@@ -317,6 +317,11 @@ struct uaudio_hid {
uint8_t mute_id;
};
+#define UAUDIO_SPDIF_OUT 0x01 /* Enable S/PDIF output */
+#define UAUDIO_SPDIF_OUT_48K 0x02 /* Out sample rate = 48K */
+#define UAUDIO_SPDIF_OUT_96K 0x04 /* Out sample rate = 96K */
+#define UAUDIO_SPDIF_IN_MIX 0x10 /* Input mix enable */
+
struct uaudio_softc {
struct sbuf sc_sndstat;
struct sndcard_func sc_sndcard_func;
@@ -334,6 +339,7 @@ struct uaudio_softc {
struct usb_xfer *sc_mixer_xfer[1];
struct uaudio_mixer_node *sc_mixer_root;
struct uaudio_mixer_node *sc_mixer_curr;
+ int (*sc_set_spdif_fn) (struct uaudio_softc *, int);
uint32_t sc_mix_info;
uint32_t sc_recsrc_info;
@@ -864,6 +870,46 @@ uaudio_probe(device_t dev)
return (ENXIO);
}
+/*
+ * Set Cmedia CM6206 S/PDIF settings
+ * Source: CM6206 Datasheet v2.3.
+ */
+static int
+uaudio_set_spdif_cm6206(struct uaudio_softc *sc, int flags)
+{
+ uint8_t cmd[2][4] = {
+ {0x20, 0x20, 0x00, 0},
+ {0x20, 0x30, 0x02, 1}
+ };
+ int i;
+
+ if (flags & UAUDIO_SPDIF_OUT)
+ cmd[1][1] = 0x00;
+ else
+ cmd[1][1] = 0x02;
+
+ if (flags & UAUDIO_SPDIF_OUT_96K)
+ cmd[0][1] = 0x60; /* 96K: 3'b110 */
+
+ if (flags & UAUDIO_SPDIF_IN_MIX)
+ cmd[1][1] = 0x03; /* SPDIFMIX */
+
+ for (i = 0; i < 2; i++) {
+ if (usbd_req_set_report(sc->sc_udev, NULL,
+ cmd[i], sizeof(cmd[0]),
+ sc->sc_mixer_iface_index, UHID_OUTPUT_REPORT, 0) != 0) {
+ return (ENXIO);
+ }
+ }
+ return (0);
+}
+
+static int
+uaudio_set_spdif_dummy(struct uaudio_softc *sc, int flags)
+{
+ return (0);
+}
+
static int
uaudio_attach(device_t dev)
{
@@ -898,6 +944,12 @@ uaudio_attach(device_t dev)
if (usb_test_quirk(uaa, UQ_AU_VENDOR_CLASS))
sc->sc_uq_au_vendor_class = 1;
+ /* set S/PDIF function */
+ if (usb_test_quirk(uaa, UQ_AU_SET_SPDIF_CM6206))
+ sc->sc_set_spdif_fn = uaudio_set_spdif_cm6206;
+ else
+ sc->sc_set_spdif_fn = uaudio_set_spdif_dummy;
+
umidi_init(dev);
device_set_usb_desc(dev);
@@ -1034,6 +1086,11 @@ uaudio_attach(device_t dev)
/* reload all mixer settings */
uaudio_mixer_reload_all(sc);
+ /* enable S/PDIF output, if any */
+ if (sc->sc_set_spdif_fn(sc,
+ UAUDIO_SPDIF_OUT | UAUDIO_SPDIF_OUT_48K) != 0) {
+ device_printf(dev, "Failed to enable S/PDIF at 48K\n");
+ }
return (0); /* success */
detach:
@@ -1114,6 +1171,9 @@ uaudio_detach_sub(device_t dev)
struct uaudio_softc *sc = device_get_softc(device_get_parent(dev));
int error = 0;
+ /* disable S/PDIF output, if any */
+ (void) sc->sc_set_spdif_fn(sc, 0);
+
repeat:
if (sc->sc_pcm_registered) {
error = pcm_unregister(dev);
diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c
index 6e0a27987f46..4ae2820fdf42 100644
--- a/sys/dev/usb/quirk/usb_quirk.c
+++ b/sys/dev/usb/quirk/usb_quirk.c
@@ -517,6 +517,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = {
/* Non-standard USB AUDIO devices */
USB_QUIRK(MAUDIO, FASTTRACKULTRA, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
USB_QUIRK(MAUDIO, FASTTRACKULTRA8R, 0x0000, 0xffff, UQ_AU_VENDOR_CLASS),
+ USB_QUIRK(CMEDIA, CM6206, 0x0000, 0xffff, UQ_AU_SET_SPDIF_CM6206),
/*
* Quirks for manufacturers which USB devices does not respond
@@ -604,6 +605,7 @@ static const char *usb_quirk_str[USB_QUIRK_MAX] = {
[UQ_AU_VENDOR_CLASS] = "UQ_AU_VENDOR_CLASS",
[UQ_SINGLE_CMD_MIDI] = "UQ_SINGLE_CMD_MIDI",
[UQ_MSC_DYMO_EJECT] = "UQ_MSC_DYMO_EJECT",
+ [UQ_AU_SET_SPDIF_CM6206] = "UQ_AU_SET_SPDIF_CM6206",
};
/*------------------------------------------------------------------------*
diff --git a/sys/dev/usb/quirk/usb_quirk.h b/sys/dev/usb/quirk/usb_quirk.h
index 73a349ef0e72..efa28779064d 100644
--- a/sys/dev/usb/quirk/usb_quirk.h
+++ b/sys/dev/usb/quirk/usb_quirk.h
@@ -110,6 +110,7 @@ enum {
UQ_AU_VENDOR_CLASS, /* audio device uses vendor and not audio class */
UQ_SINGLE_CMD_MIDI, /* at most one command per USB packet */
UQ_MSC_DYMO_EJECT, /* ejects Dymo MSC device */
+ UQ_AU_SET_SPDIF_CM6206, /* enable S/PDIF audio output */
USB_QUIRK_MAX
};
diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs
index bccc0251934d..5cce73b4d5af 100644
--- a/sys/dev/usb/usbdevs
+++ b/sys/dev/usb/usbdevs
@@ -1438,6 +1438,9 @@ product CLIPSAL 5000CT2 0x0304 5000CT2 C-Bus Touch Screen
product CLIPSAL C5000CT2 0x0305 C5000CT2 C-Bus Touch Screen
product CLIPSAL L51xx 0x0401 L51xx C-Bus Dimmer
+/* C-Media products */
+product CMEDIA CM6206 0x0102 CM106 compatible sound device
+
/* CMOTECH products */
product CMOTECH CNU510 0x5141 CDMA Technologies USB modem
product CMOTECH CNU550 0x5543 CDMA 2000 1xRTT/1xEVDO USB modem