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 grub_usb_controller_dev_t grub_usb_list
;
30 static struct grub_usb_attach_desc
*attach_hooks
;
33 grub_usb_controller_dev_register (grub_usb_controller_dev_t usb
)
35 auto int iterate_hook (grub_usb_controller_t dev
);
37 /* Iterate over all controllers found by the driver. */
38 int iterate_hook (grub_usb_controller_t dev
)
42 /* Enable the ports of the USB Root Hub. */
43 grub_usb_root_hub (dev
);
48 usb
->next
= grub_usb_list
;
52 usb
->iterate (iterate_hook
);
56 grub_usb_controller_dev_unregister (grub_usb_controller_dev_t usb
)
58 grub_usb_controller_dev_t
*p
, q
;
60 for (p
= &grub_usb_list
, q
= *p
; q
; p
= &(q
->next
), q
= q
->next
)
70 grub_usb_controller_iterate (int (*hook
) (grub_usb_controller_t dev
))
72 grub_usb_controller_dev_t p
;
74 auto int iterate_hook (grub_usb_controller_t dev
);
76 int iterate_hook (grub_usb_controller_t dev
)
84 /* Iterate over all controller drivers. */
85 for (p
= grub_usb_list
; p
; p
= p
->next
)
87 /* Iterate over the busses of the controllers. XXX: Actually, a
88 hub driver should do this. */
89 if (p
->iterate (iterate_hook
))
99 grub_usb_clear_halt (grub_usb_device_t dev
, int endpoint
)
101 dev
->toggle
[endpoint
] = 0;
102 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_OUT
103 | GRUB_USB_REQTYPE_STANDARD
104 | GRUB_USB_REQTYPE_TARGET_ENDP
),
105 GRUB_USB_REQ_CLEAR_FEATURE
,
106 GRUB_USB_FEATURE_ENDP_HALT
,
111 grub_usb_set_configuration (grub_usb_device_t dev
, int configuration
)
113 grub_memset (dev
->toggle
, 0, sizeof (dev
->toggle
));
115 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_OUT
116 | GRUB_USB_REQTYPE_STANDARD
117 | GRUB_USB_REQTYPE_TARGET_DEV
),
118 GRUB_USB_REQ_SET_CONFIGURATION
, configuration
,
123 grub_usb_get_descriptor (grub_usb_device_t dev
,
124 grub_uint8_t type
, grub_uint8_t index
,
125 grub_size_t size
, char *data
)
127 return grub_usb_control_msg (dev
, (GRUB_USB_REQTYPE_IN
128 | GRUB_USB_REQTYPE_STANDARD
129 | GRUB_USB_REQTYPE_TARGET_DEV
),
130 GRUB_USB_REQ_GET_DESCRIPTOR
,
135 struct grub_usb_desc_endp
*
136 grub_usb_get_endpdescriptor (grub_usb_device_t usbdev
, int addr
)
140 for (i
= 0; i
< usbdev
->config
[0].descconf
->numif
; i
++)
142 struct grub_usb_desc_if
*interf
;
145 interf
= usbdev
->config
[0].interf
[i
].descif
;
147 for (j
= 0; j
< interf
->endpointcnt
; j
++)
149 struct grub_usb_desc_endp
*endp
;
150 endp
= &usbdev
->config
[0].interf
[i
].descendp
[j
];
152 if (endp
->endp_addr
== addr
)
161 grub_usb_device_initialize (grub_usb_device_t dev
)
163 struct grub_usb_desc_device
*descdev
;
164 struct grub_usb_desc_config config
;
168 /* First we have to read first 8 bytes only and determine
169 * max. size of packet */
170 dev
->descdev
.maxsize0
= 0; /* invalidating, for safety only, can be removed if it is sure it is zero here */
171 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_DEVICE
,
172 0, 8, (char *) &dev
->descdev
);
176 /* Now we have valid value in dev->descdev.maxsize0,
177 * so we can read whole device descriptor */
178 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_DEVICE
,
179 0, sizeof (struct grub_usb_desc_device
),
180 (char *) &dev
->descdev
);
183 descdev
= &dev
->descdev
;
185 for (i
= 0; i
< 8; i
++)
186 dev
->config
[i
].descconf
= NULL
;
188 if (descdev
->configcnt
== 0)
190 err
= GRUB_USB_ERR_BADDEVICE
;
194 for (i
= 0; i
< descdev
->configcnt
; i
++)
200 /* First just read the first 4 bytes of the configuration
201 descriptor, after that it is known how many bytes really have
203 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_CONFIG
, i
, 4,
206 data
= grub_malloc (config
.totallen
);
209 err
= GRUB_USB_ERR_INTERNAL
;
213 dev
->config
[i
].descconf
= (struct grub_usb_desc_config
*) data
;
214 err
= grub_usb_get_descriptor (dev
, GRUB_USB_DESCRIPTOR_CONFIG
, i
,
215 config
.totallen
, data
);
219 /* Skip the configuration descriptor. */
220 pos
= dev
->config
[i
].descconf
->length
;
222 /* Read all interfaces. */
223 for (currif
= 0; currif
< dev
->config
[i
].descconf
->numif
; currif
++)
225 while (pos
< config
.totallen
226 && ((struct grub_usb_desc
*)&data
[pos
])->type
227 != GRUB_USB_DESCRIPTOR_INTERFACE
)
228 pos
+= ((struct grub_usb_desc
*)&data
[pos
])->length
;
229 dev
->config
[i
].interf
[currif
].descif
230 = (struct grub_usb_desc_if
*) &data
[pos
];
231 pos
+= dev
->config
[i
].interf
[currif
].descif
->length
;
233 while (pos
< config
.totallen
234 && ((struct grub_usb_desc
*)&data
[pos
])->type
235 != GRUB_USB_DESCRIPTOR_ENDPOINT
)
236 pos
+= ((struct grub_usb_desc
*)&data
[pos
])->length
;
238 /* Point to the first endpoint. */
239 dev
->config
[i
].interf
[currif
].descendp
240 = (struct grub_usb_desc_endp
*) &data
[pos
];
241 pos
+= (sizeof (struct grub_usb_desc_endp
)
242 * dev
->config
[i
].interf
[currif
].descif
->endpointcnt
);
246 return GRUB_USB_ERR_NONE
;
250 for (i
= 0; i
< 8; i
++)
251 grub_free (dev
->config
[i
].descconf
);
256 void grub_usb_device_attach (grub_usb_device_t dev
)
260 /* XXX: Just check configuration 0 for now. */
261 for (i
= 0; i
< dev
->config
[0].descconf
->numif
; i
++)
263 struct grub_usb_desc_if
*interf
;
264 struct grub_usb_attach_desc
*desc
;
266 interf
= dev
->config
[0].interf
[i
].descif
;
268 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
269 i
, interf
->class, interf
->subclass
, interf
->protocol
);
271 if (dev
->config
[0].interf
[i
].attached
)
274 for (desc
= attach_hooks
; desc
; desc
= desc
->next
)
275 if (interf
->class == desc
->class && desc
->hook (dev
, 0, i
))
276 dev
->config
[0].interf
[i
].attached
= 1;
278 if (dev
->config
[0].interf
[i
].attached
)
281 switch (interf
->class)
283 case GRUB_USB_CLASS_MASS_STORAGE
:
284 grub_dl_load ("usbms");
286 case GRUB_USB_CLASS_HID
:
287 grub_dl_load ("usb_keyboard");
290 /* FIXME: don't load useless modules. */
291 grub_dl_load ("usbserial_ftdi");
292 grub_dl_load ("usbserial_pl2303");
299 grub_usb_register_attach_hook_class (struct grub_usb_attach_desc
*desc
)
301 auto int usb_iterate (grub_usb_device_t dev
);
303 int usb_iterate (grub_usb_device_t usbdev
)
305 struct grub_usb_desc_device
*descdev
= &usbdev
->descdev
;
308 if (descdev
->class != 0 || descdev
->subclass
|| descdev
->protocol
!= 0
309 || descdev
->configcnt
== 0)
312 /* XXX: Just check configuration 0 for now. */
313 for (i
= 0; i
< usbdev
->config
[0].descconf
->numif
; i
++)
315 struct grub_usb_desc_if
*interf
;
317 interf
= usbdev
->config
[0].interf
[i
].descif
;
319 grub_dprintf ("usb", "iterate: interf=%d, class=%d, subclass=%d, protocol=%d\n",
320 i
, interf
->class, interf
->subclass
, interf
->protocol
);
322 if (usbdev
->config
[0].interf
[i
].attached
)
325 if (interf
->class != desc
->class)
327 if (desc
->hook (usbdev
, 0, i
))
328 usbdev
->config
[0].interf
[i
].attached
= 1;
334 desc
->next
= attach_hooks
;
337 grub_usb_iterate (usb_iterate
);
341 grub_usb_unregister_attach_hook_class (struct grub_usb_attach_desc
*desc
)
343 grub_list_remove (GRUB_AS_LIST (desc
));
349 grub_term_poll_usb
= grub_usb_poll_devices
;
354 grub_term_poll_usb
= NULL
;