aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2010-02-17 23:24:42 -0500
committerKevin O'Connor <kevin@koconnor.net>2010-02-17 23:24:42 -0500
commit7149fc813139cf564a4456815461c18a8b208e89 (patch)
treeb0866113b1380d34b1d9e1d4a1ffd8fc375f289f /src
parent3c160dde75b9920f048d4276026d680d0f582dc9 (diff)
downloadseabios-hppa-7149fc813139cf564a4456815461c18a8b208e89.zip
seabios-hppa-7149fc813139cf564a4456815461c18a8b208e89.tar.gz
seabios-hppa-7149fc813139cf564a4456815461c18a8b208e89.tar.bz2
Initial support for booting from USB drives.
This patch adds initial support for USB Mass Storage Controllers. This includes support for bulk transfers on UHCI controllers. Code to detect a USB MSC device is added, and wrappers for sending "cdb" block commands over USB are added. The scsi "inquiry" command is also added.
Diffstat (limited to 'src')
-rw-r--r--src/block.c6
-rw-r--r--src/blockcmd.c18
-rw-r--r--src/blockcmd.h14
-rw-r--r--src/config.h2
-rw-r--r--src/disk.h1
-rw-r--r--src/usb-msc.c261
-rw-r--r--src/usb-msc.h25
-rw-r--r--src/usb-uhci.c114
-rw-r--r--src/usb-uhci.h2
-rw-r--r--src/usb.c36
-rw-r--r--src/usb.h2
11 files changed, 478 insertions, 3 deletions
diff --git a/src/block.c b/src/block.c
index 365053e..3b43f97 100644
--- a/src/block.c
+++ b/src/block.c
@@ -10,6 +10,7 @@
#include "cmos.h" // inb_cmos
#include "util.h" // dprintf
#include "ata.h" // process_ata_op
+#include "usb-msc.h" // process_usb_op
struct drives_s Drives VAR16VISIBLE;
@@ -280,6 +281,9 @@ describe_drive(struct drive_s *drive_g)
case DTYPE_RAMDISK:
describe_ramdisk(drive_g);
break;
+ case DTYPE_USB:
+ describe_usb(drive_g);
+ break;
default:
printf("Unknown");
break;
@@ -308,6 +312,8 @@ process_op(struct disk_op_s *op)
return process_ramdisk_op(op);
case DTYPE_CDEMU:
return process_cdemu_op(op);
+ case DTYPE_USB:
+ return process_usb_op(op);
default:
op->count = 0;
return DISK_RET_EPARAM;
diff --git a/src/blockcmd.c b/src/blockcmd.c
index 5efbdce..48568e6 100644
--- a/src/blockcmd.c
+++ b/src/blockcmd.c
@@ -10,7 +10,9 @@
#include "disk.h" // struct disk_op_s
#include "blockcmd.h" // struct cdb_request_sense
#include "ata.h" // atapi_cmd_data
+#include "usb-msc.h" // usb_cmd_data
+// Route command to low-level handler.
static int
cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
{
@@ -18,12 +20,26 @@ cdb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
switch (type) {
case DTYPE_ATAPI:
return atapi_cmd_data(op, cdbcmd, blocksize);
+ case DTYPE_USB:
+ return usb_cmd_data(op, cdbcmd, blocksize);
default:
op->count = 0;
return DISK_RET_EPARAM;
}
}
+int
+cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data)
+{
+ struct cdb_request_sense cmd;
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = CDB_CMD_INQUIRY;
+ cmd.length = sizeof(*data);
+ op->count = 1;
+ op->buf_fl = data;
+ return cdb_cmd_data(op, &cmd, sizeof(*data));
+}
+
// Request SENSE
int
cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data)
@@ -58,5 +74,5 @@ cdb_read(struct disk_op_s *op)
cmd.command = CDB_CMD_READ_10;
cmd.lba = htonl(op->lba);
cmd.count = htons(op->count);
- return cdb_cmd_data(op, &cmd, CDROM_SECTOR_SIZE);
+ return cdb_cmd_data(op, &cmd, GET_GLOBAL(op->drive_g->blksize));
}
diff --git a/src/blockcmd.h b/src/blockcmd.h
index d645ebe..903c435 100644
--- a/src/blockcmd.h
+++ b/src/blockcmd.h
@@ -32,6 +32,7 @@ struct cdbres_read_capacity {
u32 blksize;
} PACKED;
+#define CDB_CMD_INQUIRY 0x12
#define CDB_CMD_REQUEST_SENSE 0x03
struct cdb_request_sense {
@@ -55,9 +56,22 @@ struct cdbres_request_sense {
u32 reserved_0e;
} PACKED;
+struct cdbres_inquiry {
+ u8 pdt;
+ u8 removable;
+ u8 reserved_02[2];
+ u8 additional;
+ u8 reserved_05[3];
+ char vendor[8];
+ char product[16];
+ char rev[4];
+} PACKED;
+
// blockcmd.c
+int cdb_get_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
int cdb_get_sense(struct disk_op_s *op, struct cdbres_request_sense *data);
int cdb_read_capacity(struct disk_op_s *op, struct cdbres_read_capacity *data);
+int cdb_inquiry(struct disk_op_s *op, struct cdbres_inquiry *data);
int cdb_read(struct disk_op_s *op);
#endif // blockcmd.h
diff --git a/src/config.h b/src/config.h
index e359652..1362581 100644
--- a/src/config.h
+++ b/src/config.h
@@ -36,6 +36,8 @@
#define CONFIG_USB_UHCI 1
// Support USB OHCI controllers
#define CONFIG_USB_OHCI 1
+// Support USB disks
+#define CONFIG_USB_MSC 1
// Support USB hubs
#define CONFIG_USB_HUB 1
// Support USB keyboards
diff --git a/src/disk.h b/src/disk.h
index 90ca04d..d87d71a 100644
--- a/src/disk.h
+++ b/src/disk.h
@@ -199,6 +199,7 @@ struct drive_s {
#define DTYPE_ATAPI 0x03
#define DTYPE_RAMDISK 0x04
#define DTYPE_CDEMU 0x05
+#define DTYPE_USB 0x06
#define TRANSLATION_NONE 0
#define TRANSLATION_LBA 1
diff --git a/src/usb-msc.c b/src/usb-msc.c
new file mode 100644
index 0000000..8d4a44e
--- /dev/null
+++ b/src/usb-msc.c
@@ -0,0 +1,261 @@
+// Code for handling USB Mass Storage Controller devices.
+//
+// Copyright (C) 2010 Kevin O'Connor <kevin@koconnor.net>
+//
+// This file may be distributed under the terms of the GNU LGPLv3 license.
+
+#include "util.h" // dprintf
+#include "config.h" // CONFIG_USB_MSC
+#include "usb-msc.h" // usb_msc_init
+#include "usb.h" // struct usb_s
+#include "biosvar.h" // GET_GLOBAL
+#include "blockcmd.h" // cdb_read
+#include "disk.h" // DTYPE_USB
+#include "boot.h" // add_bcv_internal
+
+#define DESCSIZE 80
+
+struct usbdrive_s {
+ struct drive_s drive;
+ struct usb_pipe *bulkin, *bulkout;
+ char *desc;
+};
+
+
+/****************************************************************
+ * Bulk-only drive command processing
+ ****************************************************************/
+
+#define USB_CDB_SIZE 12
+
+#define CBW_SIGNATURE 0x43425355 // USBC
+
+struct cbw_s {
+ u32 dCBWSignature;
+ u32 dCBWTag;
+ u32 dCBWDataTransferLength;
+ u8 bmCBWFlags;
+ u8 bCBWLUN;
+ u8 bCBWCBLength;
+ u8 CBWCB[16];
+} PACKED;
+
+#define CSW_SIGNATURE 0x53425355 // USBS
+
+struct csw_s {
+ u32 dCSWSignature;
+ u32 dCSWTag;
+ u32 dCSWDataResidue;
+ u8 bCSWStatus;
+} PACKED;
+
+// Low-level usb command transmit function.
+int
+usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize)
+{
+ dprintf(1, "usb_cmd_data id=%p write=%d count=%d bs=%d buf=%p\n"
+ , op->drive_g, 0, op->count, blocksize, op->buf_fl);
+ struct usbdrive_s *udrive_g = container_of(
+ op->drive_g, struct usbdrive_s, drive);
+ struct usb_pipe *bulkin = GET_GLOBAL(udrive_g->bulkin);
+ struct usb_pipe *bulkout = GET_GLOBAL(udrive_g->bulkout);
+
+ // Setup command block wrapper.
+ u32 bytes = blocksize * op->count;
+ struct cbw_s cbw;
+ memset(&cbw, 0, sizeof(cbw));
+ cbw.dCBWSignature = CBW_SIGNATURE;
+ cbw.dCBWTag = 999; // XXX
+ cbw.dCBWDataTransferLength = bytes;
+ cbw.bmCBWFlags = USB_DIR_IN; // XXX
+ cbw.bCBWLUN = 0; // XXX
+ cbw.bCBWCBLength = USB_CDB_SIZE;
+ memcpy(cbw.CBWCB, cdbcmd, USB_CDB_SIZE);
+
+ // Transfer cbw to device.
+ int ret = usb_send_bulk(bulkout, USB_DIR_OUT
+ , MAKE_FLATPTR(GET_SEG(SS), &cbw), sizeof(cbw));
+ if (ret)
+ goto fail;
+
+ // Transfer data from device.
+ ret = usb_send_bulk(bulkin, USB_DIR_IN, op->buf_fl, bytes);
+ if (ret)
+ goto fail;
+
+ // Transfer csw info.
+ struct csw_s csw;
+ ret = usb_send_bulk(bulkin, USB_DIR_IN
+ , MAKE_FLATPTR(GET_SEG(SS), &csw), sizeof(csw));
+ if (ret)
+ goto fail;
+
+ if (!csw.bCSWStatus)
+ return DISK_RET_SUCCESS;
+ if (csw.bCSWStatus == 2)
+ goto fail;
+
+ op->count -= csw.dCSWDataResidue / blocksize;
+ return DISK_RET_EBADTRACK;
+
+fail:
+ // XXX - reset connection
+ dprintf(1, "USB transmission failed\n");
+ op->count = 0;
+ return DISK_RET_EBADTRACK;
+}
+
+
+/****************************************************************
+ * Drive ops
+ ****************************************************************/
+
+// 16bit command demuxer for ATAPI cdroms.
+int
+process_usb_op(struct disk_op_s *op)
+{
+ switch (op->command) {
+ case CMD_READ:
+ return cdb_read(op);
+ case CMD_FORMAT:
+ case CMD_WRITE:
+ return DISK_RET_EWRITEPROTECT;
+ case CMD_RESET:
+ case CMD_ISREADY:
+ case CMD_VERIFY:
+ case CMD_SEEK:
+ return DISK_RET_SUCCESS;
+ default:
+ op->count = 0;
+ return DISK_RET_EPARAM;
+ }
+}
+
+void
+describe_usb(struct drive_s *drive_g)
+{
+ struct usbdrive_s *udrive_g = container_of(
+ drive_g, struct usbdrive_s, drive);
+ printf("%s", udrive_g->desc);
+}
+
+
+/****************************************************************
+ * Setup
+ ****************************************************************/
+
+static int
+setup_drive_cdrom(struct disk_op_s *op)
+{
+ op->drive_g->blksize = CDROM_SECTOR_SIZE;
+ op->drive_g->sectors = (u64)-1;
+ map_cd_drive(op->drive_g);
+ return 0;
+}
+
+static int
+setup_drive_hd(struct disk_op_s *op)
+{
+ struct cdbres_read_capacity info;
+ int ret = cdb_read_capacity(op, &info);
+ if (ret)
+ return ret;
+ // XXX - retry for some timeout?
+
+ u32 blksize = ntohl(info.blksize), sectors = ntohl(info.sectors);
+ if (blksize != DISK_SECTOR_SIZE) {
+ if (blksize == CDROM_SECTOR_SIZE)
+ return setup_drive_cdrom(op);
+ dprintf(1, "Unsupported USB MSC block size %d\n", blksize);
+ return -1;
+ }
+ op->drive_g->blksize = blksize;
+ op->drive_g->sectors = sectors;
+ dprintf(1, "USB MSC blksize=%d sectors=%d\n", blksize, sectors);
+
+ // Setup disk geometry translation.
+ setup_translation(op->drive_g);
+
+ // Register with bcv system.
+ add_bcv_internal(op->drive_g);
+
+ return 0;
+}
+
+// Configure a usb msc device.
+int
+usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax)
+{
+ if (!CONFIG_USB_MSC)
+ return -1;
+
+ // Verify right kind of device
+ if (iface->bInterfaceSubClass != US_SC_SCSI
+ || iface->bInterfaceProtocol != US_PR_BULK) {
+ dprintf(1, "Unsupported MSC USB device (subclass=%02x proto=%02x)\n"
+ , iface->bInterfaceSubClass, iface->bInterfaceProtocol);
+ return -1;
+ }
+
+ // Find bulk in and bulk out endpoints.
+ struct usb_endpoint_descriptor *indesc = findEndPointDesc(
+ iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_IN);
+ struct usb_endpoint_descriptor *outdesc = findEndPointDesc(
+ iface, imax, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT);
+ if (!indesc || !outdesc)
+ goto fail;
+ u32 inendp = mkendpFromDesc(endp, indesc);
+ struct usb_pipe *bulkin = alloc_bulk_pipe(inendp);
+ u32 outendp = mkendpFromDesc(endp, outdesc);
+ struct usb_pipe *bulkout = alloc_bulk_pipe(outendp);
+ if (!bulkin || !bulkout)
+ goto fail;
+
+ // Allocate drive structure.
+ char *desc = malloc_tmphigh(DESCSIZE);
+ struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g));
+ if (!udrive_g || !desc) {
+ warn_noalloc();
+ goto fail;
+ }
+ memset(udrive_g, 0, sizeof(*udrive_g));
+ udrive_g->drive.type = DTYPE_USB;
+ udrive_g->bulkin = bulkin;
+ udrive_g->bulkout = bulkout;
+
+ // Validate drive and find block size and sector count.
+ struct disk_op_s dop;
+ memset(&dop, 0, sizeof(dop));
+ dop.drive_g = &udrive_g->drive;
+ struct cdbres_inquiry data;
+ int ret = cdb_get_inquiry(&dop, &data);
+ if (ret)
+ goto fail;
+ char vendor[sizeof(data.vendor)+1], product[sizeof(data.product)+1];
+ char rev[sizeof(data.rev)+1];
+ int pdt = data.pdt & 0x1f;
+ int removable = !!(data.removable & 0x80);
+ dprintf(1, "USB MSC vendor='%s' product='%s' rev='%s'"
+ " type=%d removable=%d\n"
+ , strtcpy(vendor, data.vendor, sizeof(vendor))
+ , strtcpy(product, data.product, sizeof(product))
+ , strtcpy(rev, data.rev, sizeof(rev))
+ , pdt, removable);
+
+ if (pdt == USB_MSC_TYPE_CDROM)
+ ret = setup_drive_cdrom(&dop);
+ else
+ ret = setup_drive_hd(&dop);
+ if (ret)
+ goto fail;
+
+ snprintf(desc, DESCSIZE, "USB Drive %s %s %s", vendor, product, rev);
+ udrive_g->desc = desc;
+
+ return 0;
+fail:
+ dprintf(1, "Unable to configure USB MSC device.\n");
+ free(desc);
+ free(udrive_g);
+ return -1;
+}
diff --git a/src/usb-msc.h b/src/usb-msc.h
new file mode 100644
index 0000000..4bad91f
--- /dev/null
+++ b/src/usb-msc.h
@@ -0,0 +1,25 @@
+#ifndef __USB_MSC_H
+#define __USB_MSC_H
+
+// usb-msc.c
+struct disk_op_s;
+int usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize);
+struct usb_interface_descriptor;
+int usb_msc_init(u32 endp, struct usb_interface_descriptor *iface, int imax);
+int process_usb_op(struct disk_op_s *op);
+struct drive_s;
+void describe_usb(struct drive_s *drive_g);
+
+
+/****************************************************************
+ * MSC flags
+ ****************************************************************/
+
+#define US_SC_SCSI 0x06
+
+#define US_PR_BULK 0x50
+
+#define USB_MSC_TYPE_DISK 0x00
+#define USB_MSC_TYPE_CDROM 0x05
+
+#endif // ush-msc.h
diff --git a/src/usb-uhci.c b/src/usb-uhci.c
index ca51337..881e345 100644
--- a/src/usb-uhci.c
+++ b/src/usb-uhci.c
@@ -253,6 +253,120 @@ uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
}
struct usb_pipe *
+uhci_alloc_bulk_pipe(u32 endp)
+{
+ if (! CONFIG_USB_UHCI)
+ return NULL;
+ struct usb_s *cntl = endp2cntl(endp);
+ dprintf(7, "uhci_alloc_bulk_pipe %x\n", endp);
+
+ // Allocate a queue head.
+ struct uhci_qh *qh = malloc_low(sizeof(*qh));
+ if (!qh) {
+ warn_noalloc();
+ return NULL;
+ }
+ qh->element = UHCI_PTR_TERM;
+ qh->next_td = 0;
+ qh->pipe.endp = endp;
+
+ // Add queue head to controller list.
+ struct uhci_qh *data_qh = cntl->uhci.qh;
+ qh->link = data_qh->link;
+ barrier();
+ data_qh->link = (u32)qh | UHCI_PTR_QH;
+
+ return &qh->pipe;
+}
+
+static int
+wait_td(struct uhci_td *td)
+{
+ u64 end = calc_future_tsc(5000); // XXX - lookup real time.
+ u32 status;
+ for (;;) {
+ status = td->status;
+ if (!(status & TD_CTRL_ACTIVE))
+ break;
+ if (check_time(end)) {
+ warn_timeout();
+ return -1;
+ }
+ yield();
+ }
+ if (status & TD_CTRL_ANY_ERROR) {
+ dprintf(1, "wait_td error - status=%x\n", status);
+ return -2;
+ }
+ return 0;
+}
+
+#define STACKTDS 4
+#define TDALIGN 16
+
+int
+uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
+{
+ struct uhci_qh *qh = container_of(pipe, struct uhci_qh, pipe);
+ u32 endp = GET_FLATPTR(qh->pipe.endp);
+ dprintf(7, "uhci_send_bulk qh=%p endp=%x dir=%d data=%p size=%d\n"
+ , qh, endp, dir, data, datasize);
+ int maxpacket = endp2maxsize(endp);
+ int lowspeed = endp2speed(endp);
+ int devaddr = endp2devaddr(endp) | (endp2ep(endp) << 7);
+ int toggle = (u32)GET_FLATPTR(qh->next_td); // XXX
+
+ // Allocate 4 tds on stack (16byte aligned)
+ u8 tdsbuf[sizeof(struct uhci_td) * STACKTDS + TDALIGN - 1];
+ struct uhci_td *tds = (void*)ALIGN((u32)tdsbuf, TDALIGN);
+ memset(tds, 0, sizeof(*tds) * STACKTDS);
+
+ // Enable tds
+ SET_FLATPTR(qh->element, (u32)MAKE_FLATPTR(GET_SEG(SS), tds));
+
+ int tdpos = 0;
+ while (datasize) {
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td);
+ if (ret)
+ goto fail;
+
+ int transfer = datasize;
+ if (transfer > maxpacket)
+ transfer = maxpacket;
+ struct uhci_td *nexttd_fl = MAKE_FLATPTR(GET_SEG(SS)
+ , &tds[tdpos % STACKTDS]);
+ td->link = (transfer==datasize ? UHCI_PTR_TERM : (u32)nexttd_fl);
+ td->token = (uhci_explen(transfer) | toggle
+ | (devaddr << TD_TOKEN_DEVADDR_SHIFT)
+ | (dir ? USB_PID_IN : USB_PID_OUT));
+ td->buffer = data;
+ barrier();
+ td->status = (uhci_maxerr(3) | (lowspeed ? TD_CTRL_LS : 0)
+ | TD_CTRL_ACTIVE);
+ toggle ^= TD_TOKEN_TOGGLE;
+
+ data += transfer;
+ datasize -= transfer;
+ }
+ int i;
+ for (i=0; i<STACKTDS; i++) {
+ struct uhci_td *td = &tds[tdpos++ % STACKTDS];
+ int ret = wait_td(td);
+ if (ret)
+ goto fail;
+ }
+
+ SET_FLATPTR(qh->next_td, (void*)toggle); // XXX
+ return 0;
+fail:
+ dprintf(1, "uhci_send_bulk failed\n");
+ SET_FLATPTR(qh->element, UHCI_PTR_TERM);
+ uhci_waittick();
+ return -1;
+}
+
+struct usb_pipe *
uhci_alloc_intr_pipe(u32 endp, int frameexp)
{
if (! CONFIG_USB_UHCI)
diff --git a/src/usb-uhci.h b/src/usb-uhci.h
index d9c10ae..d7ebb4e 100644
--- a/src/usb-uhci.h
+++ b/src/usb-uhci.h
@@ -8,6 +8,8 @@ struct usb_s;
void uhci_init(void *data);
int uhci_control(u32 endp, int dir, const void *cmd, int cmdsize
, void *data, int datasize);
+struct usb_pipe *uhci_alloc_bulk_pipe(u32 endp);
+int uhci_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
struct usb_pipe *uhci_alloc_intr_pipe(u32 endp, int frameexp);
int uhci_poll_intr(struct usb_pipe *pipe, void *data);
diff --git a/src/usb.c b/src/usb.c
index 1ed3c80..cc3b201 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -13,6 +13,7 @@
#include "usb-ohci.h" // ohci_init
#include "usb-hid.h" // usb_keyboard_setup
#include "usb-hub.h" // usb_hub_init
+#include "usb-msc.h" // usb_msc_init
#include "usb.h" // struct usb_s
#include "biosvar.h" // GET_GLOBAL
@@ -39,6 +40,33 @@ send_control(u32 endp, int dir, const void *cmd, int cmdsize
}
struct usb_pipe *
+alloc_bulk_pipe(u32 endp)
+{
+ struct usb_s *cntl = endp2cntl(endp);
+ switch (cntl->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_alloc_bulk_pipe(endp);
+ case USB_TYPE_OHCI:
+ return NULL;
+ }
+}
+
+int
+usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize)
+{
+ u32 endp = GET_FLATPTR(pipe->endp);
+ struct usb_s *cntl = endp2cntl(endp);
+ switch (cntl->type) {
+ default:
+ case USB_TYPE_UHCI:
+ return uhci_send_bulk(pipe, dir, data, datasize);
+ case USB_TYPE_OHCI:
+ return -1;
+ }
+}
+
+struct usb_pipe *
alloc_intr_pipe(u32 endp, int period)
{
struct usb_s *cntl = endp2cntl(endp);
@@ -220,6 +248,7 @@ configure_usb_device(struct usb_s *cntl, int lowspeed)
if ((iface->bInterfaceClass != USB_CLASS_HID
|| iface->bInterfaceSubClass != USB_INTERFACE_SUBCLASS_BOOT
|| iface->bInterfaceProtocol != USB_INTERFACE_PROTOCOL_KEYBOARD)
+ && (iface->bInterfaceClass != USB_CLASS_MASS_STORAGE)
&& (iface->bInterfaceClass != USB_CLASS_HUB))
// Not a supported device.
goto fail;
@@ -237,8 +266,11 @@ configure_usb_device(struct usb_s *cntl, int lowspeed)
free(config);
return usb_hub_init(endp);
}
- ret = usb_keyboard_init(endp, iface, ((void*)config + config->wTotalLength
- - (void*)iface));
+ int imax = (void*)config + config->wTotalLength - (void*)iface;
+ if (iface->bInterfaceClass == USB_CLASS_MASS_STORAGE)
+ ret = usb_msc_init(endp, iface, imax);
+ else
+ ret = usb_keyboard_init(endp, iface, imax);
if (ret)
goto fail;
diff --git a/src/usb.h b/src/usb.h
index 925f8ae..d947891 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -37,6 +37,8 @@ int configure_usb_device(struct usb_s *cntl, int lowspeed);
struct usb_ctrlrequest;
int send_default_control(u32 endp, const struct usb_ctrlrequest *req
, void *data);
+int usb_send_bulk(struct usb_pipe *pipe, int dir, void *data, int datasize);
+struct usb_pipe *alloc_bulk_pipe(u32 endp);
struct usb_pipe *alloc_intr_pipe(u32 endp, int period);
int usb_poll_intr(struct usb_pipe *pipe, void *data);
struct usb_interface_descriptor;