blob: a5f123acc79ecc519cbbcd99e1d709d45420b232 [file] [log] [blame]
#ifndef _USBHUB_H
#define _USBHUB_H
/** @file
*
* USB hubs
*
*/
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/usb.h>
#include <ipxe/list.h>
#include <ipxe/process.h>
/** Request recipient is a port */
#define USB_HUB_RECIP_PORT ( 3 << 0 )
/** A basic USB hub descriptor */
struct usb_hub_descriptor_basic {
/** Descriptor header */
struct usb_descriptor_header header;
/** Number of ports */
uint8_t ports;
/** Characteristics */
uint16_t characteristics;
/** Power-on delay (in 2ms intervals */
uint8_t delay;
/** Controller current (in mA) */
uint8_t current;
} __attribute__ (( packed ));
/** A basic USB hub descriptor */
#define USB_HUB_DESCRIPTOR 41
/** An enhanced USB hub descriptor */
struct usb_hub_descriptor_enhanced {
/** Basic USB hub descriptor */
struct usb_hub_descriptor_basic basic;
/** Header decode latency */
uint8_t latency;
/** Maximum delay */
uint16_t delay;
/** Removable device bitmask */
uint16_t removable;
} __attribute__ (( packed ));
/** An enhanced USB hub descriptor */
#define USB_HUB_DESCRIPTOR_ENHANCED 42
/** A USB hub descriptor */
union usb_hub_descriptor {
/** Descriptor header */
struct usb_descriptor_header header;
/** Basic hub descriptor */
struct usb_hub_descriptor_basic basic;
/** Enhanced hub descriptor */
struct usb_hub_descriptor_enhanced enhanced;
} __attribute__ (( packed ));
/** Port status */
struct usb_hub_port_status {
/** Current status */
uint16_t current;
/** Changed status */
uint16_t changed;
} __attribute__ (( packed ));
/** Current connect status feature */
#define USB_HUB_PORT_CONNECTION 0
/** Port enabled/disabled feature */
#define USB_HUB_PORT_ENABLE 1
/** Port reset feature */
#define USB_HUB_PORT_RESET 4
/** Port power feature */
#define USB_HUB_PORT_POWER 8
/** Low-speed device attached */
#define USB_HUB_PORT_LOW_SPEED 9
/** High-speed device attached */
#define USB_HUB_PORT_HIGH_SPEED 10
/** Connect status changed */
#define USB_HUB_C_PORT_CONNECTION 16
/** Port enable/disable changed */
#define USB_HUB_C_PORT_ENABLE 17
/** Suspend changed */
#define USB_HUB_C_PORT_SUSPEND 18
/** Over-current indicator changed */
#define USB_HUB_C_PORT_OVER_CURRENT 19
/** Reset changed */
#define USB_HUB_C_PORT_RESET 20
/** Link state changed */
#define USB_HUB_C_PORT_LINK_STATE 25
/** Configuration error */
#define USB_HUB_C_PORT_CONFIG_ERROR 26
/** Calculate feature from change bit number */
#define USB_HUB_C_FEATURE( bit ) ( 16 + (bit) )
/** USB features */
#define USB_HUB_FEATURES \
( ( 1 << USB_HUB_C_PORT_CONNECTION ) | \
( 1 << USB_HUB_C_PORT_ENABLE ) | \
( 1 << USB_HUB_C_PORT_SUSPEND ) | \
( 1 << USB_HUB_C_PORT_OVER_CURRENT ) | \
( 1 << USB_HUB_C_PORT_RESET ) )
/** USB features for enhanced hubs */
#define USB_HUB_FEATURES_ENHANCED \
( ( 1 << USB_HUB_C_PORT_CONNECTION ) | \
( 1 << USB_HUB_C_PORT_OVER_CURRENT ) | \
( 1 << USB_HUB_C_PORT_RESET ) | \
( 1 << USB_HUB_C_PORT_LINK_STATE ) | \
( 1 << USB_HUB_C_PORT_CONFIG_ERROR ) )
/** Set hub depth */
#define USB_HUB_SET_HUB_DEPTH \
( USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE | \
USB_REQUEST_TYPE ( 12 ) )
/** Clear transaction translator buffer */
#define USB_HUB_CLEAR_TT_BUFFER \
( USB_DIR_OUT | USB_TYPE_CLASS | USB_HUB_RECIP_PORT | \
USB_REQUEST_TYPE ( 8 ) )
/**
* Get hub descriptor
*
* @v usb USB device
* @v enhanced Hub is an enhanced hub
* @v data Hub descriptor to fill in
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_get_descriptor ( struct usb_device *usb, int enhanced,
union usb_hub_descriptor *data ) {
unsigned int desc;
size_t len;
/* Determine descriptor type and length */
desc = ( enhanced ? USB_HUB_DESCRIPTOR_ENHANCED : USB_HUB_DESCRIPTOR );
len = ( enhanced ? sizeof ( data->enhanced ) : sizeof ( data->basic ) );
return usb_get_descriptor ( usb, USB_TYPE_CLASS, desc, 0, 0,
&data->header, len );
}
/**
* Get port status
*
* @v usb USB device
* @v port Port address
* @v status Port status descriptor to fill in
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_get_port_status ( struct usb_device *usb, unsigned int port,
struct usb_hub_port_status *status ) {
return usb_get_status ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
port, status, sizeof ( *status ) );
}
/**
* Clear port feature
*
* @v usb USB device
* @v port Port address
* @v feature Feature to clear
* @v index Index (when clearing a port indicator)
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_clear_port_feature ( struct usb_device *usb, unsigned int port,
unsigned int feature, unsigned int index ) {
return usb_clear_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
feature, ( ( index << 8 ) | port ) );
}
/**
* Set port feature
*
* @v usb USB device
* @v port Port address
* @v feature Feature to clear
* @v index Index (when clearing a port indicator)
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_set_port_feature ( struct usb_device *usb, unsigned int port,
unsigned int feature, unsigned int index ) {
return usb_set_feature ( usb, ( USB_TYPE_CLASS | USB_HUB_RECIP_PORT ),
feature, ( ( index << 8 ) | port ) );
}
/**
* Set hub depth
*
* @v usb USB device
* @v depth Hub depth
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_set_hub_depth ( struct usb_device *usb, unsigned int depth ) {
return usb_control ( usb, USB_HUB_SET_HUB_DEPTH, depth, 0, NULL, 0 );
}
/**
* Clear transaction translator buffer
*
* @v usb USB device
* @v device Device address
* @v endpoint Endpoint address
* @v attributes Endpoint attributes
* @v tt_port Transaction translator port (or 1 for single-TT hubs)
* @ret rc Return status code
*/
static inline __attribute__ (( always_inline )) int
usb_hub_clear_tt_buffer ( struct usb_device *usb, unsigned int device,
unsigned int endpoint, unsigned int attributes,
unsigned int tt_port ) {
unsigned int value;
/* Calculate value */
value = ( ( ( endpoint & USB_ENDPOINT_MAX ) << 0 ) | ( device << 4 ) |
( ( attributes & USB_ENDPOINT_ATTR_TYPE_MASK ) << 11 ) |
( ( endpoint & USB_ENDPOINT_IN ) << 8 ) );
return usb_control ( usb, USB_HUB_CLEAR_TT_BUFFER, value,
tt_port, NULL, 0 );
}
/** Transaction translator port value for single-TT hubs */
#define USB_HUB_TT_SINGLE 1
/** A USB hub device */
struct usb_hub_device {
/** Name */
const char *name;
/** USB device */
struct usb_device *usb;
/** USB hub */
struct usb_hub *hub;
/** Features */
unsigned int features;
/** Flags */
unsigned int flags;
/** Interrupt endpoint */
struct usb_endpoint intr;
/** Interrupt endpoint refill process */
struct process refill;
};
/** Hub requires additional settling delay */
#define USB_HUB_SLOW_START 0x0001
/** Additional setting delay for out-of-spec hubs */
#define USB_HUB_SLOW_START_DELAY_MS 500
/** Interrupt ring fill level
*
* This is a policy decision.
*/
#define USB_HUB_INTR_FILL 4
/** Maximum time to wait for port to become enabled
*
* This is a policy decision.
*/
#define USB_HUB_ENABLE_MAX_WAIT_MS 100
#endif /* _USBHUB_H */