>From 7c1a8f06d797829da00b553c40e1bcf14365d22e Mon Sep 17 00:00:00 2001 From: Sven Schnelle Date: Sun, 10 Jun 2012 18:58:34 +0200 Subject: [PATCH] Support USB MSC devices with multiples LUNs To: seabios@seabios.org There are USB Mass storage devices which have more than one device. Examples are CD Changers, or USB sticks which are partitioned in a CDROM and Harddisk device. Signed-off-by: Sven Schnelle Signed-off-by: Kevin O'Connor --- src/boot.c | 6 ++-- src/boot.h | 2 +- src/usb-msc.c | 80 ++++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 63 insertions(+), 25 deletions(-) diff --git a/src/boot.c b/src/boot.c index 6949490..392c692 100644 --- a/src/boot.c +++ b/src/boot.c @@ -205,15 +205,15 @@ build_usb_path(char *buf, int max, struct usbhub_s *hub) return p; } -int bootprio_find_usb(struct usbdevice_s *usbdev) +int bootprio_find_usb(struct usbdevice_s *usbdev, int lun) { if (!CONFIG_BOOTORDER) return -1; - // Find usb - for example: /pci@i0cf8/usb@1,2/hub@1/network@0/ethernet@0 + // Find usb - for example: /pci@i0cf8/usb@1,2/storage@1/channel@0/disk@0,0 char desc[256], *p; p = build_pci_path(desc, sizeof(desc), "usb", usbdev->hub->cntl->pci); p = build_usb_path(p, desc+sizeof(desc)-p, usbdev->hub); - snprintf(p, desc+sizeof(desc)-p, "/*@%x", usbdev->port+1); + snprintf(p, desc+sizeof(desc)-p, "/*@%x/*@0/*@0,%d", usbdev->port+1, lun); return find_prio(desc); } diff --git a/src/boot.h b/src/boot.h index c7c34dc..afe9f2e 100644 --- a/src/boot.h +++ b/src/boot.h @@ -20,6 +20,6 @@ int bootprio_find_fdc_device(struct pci_device *pci, int port, int fdid); int bootprio_find_pci_rom(struct pci_device *pci, int instance); int bootprio_find_named_rom(const char *name, int instance); struct usbdevice_s; -int bootprio_find_usb(struct usbdevice_s *usbdev); +int bootprio_find_usb(struct usbdevice_s *usbdev, int lun); #endif // __BOOT_H diff --git a/src/usb-msc.c b/src/usb-msc.c index c53a1f5..46737c0 100644 --- a/src/usb-msc.c +++ b/src/usb-msc.c @@ -16,6 +16,7 @@ struct usbdrive_s { struct drive_s drive; struct usb_pipe *bulkin, *bulkout; + int lun; }; @@ -78,7 +79,7 @@ usb_cmd_data(struct disk_op_s *op, void *cdbcmd, u16 blocksize) cbw.dCBWTag = 999; // XXX cbw.dCBWDataTransferLength = bytes; cbw.bmCBWFlags = cdb_is_read(cdbcmd, blocksize) ? USB_DIR_IN : USB_DIR_OUT; - cbw.bCBWLUN = 0; // XXX + cbw.bCBWLUN = GET_GLOBAL(udrive_g->lun); cbw.bCBWCBLength = USB_CDB_SIZE; // Transfer cbw to device. @@ -117,6 +118,48 @@ fail: return DISK_RET_EBADTRACK; } +static int +usb_msc_maxlun(struct usb_pipe *pipe) +{ + struct usb_ctrlrequest req; + req.bRequestType = USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; + req.bRequest = 0xfe; + req.wValue = 0; + req.wIndex = 0; + req.wLength = 1; + unsigned char maxlun; + int ret = send_default_control(pipe, &req, &maxlun); + if (ret) + return 0; + return maxlun; +} + +static int +usb_msc_init_lun(struct usb_pipe *inpipe, struct usb_pipe *outpipe, + struct usbdevice_s *usbdev, int lun) +{ + // Allocate drive structure. + struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g)); + if (!udrive_g) { + warn_noalloc(); + return -1; + } + memset(udrive_g, 0, sizeof(*udrive_g)); + udrive_g->drive.type = DTYPE_USB; + udrive_g->lun = lun; + + udrive_g->bulkin = inpipe; + udrive_g->bulkout = outpipe; + + int ret = scsi_init_drive(&udrive_g->drive, "USB MSC" + , bootprio_find_usb(usbdev, lun)); + if (ret) { + dprintf(1, "Unable to configure USB MSC drive.\n"); + free(udrive_g); + return -1; + } + return 0; +} /**************************************************************** * Setup @@ -140,39 +183,34 @@ usb_msc_init(struct usbdevice_s *usbdev) return -1; } - // Allocate drive structure. - struct usbdrive_s *udrive_g = malloc_fseg(sizeof(*udrive_g)); - if (!udrive_g) { - warn_noalloc(); - goto fail; - } - memset(udrive_g, 0, sizeof(*udrive_g)); - udrive_g->drive.type = DTYPE_USB; - // Find bulk in and bulk out endpoints. struct usb_endpoint_descriptor *indesc = findEndPointDesc( usbdev, USB_ENDPOINT_XFER_BULK, USB_DIR_IN); struct usb_endpoint_descriptor *outdesc = findEndPointDesc( usbdev, USB_ENDPOINT_XFER_BULK, USB_DIR_OUT); + struct usb_pipe *inpipe = NULL, *outpipe = NULL; if (!indesc || !outdesc) goto fail; - udrive_g->bulkin = usb_alloc_pipe(usbdev, indesc); - udrive_g->bulkout = usb_alloc_pipe(usbdev, outdesc); - if (!udrive_g->bulkin || !udrive_g->bulkout) + inpipe = usb_alloc_pipe(usbdev, indesc); + outpipe = usb_alloc_pipe(usbdev, outdesc); + if (!inpipe || !outpipe) goto fail; - int prio = bootprio_find_usb(usbdev); - int ret = scsi_init_drive(&udrive_g->drive, "USB MSC", prio); - if (ret) + int maxlun = usb_msc_maxlun(usbdev->defpipe); + int lun, pipesused = 0; + for (lun = 0; lun < maxlun + 1; lun++) { + int ret = usb_msc_init_lun(inpipe, outpipe, usbdev, lun); + if (!ret) + pipesused = 1; + } + + if (!pipesused) goto fail; return 0; fail: dprintf(1, "Unable to configure USB MSC device.\n"); - if (udrive_g) { - free_pipe(udrive_g->bulkin); - free_pipe(udrive_g->bulkout); - free(udrive_g); - } + free_pipe(inpipe); + free_pipe(outpipe); return -1; } -- 1.7.6.5