X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fusb-hub.c;h=b2d9ff25e1084bb50860ef56a2e697afe1706756;hb=refs%2Fheads%2Fcoreboot;hp=ce9326b2a8e7ef74ef4baf742df86c185fafdd2b;hpb=54671c1e9120287f7aaa2252892c9be4c2de5a76;p=seabios.git diff --git a/src/usb-hub.c b/src/usb-hub.c index ce9326b..b2d9ff2 100644 --- a/src/usb-hub.c +++ b/src/usb-hub.c @@ -10,7 +10,7 @@ #include "usb.h" // struct usb_s static int -get_hub_desc(struct usb_hub_descriptor *desc, u32 endp) +get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE; @@ -18,121 +18,168 @@ get_hub_desc(struct usb_hub_descriptor *desc, u32 endp) req.wValue = USB_DT_HUB<<8; req.wIndex = 0; req.wLength = sizeof(*desc); - return send_default_control(endp, &req, desc); + return send_default_control(pipe, &req, desc); } static int -set_port_feature(int port, int feature, u32 endp) +set_port_feature(struct usbhub_s *hub, int port, int feature) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; req.bRequest = USB_REQ_SET_FEATURE; req.wValue = feature; - req.wIndex = port; + req.wIndex = port + 1; req.wLength = 0; - return send_default_control(endp, &req, NULL); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; } static int -clear_port_feature(int port, int feature, u32 endp) +clear_port_feature(struct usbhub_s *hub, int port, int feature) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; req.bRequest = USB_REQ_CLEAR_FEATURE; req.wValue = feature; - req.wIndex = port; + req.wIndex = port + 1; req.wLength = 0; - return send_default_control(endp, &req, NULL); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, NULL); + mutex_unlock(&hub->lock); + return ret; } static int -get_port_status(int port, struct usb_port_status *sts, u32 endp) +get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts) { struct usb_ctrlrequest req; req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER; req.bRequest = USB_REQ_GET_STATUS; req.wValue = 0; - req.wIndex = port; + req.wIndex = port + 1; req.wLength = sizeof(*sts); - return send_default_control(endp, &req, sts); + mutex_lock(&hub->lock); + int ret = send_default_control(hub->pipe, &req, sts); + mutex_unlock(&hub->lock); + return ret; } -// Configure a usb hub and then find devices connected to it. -int -usb_hub_init(u32 endp) +// Check if device attached to port +static int +usb_hub_detect(struct usbhub_s *hub, u32 port) { - if (!CONFIG_USB_HUB) - return 0; - - struct usb_hub_descriptor desc; - int ret = get_hub_desc(&desc, endp); + // Turn on power to port. + int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER); if (ret) - return ret; + goto fail; + + // Wait for port power to stabilize. + msleep(hub->powerwait); - // Turn on power to all ports. - int i; - for (i=1; i<=desc.bNbrPorts; i++) { - ret = set_port_feature(i, USB_PORT_FEAT_POWER, endp); + // Check periodically for a device connect. + struct usb_port_status sts; + u64 end = calc_future_tsc(USB_TIME_SIGATT); + for (;;) { + ret = get_port_status(hub, port, &sts); if (ret) goto fail; + if (sts.wPortStatus & USB_PORT_STAT_CONNECTION) + // Device connected. + break; + if (check_tsc(end)) + // No device found. + return -1; + msleep(5); } - // Wait for port detection. - msleep(desc.bPwrOn2PwrGood * 2 + USB_TIME_SIGATT); - // XXX - should poll for ports becoming active sooner and then - // possibly wait USB_TIME_ATTDB. - - // Detect down stream devices. - struct usb_s *cntl = endp2cntl(endp); - int totalcount = 0; - for (i=1; i<=desc.bNbrPorts; i++) { - struct usb_port_status sts; - ret = get_port_status(i, &sts, endp); - if (ret) - goto fail; - if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) - // XXX - power down port? - continue; + // XXX - wait USB_TIME_ATTDB time? - // Reset port. - ret = set_port_feature(i, USB_PORT_FEAT_RESET, endp); + return 0; + +fail: + dprintf(1, "Failure on hub port %d detect\n", port); + return -1; +} + +// Disable port +static void +usb_hub_disconnect(struct usbhub_s *hub, u32 port) +{ + int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE); + if (ret) + dprintf(1, "Failure on hub port %d disconnect\n", port); +} + +// Reset device on port +static int +usb_hub_reset(struct usbhub_s *hub, u32 port) +{ + int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET); + if (ret) + goto fail; + + // Wait for reset to complete. + struct usb_port_status sts; + u64 end = calc_future_tsc(USB_TIME_DRST * 2); + for (;;) { + ret = get_port_status(hub, port, &sts); if (ret) goto fail; - - // Wait for reset to complete. - u64 end = calc_future_tsc(USB_TIME_DRST * 2); - for (;;) { - ret = get_port_status(i, &sts, endp); - if (ret) - goto fail; - if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) - break; - if (check_time(end)) { - // Timeout. - warn_timeout(); - goto fail; - } - yield(); - } - if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) - // Device no longer present. XXX - power down port? - continue; - - // XXX - should try to parallelize configuration. - int count = configure_usb_device( - cntl, !!(sts.wPortStatus & USB_PORT_STAT_LOW_SPEED)); - if (! count) { - // Shutdown port - ret = clear_port_feature(i, USB_PORT_FEAT_ENABLE, endp); - if (ret) - goto fail; + if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) + break; + if (check_tsc(end)) { + warn_timeout(); + goto fail; } - totalcount += count; + msleep(5); } - return totalcount; + // Reset complete. + if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) + // Device no longer present + return -1; + + return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK) + >> USB_PORT_STAT_SPEED_SHIFT); fail: - dprintf(1, "Failure on hub setup\n"); - return 0; + dprintf(1, "Failure on hub port %d reset\n", port); + usb_hub_disconnect(hub, port); + return -1; +} + +static struct usbhub_op_s HubOp = { + .detect = usb_hub_detect, + .reset = usb_hub_reset, + .disconnect = usb_hub_disconnect, +}; + +// Configure a usb hub and then find devices connected to it. +int +usb_hub_init(struct usb_pipe *pipe) +{ + ASSERT32FLAT(); + if (!CONFIG_USB_HUB) + return -1; + + struct usb_hub_descriptor desc; + int ret = get_hub_desc(pipe, &desc); + if (ret) + return ret; + + struct usbhub_s hub; + memset(&hub, 0, sizeof(hub)); + hub.pipe = pipe; + hub.cntl = pipe->cntl; + hub.powerwait = desc.bPwrOn2PwrGood * 2; + hub.portcount = desc.bNbrPorts; + hub.op = &HubOp; + usb_enumerate(&hub); + + dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount); + if (hub.devcount) + return 0; + return -1; }