Warning, cross-references for /kernel/drivers/usb/hub.c need to be fixed.
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019 #include <smp/apic.h>
0020 #include <drivers/usb/usb.h>
0021 #include <drivers/usb/uhci.h>
0022 #include <util/printf.h>
0023 #include <kernel.h>
0024 #include <sched/sched.h>
0025
0026 #define USB_HUB_CLASS 0x9
0027
0028 #define DEBUG_USB_HUB
0029
0030 #ifdef DEBUG_USB_HUB
0031 #define DLOG(fmt,...) DLOG_PREFIX("usb-hub",fmt,##__VA_ARGS__)
0032 #else
0033 #define DLOG(fmt,...) ;
0034 #endif
0035
0036 bool uhci_enumerate (void);
0037
0038 #define HUB_PORT_STAT_POWER 0x0100
0039 #define HUB_PORT_RESET 4
0040 #define HUB_PORT_POWER 8
0041 #define HUB_PORT_C_RESET 20
0042
0043 struct usb_hub_desc
0044 {
0045 uint8 bDescLength;
0046 uint8 bDescriptorType;
0047 uint8 bNbrPorts;
0048 union {
0049 uint16 wHubCharacteristics;
0050 struct {
0051 uint16 lpsMode:2;
0052 uint16 compound:1;
0053 uint16 opMode:2;
0054 uint16 _reserved:11;
0055 };
0056 };
0057 uint8 bPwrOn2PwrGood;
0058 uint8 bHubContrCurrent;
0059
0060 } PACKED;
0061 typedef struct usb_hub_desc USB_HUB_DESC;
0062
0063 static uint16
0064 hub_port_status (uint address, uint port)
0065 {
0066 sint status;
0067 USB_DEV_REQ req;
0068 uint8 data[4];
0069
0070 req.bmRequestType = 0xA3;
0071 req.bRequest = USB_GET_STATUS;
0072 req.wValue = 0;
0073 req.wIndex = port;
0074 req.wLength = 4;
0075
0076 status = uhci_control_transfer (address, &req, sizeof (req), data, 4, 64);
0077 DLOG ("GET_PORT_STATUS: status=%d port status: %.04X",
0078 status, *((uint16 *)data));
0079
0080 return *((uint16 *)data);
0081 }
0082
0083 static bool
0084 hub_set_port_feature (uint address, uint port, uint feature)
0085 {
0086 sint status;
0087 USB_DEV_REQ req;
0088
0089 req.bmRequestType = 0x23;
0090 req.bRequest = USB_SET_FEATURE;
0091 req.wValue = feature;
0092 req.wIndex = port;
0093 req.wLength = 0;
0094
0095 status = uhci_control_transfer (address, &req, sizeof (req), NULL, 0, 64);
0096 DLOG ("SET_PORT_FEATURE: status=%d", status);
0097
0098 return status == 0;
0099 }
0100
0101 static bool
0102 hub_clr_port_feature (uint address, uint port, uint feature)
0103 {
0104 sint status;
0105 USB_DEV_REQ req;
0106
0107 req.bmRequestType = 0x23;
0108 req.bRequest = USB_CLEAR_FEATURE;
0109 req.wValue = feature;
0110 req.wIndex = port;
0111 req.wLength = 0;
0112
0113 status = uhci_control_transfer (address, &req, sizeof (req), NULL, 0, 64);
0114 DLOG ("CLEAR_PORT_FEATURE: status=%d", status);
0115
0116 return status == 0;
0117 }
0118
0119 static bool
0120 probe_hub (USB_DEVICE_INFO *info, USB_CFG_DESC *cfgd, USB_IF_DESC *ifd)
0121 {
0122 sint status, i, address = info->address;
0123 USB_DEV_REQ req;
0124 USB_HUB_DESC hubd;
0125
0126 if (ifd->bInterfaceClass != USB_HUB_CLASS)
0127 return FALSE;
0128
0129
0130 usb_set_configuration (info, cfgd->bConfigurationValue);
0131
0132 memset (&hubd, 0, sizeof (hubd));
0133
0134 DLOG ("Probing hub @ %d", address);
0135 delay (100);
0136 req.bmRequestType = 0xA0;
0137 req.bRequest = USB_GET_DESCRIPTOR;
0138 req.wValue = 0x29 << 8;
0139 req.wIndex = 0;
0140 req.wLength = sizeof (USB_HUB_DESC);
0141
0142 status = uhci_control_transfer (address, &req, sizeof (req), &hubd, sizeof (hubd), 64);
0143 DLOG ("GET_HUB_DESCRIPTOR: status=%d len=%d nbrports=%d delay=%d",
0144 status, hubd.bDescLength, hubd.bNbrPorts, hubd.bPwrOn2PwrGood);
0145 if (status != 0) return FALSE;
0146 for (i=1; i<=hubd.bNbrPorts; i++) {
0147
0148 while (!((status=hub_port_status (address, i)) & HUB_PORT_STAT_POWER)) {
0149 hub_set_port_feature (address, i, HUB_PORT_POWER);
0150 delay (2*hubd.bPwrOn2PwrGood);
0151 }
0152 if (status & 1) {
0153
0154 hub_set_port_feature (address, i, HUB_PORT_RESET);
0155 delay (10);
0156 hub_port_status (address, i);
0157 hub_clr_port_feature (address, i, HUB_PORT_C_RESET);
0158 hub_port_status (address, i);
0159 delay (2*hubd.bPwrOn2PwrGood);
0160 uhci_enumerate ();
0161 }
0162 }
0163 return TRUE;
0164 }
0165
0166 static USB_DRIVER hub_driver = {
0167 .probe = probe_hub
0168 };
0169
0170 extern bool
0171 usb_hub_driver_init (void)
0172 {
0173 return usb_register_driver (&hub_driver);
0174 }
0175
0176 #include "module/header.h"
0177
0178 static const struct module_ops mod_ops = {
0179 .init = usb_hub_driver_init
0180 };
0181
0182 DEF_MODULE (usb___hub, "USB hub driver", &mod_ops, {"usb"});
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193