#ifndef _USBHUB_H #define _USBHUB_H /** @file * * USB hubs * */ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL ); #include #include #include /** 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 */