|
|
1.1 ! root 1: // Main code for handling USB controllers and devices. ! 2: // ! 3: // Copyright (C) 2009 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 "pci.h" // foreachpci ! 9: #include "config.h" // CONFIG_* ! 10: #include "pci_regs.h" // PCI_CLASS_REVISION ! 11: #include "pci_ids.h" // PCI_CLASS_SERIAL_USB_UHCI ! 12: #include "usb-uhci.h" // uhci_init ! 13: #include "usb-ohci.h" // ohci_init ! 14: #include "usb-hid.h" // usb_keyboard_setup ! 15: #include "usb.h" // struct usb_s ! 16: #include "biosvar.h" // GET_GLOBAL ! 17: ! 18: struct usb_s USBControllers[16] VAR16VISIBLE; ! 19: ! 20: static int ! 21: send_control(u32 endp, int dir, const void *cmd, int cmdsize ! 22: , void *data, int datasize) ! 23: { ! 24: struct usb_s *cntl = endp2cntl(endp); ! 25: switch (cntl->type) { ! 26: default: ! 27: case USB_TYPE_UHCI: ! 28: return uhci_control(endp, dir, cmd, cmdsize, data, datasize); ! 29: case USB_TYPE_OHCI: ! 30: return ohci_control(endp, dir, cmd, cmdsize, data, datasize); ! 31: } ! 32: } ! 33: ! 34: struct usb_pipe * ! 35: alloc_intr_pipe(u32 endp, int period) ! 36: { ! 37: struct usb_s *cntl = endp2cntl(endp); ! 38: switch (cntl->type) { ! 39: default: ! 40: case USB_TYPE_UHCI: ! 41: return uhci_alloc_intr_pipe(endp, period); ! 42: case USB_TYPE_OHCI: ! 43: return ohci_alloc_intr_pipe(endp, period); ! 44: } ! 45: } ! 46: ! 47: int ! 48: usb_poll_intr(struct usb_pipe *pipe, void *data) ! 49: { ! 50: u32 endp = GET_FLATPTR(pipe->endp); ! 51: struct usb_s *cntl = endp2cntl(endp); ! 52: switch (GET_GLOBAL(cntl->type)) { ! 53: default: ! 54: case USB_TYPE_UHCI: ! 55: return uhci_poll_intr(pipe, data); ! 56: case USB_TYPE_OHCI: ! 57: return ohci_poll_intr(pipe, data); ! 58: } ! 59: } ! 60: ! 61: int ! 62: send_default_control(u32 endp, const struct usb_ctrlrequest *req, void *data) ! 63: { ! 64: return send_control(endp, req->bRequestType & USB_DIR_IN ! 65: , req, sizeof(*req), data, req->wLength); ! 66: } ! 67: ! 68: // Get the first 8 bytes of the device descriptor. ! 69: static int ! 70: get_device_info8(struct usb_device_descriptor *dinfo, u32 endp) ! 71: { ! 72: struct usb_ctrlrequest req; ! 73: req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ! 74: req.bRequest = USB_REQ_GET_DESCRIPTOR; ! 75: req.wValue = USB_DT_DEVICE<<8; ! 76: req.wIndex = 0; ! 77: req.wLength = 8; ! 78: return send_default_control(endp, &req, dinfo); ! 79: } ! 80: ! 81: static struct usb_config_descriptor * ! 82: get_device_config(u32 endp) ! 83: { ! 84: struct usb_config_descriptor cfg; ! 85: ! 86: struct usb_ctrlrequest req; ! 87: req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ! 88: req.bRequest = USB_REQ_GET_DESCRIPTOR; ! 89: req.wValue = USB_DT_CONFIG<<8; ! 90: req.wIndex = 0; ! 91: req.wLength = sizeof(cfg); ! 92: int ret = send_default_control(endp, &req, &cfg); ! 93: if (ret) ! 94: return NULL; ! 95: ! 96: void *config = malloc_tmphigh(cfg.wTotalLength); ! 97: if (!config) ! 98: return NULL; ! 99: req.wLength = cfg.wTotalLength; ! 100: ret = send_default_control(endp, &req, config); ! 101: if (ret) ! 102: return NULL; ! 103: //hexdump(config, cfg.wTotalLength); ! 104: return config; ! 105: } ! 106: ! 107: static u32 ! 108: set_address(u32 endp) ! 109: { ! 110: dprintf(3, "set_address %x\n", endp); ! 111: struct usb_s *cntl = endp2cntl(endp); ! 112: if (cntl->maxaddr >= USB_MAXADDR) ! 113: return 0; ! 114: ! 115: struct usb_ctrlrequest req; ! 116: req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ! 117: req.bRequest = USB_REQ_SET_ADDRESS; ! 118: req.wValue = cntl->maxaddr + 1; ! 119: req.wIndex = 0; ! 120: req.wLength = 0; ! 121: int ret = send_default_control(endp, &req, NULL); ! 122: if (ret) ! 123: return 0; ! 124: msleep(2); ! 125: ! 126: cntl->maxaddr++; ! 127: return mkendp(cntl, cntl->maxaddr, 0, endp2speed(endp), endp2maxsize(endp)); ! 128: } ! 129: ! 130: static int ! 131: set_configuration(u32 endp, u16 val) ! 132: { ! 133: struct usb_ctrlrequest req; ! 134: req.bRequestType = USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE; ! 135: req.bRequest = USB_REQ_SET_CONFIGURATION; ! 136: req.wValue = val; ! 137: req.wIndex = 0; ! 138: req.wLength = 0; ! 139: return send_default_control(endp, &req, NULL); ! 140: } ! 141: ! 142: // Called for every found device - see if a driver is available for ! 143: // this device and do setup if so. ! 144: int ! 145: configure_usb_device(struct usb_s *cntl, int lowspeed) ! 146: { ! 147: dprintf(1, "config_usb: %p %d\n", cntl, lowspeed); ! 148: ! 149: // Get device info ! 150: u32 endp = mkendp(cntl, 0, 0, lowspeed, 8); ! 151: struct usb_device_descriptor dinfo; ! 152: int ret = get_device_info8(&dinfo, endp); ! 153: if (ret) ! 154: return 0; ! 155: dprintf(3, "device rev=%04x cls=%02x sub=%02x proto=%02x size=%02x\n" ! 156: , dinfo.bcdUSB, dinfo.bDeviceClass, dinfo.bDeviceSubClass ! 157: , dinfo.bDeviceProtocol, dinfo.bMaxPacketSize0); ! 158: if (dinfo.bMaxPacketSize0 < 8 || dinfo.bMaxPacketSize0 > 64) ! 159: return 0; ! 160: endp = mkendp(cntl, 0, 0, lowspeed, dinfo.bMaxPacketSize0); ! 161: ! 162: // Get configuration ! 163: struct usb_config_descriptor *config = get_device_config(endp); ! 164: if (!config) ! 165: return 0; ! 166: ! 167: // Determine if a driver exists for this device - only look at the ! 168: // first interface of the first configuration. ! 169: struct usb_interface_descriptor *iface = (void*)(&config[1]); ! 170: if (iface->bInterfaceClass != USB_CLASS_HID ! 171: || iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT ! 172: || iface->bInterfaceProtocol != USB_INTERFACE_PROTOCOL_KEYBOARD) ! 173: // Not a "boot" keyboard ! 174: goto fail; ! 175: ! 176: // Set the address and configure device. ! 177: endp = set_address(endp); ! 178: if (!endp) ! 179: goto fail; ! 180: ret = set_configuration(endp, config->bConfigurationValue); ! 181: if (ret) ! 182: goto fail; ! 183: ! 184: // Configure driver. ! 185: ret = usb_keyboard_init(endp, iface, ((void*)config + config->wTotalLength ! 186: - (void*)iface)); ! 187: if (ret) ! 188: goto fail; ! 189: ! 190: free(config); ! 191: return 1; ! 192: fail: ! 193: free(config); ! 194: return 0; ! 195: } ! 196: ! 197: void ! 198: usb_setup() ! 199: { ! 200: if (! CONFIG_USB) ! 201: return; ! 202: ! 203: dprintf(3, "init usb\n"); ! 204: ! 205: usb_keyboard_setup(); ! 206: ! 207: // Look for USB controllers ! 208: int count = 0; ! 209: int bdf, max; ! 210: foreachpci(bdf, max) { ! 211: u32 code = pci_config_readl(bdf, PCI_CLASS_REVISION) >> 8; ! 212: ! 213: if (code >> 8 != PCI_CLASS_SERIAL_USB) ! 214: continue; ! 215: ! 216: struct usb_s *cntl = &USBControllers[count]; ! 217: cntl->bdf = bdf; ! 218: ! 219: if (code == PCI_CLASS_SERIAL_USB_UHCI) ! 220: run_thread(uhci_init, cntl); ! 221: else if (code == PCI_CLASS_SERIAL_USB_OHCI) ! 222: run_thread(ohci_init, cntl); ! 223: else ! 224: continue; ! 225: ! 226: count++; ! 227: if (count >= ARRAY_SIZE(USBControllers)) ! 228: break; ! 229: } ! 230: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.