Yes, the kernel patch is open sourced. Just not revisioned on a public repo. When my grand plans of a new cloud server to handle user kernel compile requests comes to fruition, it'd be revisioned there.
Until then, here's the current patch. Note only the DSD kernel will apply this patch. Everything else is stock. For this to work, the USB module has to be compiled as a dynamic kernel module. That may or may not be ideal so it'll be something to improve on down the road. The idea is to devise a way for user to dynamically change the native DSD capability by power cycling the DAC (rather than reboot the PC).
Code:
--- linux-4.4.9-rt17/sound/usb/endpoint.c 2017-07-23 12:01:47.000000000 +0800
+++ linux-4.4.9-rt17.dsd/sound/usb/endpoint.c 2019-01-28 10:53:17.063781183 +0800
@@ -634,7 +634,21 @@
ep->datainterval = fmt->datainterval;
ep->stride = frame_bits >> 3;
- ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0;
+
+ switch (pcm_format) {
+ case SNDRV_PCM_FORMAT_U8:
+ ep->silence_value = 0x80;
+ break;
+ case SNDRV_PCM_FORMAT_DSD_U8:
+ case SNDRV_PCM_FORMAT_DSD_U16_LE:
+ case SNDRV_PCM_FORMAT_DSD_U32_LE:
+ case SNDRV_PCM_FORMAT_DSD_U16_BE:
+ case SNDRV_PCM_FORMAT_DSD_U32_BE:
+ ep->silence_value = 0x69;
+ break;
+ default:
+ ep->silence_value = 0;
+ }
/* assume max. frequency is 25% higher than nominal */
ep->freqmax = ep->freqn + (ep->freqn >> 2);
--- linux-4.4.9-rt17/sound/usb/quirks.c 2017-07-23 12:01:47.000000000 +0800
+++ linux-4.4.9-rt17.dsd/sound/usb/quirks.c 2019-04-16 12:35:57.865416343 +0800
@@ -19,6 +19,10 @@
#include <linux/usb.h>
#include <linux/usb/audio.h>
#include <linux/usb/midi.h>
+#include <linux/fs.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <linux/buffer_head.h>
#include <sound/control.h>
#include <sound/core.h>
@@ -1152,6 +1156,7 @@
static bool is_marantz_denon_dac(unsigned int id)
{
switch (id) {
+ case USB_ID(0x0644, 0x8043): /* Snakeoil: TEAC UD-501 */
case USB_ID(0x154e, 0x1003): /* Denon DA-300USB */
case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
@@ -1265,6 +1270,29 @@
mdelay(1);
}
+short toDec(const char x)
+{
+ switch (x) {
+ case '0': return 0;
+ case '1': return 1;
+ case '2': return 2;
+ case '3': return 3;
+ case '4': return 4;
+ case '5': return 5;
+ case '6': return 6;
+ case '7': return 7;
+ case '8': return 8;
+ case '9': return 9;
+ case 'a': return 10;
+ case 'b': return 11;
+ case 'c': return 12;
+ case 'd': return 13;
+ case 'e': return 14;
+ case 'f': return 15;
+ }
+ return 0;
+}
+
/*
* snd_usb_interface_dsd_format_quirks() is called from format.c to
* augment the PCM format bit-field for DSD types. The UAC standards
@@ -1276,6 +1304,73 @@
struct audioformat *fp,
unsigned int sample_bytes)
{
+ char dsdConfig[256];
+ size_t dsdRetVal = 0;
+ struct file * filp = NULL;
+ int loop = 0;
+ unsigned short usb_1 = 0;
+ unsigned short usb_2 = 0;
+ int altset = 0;
+ u64 dsdFormat = 0;
+
+ filp = filp_open("/var/www/config/dsd_config", 0, 0);
+ if (IS_ERR(filp)) {
+ printk(KERN_INFO "@Snakeoil DSD Config file not found. Waiting...\n");
+ }
+ else
+ {
+ dsdRetVal = kernel_read(filp, 0, (void*)dsdConfig, 256);
+
+ if (dsdRetVal) {
+ char * ch;
+ //262a-9227-2-DSD_U8
+ //0123456789-1234567
+ if (dsdRetVal < 19) {
+ if (fp->altsetting == 1)
+ printk(KERN_INFO "@Snakeoil DSD Config file size is too small: %ld.\n", dsdRetVal);
+ } else if (!(dsdConfig[4] == ':' && dsdConfig[9] == '-' && dsdConfig[11] == '-' &&
+ strncmp(&dsdConfig[12], "DSD_U", 5) == 0)) {
+ if (fp->altsetting == 1)
+ printk(KERN_INFO "@Snakeoil DSD Config file appears to be corrupted.\n");
+ } else {
+ dsdConfig[dsdRetVal-1] = '\0';
+ if (fp->altsetting == 1)
+ printk(KERN_INFO "@Snakeoil DSD Config string: (%s)\n", dsdConfig);
+ ch = dsdConfig;
+ usb_1 = (toDec(dsdConfig[0]) << 12) + (toDec(dsdConfig[1]) << 8) +
+ (toDec(dsdConfig[2]) << 4 ) + toDec(dsdConfig[3]);
+ usb_2 = (toDec(dsdConfig[5]) << 12) + (toDec(dsdConfig[6]) << 8) +
+ (toDec(dsdConfig[7]) << 4 ) + toDec(dsdConfig[8]);
+ altset = toDec(dsdConfig[10]);
+ ch = dsdConfig+17;
+ dsdFormat = (*ch == '8')? SNDRV_PCM_FMTBIT_DSD_U8
+ : (strncmp(ch, "16_LE", 5) == 0)
+ ? SNDRV_PCM_FMTBIT_DSD_U16_LE
+ : (strncmp(ch, "32_LE", 5) == 0)
+ ? SNDRV_PCM_FMTBIT_DSD_U32_LE
+ : (strncmp(ch, "16_BE", 5) == 0)
+ ? SNDRV_PCM_FMTBIT_DSD_U16_BE
+ : SNDRV_PCM_FMTBIT_DSD_U32_BE; // force this as default
+
+ if (chip->usb_id == USB_ID(usb_1, usb_2) && fp->altsetting == altset) {
+ printk(KERN_INFO "@Snakeoil USB_ID: %x:%x Altset: %d NativeDSD: (%s)\n", usb_1, usb_2, fp->altsetting,
+ (dsdFormat == SNDRV_PCM_FMTBIT_DSD_U8? "DSD_U8":
+ dsdFormat == SNDRV_PCM_FMTBIT_DSD_U16_LE? "DSD_U16_LE":
+ dsdFormat == SNDRV_PCM_FMTBIT_DSD_U32_LE? "DSD_U32_LE":
+ dsdFormat == SNDRV_PCM_FMTBIT_DSD_U16_BE? "DSD_U16_BE":
+ dsdFormat == SNDRV_PCM_FMTBIT_DSD_U32_BE? "DSD_U32_BE": "ERROR"));
+
+ return dsdFormat;
+ } else {
+ printk(KERN_INFO "@Snakeoil USB_ID: %x:%x Altset: %d NativeDSD: (None)\n", usb_1, usb_2, fp->altsetting);
+ }
+ }
+ }
+ else if (fp->altsetting == 1) {
+ printk(KERN_INFO "@Snakeoil No Custom DSD Format defined\n");
+ }
+ }
+
/* Playback Designs */
if (le16_to_cpu(chip->dev->descriptor.idVendor) == 0x23ba) {
switch (fp->altsetting) {
@@ -1293,19 +1388,27 @@
/* XMOS based USB DACs */
switch (chip->usb_id) {
+ case USB_ID(0x16d0, 0x078c): /* Rockna Audio WaveDream */
+ case USB_ID(0x20b1, 0x2004): /* Matrix Audio X-SPDIF 2 */
case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */
case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */
case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */
case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */
+ case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */
+ case USB_ID(0x16d0, 0x071a): /* Amanero Combo384 */
if (fp->altsetting == 2)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
-
case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */
case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */
case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */
case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */
case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */
+ case USB_ID(0x20b1, 0x0002): /* Snakeoil: Molamola */
+ case USB_ID(0x20b1, 0x3089): /* Snakeoil: Molamola new firmware */
+ case USB_ID(0x20b1, 0x3036): /* HOLO DAC */
+ case USB_ID(0x20b0, 0x000a): /* Snakeoil: xDuoo XD-05 */
+ case USB_ID(0x20b1, 0x30c6): /* https://www.snakeoil-os.net/forums/Thread-Native-DSD-support-for-new-DAC */
if (fp->altsetting == 3)
return SNDRV_PCM_FMTBIT_DSD_U32_BE;
break;
To make Snakeoil even better we need more people to look deeper into the kernel code, as well as trying various options. Keeping this a secret is going against that grain. Eventually I'll gather enough Snakeoil supporters to fund up a server, then I have to write the system to make it easy for people to get their kernels.. The idea is:
And I strongly believe this will bring Snakeoil to another a level.
The backend will be gitlab (and runners) and nextcloud (file hosting). I will code up a frontend to link it all together. In reality this isn't hard to code. Alas if only I am doing this full time.