usb: add support for "grouped" interfaces and the Interface Association Descriptor
This is used for some devices that have multiple interfaces that form a logic device. An example is Video Class, which has a Control interface and a Streaming interface. There can be additional interfaces on the same (physical) devices (e.g. a microphone), and Interface Association Descriptor handles this case. Signed-off-by: Brad Hards <bradh@frogmouth.net> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
		
							parent
							
								
									fef13fa8e4
								
							
						
					
					
						commit
						6e625fc704
					
				@ -91,6 +91,18 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
 | 
				
			|||||||
    dest[0x08] = conf->bMaxPower;
 | 
					    dest[0x08] = conf->bMaxPower;
 | 
				
			||||||
    wTotalLength += bLength;
 | 
					    wTotalLength += bLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* handle grouped interfaces if any*/
 | 
				
			||||||
 | 
					    for (i = 0; i < conf->nif_groups; i++) {
 | 
				
			||||||
 | 
					        rc = usb_desc_iface_group(&(conf->if_groups[i]),
 | 
				
			||||||
 | 
					                                  dest + wTotalLength,
 | 
				
			||||||
 | 
					                                  len - wTotalLength);
 | 
				
			||||||
 | 
					        if (rc < 0) {
 | 
				
			||||||
 | 
					            return rc;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        wTotalLength += rc;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* handle normal (ungrouped / no IAD) interfaces if any */
 | 
				
			||||||
    for (i = 0; i < conf->nif; i++) {
 | 
					    for (i = 0; i < conf->nif; i++) {
 | 
				
			||||||
        rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
 | 
					        rc = usb_desc_iface(conf->ifs + i, dest + wTotalLength, len - wTotalLength);
 | 
				
			||||||
        if (rc < 0) {
 | 
					        if (rc < 0) {
 | 
				
			||||||
@ -104,6 +116,41 @@ int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len)
 | 
				
			|||||||
    return wTotalLength;
 | 
					    return wTotalLength;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
 | 
				
			||||||
 | 
					                         size_t len)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int pos = 0;
 | 
				
			||||||
 | 
					    int i = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* handle interface association descriptor */
 | 
				
			||||||
 | 
					    uint8_t bLength = 0x08;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (len < bLength) {
 | 
				
			||||||
 | 
					        return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dest[0x00] = bLength;
 | 
				
			||||||
 | 
					    dest[0x01] = USB_DT_INTERFACE_ASSOC;
 | 
				
			||||||
 | 
					    dest[0x02] = iad->bFirstInterface;
 | 
				
			||||||
 | 
					    dest[0x03] = iad->bInterfaceCount;
 | 
				
			||||||
 | 
					    dest[0x04] = iad->bFunctionClass;
 | 
				
			||||||
 | 
					    dest[0x05] = iad->bFunctionSubClass;
 | 
				
			||||||
 | 
					    dest[0x06] = iad->bFunctionProtocol;
 | 
				
			||||||
 | 
					    dest[0x07] = iad->iFunction;
 | 
				
			||||||
 | 
					    pos += bLength;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* handle associated interfaces in this group */
 | 
				
			||||||
 | 
					    for (i = 0; i < iad->nif; i++) {
 | 
				
			||||||
 | 
					        int rc = usb_desc_iface(&(iad->ifs[i]), dest + pos, len - pos);
 | 
				
			||||||
 | 
					        if (rc < 0) {
 | 
				
			||||||
 | 
					            return rc;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        pos += rc;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return pos;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 | 
					int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    uint8_t bLength = 0x09;
 | 
					    uint8_t bLength = 0x09;
 | 
				
			||||||
 | 
				
			|||||||
@ -30,6 +30,24 @@ struct USBDescConfig {
 | 
				
			|||||||
    uint8_t                   bmAttributes;
 | 
					    uint8_t                   bmAttributes;
 | 
				
			||||||
    uint8_t                   bMaxPower;
 | 
					    uint8_t                   bMaxPower;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* grouped interfaces */
 | 
				
			||||||
 | 
					    uint8_t                   nif_groups;
 | 
				
			||||||
 | 
					    const USBDescIfaceAssoc   *if_groups;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* "normal" interfaces */
 | 
				
			||||||
 | 
					    uint8_t                   nif;
 | 
				
			||||||
 | 
					    const USBDescIface        *ifs;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* conceptually an Interface Association Descriptor, and releated interfaces */
 | 
				
			||||||
 | 
					struct USBDescIfaceAssoc {
 | 
				
			||||||
 | 
					    uint8_t                   bFirstInterface;
 | 
				
			||||||
 | 
					    uint8_t                   bInterfaceCount;
 | 
				
			||||||
 | 
					    uint8_t                   bFunctionClass;
 | 
				
			||||||
 | 
					    uint8_t                   bFunctionSubClass;
 | 
				
			||||||
 | 
					    uint8_t                   bFunctionProtocol;
 | 
				
			||||||
 | 
					    uint8_t                   iFunction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uint8_t                   nif;
 | 
					    uint8_t                   nif;
 | 
				
			||||||
    const USBDescIface        *ifs;
 | 
					    const USBDescIface        *ifs;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
@ -75,6 +93,8 @@ int usb_desc_device(const USBDescID *id, const USBDescDevice *dev,
 | 
				
			|||||||
int usb_desc_device_qualifier(const USBDescDevice *dev,
 | 
					int usb_desc_device_qualifier(const USBDescDevice *dev,
 | 
				
			||||||
                              uint8_t *dest, size_t len);
 | 
					                              uint8_t *dest, size_t len);
 | 
				
			||||||
int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
 | 
					int usb_desc_config(const USBDescConfig *conf, uint8_t *dest, size_t len);
 | 
				
			||||||
 | 
					int usb_desc_iface_group(const USBDescIfaceAssoc *iad, uint8_t *dest,
 | 
				
			||||||
 | 
					                         size_t len);
 | 
				
			||||||
int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
 | 
					int usb_desc_iface(const USBDescIface *iface, uint8_t *dest, size_t len);
 | 
				
			||||||
int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
 | 
					int usb_desc_endpoint(const USBDescEndpoint *ep, uint8_t *dest, size_t len);
 | 
				
			||||||
int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
 | 
					int usb_desc_other(const USBDescOther *desc, uint8_t *dest, size_t len);
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										1
									
								
								hw/usb.h
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								hw/usb.h
									
									
									
									
									
								
							@ -141,6 +141,7 @@ typedef struct USBDesc USBDesc;
 | 
				
			|||||||
typedef struct USBDescID USBDescID;
 | 
					typedef struct USBDescID USBDescID;
 | 
				
			||||||
typedef struct USBDescDevice USBDescDevice;
 | 
					typedef struct USBDescDevice USBDescDevice;
 | 
				
			||||||
typedef struct USBDescConfig USBDescConfig;
 | 
					typedef struct USBDescConfig USBDescConfig;
 | 
				
			||||||
 | 
					typedef struct USBDescIfaceAssoc USBDescIfaceAssoc;
 | 
				
			||||||
typedef struct USBDescIface USBDescIface;
 | 
					typedef struct USBDescIface USBDescIface;
 | 
				
			||||||
typedef struct USBDescEndpoint USBDescEndpoint;
 | 
					typedef struct USBDescEndpoint USBDescEndpoint;
 | 
				
			||||||
typedef struct USBDescOther USBDescOther;
 | 
					typedef struct USBDescOther USBDescOther;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user