2
votes

I'm trying to send/receive audio over USB from my embedded linux device to/from a Windows host.

I understand there are 2 protocols to send audio over USB - USB Audio Class 1 and 2 (UAC1 & UAC2). I found them explained here: http://www.thewelltemperedcomputer.com/HW/USB_Audio.htm.

I have currently used the existing UAC1 device driver in Linux to get audio from the host PC. It works for me. I am now trying to change the device driver to also be capable of sending audio to the host PC.

I see that there's a UAC2 driver (in the latest Linux kernel) that both sends and receives audio from the host. But I'd like to have a UAC1 driver that does that, so that I don't have to install any extra drivers on the Windows host (especially ones I have to buy: http://www.thesycon.de/eng/usb_audiodriver.shtml).

I've modified the linux device driver at linux/drivers/usb/gadget/f_audio.c (I'm using an older kernel). I've changed the USB header descriptor to include the extra endpoint for sending audio to host.

static struct usb_descriptor_header *hs_audio_desc[] = {
    (struct usb_descriptor_header *)&std_ac_if_desc,

    (struct usb_descriptor_header *)&ac_hdr_desc,
    (struct usb_descriptor_header *)&usb_it_desc,
    (struct usb_descriptor_header *)&usb_ot_desc,

    (struct usb_descriptor_header *)&std_as_out_if0_desc,
    (struct usb_descriptor_header *)&std_as_out_if1_desc,

    (struct usb_descriptor_header *)&as_out_hdr_desc,
    (struct usb_descriptor_header *)&as_out_fmt1_desc,
    (struct usb_descriptor_header *)&hs_epout_desc,
    (struct usb_descriptor_header *)&as_iso_out_desc,

    (struct usb_descriptor_header *)&std_as_in_if0_desc,
    (struct usb_descriptor_header *)&std_as_in_if1_desc,

    (struct usb_descriptor_header *)&as_in_hdr_desc,
    (struct usb_descriptor_header *)&as_in_fmt1_desc,
    (struct usb_descriptor_header *)&hs_epin_desc,
    (struct usb_descriptor_header *)&as_iso_in_desc,
    NULL,
};

The OUT endpoint is defined as:

struct usb_endpoint_descriptor hs_epout_desc = {
    .bLength = USB_DT_ENDPOINT_SIZE,
    .bDescriptorType = USB_DT_ENDPOINT,

    .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
  .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
    .bInterval = 4,
};

The IN endpoint is defined as:

struct usb_endpoint_descriptor hs_epin_desc = {
    .bLength = USB_DT_ENDPOINT_SIZE,
    .bDescriptorType = USB_DT_ENDPOINT,
    .bEndpointAddress = USB_DIR_IN,
    .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
  .wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
    .bInterval = 4,
};

In epautoconf.c, the bEndpointAddress field is usually OR'ed with the endpoint number. I see in my case that this is happening. The 'bEndpointAddress' field for my OUT endpoint is 0x01 and for my IN endpoint is 0x81 when I print it in epautoconf.c. I'm however not able to see it on the host side. On my Windows PC, I use USB View tool to see the descriptors and I see that the values are 0x00 and 0x80.

What could have possibly changed the value of bEndpointAdress?

These are the USB descriptors I see in Windows using USB View tool:

Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x40 (64)
idVendor:           0x1D6B
idProduct:          0x0101
bcdDevice:          0x0316
iManufacturer:        0x01
0x0409: "Linux 3.2.0 with musb-hdrc"
iProduct:             0x02
0x0409: "Linux USB Audio Gadget"
iSerialNumber:        0x00
bNumConfigurations:   0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed:     High
Device Address:       0x13
Open Pipes:              0

Configuration Descriptor:
wTotalLength:       0x0095
bNumInterfaces:       0x03
bConfigurationValue:  0x01
iConfiguration:       0x00
bmAttributes:         0xC0 (Bus Powered Self Powered )
MaxPower:             0x01 (2 Ma)

Interface Descriptor:
bInterfaceNumber:     0x00
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x01 (Audio Control)
bInterfaceProtocol:   0x00
iInterface:           0x04
0x0409: "Topology Control"

Audio Control Interface Header Descriptor:
bLength:              0x0A
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bcdADC:             0x0100
wTotalLength:       0x001F
bInCollection:        0x02
baInterfaceNr[1]:     0x01
baInterfaceNr[2]:     0x02

Audio Control Input Terminal Descriptor:
bLength:              0x0C
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bTerminalID:          0x02
wTerminalType:      0x0201 (Microphone)
bAssocTerminal:       0x00
bNrChannels:          0x02
wChannelConfig:     0x0003
iChannelNames:        0x00
iTerminal:            0x07

Audio Control Output Terminal Descriptor:
bLength:              0x09
bDescriptorType:      0x24
bDescriptorSubtype:   0x03
bTerminalID:          0x01
wTerminalType:      0x0301 (Speaker)
bAssocTerminal:       0x00
bSoruceID:            0x00
iTerminal:            0x09

Interface Descriptor:
bInterfaceNumber:     0x01
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x0B
0x0409: "Playback Inactive"

Interface Descriptor:
bInterfaceNumber:     0x01
bAlternateSetting:    0x01
bNumEndpoints:        0x01
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x0C
0x0409: "Playback Active"

Audio Streaming Class Specific Interface Descriptor:
bLength:              0x07
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bTerminalLink:        0x01
bDelay:               0x01
wFormatTag:         0x0001 (PCM)

Audio Streaming Format Type Descriptor:
bLength:              0x0B
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bFormatType:          0x01
bNrChannels:          0x00
bSubframeSize:        0x02
bBitResolution:       0x10
bSamFreqType:         0x01
tSamFreq[1]:      0x00BB80 (48000 Hz)

Endpoint Descriptor:
bEndpointAddress:     0x00  OUT
Transfer Type: Isochronous
wMaxPacketSize:     0x00C8 (200)
bInterval:            0x04

Audio Streaming Class Specific Audio Data Endpoint Descriptor:
bLength:              0x07
bDescriptorType:      0x25
bDescriptorSubtype:   0x01
bmAttributes:         0x00
bLockDelayUnits:      0x00
wLockDelay:         0x0000

Interface Descriptor:
bInterfaceNumber:     0x02
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x0D
0x0409: "Capture Inactive"

Interface Descriptor:
bInterfaceNumber:     0x02
bAlternateSetting:    0x01
bNumEndpoints:        0x01
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x0E
0x0409: "Capture Active"

Audio Streaming Class Specific Interface Descriptor:
bLength:              0x07
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bTerminalLink:        0x02
bDelay:               0x01
wFormatTag:         0x0001 (PCM)

Audio Streaming Format Type Descriptor:
bLength:              0x0B
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bFormatType:          0x01
bNrChannels:          0x00
bSubframeSize:        0x02
bBitResolution:       0x10
bSamFreqType:         0x01
tSamFreq[1]:      0x00BB80 (48000 Hz)

Endpoint Descriptor:
bEndpointAddress:     0x80  IN
Transfer Type: Isochronous
wMaxPacketSize:     0x00C8 (200)
bInterval:            0x04

Audio Streaming Class Specific Audio Data Endpoint Descriptor:
bLength:              0x07
bDescriptorType:      0x25
bDescriptorSubtype:   0x01
bmAttributes:         0x00
bLockDelayUnits:      0x00
wLockDelay:         0x0000

Why won't Windows install the UAC1 driver?

1
Have you tried using #pragma pack(1) around your structure declaration?Peter L.
Thanks Peter. But the other elements like bLength and bInterval have the same values as defined. Only bEndpointAddress is changed.linux22
I tried using #pragma pack(1) just now. Unfortunately, it doesn't make a difference.linux22
Try using #pragma pack(1) on both ends, client and host. Also, on StackOverflow you can use the '@' before someone's account name in a reply to enable a notice on their in-box.Peter L.
Thanks @peter-l! I was not able to modify the host driver. So I couldn't use #pragma pack(1).linux22

1 Answers

1
votes

For my first question, I got an answer from the linux-usb mailing list. It turns out that 'epautoconf.c' does not change 'bEndpointAdress'. So I changed the value in the definition of 'bEndpointAdress' and it is correctly conveyed to the host now.

Windows installs the UAC1 driver correctly when I use this configuration:

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed:     High
Device Address:       0x11
Open Pipes:              0

Configuration Descriptor:
wTotalLength:       0x00E7
bNumInterfaces:       0x03
bConfigurationValue:  0x01
iConfiguration:       0x00
bmAttributes:         0xC0 (Bus Powered Self Powered )
MaxPower:             0x01 (2 Ma)

Interface Descriptor:
bInterfaceNumber:     0x00
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x01 (Audio Control)
bInterfaceProtocol:   0x00
iInterface:           0x00

Audio Control Interface Header Descriptor:
bLength:              0x0A
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bcdADC:             0x0100
wTotalLength:       0x0065
bInCollection:        0x02
baInterfaceNr[1]:     0x01
baInterfaceNr[2]:     0x02

Audio Control Input Terminal Descriptor:
bLength:              0x0C
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bTerminalID:          0x01
wTerminalType:      0x0201 (Microphone)
bAssocTerminal:       0x00
bNrChannels:          0x02
wChannelConfig:     0x0003
iChannelNames:        0x00
iTerminal:            0x00

Audio Control Feature Unit Descriptor:
bLength:              0x0A
bDescriptorType:      0x24
bDescriptorSubtype:   0x06
bUnitID:              0x02
bSourceID:            0x01
bControlSize:         0x01
bmaControls[0]:
03 
bmaControls[1]:
00 
bmaControls[2]:
00 
iFeature:             0x00

Audio Control Input Terminal Descriptor:
bLength:              0x0C
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bTerminalID:          0x03
wTerminalType:      0x0402 (Headset)
bAssocTerminal:       0x09
bNrChannels:          0x02
wChannelConfig:     0x0003
iChannelNames:        0x00
iTerminal:            0x00

Audio Control Feature Unit Descriptor:
bLength:              0x0A
bDescriptorType:      0x24
bDescriptorSubtype:   0x06
bUnitID:              0x04
bSourceID:            0x03
bControlSize:         0x01
bmaControls[0]:
03 
bmaControls[1]:
00 
bmaControls[2]:
00 
iFeature:             0x00

Audio Control Selector Unit Descriptor:
bLength:              0x06
bDescriptorType:      0x24
bDescriptorSubtype:   0x05
bUnitID:              0x05
bNrInPins:            0x01
baSourceID[1]:        0x04
iSelector:            0x09

Audio Control Output Terminal Descriptor:
bLength:              0x09
bDescriptorType:      0x24
bDescriptorSubtype:   0x03
bTerminalID:          0x06
wTerminalType:      0x0101 (USB streaming)
bAssocTerminal:       0x00
bSoruceID:            0x05
iTerminal:            0x00

Audio Control Input Terminal Descriptor:
bLength:              0x0C
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bTerminalID:          0x07
wTerminalType:      0x0101 (USB streaming)
bAssocTerminal:       0x00
bNrChannels:          0x02
wChannelConfig:     0x0003
iChannelNames:        0x00
iTerminal:            0x00

Audio Control Feature Unit Descriptor:
bLength:              0x0A
bDescriptorType:      0x24
bDescriptorSubtype:   0x06
bUnitID:              0x08
bSourceID:            0x0A
bControlSize:         0x01
bmaControls[0]:
01 
bmaControls[1]:
02 
bmaControls[2]:
02 
iFeature:             0x00

Audio Control Output Terminal Descriptor:
bLength:              0x09
bDescriptorType:      0x24
bDescriptorSubtype:   0x03
bTerminalID:          0x09
wTerminalType:      0x0402 (Headset)
bAssocTerminal:       0x03
bSoruceID:            0x08
iTerminal:            0x00

Audio Control Mixer Unit Descriptor:
bLength:              0x0D
bDescriptorType:      0x24
bDescriptorSubtype:   0x04
bUnitID:              0x0A
bNrInPins:            0x02
baSourceID[1]:        0x07
baSourceID[2]:        0x02
bNrChannels:          0x02
wChannelConfig:     0x0003
iChannelNames:        0x00
bmControls:
00 
iMixer:               0x00

Interface Descriptor:
bInterfaceNumber:     0x01
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x00

Interface Descriptor:
bInterfaceNumber:     0x01
bAlternateSetting:    0x01
bNumEndpoints:        0x01
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x00

Audio Streaming Class Specific Interface Descriptor:
bLength:              0x07
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bTerminalLink:        0x06
bDelay:               0x01
wFormatTag:         0x0001 (PCM)

Audio Streaming Format Type Descriptor:
bLength:              0x0B
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bFormatType:          0x01
bNrChannels:          0x02
bSubframeSize:        0x02
bBitResolution:       0x10
bSamFreqType:         0x01
tSamFreq[1]:      0x00BB80 (48000 Hz)

Endpoint Descriptor:
bEndpointAddress:     0x01  OUT
Transfer Type: Isochronous
wMaxPacketSize:     0x00C8 (200)
bInterval:            0x04

Audio Streaming Class Specific Audio Data Endpoint Descriptor:
bLength:              0x07
bDescriptorType:      0x25
bDescriptorSubtype:   0x01
bmAttributes:         0x01
bLockDelayUnits:      0x00
wLockDelay:         0x0000

Interface Descriptor:
bInterfaceNumber:     0x02
bAlternateSetting:    0x00
bNumEndpoints:        0x00
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x00

Interface Descriptor:
bInterfaceNumber:     0x02
bAlternateSetting:    0x01
bNumEndpoints:        0x01
bInterfaceClass:      0x01 (Audio)
bInterfaceSubClass:   0x02 (Audio Streaming)
bInterfaceProtocol:   0x00
iInterface:           0x00

Audio Streaming Class Specific Interface Descriptor:
bLength:              0x07
bDescriptorType:      0x24
bDescriptorSubtype:   0x01
bTerminalLink:        0x07
bDelay:               0x01
wFormatTag:         0x0001 (PCM)

Audio Streaming Format Type Descriptor:
bLength:              0x0B
bDescriptorType:      0x24
bDescriptorSubtype:   0x02
bFormatType:          0x01
bNrChannels:          0x02
bSubframeSize:        0x02
bBitResolution:       0x10
bSamFreqType:         0x01
tSamFreq[1]:      0x00BB80 (48000 Hz)

Endpoint Descriptor:
bEndpointAddress:     0x81  IN
Transfer Type: Isochronous
wMaxPacketSize:     0x00C8 (200)
bInterval:            0x04

Audio Streaming Class Specific Audio Data Endpoint Descriptor:
bLength:              0x07
bDescriptorType:      0x25
bDescriptorSubtype:   0x01
bmAttributes:         0x01
bLockDelayUnits:      0x01
wLockDelay:         0x0004