1 /* usb.c - Generic USB interfaces. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008 Free Software Foundation, Inc.
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.
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.
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/>.
23 #include <grub/misc.h>
24 #include <grub/list.h>
25 #include <grub/term.h>
27 GRUB_MOD_LICENSE ("GPLv3+");
29 static struct grub_usb_attach_desc
*attach_hooks
;
32 /* Context for grub_usb_controller_iterate. */
33 struct grub_usb_controller_iterate_ctx
35 grub_usb_controller_iterate_hook_t hook
;
37 grub_usb_controller_dev_t p
;
40 /* Helper for grub_usb_controller_iterate. */
42 grub_usb_controller_iterate_iter (grub_usb_controller_t dev
, void *data
)
44 struct grub_usb_controller_iterate_ctx
*ctx
= data
;
47 if (ctx
->hook (dev
, ctx
->hook_data
))
53 grub_usb_controller_iterate (grub_usb_controller_iterate_hook_t hook
,
56 struct grub_usb_controller_iterate_ctx ctx
= {
58 .hook_data
= hook_data
61 /* Iterate over all controller drivers. */
62 for (ctx
.p
= grub_usb_list
; ctx
.p
; ctx
.p
= ctx
.p
->next
)
64 /* Iterate over the busses of the controllers. XXX: Actually, a
65 hub driver should do this. */
66 if (ctx
.p
->iterate (grub_usb_controller_iterate_iter
, &ctx
))
76 grub_usb_clear_halt (grub_usb_device_t dev
, int endpoint
)
78 dev
->toggle
[endpoint
] = 0;
79 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_OUT
80 | GRUB_USB_REQTYPE_STANDARD
81 | GRUB_USB_REQTYPE_TARGET_ENDP
),
82 GRUB_USB_REQ_CLEAR_FEATURE
,
83 GRUB_USB_FEATURE_ENDP_HALT
,
88 grub_usb_set_configuration (grub_usb_device_t dev
, int configuration
)
90 grub_memset (dev
->toggle
, 0, sizeof (dev
->toggle
));
92 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_OUT
93 | GRUB_USB_REQTYPE_STANDARD
94 | GRUB_USB_REQTYPE_TARGET_DEV
),
95 GRUB_USB_REQ_SET_CONFIGURATION
, configuration
,
100 grub_usb_get_descriptor (grub_usb_device_t dev
,
101 grub_uint8_t type
, grub_uint8_t index
,
102 grub_size_t size
, char *data
)
104 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_IN
105 | GRUB_USB_REQTYPE_STANDARD
106 | GRUB_USB_REQTYPE_TARGET_DEV
),
107 GRUB_USB_REQ_GET_DESCRIPTOR
,
113 grub_usb_device_initialize (grub_usb_device_t dev
)
115 struct grub_usb_desc_device
*descdev
;
116 struct grub_usb_desc_config config
;
120 /* First we have to read first 8 bytes only and determine
121 * max. size of packet */
122 dev
->descdev
.maxsize0
= 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */
123 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_DEVICE
,
124 0, 8, (char *) &dev
->descdev
);
128 /* Now we have valid value in dev->descdev.maxsize0,
129 * so we can read whole device descriptor */
130 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_DEVICE
,
131 0, sizeof (struct grub_usb_desc_device
),
132 (char *) &dev
->descdev
);
135 descdev
= &dev
->descdev
;
137 for (i
= 0; i
< 8; i
++)
138 dev
->config
[i
].descconf
= NULL
;
140 if (descdev
->configcnt
== 0)
142 err
= GRUB_USB_ERR_BADDEVICE
;
146 for (i
= 0; i
< descdev
->configcnt
; i
++)
151 struct grub_usb_desc
*desc
;
153 /* First just read the first 4 bytes of the configuration
154 descriptor, after that it is known how many bytes really have
156 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_CONFIG
, i
, 4,
159 data
= grub_malloc (config
.totallen
);
162 err
= GRUB_USB_ERR_INTERNAL
;
166 dev
->config
[i
].descconf
= (struct grub_usb_desc_config
*) data
;
167 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_CONFIG
, i
,
168 config
.totallen
, data
);
172 /* Skip the configuration descriptor. */
173 pos
= dev
->config
[i
].descconf
->length
;
175 /* Read all interfaces. */
176 for (currif
= 0; currif
< dev
->config
[i
].descconf
->numif
; currif
++)
178 while (pos
< config
.totallen
)
180 desc
= (struct grub_usb_desc
*)&data
[pos
];
181 if (desc
->type
== GRUB_USB_DESCRIPTOR_INTERFACE
)
185 err
= GRUB_USB_ERR_BADDEVICE
;
191 dev
->config
[i
].interf
[currif
].descif
192 = (struct grub_usb_desc_if
*) &data
[pos
];
193 pos
+= dev
->config
[i
].interf
[currif
].descif
->length
;
195 while (pos
< config
.totallen
)
197 desc
= (struct grub_usb_desc
*)&data
[pos
];
198 if (desc
->type
== GRUB_USB_DESCRIPTOR_ENDPOINT
)
202 err
= GRUB_USB_ERR_BADDEVICE
;
208 /* Point to the first endpoint. */
209 dev
->config
[i
].interf
[currif
].descendp
210 = (struct grub_usb_desc_endp
*) &data
[pos
];
211 pos
+= (sizeof (struct grub_usb_desc_endp
)
212 * dev
->config
[i
].interf
[currif
].descif
->endpointcnt
);
216 return GRUB_USB_ERR_NONE
;
220 for (i
= 0; i
< 8; i
++)
221 grub_free (dev
->config
[i
].descconf
);
226 void grub_usb_device_attach (grub_usb_device_t dev
)
230 /* XXX: Just check configuration 0 for now. */
231 for (i
= 0; i
< dev
->config
[0].descconf
->numif
; i
++)
233 struct grub_usb_desc_if
*interf
;
234 struct grub_usb_attach_desc
*desc
;
236 interf
= dev
->config
[0].interf
[i
].descif
;
238 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
239 i
, interf
->class, interf
->subclass
, interf
->protocol
);
241 if (dev
->config
[0].interf
[i
].attached
)
244 for (desc
= attach_hooks
; desc
; desc
= desc
->next
)
245 if (interf
->class == desc
->class)
247 grub_boot_time ("Probing USB device driver class %x", desc
->class);
248 if (desc
->hook (dev
, 0, i
))
249 dev
->config
[0].interf
[i
].attached
= 1;
250 grub_boot_time ("Probed USB device driver class %x", desc
->class);
253 if (dev
->config
[0].interf
[i
].attached
)
256 switch (interf
->class)
258 case GRUB_USB_CLASS_MASS_STORAGE
:
259 grub_dl_load ("usbms");
262 case GRUB_USB_CLASS_HID
:
263 grub_dl_load ("usb_keyboard");
267 /* FIXME: don't load useless modules. */
268 grub_dl_load ("usbserial_ftdi");
270 grub_dl_load ("usbserial_pl2303");
272 grub_dl_load ("usbserial_usbdebug");
279 /* Helper for grub_usb_register_attach_hook_class. */
281 grub_usb_register_attach_hook_class_iter (grub_usb_device_t usbdev
, void *data
)
283 struct grub_usb_attach_desc
*desc
= data
;
284 struct grub_usb_desc_device
*descdev
= &usbdev
->descdev
;
287 if (descdev
->class != 0 || descdev
->subclass
|| descdev
->protocol
!= 0
288 || descdev
->configcnt
== 0)
291 /* XXX: Just check configuration 0 for now. */
292 for (i
= 0; i
< usbdev
->config
[0].descconf
->numif
; i
++)
294 struct grub_usb_desc_if
*interf
;
296 interf
= usbdev
->config
[0].interf
[i
].descif
;
298 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
299 i
, interf
->class, interf
->subclass
, interf
->protocol
);
301 if (usbdev
->config
[0].interf
[i
].attached
)
304 if (interf
->class != desc
->class)
306 if (desc
->hook (usbdev
, 0, i
))
307 usbdev
->config
[0].interf
[i
].attached
= 1;
314 grub_usb_register_attach_hook_class (struct grub_usb_attach_desc
*desc
)
316 desc
->next
= attach_hooks
;
319 grub_usb_iterate (grub_usb_register_attach_hook_class_iter
, desc
);
323 grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc
*desc
)
325 grub_list_remove (GRUB_AS_LIST (desc
));
331 grub_term_poll_usb
= grub_usb_poll_devices
;
336 grub_term_poll_usb
= NULL
;