[PATCH] Add quirk to enable Avid Mbox 3 support

Takashi Iwai tiwai at suse.de
Wed Aug 17 09:45:53 CEST 2022


On Wed, 17 Aug 2022 09:15:50 +0200,
connerknoxpublic at gmail.com wrote:
> 
> From: Conner Knox <connerknoxpublic at gmail.com>
> 
> Appreciate the attention on this, no worries on the wait.
> I figured I might have sent something to the wrong spot.
> 
> I've added the Signed-off-by line, appologies for
> missing that requirement - first time contributor. As
> such, please let me know if I need to change
> anything else.
> 
> I had some memset's in the code already, and the excess
> 0s were for clarity of what was in the buffer.
> Since I wasn't sure exactly what the recommendation was
> I left the code alone.  Let me know if it needs changed.
> 
> I may make further changes to address the aforementioned
> shortcomings when I get time as well.
> 
> Thanks again for your time.
> 
> Signed-off-by: Conner Knox <connerknoxpublic at gmail.com>

Now we have signed-off-by line, but the patch description should
contain what to be put in the git commit log.  So please write what
your patch fixes and some technical details if you want to add there.

The rest comments could be put after the line "---" if you want, but
usually not needed unless you need extra notes.

Care to resubmit with the proper patch description, so that I can take
it as is?


thanks,

Takashi

> ---
>  sound/usb/quirks-table.h |  76 ++++++++++
>  sound/usb/quirks.c       | 311 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 387 insertions(+)
> 
> diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
> index 0ea39565e623..5f43863e5a5f 100644
> --- a/sound/usb/quirks-table.h
> +++ b/sound/usb/quirks-table.h
> @@ -2978,6 +2978,82 @@ YAMAHA_DEVICE(0x7010, "UB99"),
>  		}
>  	}
>  },
> +/* DIGIDESIGN MBOX 3 */
> +{
> +	USB_DEVICE(0x0dba, 0x5000),
> +	.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
> +		.vendor_name = "Digidesign",
> +		.product_name = "Mbox 3",
> +		.ifnum = QUIRK_ANY_INTERFACE,
> +		.type = QUIRK_COMPOSITE,
> +		.data = (const struct snd_usb_audio_quirk[]) {
> +			{
> +				.ifnum = 0,
> +				.type = QUIRK_IGNORE_INTERFACE
> +			},
> +			{
> +				.ifnum = 1,
> +				.type = QUIRK_IGNORE_INTERFACE
> +			},
> +			{
> +				.ifnum = 2,
> +				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
> +				.data = &(const struct audioformat) {
> +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
> +					.channels = 4,
> +					.iface = 2,
> +					.altsetting = 1,
> +					.altset_idx = 1,
> +					.attributes = 0x00,
> +					.endpoint = 0x01,
> +					.ep_attr = USB_ENDPOINT_XFER_ISOC |
> +						USB_ENDPOINT_SYNC_ASYNC,
> +					.rates = SNDRV_PCM_RATE_48000,
> +					.rate_min = 48000,
> +					.rate_max = 48000,
> +					.nr_rates = 1,
> +					.rate_table = (unsigned int[]) {
> +						48000
> +					}
> +				}
> +			},
> +			{
> +				.ifnum = 3,
> +				.type = QUIRK_AUDIO_FIXED_ENDPOINT,
> +				.data = &(const struct audioformat) {
> +					.formats = SNDRV_PCM_FMTBIT_S24_3LE,
> +					.channels = 4,
> +					.iface = 3,
> +					.altsetting = 1,
> +					.altset_idx = 1,
> +					.endpoint = 0x81,
> +					.attributes = 0x00,
> +					.ep_attr = USB_ENDPOINT_XFER_ISOC |
> +						USB_ENDPOINT_SYNC_ASYNC,
> +					.maxpacksize = 0x009c,
> +					.rates = SNDRV_PCM_RATE_48000,
> +					.rate_min = 48000,
> +					.rate_max = 48000,
> +					.nr_rates = 1,
> +					.rate_table = (unsigned int[]) {
> +						48000
> +					}
> +				}
> +			},
> +			{
> +				.ifnum = 4,
> +				.type = QUIRK_MIDI_FIXED_ENDPOINT,
> +				.data = & (const struct snd_usb_midi_endpoint_info) {
> +					.out_cables = 0x0001,
> +					.in_cables  = 0x0001
> +				}
> +			},
> +			{
> +				.ifnum = -1
> +			}
> +		}
> +	}
> +},
>  {
>  	/* Tascam US122 MKII - playback-only support */
>  	USB_DEVICE_VENDOR_SPEC(0x0644, 0x8021),
> diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
> index ab9f3da49941..e7caa7eeb955 100644
> --- a/sound/usb/quirks.c
> +++ b/sound/usb/quirks.c
> @@ -1020,6 +1020,313 @@ static int snd_usb_axefx3_boot_quirk(struct usb_device *dev)
>  	return 0;
>  }
>  
> +static void mbox3_setup_48_24_magic(struct usb_device *dev)
> +{
> +	u8 com_buff[4];
> +
> +	/* Load 48000Hz rate into buffer */
> +	com_buff[0] = 0x80;
> +	com_buff[1] = 0xbb;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +
> +	/* Set 48000Hz sample rate */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			0x01, 0x21, 0x0100, 0x0001, &com_buff, 0x0004);
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			0x01, 0x21, 0x0100, 0x8101, &com_buff, 0x0004);
> +
> +	/* Set clock source to Internal (as opposed to S/PDIF) */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x01;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0100, 0x8001, &com_buff, 1);
> +
> +	/* Mute the hardware loopbacks to start the device in a known state.
> +	 * The Mbox 3 is little endian and
> +	 * the data written here seems a bit odd.
> +	 * 0x8000 (shown in big endian form) is muted
> +	 * and volume increases to 0xffff it seems.
> +	 * I've yet to observe 0xffff being sent.
> +	 * Instead, full volume seems to be 0x0000.
> +	 * Per my understanding of 16 bit integers, this is seems strange, but maybe I'm missing something
> +	 */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x80;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	/* Analogue input 1 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0110, 0x4001, &com_buff, 2);
> +	/* Analogue input 1 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0111, 0x4001, &com_buff, 2);
> +	/* Analogue input 2 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0114, 0x4001, &com_buff, 2);
> +	/* Analogue input 2 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0115, 0x4001, &com_buff, 2);
> +	/* Analogue input 3 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0118, 0x4001, &com_buff, 2);
> +	/* Analogue input 3 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0119, 0x4001, &com_buff, 2);
> +	/* Analogue input 4 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011c, 0x4001, &com_buff, 2);
> +	/* Analogue input 4 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011d, 0x4001, &com_buff, 2);
> +
> +	/* Set software sends to output */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	/* Analogue software return 1 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0100, 0x4001, &com_buff, 2);
> +	/* Analogue software return 1 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0101, 0x4001, &com_buff, 2);
> +	/* Analogue software return 2 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0104, 0x4001, &com_buff, 2);
> +	/* Analogue software return 2 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0105, 0x4001, &com_buff, 2);
> +	/* Analogue software return 3 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0108, 0x4001, &com_buff, 2);
> +	/* Analogue software return 3 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0109, 0x4001, &com_buff, 2);
> +	/* Analogue software return 4 left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010c, 0x4001, &com_buff, 2);
> +	/* Analogue software return 4 right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010d, 0x4001, &com_buff, 2);
> +
> +	/* Return to muting sends */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x80;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	/* Analogue fx return left channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0120, 0x4001, &com_buff, 2);
> +	/* Analogue fx return right channel: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0121, 0x4001, &com_buff, 2);
> +
> +	/* Analogue software input 1 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0100, 0x4201, &com_buff, 2);
> +	/* Analogue software input 2 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0101, 0x4201, &com_buff, 2);
> +	/* Analogue software input 3 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0102, 0x4201, &com_buff, 2);
> +	/* Analogue software input 4 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0103, 0x4201, &com_buff, 2);
> +	/* Analogue input 1 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0104, 0x4201, &com_buff, 2);
> +	/* Analogue input 2 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0105, 0x4201, &com_buff, 2);
> +	/* Analogue input 3 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0106, 0x4201, &com_buff, 2);
> +	/* Analogue input 4 fx send: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0107, 0x4201, &com_buff, 2);
> +
> +	/* Toggle allowing host control */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x02;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			3, 0x21, 0x0000, 0x2001, &com_buff, 1);
> +
> +	/* Do not dim fx returns */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 3, 0x21, 0x0002, 0x2001, &com_buff, 1);
> +
> +	/* Do not set fx returns to mono */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 3, 0x21, 0x0001, 0x2001, &com_buff, 1);
> +
> +	/* Mute the S/PDIF hardware loopback
> +	 * same odd volume logic here as above
> +	 */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x80;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	/* S/PDIF hardware input 1 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0112, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 1 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0113, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 2 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0116, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 2 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0117, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 3 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011a, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 3 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011b, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 4 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011e, 0x4001, &com_buff, 2);
> +	/* S/PDIF hardware input 4 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x011f, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 1 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0102, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 1 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0103, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 2 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0106, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 2 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0107, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 3 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010a, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 3 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010b, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 4 left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010e, 0x4001, &com_buff, 2);
> +	/* S/PDIF software return 4 right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x010f, 0x4001, &com_buff, 2);
> +	/* S/PDIF fx returns left channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0122, 0x4001, &com_buff, 2);
> +	/* S/PDIF fx returns right channel */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0123, 0x4001, &com_buff, 2);
> +
> +	/* Set the dropdown "Effect" to the first option */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0200, 0x4301, &com_buff, 1);
> +
> +	/* Set the effect duration to 0 */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0400, 0x4301, &com_buff, 2);
> +
> +	/* Set the effect volume and feedback to 0 */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	/* feedback: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0500, 0x4301, &com_buff, 1);
> +	/* volume: */
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			1, 0x21, 0x0300, 0x4301, &com_buff, 1);
> +
> +	/* Set soft button hold duration */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x05;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			3, 0x21, 0x0005, 0x2001, &com_buff, 1);
> +
> +	/* Use dim LEDs for button of state */
> +	memset(com_buff, 0x00, 4);
> +	com_buff[0] = 0x00;
> +	com_buff[1] = 0x00;
> +	com_buff[2] = 0x00;
> +	com_buff[3] = 0x00;
> +	snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0),
> +			3, 0x21, 0x0004, 0x2001, &com_buff, 1);
> +
> +	return;
> +}
> +
> +#define MBOX3_DESCRIPTOR_SIZE	464
> +
> +static int snd_usb_mbox3_boot_quirk(struct usb_device *dev)
> +{
> +	struct usb_host_config *config = dev->actconfig;
> +	int err;
> +	int descriptor_size;
> +
> +	descriptor_size = le16_to_cpu(get_cfg_desc(config)->wTotalLength);
> +
> +	if (descriptor_size != MBOX3_DESCRIPTOR_SIZE) {
> +		dev_err(&dev->dev, "Invalid descriptor size=%d.\n", descriptor_size);
> +		return -ENODEV;
> +	}
> +
> +	dev_dbg(&dev->dev, "device initialised!\n");
> +
> +	err = usb_get_descriptor(dev, USB_DT_DEVICE, 0,
> +		&dev->descriptor, sizeof(dev->descriptor));
> +	config = dev->actconfig;
> +	if (err < 0)
> +		dev_dbg(&dev->dev, "error usb_get_descriptor: %d\n", err);
> +
> +	err = usb_reset_configuration(dev);
> +	if (err < 0)
> +		dev_dbg(&dev->dev, "error usb_reset_configuration: %d\n", err);
> +	dev_dbg(&dev->dev, "mbox3_boot: new boot length = %d\n",
> +		le16_to_cpu(get_cfg_desc(config)->wTotalLength));
> +
> +	mbox3_setup_48_24_magic(dev);
> +	dev_info(&dev->dev, "Digidesign Mbox 3: 24bit 48kHz");
> +
> +	return 0; /* Successful boot */
> +}
>  
>  #define MICROBOOK_BUF_SIZE 128
>  
> @@ -1324,6 +1631,10 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev,
>  	case USB_ID(0x0dba, 0x3000):
>  		/* Digidesign Mbox 2 */
>  		return snd_usb_mbox2_boot_quirk(dev);
> +	case USB_ID(0x0dba, 0x5000):
> +		/* Digidesign Mbox 3 */
> +		return snd_usb_mbox3_boot_quirk(dev);
> +
>  
>  	case USB_ID(0x1235, 0x0010): /* Focusrite Novation Saffire 6 USB */
>  	case USB_ID(0x1235, 0x0018): /* Focusrite Novation Twitch */
> -- 
> 2.37.2
> 


More information about the Alsa-devel mailing list