1 /* usbms.c - USB Mass Storage Support. */
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/scsi.h>
24 #include <grub/scsicmd.h>
25 #include <grub/misc.h>
27 #define GRUB_USBMS_DIRECTION_BIT 7
29 /* The USB Mass Storage Command Block Wrapper. */
32 grub_uint32_t signature
;
34 grub_uint32_t transfer_length
;
38 grub_uint8_t cbwcb
[16];
39 } __attribute__ ((packed
));
43 grub_uint32_t signature
;
45 grub_uint32_t residue
;
47 } __attribute__ ((packed
));
51 struct grub_usb_device
*dev
;
56 struct grub_usb_desc_endp
*in
;
57 struct grub_usb_desc_endp
*out
;
62 struct grub_usbms_dev
*next
;
64 typedef struct grub_usbms_dev
*grub_usbms_dev_t
;
66 static grub_usbms_dev_t grub_usbms_dev_list
;
71 grub_usbms_reset (grub_usb_device_t dev
, int interface
)
73 return grub_usb_control_msg (dev
, 0x21, 255, 0, interface
, 0, 0);
77 grub_usbms_finddevs (void)
79 auto int usb_iterate (grub_usb_device_t dev
);
81 int usb_iterate (grub_usb_device_t usbdev
)
84 struct grub_usb_desc_device
*descdev
= &usbdev
->descdev
;
87 if (descdev
->class != 0 || descdev
->subclass
|| descdev
->protocol
!= 0)
90 /* XXX: Just check configuration 0 for now. */
91 for (i
= 0; i
< usbdev
->config
[0].descconf
->numif
; i
++)
93 struct grub_usbms_dev
*usbms
;
94 struct grub_usb_desc_if
*interf
;
98 interf
= usbdev
->config
[0].interf
[i
].descif
;
100 /* If this is not a USB Mass Storage device with a supported
101 protocol, just skip it. */
102 if (interf
->class != GRUB_USB_CLASS_MASS_STORAGE
103 || interf
->subclass
!= GRUB_USBMS_SUBCLASS_BULK
104 || interf
->protocol
!= GRUB_USBMS_PROTOCOL_BULK
)
110 usbms
= grub_malloc (sizeof (struct grub_usbms_dev
));
115 usbms
->interface
= i
;
119 /* Iterate over all endpoints of this interface, at least a
120 IN and OUT bulk endpoint are required. */
121 for (j
= 0; j
< interf
->endpointcnt
; j
++)
123 struct grub_usb_desc_endp
*endp
;
124 endp
= &usbdev
->config
[0].interf
[i
].descendp
[j
];
126 if ((endp
->endp_addr
& 128) && (endp
->attrib
& 3) == 2)
128 /* Bulk IN endpoint. */
130 grub_usb_clear_halt (usbdev
, endp
->endp_addr
& 128);
131 usbms
->in_maxsz
= endp
->maxpacket
;
133 else if (!(endp
->endp_addr
& 128) && (endp
->attrib
& 3) == 2)
135 /* Bulk OUT endpoint. */
137 grub_usb_clear_halt (usbdev
, endp
->endp_addr
& 128);
138 usbms
->out_maxsz
= endp
->maxpacket
;
142 if (!usbms
->in
|| !usbms
->out
)
148 /* Query the amount of LUNs. */
149 err
= grub_usb_control_msg (usbdev
, 0xA1, 254,
150 0, i
, 1, (char *) &luns
);
153 /* In case of a stall, clear the stall. */
154 if (err
== GRUB_USB_ERR_STALL
)
156 grub_usb_clear_halt (usbdev
, usbms
->in
->endp_addr
& 3);
157 grub_usb_clear_halt (usbdev
, usbms
->out
->endp_addr
& 3);
160 /* Just set the amount of LUNs to one. */
161 grub_errno
= GRUB_ERR_NONE
;
167 /* XXX: Check the magic values, does this really make
169 grub_usb_control_msg (usbdev
, (1 << 6) | 1, 255,
172 /* XXX: To make Qemu work? */
173 if (usbms
->luns
== 0)
176 usbms
->next
= grub_usbms_dev_list
;
177 grub_usbms_dev_list
= usbms
;
179 /* XXX: Activate the first configuration. */
180 grub_usb_set_configuration (usbdev
, 1);
182 /* Bulk-Only Mass Storage Reset, after the reset commands
184 grub_usbms_reset (usbdev
, i
);
192 grub_usb_iterate (usb_iterate
);
198 grub_usbms_iterate (int (*hook
) (const char *name
, int luns
))
203 for (p
= grub_usbms_dev_list
; p
; p
= p
->next
)
206 grub_sprintf (devname
, "usb%d", cnt
);
208 if (hook (devname
, p
->luns
))
217 grub_usbms_transfer (struct grub_scsi
*scsi
, grub_size_t cmdsize
, char *cmd
,
218 grub_size_t size
, char *buf
, int read_write
)
220 struct grub_usbms_cbw cbw
;
221 grub_usbms_dev_t dev
= (grub_usbms_dev_t
) scsi
->data
;
222 struct grub_usbms_csw status
;
223 static grub_uint32_t tag
= 0;
224 grub_usb_err_t err
= GRUB_USB_ERR_NONE
;
225 int retrycnt
= 3 + 1;
230 return grub_error (GRUB_ERR_IO
, "USB Mass Storage stalled");
232 /* Setup the request. */
233 grub_memset (&cbw
, 0, sizeof (cbw
));
234 cbw
.signature
= grub_cpu_to_le32 (0x43425355);
236 cbw
.transfer_length
= grub_cpu_to_le32 (size
);
237 cbw
.flags
= (!read_write
) << GRUB_USBMS_DIRECTION_BIT
;
238 cbw
.lun
= scsi
->lun
<< GRUB_SCSI_LUN_SHIFT
;
239 cbw
.length
= cmdsize
;
240 grub_memcpy (cbw
.cbwcb
, cmd
, cmdsize
);
242 /* Write the request. */
243 err
= grub_usb_bulk_write (dev
->dev
, dev
->out
->endp_addr
& 15,
244 sizeof (cbw
), (char *) &cbw
);
247 if (err
== GRUB_USB_ERR_STALL
)
249 grub_usb_clear_halt (dev
->dev
, dev
->out
->endp_addr
);
252 return grub_error (GRUB_ERR_IO
, "USB Mass Storage request failed");;
255 /* Read/write the data. */
258 err
= grub_usb_bulk_read (dev
->dev
, dev
->in
->endp_addr
& 15, size
, buf
);
259 grub_dprintf ("usb", "read: %d %d\n", err
, GRUB_USB_ERR_STALL
);
262 if (err
== GRUB_USB_ERR_STALL
)
264 grub_usb_clear_halt (dev
->dev
, dev
->in
->endp_addr
);
267 return grub_error (GRUB_ERR_READ_ERROR
,
268 "can't read from USB Mass Storage device");
273 err
= grub_usb_bulk_write (dev
->dev
, dev
->in
->endp_addr
& 15, size
, buf
);
274 grub_dprintf ("usb", "write: %d %d\n", err
, GRUB_USB_ERR_STALL
);
277 if (err
== GRUB_USB_ERR_STALL
)
279 grub_usb_clear_halt (dev
->dev
, dev
->out
->endp_addr
);
282 return grub_error (GRUB_ERR_WRITE_ERROR
,
283 "can't write to USB Mass Storage device");
287 /* Read the status. */
288 err
= grub_usb_bulk_read (dev
->dev
, dev
->in
->endp_addr
& 15,
289 sizeof (status
), (char *) &status
);
292 if (err
== GRUB_USB_ERR_STALL
)
294 grub_usb_clear_halt (dev
->dev
, dev
->in
->endp_addr
);
297 return grub_error (GRUB_ERR_READ_ERROR
,
298 "can't read status from USB Mass Storage device");
301 /* XXX: Magic and check this code. */
302 if (status
.status
== 2)
304 /* XXX: Phase error, reset device. */
305 grub_usbms_reset (dev
->dev
, dev
->interface
);
306 grub_usb_clear_halt (dev
->dev
, dev
->in
->endp_addr
);
307 grub_usb_clear_halt (dev
->dev
, dev
->out
->endp_addr
);
313 return grub_error (GRUB_ERR_READ_ERROR
,
314 "error communication with USB Mass Storage device");
316 return GRUB_ERR_NONE
;
321 grub_usbms_read (struct grub_scsi
*scsi
, grub_size_t cmdsize
, char *cmd
,
322 grub_size_t size
, char *buf
)
324 return grub_usbms_transfer (scsi
, cmdsize
, cmd
, size
, buf
, 0);
328 grub_usbms_write (struct grub_scsi
*scsi
, grub_size_t cmdsize
, char *cmd
,
329 grub_size_t size
, char *buf
)
331 return grub_usbms_transfer (scsi
, cmdsize
, cmd
, size
, buf
, 1);
335 grub_usbms_open (const char *name
, struct grub_scsi
*scsi
)
341 if (grub_strncmp (name
, "usb", 3))
342 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
343 "not a USB Mass Storage device");
345 devnum
= grub_strtoul (name
+ 3, NULL
, 10);
346 for (p
= grub_usbms_dev_list
; p
; p
= p
->next
)
348 /* Check if this is the devnumth device. */
352 scsi
->name
= grub_strdup (name
);
353 scsi
->luns
= p
->luns
;
357 return GRUB_ERR_NONE
;
363 return grub_error (GRUB_ERR_UNKNOWN_DEVICE
,
364 "not a USB Mass Storage device");
368 grub_usbms_close (struct grub_scsi
*scsi
)
370 grub_free (scsi
->name
);
373 static struct grub_scsi_dev grub_usbms_dev
=
376 .iterate
= grub_usbms_iterate
,
377 .open
= grub_usbms_open
,
378 .close
= grub_usbms_close
,
379 .read
= grub_usbms_read
,
380 .write
= grub_usbms_write
385 grub_usbms_finddevs ();
386 grub_scsi_dev_register (&grub_usbms_dev
);
391 grub_scsi_dev_unregister (&grub_usbms_dev
);