|
|
1.1 ! root 1: // Code for handling standard USB hubs. ! 2: // ! 3: // Copyright (C) 2010 Kevin O'Connor <[email protected]> ! 4: // ! 5: // This file may be distributed under the terms of the GNU LGPLv3 license. ! 6: ! 7: #include "util.h" // dprintf ! 8: #include "config.h" // CONFIG_USB_HUB ! 9: #include "usb-hub.h" // struct usb_hub_descriptor ! 10: #include "usb.h" // struct usb_s ! 11: ! 12: static int ! 13: get_hub_desc(struct usb_pipe *pipe, struct usb_hub_descriptor *desc) ! 14: { ! 15: struct usb_ctrlrequest req; ! 16: req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE; ! 17: req.bRequest = USB_REQ_GET_DESCRIPTOR; ! 18: req.wValue = USB_DT_HUB<<8; ! 19: req.wIndex = 0; ! 20: req.wLength = sizeof(*desc); ! 21: return send_default_control(pipe, &req, desc); ! 22: } ! 23: ! 24: static int ! 25: set_port_feature(struct usbhub_s *hub, int port, int feature) ! 26: { ! 27: struct usb_ctrlrequest req; ! 28: req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; ! 29: req.bRequest = USB_REQ_SET_FEATURE; ! 30: req.wValue = feature; ! 31: req.wIndex = port + 1; ! 32: req.wLength = 0; ! 33: mutex_lock(&hub->lock); ! 34: int ret = send_default_control(hub->pipe, &req, NULL); ! 35: mutex_unlock(&hub->lock); ! 36: return ret; ! 37: } ! 38: ! 39: static int ! 40: clear_port_feature(struct usbhub_s *hub, int port, int feature) ! 41: { ! 42: struct usb_ctrlrequest req; ! 43: req.bRequestType = USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_OTHER; ! 44: req.bRequest = USB_REQ_CLEAR_FEATURE; ! 45: req.wValue = feature; ! 46: req.wIndex = port + 1; ! 47: req.wLength = 0; ! 48: mutex_lock(&hub->lock); ! 49: int ret = send_default_control(hub->pipe, &req, NULL); ! 50: mutex_unlock(&hub->lock); ! 51: return ret; ! 52: } ! 53: ! 54: static int ! 55: get_port_status(struct usbhub_s *hub, int port, struct usb_port_status *sts) ! 56: { ! 57: struct usb_ctrlrequest req; ! 58: req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_OTHER; ! 59: req.bRequest = USB_REQ_GET_STATUS; ! 60: req.wValue = 0; ! 61: req.wIndex = port + 1; ! 62: req.wLength = sizeof(*sts); ! 63: mutex_lock(&hub->lock); ! 64: int ret = send_default_control(hub->pipe, &req, sts); ! 65: mutex_unlock(&hub->lock); ! 66: return ret; ! 67: } ! 68: ! 69: // Check if device attached to port ! 70: static int ! 71: usb_hub_detect(struct usbhub_s *hub, u32 port) ! 72: { ! 73: // Turn on power to port. ! 74: int ret = set_port_feature(hub, port, USB_PORT_FEAT_POWER); ! 75: if (ret) ! 76: goto fail; ! 77: ! 78: // Wait for port power to stabilize. ! 79: msleep(hub->powerwait); ! 80: ! 81: // Check periodically for a device connect. ! 82: struct usb_port_status sts; ! 83: u64 end = calc_future_tsc(USB_TIME_SIGATT); ! 84: for (;;) { ! 85: ret = get_port_status(hub, port, &sts); ! 86: if (ret) ! 87: goto fail; ! 88: if (sts.wPortStatus & USB_PORT_STAT_CONNECTION) ! 89: // Device connected. ! 90: break; ! 91: if (check_tsc(end)) ! 92: // No device found. ! 93: return -1; ! 94: msleep(5); ! 95: } ! 96: ! 97: // XXX - wait USB_TIME_ATTDB time? ! 98: ! 99: return 0; ! 100: ! 101: fail: ! 102: dprintf(1, "Failure on hub port %d detect\n", port); ! 103: return -1; ! 104: } ! 105: ! 106: // Disable port ! 107: static void ! 108: usb_hub_disconnect(struct usbhub_s *hub, u32 port) ! 109: { ! 110: int ret = clear_port_feature(hub, port, USB_PORT_FEAT_ENABLE); ! 111: if (ret) ! 112: dprintf(1, "Failure on hub port %d disconnect\n", port); ! 113: } ! 114: ! 115: // Reset device on port ! 116: static int ! 117: usb_hub_reset(struct usbhub_s *hub, u32 port) ! 118: { ! 119: int ret = set_port_feature(hub, port, USB_PORT_FEAT_RESET); ! 120: if (ret) ! 121: goto fail; ! 122: ! 123: // Wait for reset to complete. ! 124: struct usb_port_status sts; ! 125: u64 end = calc_future_tsc(USB_TIME_DRST * 2); ! 126: for (;;) { ! 127: ret = get_port_status(hub, port, &sts); ! 128: if (ret) ! 129: goto fail; ! 130: if (!(sts.wPortStatus & USB_PORT_STAT_RESET)) ! 131: break; ! 132: if (check_tsc(end)) { ! 133: warn_timeout(); ! 134: goto fail; ! 135: } ! 136: msleep(5); ! 137: } ! 138: ! 139: // Reset complete. ! 140: if (!(sts.wPortStatus & USB_PORT_STAT_CONNECTION)) ! 141: // Device no longer present ! 142: return -1; ! 143: ! 144: return ((sts.wPortStatus & USB_PORT_STAT_SPEED_MASK) ! 145: >> USB_PORT_STAT_SPEED_SHIFT); ! 146: ! 147: fail: ! 148: dprintf(1, "Failure on hub port %d reset\n", port); ! 149: usb_hub_disconnect(hub, port); ! 150: return -1; ! 151: } ! 152: ! 153: static struct usbhub_op_s HubOp = { ! 154: .detect = usb_hub_detect, ! 155: .reset = usb_hub_reset, ! 156: .disconnect = usb_hub_disconnect, ! 157: }; ! 158: ! 159: // Configure a usb hub and then find devices connected to it. ! 160: int ! 161: usb_hub_init(struct usb_pipe *pipe) ! 162: { ! 163: ASSERT32FLAT(); ! 164: if (!CONFIG_USB_HUB) ! 165: return -1; ! 166: ! 167: struct usb_hub_descriptor desc; ! 168: int ret = get_hub_desc(pipe, &desc); ! 169: if (ret) ! 170: return ret; ! 171: ! 172: struct usbhub_s hub; ! 173: memset(&hub, 0, sizeof(hub)); ! 174: hub.pipe = pipe; ! 175: hub.cntl = pipe->cntl; ! 176: hub.powerwait = desc.bPwrOn2PwrGood * 2; ! 177: hub.portcount = desc.bNbrPorts; ! 178: hub.op = &HubOp; ! 179: usb_enumerate(&hub); ! 180: ! 181: dprintf(1, "Initialized USB HUB (%d ports used)\n", hub.devcount); ! 182: if (hub.devcount) ! 183: return 0; ! 184: return -1; ! 185: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.