Why ?

The U2A works fine under Linux, since it implements a standard USB audio class device interface (a big "thank you" to EgoSys for adhering to standards!). However, finer control of the internal routing and input selection is not possible. In short we are missing the equivalent of the U2A control panel for Windows:

U2A Control Panel applet for Windows


I have managed to snoop the USB traffic between the U2A control panel applet and the sound card with the help of SnoopyPro. Hopefully that should be sufficient to start implementing the corresponding Linux applet. I was surprised to learn that all the traffic goes to the main audio interface and nothing to the HID device which is also implemented by the U2A.


I have installed libusb-dev and wxPython to develop a GUI client. I am currently stuck when I try to open the USB device to write to it - getting an assertion error from the libusb python wrapper. Hmmmm... I'll try writing some plain C first, to make the card toggle between digital and analog in.


Finally got time to get some C code up and running. Sadly, this shows that the standard USB sound driver blocks my attempts to claim/open the audio interface. This explains my problems getting the Python wrapper to work. Running the C program as root shows that snd_usb_audio is using the card and after I rmmod snd_usb_audio, I can claim the audio interface. Not a usable solution for re-configuring sound card settings.

#include <stdio.h>
#include <usb.h>

int main(int argc, char *argv[])
  struct usb_bus *bus;



  for (bus = usb_busses; bus; bus = bus->next)
    struct usb_device *dev;

    for (dev = bus->devices; dev; dev = dev->next)
	if ((dev->descriptor.idVendor == 0x0A92) && (dev->descriptor.idProduct == 0x0011)) 

	    printf("U2A sound card found!: --- \n");
            printf("  %d configurations.\n", dev->descriptor.bNumConfigurations);
            printf("  %d interfaces in config 0.\n", dev->config[0].bNumInterfaces);

            usb_dev_handle *dev_handle;
            dev_handle = usb_open(dev);
            if (dev_handle == 0) {
              printf("Couldn't open sound card.\n");
            printf("Got handle %d.\n", dev_handle);

            // Driver query code lifted from gphoto2's libusb.c
            int ret;
            char name[64];
            ret = usb_get_driver_np (dev_handle, 0, name, sizeof(name));
            printf("Driver query returned %d. Driver name is %s.\n", ret, name);

            if (usb_claim_interface(dev_handle, 0) == 0) {
              if (usb_release_interface(dev_handle, 0) != 0) {
                printf("Couldn't release interface.\n");
            else {
              printf("Aiii! Couldn't claim interface.\n");

            if (usb_close(dev_handle) != 0) {
              printf("Error closing sound card.\n");

	printf("%04X - %04X\n",
	    dev->descriptor.idVendor, dev->descriptor.idProduct

  return 0;

Seems like I need to investigate how I can send commands to the sound card through the driver - ioctl() calls ?


Here I am, at it again after the summer holidays. A patch by ALSA-developer Clemens Ladisch for the USB audio driver implements a hardware dependant interface that allows me to send control transfers to the device through an ioctl() call (please note that this patch only applies cleanly to an older CVS version of the ALSA drivers). I have been able to squirt off a control transfer package to the sound card without getting an error code back, so that definitely counts as progress :-). See below for a useless example that nevertheless seems to send two bytes without complaints.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include "asoundlib.h"
#include "sound/asound.h"

int main(int argc, char *argv[])
        int err;

        snd_hwdep_t *hw;
        char *devicename = "hw:0,1";

        if ((err = snd_hwdep_open(&hw, devicename, O_RDWR)) < 0) {
                printf("hwdep interface open error: %s\n", snd_strerror(err));
                return 0;
        printf("hwdep '%s' opened\n", devicename);        

        snd_hwdep_info_t *info;
        if ((err = snd_hwdep_info(hw, info)) < 0) {
                printf("error getting hwdep_info\n");
                return err;
        printf("ID   = %s\n", snd_hwdep_info_get_id(info));
        printf("NAME = %s\n", snd_hwdep_info_get_name(info));

        struct usbdevfs_ctrltransfer ctrl;
        #define CMD_LEN 2
        char command_string[CMD_LEN] = "\xff\x0f";

        ctrl.bRequest = USB_REQ_CLEAR_FEATURE;
        ctrl.bRequestType = 0;
        ctrl.wValue = 0;
        ctrl.wIndex = 0;

        ctrl.wLength = CMD_LEN;
        ctrl.data = command_string;  
        ctrl.timeout = 1000;   // milli-seconds

        printf("Sending %d bytes...\n", ctrl.wLength);
        if ((err = snd_hwdep_ioctl(hw, USBDEVFS_CONTROL, &ctrl)) < 0) {
                printf("hwdep ioctl error: %s\n", snd_strerror(err));
                return 0;

        printf("OK - orderly shutdown\n");

        return 0;

I am now reading up on the USB 1.1 spec to be able to decode the SnoopyPro traces correctly so I can start sending the correct commands to the sound card.

Valid XHTML 1.0!