]> git.proxmox.com Git - grub2.git/blame - grub-core/bus/usb/usb.c
Implement boot time analysis framework.
[grub2.git] / grub-core / bus / usb / usb.c
CommitLineData
d64399b5 1/* usb.c - Generic USB interfaces. */
2/*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <grub/dl.h>
21#include <grub/mm.h>
22#include <grub/usb.h>
23#include <grub/misc.h>
440ab685 24#include <grub/list.h>
52d8255d 25#include <grub/term.h>
d64399b5 26
e745cf0c
VS
27GRUB_MOD_LICENSE ("GPLv3+");
28
d64399b5 29static grub_usb_controller_dev_t grub_usb_list;
7d4e39d6 30static struct grub_usb_attach_desc *attach_hooks;
d64399b5 31
5fdbaed1
CW
32/* Iterate over all controllers found by the driver. */
33static int
34grub_usb_controller_dev_register_iter (grub_usb_controller_t dev, void *data)
d64399b5 35{
5fdbaed1 36 grub_usb_controller_dev_t usb = data;
d64399b5 37
5fdbaed1 38 dev->dev = usb;
d64399b5 39
5fdbaed1
CW
40 /* Enable the ports of the USB Root Hub. */
41 grub_usb_root_hub (dev);
d64399b5 42
5fdbaed1
CW
43 return 0;
44}
d64399b5 45
5fdbaed1
CW
46void
47grub_usb_controller_dev_register (grub_usb_controller_dev_t usb)
48{
d64399b5 49 usb->next = grub_usb_list;
50 grub_usb_list = usb;
51
52 if (usb->iterate)
5fdbaed1 53 usb->iterate (grub_usb_controller_dev_register_iter, usb);
d64399b5 54}
55
56void
57grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb)
58{
59 grub_usb_controller_dev_t *p, q;
60
61 for (p = &grub_usb_list, q = *p; q; p = &(q->next), q = q->next)
62 if (q == usb)
63 {
64 *p = q->next;
65 break;
66 }
67}
68
69#if 0
5fdbaed1
CW
70/* Context for grub_usb_controller_iterate. */
71struct grub_usb_controller_iterate_ctx
d64399b5 72{
5fdbaed1
CW
73 grub_usb_controller_iterate_hook_t hook;
74 void *hook_data;
d64399b5 75 grub_usb_controller_dev_t p;
5fdbaed1 76};
d64399b5 77
5fdbaed1
CW
78/* Helper for grub_usb_controller_iterate. */
79static int
80grub_usb_controller_iterate_iter (grub_usb_controller_t dev, void *data)
81{
82 struct grub_usb_controller_iterate_ctx *ctx = data;
d64399b5 83
5fdbaed1
CW
84 dev->dev = ctx->p;
85 if (ctx->hook (dev, ctx->hook_data))
86 return 1;
87 return 0;
88}
89
90int
91grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook,
92 void *hook_data)
93{
94 struct grub_usb_controller_iterate_ctx ctx = {
95 .hook = hook,
96 .hook_data = hook_data
97 };
d64399b5 98
99 /* Iterate over all controller drivers. */
5fdbaed1 100 for (ctx.p = grub_usb_list; ctx.p; ctx.p = ctx.p->next)
d64399b5 101 {
102 /* Iterate over the busses of the controllers. XXX: Actually, a
103 hub driver should do this. */
5fdbaed1 104 if (ctx.p->iterate (grub_usb_controller_iterate_iter, &ctx))
d64399b5 105 return 1;
106 }
107
108 return 0;
109}
110#endif
111
112\f
113grub_usb_err_t
114grub_usb_clear_halt (grub_usb_device_t dev, int endpoint)
115{
116 dev->toggle[endpoint] = 0;
117 return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
118 | GRUB_USB_REQTYPE_STANDARD
119 | GRUB_USB_REQTYPE_TARGET_ENDP),
120 GRUB_USB_REQ_CLEAR_FEATURE,
121 GRUB_USB_FEATURE_ENDP_HALT,
122 endpoint, 0, 0);
123}
124
125grub_usb_err_t
126grub_usb_set_configuration (grub_usb_device_t dev, int configuration)
127{
5d538b8b 128 grub_memset (dev->toggle, 0, sizeof (dev->toggle));
d64399b5 129
130 return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_OUT
131 | GRUB_USB_REQTYPE_STANDARD
132 | GRUB_USB_REQTYPE_TARGET_DEV),
133 GRUB_USB_REQ_SET_CONFIGURATION, configuration,
134 0, 0, NULL);
135}
136
137grub_usb_err_t
138grub_usb_get_descriptor (grub_usb_device_t dev,
139 grub_uint8_t type, grub_uint8_t index,
140 grub_size_t size, char *data)
141{
142 return grub_usb_control_msg (dev, (GRUB_USB_REQTYPE_IN
143 | GRUB_USB_REQTYPE_STANDARD
144 | GRUB_USB_REQTYPE_TARGET_DEV),
145 GRUB_USB_REQ_GET_DESCRIPTOR,
146 (type << 8) | index,
147 0, size, data);
148}
149
d64399b5 150grub_usb_err_t
151grub_usb_device_initialize (grub_usb_device_t dev)
152{
153 struct grub_usb_desc_device *descdev;
154 struct grub_usb_desc_config config;
155 grub_usb_err_t err;
156 int i;
157
778ff324
AN
158 /* First we have to read first 8 bytes only and determine
159 * max. size of packet */
160 dev->descdev.maxsize0 = 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */
161 err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE,
12cd7239 162 0, 8, (char *) &dev->descdev);
778ff324
AN
163 if (err)
164 return err;
165
166 /* Now we have valid value in dev->descdev.maxsize0,
167 * so we can read whole device descriptor */
d64399b5 168 err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_DEVICE,
169 0, sizeof (struct grub_usb_desc_device),
170 (char *) &dev->descdev);
171 if (err)
172 return err;
173 descdev = &dev->descdev;
174
175 for (i = 0; i < 8; i++)
176 dev->config[i].descconf = NULL;
177
ff44d107
VS
178 if (descdev->configcnt == 0)
179 {
180 err = GRUB_USB_ERR_BADDEVICE;
181 goto fail;
182 }
183
d64399b5 184 for (i = 0; i < descdev->configcnt; i++)
185 {
186 int pos;
187 int currif;
188 char *data;
189
190 /* First just read the first 4 bytes of the configuration
191 descriptor, after that it is known how many bytes really have
192 to be read. */
193 err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i, 4,
194 (char *) &config);
195
196 data = grub_malloc (config.totallen);
197 if (! data)
198 {
199 err = GRUB_USB_ERR_INTERNAL;
200 goto fail;
201 }
202
203 dev->config[i].descconf = (struct grub_usb_desc_config *) data;
204 err = grub_usb_get_descriptor (dev, GRUB_USB_DESCRIPTOR_CONFIG, i,
205 config.totallen, data);
206 if (err)
207 goto fail;
208
209 /* Skip the configuration descriptor. */
443a6c4b 210 pos = dev->config[i].descconf->length;
b39f9d20 211
d64399b5 212 /* Read all interfaces. */
213 for (currif = 0; currif < dev->config[i].descconf->numif; currif++)
214 {
443a6c4b
VS
215 while (pos < config.totallen
216 && ((struct grub_usb_desc *)&data[pos])->type
217 != GRUB_USB_DESCRIPTOR_INTERFACE)
218 pos += ((struct grub_usb_desc *)&data[pos])->length;
d64399b5 219 dev->config[i].interf[currif].descif
220 = (struct grub_usb_desc_if *) &data[pos];
443a6c4b
VS
221 pos += dev->config[i].interf[currif].descif->length;
222
223 while (pos < config.totallen
224 && ((struct grub_usb_desc *)&data[pos])->type
225 != GRUB_USB_DESCRIPTOR_ENDPOINT)
226 pos += ((struct grub_usb_desc *)&data[pos])->length;
d64399b5 227
228 /* Point to the first endpoint. */
229 dev->config[i].interf[currif].descendp
230 = (struct grub_usb_desc_endp *) &data[pos];
231 pos += (sizeof (struct grub_usb_desc_endp)
232 * dev->config[i].interf[currif].descif->endpointcnt);
233 }
234 }
235
1b43dba9 236 return GRUB_USB_ERR_NONE;
237
238 fail:
239
240 for (i = 0; i < 8; i++)
241 grub_free (dev->config[i].descconf);
242
243 return err;
244}
245
246void grub_usb_device_attach (grub_usb_device_t dev)
247{
248 int i;
249
f5db3949
VS
250 /* XXX: Just check configuration 0 for now. */
251 for (i = 0; i < dev->config[0].descconf->numif; i++)
252 {
253 struct grub_usb_desc_if *interf;
254 struct grub_usb_attach_desc *desc;
255
256 interf = dev->config[0].interf[i].descif;
257
258 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
259 i, interf->class, interf->subclass, interf->protocol);
260
261 if (dev->config[0].interf[i].attached)
262 continue;
263
264 for (desc = attach_hooks; desc; desc = desc->next)
e744219b
VS
265 if (interf->class == desc->class)
266 {
267 grub_boot_time ("Probing USB device driver class %x", desc->class);
268 if (desc->hook (dev, 0, i))
269 dev->config[0].interf[i].attached = 1;
270 grub_boot_time ("Probed USB device driver class %x", desc->class);
271 }
a17b90f0
VS
272
273 if (dev->config[0].interf[i].attached)
274 continue;
275
276 switch (interf->class)
277 {
278 case GRUB_USB_CLASS_MASS_STORAGE:
279 grub_dl_load ("usbms");
cfe1288b 280 grub_print_error ();
a17b90f0
VS
281 break;
282 case GRUB_USB_CLASS_HID:
283 grub_dl_load ("usb_keyboard");
cfe1288b 284 grub_print_error ();
a17b90f0 285 break;
34364df6 286 case 0xff:
dd20a786
VS
287 /* FIXME: don't load useless modules. */
288 grub_dl_load ("usbserial_ftdi");
cfe1288b 289 grub_print_error ();
9edd681b 290 grub_dl_load ("usbserial_pl2303");
cfe1288b 291 grub_print_error ();
66a93674
VS
292 grub_dl_load ("usbserial_usbdebug");
293 grub_print_error ();
34364df6 294 break;
a17b90f0 295 }
f5db3949 296 }
d64399b5 297}
440ab685 298
5fdbaed1
CW
299/* Helper for grub_usb_register_attach_hook_class. */
300static int
301grub_usb_register_attach_hook_class_iter (grub_usb_device_t usbdev, void *data)
440ab685 302{
5fdbaed1
CW
303 struct grub_usb_attach_desc *desc = data;
304 struct grub_usb_desc_device *descdev = &usbdev->descdev;
305 int i;
440ab685 306
5fdbaed1
CW
307 if (descdev->class != 0 || descdev->subclass || descdev->protocol != 0
308 || descdev->configcnt == 0)
309 return 0;
440ab685 310
5fdbaed1
CW
311 /* XXX: Just check configuration 0 for now. */
312 for (i = 0; i < usbdev->config[0].descconf->numif; i++)
313 {
314 struct grub_usb_desc_if *interf;
440ab685 315
5fdbaed1 316 interf = usbdev->config[0].interf[i].descif;
440ab685 317
5fdbaed1
CW
318 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
319 i, interf->class, interf->subclass, interf->protocol);
440ab685 320
5fdbaed1
CW
321 if (usbdev->config[0].interf[i].attached)
322 continue;
440ab685 323
5fdbaed1
CW
324 if (interf->class != desc->class)
325 continue;
326 if (desc->hook (usbdev, 0, i))
327 usbdev->config[0].interf[i].attached = 1;
440ab685
VS
328 }
329
5fdbaed1
CW
330 return 0;
331}
332
333void
334grub_usb_register_attach_hook_class (struct grub_usb_attach_desc *desc)
335{
440ab685
VS
336 desc->next = attach_hooks;
337 attach_hooks = desc;
338
5fdbaed1 339 grub_usb_iterate (grub_usb_register_attach_hook_class_iter, desc);
440ab685
VS
340}
341
342void
343grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc *desc)
344{
87edb894 345 grub_list_remove (GRUB_AS_LIST (desc));
440ab685 346}
52d8255d
VS
347
348
349GRUB_MOD_INIT(usb)
350{
351 grub_term_poll_usb = grub_usb_poll_devices;
352}
353
354GRUB_MOD_FINI(usb)
355{
356 grub_term_poll_usb = NULL;
357}