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