X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=usb%2Fdrivers%2Fclass%2Fstorage.c;h=ce3ceadc54abe136252bcceaf61ca59b049cb03c;hb=HEAD;hp=ff503f712f001bfde4fc3a4bf5c7552c88b9b13b;hpb=7bff2456c919b94efa534efd15dec289314a682e;p=ppcskel.git diff --git a/usb/drivers/class/storage.c b/usb/drivers/class/storage.c index ff503f7..ce3cead 100644 --- a/usb/drivers/class/storage.c +++ b/usb/drivers/class/storage.c @@ -1,9 +1,11 @@ /* + * storage.c -- Bulk-only USB mass storage support + * * Copyright (c) 2007, Benedikt Sauter + * Copyright (C) 2008, Sven Peter (svpe) + * Copyright (C) 2010, Bernhard Urban * All rights reserved. * - * Short descripton of file: - * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -32,13 +34,12 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -//#include -//#include - #include "../../core/core.h" #include "../../core/usb.h" #include "../../usbspec/usb11spec.h" #include "../../../malloc.h" +#include "../../../string.h" +#include "../../../irq.h" #include "storage.h" @@ -48,180 +49,925 @@ void usb_storage_probe(); void usb_storage_check(); -usb_device * massstorage[MAX_DEVICES]; +struct usb_device *massstorage[MAX_DEVICES]; u16 sectorsize[MAX_DEVICES]; u8 massstorage_in_use; -usb_driver storage = { - .name = "storage", - .probe = usb_storage_probe, - .check = usb_storage_check, - .data = NULL +struct usb_driver storage = { + .name = "storage", + .probe = usb_storage_probe, + .check = usb_storage_check, + .data = NULL }; void usb_storage_init() { - massstorage_in_use = 0; - usb_register_driver(&storage); + massstorage_in_use = 0; + usb_register_driver(&storage); } void usb_storage_probe() { - // schaue ob aktuell enumeriertes geraet ein storage ist - #if DEBUG - core.stdout("Probe: Storage\r\n"); - #endif + // schaue ob aktuell enumeriertes geraet ein storage ist + #if DEBUG + core.stdout("Probe: Storage\r\n"); + #endif - /* read interface descriptor for class code */ - char buf[32]; - - usb_device* dev; - element * iterator = core.devices->head; - - while(iterator != NULL) { - dev = (usb_device*)iterator->data; + /* read interface descriptor for class code */ + u8 buf[32]; + + struct usb_device* dev; + struct element * iterator = core.devices->head; + + while(iterator != NULL) { + dev = (struct usb_device*)iterator->data; + + /* get interface descriptor */ + usb_control_msg(dev, 0x80, GET_DESCRIPTOR,2, 0, 32, buf, 0); + + if(buf[14]==MASS_STORAGE_CLASSCODE){ + massstorage[massstorage_in_use] = dev; + massstorage_in_use++; + #if DEBUG + core.stdout("Storage: Found Storage Device\r\n"); + #endif + + /* here is only my lib driver test */ + usb_storage_open(0); + usb_storage_inquiry(0); + usb_storage_read_capacity(0); + + //char * buf = (char*)malloc(512); + //free(buf); + //char buf[512]; + //usb_storage_read_sector(0,1,buf); + + /* end of driver test */ + } + + iterator=iterator->next; + } +} - /* get interface descriptor */ - usb_control_msg(dev, 0x80, GET_DESCRIPTOR,2, 0, 32,buf, 8, 0); - if(buf[14]==MASS_STORAGE_CLASSCODE){ - massstorage[massstorage_in_use] = dev; - massstorage_in_use++; - #if DEBUG - core.stdout("Storage: Found Storage Device\r\n"); - #endif +void usb_storage_check() +{ + // wird periodisch augerufen + // da ein mass storage aber keinen interrupt oder isochronen endpunkt + // hat passiert hier nichts +} - /* here is only my lib driver test */ - usb_storage_open(0); - usb_storage_inquiry(0); - usb_storage_read_capacity(0); - //char * buf = (char*)malloc(512); - //free(buf); - //char buf[512]; - //usb_storage_read_sector(0,1,buf); - /* end of driver test */ - } +u8 usb_storage_inquiry(u8 device) +{ + /* send cwb "usbc" */ + + usb_storage_cbw *cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw)); + cbw->dCBWSignature= 0x43425355; + cbw->dCBWTag=0x826A6008; + cbw->dCBWDataTransferLength=0x00000024; + cbw->bCWDFlags=0x80; + cbw->bCBWLun=0x00; + cbw->bCBWCBLength=0x01; - iterator=iterator->next; - } + u8 i; + for(i=0;i<16;i++) + cbw->CBWCB[i]=0x00; + + cbw->CBWCB[0]=0x12; // 0x12 = INQUIRY + + usb_bulk_write(massstorage[device], 2, (u8*)cbw, 31, 0); + usb_bulk_read(massstorage[device], 1, (u8*)cbw, 36, 0); + usb_bulk_read(massstorage[device], 1, (u8*)cbw, 13, 0); + + free(cbw); + + return 0; } -void usb_storage_check() +u8 usb_storage_read_capacity(u8 device) +{ + /* send cwb "usbc" */ + + u8 tmp[8]; + u8 i; + usb_storage_cbw * cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw)); + + usb_control_msg(massstorage[device], 0x02,1,0, 0x8100, 0,tmp, 0); + + cbw->dCBWSignature= 0x43425355; + cbw->dCBWTag=0x826A6008; + cbw->dCBWDataTransferLength=0x00000008; + cbw->bCWDFlags=0x80; + cbw->bCBWLun=0x00; + cbw->bCBWCBLength=0x0A; + + for(i=0;i<16;i++) + cbw->CBWCB[i]=0x00; + + cbw->CBWCB[0]=0x25; // 0x12 = INQUIRY + + usb_bulk_write(massstorage[device], 2, (u8*)cbw, 31, 0); + usb_bulk_read(massstorage[device], 1, (u8*)cbw, 8, 0); + usb_bulk_read(massstorage[device], 1, (u8*)cbw, 13, 0); + + free(cbw); + + return 0; +} + + +u8 usb_storage_read_sector(u8 device, u32 sector, char * buf) +{ + /* send cwb "usbc" */ + u8 tmpbuf[] = {0x55,0x53,0x42,0x43,0x08, + 0xE0,0x63,0x82,0x00,0x02, + 0x00,0x00,0x80,0x00,0x0A, + 0x28,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x01,0x00, + 0x00,0x00,0x00,0x00,0x00, + 0x00, + 0x00,0x00,0x00,0x00,0x00}; + + usb_bulk_write(massstorage[device], 2, tmpbuf, 31, 0); + //usb_bulk_read(massstorage[device], 1, buf,64,0); + //usb_bulk_read(massstorage[device], 1, buf, 13, 0); + + + return 0; +} + + +u8 usb_storage_write_sector(u8 device, u32 sector, char * buf) { - // wird periodisch augerufen - // da ein mass storage aber keinen interrupt oder isochronen endpunkt - // hat passiert hier nichts + + return 0; } +#define TAG_START 0x0BADC0DE + +#define CBW_SIZE 31 +#define CBW_SIGNATURE 0x43425355 +#define CBW_IN (1 << 7) +#define CBW_OUT 0 + +#define CSW_SIZE 13 +#define CSW_SIGNATURE 0x53425355 + +#define SCSI_TEST_UNIT_READY 0x00 +#define SCSI_REQUEST_SENSE 0x03 +#define SCSI_READ_CAPACITY 0x25 +#define SCSI_READ_10 0x28 +#define SCSI_WRITE_10 0x2A + +#define SCSI_SENSE_REPLY_SIZE 18 +#define SCSI_SENSE_NOT_READY 0x02 +#define SCSI_SENSE_MEDIUM_ERROR 0x03 +#define SCSI_SENSE_HARDWARE_ERROR 0x04 + +#define USB_CLASS_MASS_STORAGE 0x08 +#define MASS_STORAGE_SCSI_COMMANDS 0x06 +#define MASS_STORAGE_BULK_ONLY 0x50 + +#define USBSTORAGE_GET_MAX_LUN 0xFE +#define USBSTORAGE_RESET 0xFF + +#define USB_ENDPOINT_BULK 0x02 +#define USBSTORAGE_CYCLE_RETRIES 3 -/** - * open connection to an storage device +#define MAX_TRANSFER_SIZE 4096 + +#define DEVLIST_MAXSIZE 8 + +/* +The following is for implementing a DISC_INTERFACE +as used by libfat +*/ + +static usbstorage_handle __usbfd; +static u8 __lun = 0; +static u8 __mounted = 0; +static u16 __vid = 0; +static u16 __pid = 0; + +static s32 __usbstorage_reset(usbstorage_handle *dev); +static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun); + +/* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout + * but there's currently no other known way of doing this and it's in my humble + * opinion still better than having a function blocking forever while waiting + * for the USB data/IOS reply.. */ -u8 usb_storage_open(u8 device) + +static s32 __usb_deviceremoved_cb(s32 retval,void *arg) { - /* set configuration */ - char tmp[8]; - usb_control_msg(massstorage[device], 0x00,SET_CONFIGURATION,0x0100, 0, 0,tmp, 8, 0); + return 0; +} +static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData) +{ + s32 retval; - /* class request */ - usb_control_msg(massstorage[device], 0xA1,0xFE,0, 0, 1,tmp, 8, 0); + dev->retval = USBSTORAGE_PROCESSING; + retval = USB_WriteBlkMsgAsync(dev->usb_fd, bEndpoint, wLength, rpData, (void *)dev); + dev->retval = retval; - /* wait until the stick is complete ready */ - wait_ms(10); - - //FIXME and all other return values!!! - return 1; + if(retval==USBSTORAGE_ETIMEDOUT) + USBStorage_Close(dev); + return retval; } -u8 usb_storage_inquiry(u8 device) +static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData) +{ + s32 retval; + + dev->retval = USBSTORAGE_PROCESSING; + retval = USB_WriteCtrlMsgAsync(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData, (void *)dev); + dev->retval = retval; + + if(retval==USBSTORAGE_ETIMEDOUT) + USBStorage_Close(dev); + return retval; +} + +s32 USBStorage_Initialize() +{ + return 0; +} + +static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen) +{ + s32 retval = USBSTORAGE_OK; + + if(cbLen == 0 || cbLen > 16) + return -1; + + memset(dev->buffer, 0, CBW_SIZE); + + __stwbrx(dev->buffer, 0, CBW_SIGNATURE); + __stwbrx(dev->buffer, 4, dev->tag); + __stwbrx(dev->buffer, 8, len); + dev->buffer[12] = flags; + dev->buffer[13] = lun; + dev->buffer[14] = (cbLen > 6 ? 0x10 : 6); + + memcpy(dev->buffer + 15, cb, cbLen); + + if(dev->suspended == 1) + { + USB_ResumeDevice(dev->usb_fd); + dev->suspended = 0; + } + + retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer); + + if(retval == CBW_SIZE) return USBSTORAGE_OK; + else if(retval > 0) return USBSTORAGE_ESHORTWRITE; + + return retval; +} + +static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue) { - /* send cwb "usbc" */ - - usb_storage_cbw *cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw)); - cbw->dCBWSignature= 0x43425355; - cbw->dCBWTag=0x826A6008; - cbw->dCBWDataTransferLength=0x00000024; - cbw->bCWDFlags=0x80; - cbw->bCBWLun=0x00; - cbw->bCBWCBLength=0x01; + s32 retval = USBSTORAGE_OK; + u32 signature, tag, _dataResidue, _status; - u8 i; - for(i=0;i<16;i++) - cbw->CBWCB[i]=0x00; + memset(dev->buffer, 0, CSW_SIZE); - cbw->CBWCB[0]=0x12; // 0x12 = INQUIRY + retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer); + if(retval > 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD; + else if(retval < 0) return retval; - usb_bulk_write(massstorage[device], 2, (char*)cbw, 31, 0); - usb_bulk_read(massstorage[device], 1, (char*)cbw, 36, 0); - usb_bulk_read(massstorage[device], 1, (char*)cbw, 13, 0); + signature = __lwbrx(dev->buffer, 0); + tag = __lwbrx(dev->buffer, 4); + _dataResidue = __lwbrx(dev->buffer, 8); + _status = dev->buffer[12]; - free(cbw); + if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE; - return 0; + if(dataResidue != NULL) + *dataResidue = _dataResidue; + if(status != NULL) + *status = _status; + + if(tag != dev->tag) return USBSTORAGE_ETAG; + dev->tag++; + + return USBSTORAGE_OK; } +static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue) +{ + s32 retval = USBSTORAGE_OK; + + u8 status = 0; + u32 dataResidue = 0; + u32 thisLen; + + s8 retries = USBSTORAGE_CYCLE_RETRIES + 1; + + do + { + retries--; + + if(retval == USBSTORAGE_ETIMEDOUT) + break; + + if(write) + { + retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen); + if(retval == USBSTORAGE_ETIMEDOUT) + break; + if(retval < 0) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + continue; + } + while(len > 0) + { + thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len; + memset(dev->buffer, 0, MAX_TRANSFER_SIZE); + memcpy(dev->buffer, buffer, thisLen); + retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, dev->buffer); + + if(retval == USBSTORAGE_ETIMEDOUT) + break; + + if(retval < 0) + { + retval = USBSTORAGE_EDATARESIDUE; + break; + } + + + if(retval != thisLen && len > 0) + { + retval = USBSTORAGE_EDATARESIDUE; + break; + } + len -= retval; + buffer += retval; + } + + if(retval < 0) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + continue; + } + } + else + { + retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen); + + if(retval == USBSTORAGE_ETIMEDOUT) + break; + + if(retval < 0) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + continue; + } + while(len > 0) + { + thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len; + retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, dev->buffer); + if(retval < 0) + break; + + memcpy(buffer, dev->buffer, retval); + len -= retval; + buffer += retval; + + if(retval != thisLen) + break; + } + + if(retval < 0) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + continue; + } + } + + retval = __read_csw(dev, &status, &dataResidue); + + if(retval == USBSTORAGE_ETIMEDOUT) + break; + + if(retval < 0) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + continue; + } + + retval = USBSTORAGE_OK; + } while(retval < 0 && retries > 0); + + if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT) + { + if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT) + retval = USBSTORAGE_ETIMEDOUT; + } + + + if(_status != NULL) + *_status = status; + if(_dataResidue != NULL) + *_dataResidue = dataResidue; + + return retval; +} -u8 usb_storage_read_capacity(u8 device) +static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun) { - /* send cwb "usbc" */ + s32 retval; + u8 cmd[16]; + u8 sense[SCSI_SENSE_REPLY_SIZE]; + u8 status = 0; + + memset(cmd, 0, sizeof(cmd)); + cmd[0] = SCSI_TEST_UNIT_READY; + + retval = __cycle(dev, lun, NULL, 0, cmd, 1, 0, &status, NULL); + if(retval < 0) return retval; + + if(status != 0) + { + cmd[0] = SCSI_REQUEST_SENSE; + cmd[1] = lun << 5; + cmd[4] = SCSI_SENSE_REPLY_SIZE; + cmd[5] = 0; + memset(sense, 0, SCSI_SENSE_REPLY_SIZE); + retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL); + if(retval < 0) return retval; + + status = sense[2] & 0x0F; + if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR) return USBSTORAGE_ESENSE; + } + + return retval; +} - char tmp[8]; - u8 i; - usb_storage_cbw * cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw)); +static s32 __usbstorage_reset(usbstorage_handle *dev) +{ + s32 retval; + + if(dev->suspended == 1) + { + USB_ResumeDevice(dev->usb_fd); + dev->suspended = 0; + } + + /* control message request type bitmask */ +#define USB_CTRLTYPE_DIR_HOST2DEVICE (0<<7) +#define USB_CTRLTYPE_DIR_DEVICE2HOST (1<<7) +#define USB_CTRLTYPE_TYPE_STANDARD (0<<5) +#define USB_CTRLTYPE_TYPE_CLASS (1<<5) +#define USB_CTRLTYPE_TYPE_VENDOR (2<<5) +#define USB_CTRLTYPE_TYPE_RESERVED (3<<5) +#define USB_CTRLTYPE_REC_DEVICE 0 +#define USB_CTRLTYPE_REC_INTERFACE 1 +#define USB_CTRLTYPE_REC_ENDPOINT 2 +#define USB_CTRLTYPE_REC_OTHER 3 + retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL); + + /* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */ + if(retval < 0 && retval != -7004) + goto end; + + /* gives device enough time to process the reset */ + usleep(60); + + retval = USB_ClearHalt(dev->usb_fd, dev->ep_in); + if(retval < 0) + goto end; + retval = USB_ClearHalt(dev->usb_fd, dev->ep_out); + +end: + return retval; +} - usb_control_msg(massstorage[device], 0x02,1,0, 0x8100, 0,tmp, 8, 0); // +s32 USBStorage_Open(usbstorage_handle *dev, const char *bus, u16 vid, u16 pid) +{ + s32 retval = -1; + u8 conf,*max_lun = NULL; + u32 iConf, iInterface, iEp; + usb_devdesc udd; + usb_configurationdesc *ucd; + usb_interfacedesc *uid; + usb_endpointdesc *ued; + + max_lun = malloc(1); + if(max_lun==NULL) return IPC_ENOMEM; + + memset(dev, 0, sizeof(*dev)); + + dev->tag = TAG_START; + + retval = USB_OpenDevice(bus, vid, pid, &dev->usb_fd); + if(retval < 0) + goto free_and_return; + + retval = USB_GetDescriptors(dev->usb_fd, &udd); + if(retval < 0) + goto free_and_return; + + for(iConf = 0; iConf < udd.bNumConfigurations; iConf++) + { + ucd = &udd.configurations[iConf]; + for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++) + { + uid = &ucd->interfaces[iInterface]; + if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE && + uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS && + uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY) + { + if(uid->bNumEndpoints < 2) + continue; + + dev->ep_in = dev->ep_out = 0; + for(iEp = 0; iEp < uid->bNumEndpoints; iEp++) + { + ued = &uid->endpoints[iEp]; + if(ued->bmAttributes != USB_ENDPOINT_BULK) + continue; + + if(ued->bEndpointAddress & USB_ENDPOINT_IN) + dev->ep_in = ued->bEndpointAddress; + else + dev->ep_out = ued->bEndpointAddress; + } + if(dev->ep_in != 0 && dev->ep_out != 0) + { + dev->configuration = ucd->bConfigurationValue; + dev->interface = uid->bInterfaceNumber; + dev->altInterface = uid->bAlternateSetting; + goto found; + } + } + } + } + + USB_FreeDescriptors(&udd); + retval = USBSTORAGE_ENOINTERFACE; + goto free_and_return; + +found: + USB_FreeDescriptors(&udd); + + retval = USBSTORAGE_EINIT; + if(USB_GetConfiguration(dev->usb_fd, &conf) < 0) + goto free_and_return; + if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0) + goto free_and_return; + if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0) + goto free_and_return; + dev->suspended = 0; + + retval = USBStorage_Reset(dev); + if(retval < 0) + goto free_and_return; + + retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_DEVICE2HOST | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_GET_MAX_LUN, 0, dev->interface, 1, max_lun); + if(retval < 0) + dev->max_lun = 1; + else + dev->max_lun = *max_lun; + + + if(retval == USBSTORAGE_ETIMEDOUT) + goto free_and_return; + + retval = USBSTORAGE_OK; + dev->sector_size = (u32 *)calloc(dev->max_lun, sizeof(u32)); + if(dev->sector_size == NULL) + { + retval = IPC_ENOMEM; + goto free_and_return; + } + + if(dev->max_lun == 0) + dev->max_lun++; + + /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */ + /* + * Some devices (i.e. Iomega Zip100) need this -- apparently + * the bulk pipes get STALLed when the GetMaxLUN request is + * processed. This is, in theory, harmless to all other devices + * (regardless of if they stall or not). + */ + USB_ClearHalt(dev->usb_fd, dev->ep_in); + USB_ClearHalt(dev->usb_fd, dev->ep_out); + + dev->buffer = malloc(MAX_TRANSFER_SIZE); + + if(dev->buffer == NULL) retval = IPC_ENOMEM; + else { + USB_DeviceRemovalNotifyAsync(dev->usb_fd,__usb_deviceremoved_cb,dev); + retval = USBSTORAGE_OK; + } + +free_and_return: + if(max_lun!=NULL) free(max_lun); + if(retval < 0) + { + USB_CloseDevice(&dev->usb_fd); + if(dev->buffer != NULL) + free(dev->buffer); + if(dev->sector_size != NULL) + free(dev->sector_size); + memset(dev, 0, sizeof(*dev)); + return retval; + } + return 0; +} + +s32 USBStorage_Close(usbstorage_handle *dev) +{ + USB_CloseDevice(&dev->usb_fd); + if(dev->sector_size!=NULL) + free(dev->sector_size); + if(dev->buffer!=NULL) + free(dev->buffer); + memset(dev, 0, sizeof(*dev)); + return 0; +} + +s32 USBStorage_Reset(usbstorage_handle *dev) +{ + s32 retval; + + retval = __usbstorage_reset(dev); - cbw->dCBWSignature= 0x43425355; - cbw->dCBWTag=0x826A6008; - cbw->dCBWDataTransferLength=0x00000008; - cbw->bCWDFlags=0x80; - cbw->bCBWLun=0x00; - cbw->bCBWCBLength=0x0A; + return retval; +} - for(i=0;i<16;i++) - cbw->CBWCB[i]=0x00; +s32 USBStorage_GetMaxLUN(usbstorage_handle *dev) +{ + return dev->max_lun; +} - cbw->CBWCB[0]=0x25; // 0x12 = INQUIRY +s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun) +{ + s32 retval; - usb_bulk_write(massstorage[device], 2, (char*)cbw, 31, 0); - usb_bulk_read(massstorage[device], 1, (char*)cbw, 8, 0); - usb_bulk_read(massstorage[device], 1, (char*)cbw, 13, 0); + if(lun >= dev->max_lun) + return IPC_EINVAL; - free(cbw); + retval = __usbstorage_clearerrors(dev, lun); + if(retval < 0) + return retval; - return 0; + retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], NULL); + return retval; } +s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors) +{ + s32 retval; + u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5}; + u8 response[8]; + + retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL); + if(retval >= 0) + { + if(n_sectors != NULL) + memcpy(n_sectors, response, 4); + if(sector_size != NULL) + memcpy(sector_size, response + 4, 4); + retval = USBSTORAGE_OK; + } + + return retval; +} -u8 usb_storage_read_sector(u8 device, u32 sector, char * buf) +s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer) { - /* send cwb "usbc" */ - char tmpbuf[] = {0x55,0x53,0x42,0x43,0x08, - 0xE0,0x63,0x82,0x00,0x02, - 0x00,0x00,0x80,0x00,0x0A, - 0x28,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x01,0x00, - 0x00,0x00,0x00,0x00,0x00, - 0x00, - 0x00,0x00,0x00,0x00,0x00}; + u8 status = 0; + s32 retval; + u8 cmd[] = { + SCSI_READ_10, + lun << 5, + sector >> 24, + sector >> 16, + sector >> 8, + sector, + 0, + n_sectors >> 8, + n_sectors, + 0 + }; + if(lun >= dev->max_lun || dev->sector_size[lun] == 0) + return IPC_EINVAL; + retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL); + if(retval > 0 && status != 0) + retval = USBSTORAGE_ESTATUS; + return retval; +} - usb_bulk_write(massstorage[device], 2, tmpbuf, 31, 0); - //usb_bulk_read(massstorage[device], 1, buf,64,0); - //usb_bulk_read(massstorage[device], 1, buf, 13, 0); +s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer) +{ + u8 status = 0; + s32 retval; + u8 cmd[] = { + SCSI_WRITE_10, + lun << 5, + sector >> 24, + sector >> 16, + sector >> 8, + sector, + 0, + n_sectors >> 8, + n_sectors, + 0 + }; + if(lun >= dev->max_lun || dev->sector_size[lun] == 0) + return IPC_EINVAL; + retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL); + if(retval > 0 && status != 0) + retval = USBSTORAGE_ESTATUS; + return retval; +} + +s32 USBStorage_Suspend(usbstorage_handle *dev) +{ + if(dev->suspended == 1) + return USBSTORAGE_OK; + + USB_SuspendDevice(dev->usb_fd); + dev->suspended = 1; + + return USBSTORAGE_OK; - - return 0; } +/* +The following is for implementing a DISC_INTERFACE +as used by libfat +*/ -u8 usb_storage_write_sector(u8 device, u32 sector, char * buf) +static BOOL __usbstorage_IsInserted(void); + +static BOOL __usbstorage_Startup(void) { + USB_Initialize(); + USBStorage_Initialize(); + return __usbstorage_IsInserted(); +} - return 0; +static BOOL __usbstorage_IsInserted(void) +{ + u8 *buffer; + u8 dummy; + u8 i, j; + u16 vid, pid; + s32 maxLun; + s32 retval; + + __mounted = 0; //reset it here and check if device is still attached + + buffer = malloc(DEVLIST_MAXSIZE << 3); + if(buffer == NULL) + return FALSE; + memset(buffer, 0, DEVLIST_MAXSIZE << 3); + + if(USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0) + { + if(__vid!=0 || __pid!=0) USBStorage_Close(&__usbfd); + memset(&__usbfd, 0, sizeof(__usbfd)); + __lun = 0; + __vid = 0; + __pid = 0; + + free(buffer); + return FALSE; + } + + if(__vid!=0 || __pid!=0) + { + for(i = 0; i < DEVLIST_MAXSIZE; i++) + { + memcpy(&vid, (buffer + (i << 3) + 4), 2); + memcpy(&pid, (buffer + (i << 3) + 6), 2); + if(vid != 0 || pid != 0) + { + + if( (vid == __vid) && (pid == __pid)) + { + __mounted = 1; + free(buffer); + usleep(50); // I don't know why I have to wait but it's needed + return TRUE; + } + } + } + USBStorage_Close(&__usbfd); + } + + memset(&__usbfd, 0, sizeof(__usbfd)); + __lun = 0; + __vid = 0; + __pid = 0; + + for(i = 0; i < DEVLIST_MAXSIZE; i++) + { + memcpy(&vid, (buffer + (i << 3) + 4), 2); + memcpy(&pid, (buffer + (i << 3) + 6), 2); + if(vid == 0 || pid == 0) + continue; + + if(USBStorage_Open(&__usbfd, "oh0", vid, pid) < 0) + continue; + + maxLun = USBStorage_GetMaxLUN(&__usbfd); + for(j = 0; j < maxLun; j++) + { + retval = USBStorage_MountLUN(&__usbfd, j); + if(retval == USBSTORAGE_ETIMEDOUT) + { + break; + } + + if(retval < 0) + continue; + + __mounted = 1; + __lun = j; + __vid = vid; + __pid = pid; + i = DEVLIST_MAXSIZE; + break; + } + } + free(buffer); + if(__mounted == 1) + return TRUE; + return FALSE; +} + +static BOOL __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer) +{ + s32 retval; + + if(__mounted != 1) + return FALSE; + + retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer); + if(retval == USBSTORAGE_ETIMEDOUT) + { + __mounted = 0; + } + if(retval < 0) + return FALSE; + return TRUE; +} + +static BOOL __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer) +{ + s32 retval; + + if(__mounted != 1) + return FALSE; + + retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer); + if(retval == USBSTORAGE_ETIMEDOUT) + { + __mounted = 0; + } + if(retval < 0) + return FALSE; + return TRUE; +} + +static BOOL __usbstorage_ClearStatus(void) +{ + return TRUE; +} + +static BOOL __usbstorage_Shutdown(void) +{ + //if(__mounted == 1) USBStorage_Close(&__usbfd); + __mounted = 0; + return TRUE; } + +const DISC_INTERFACE __io_usbstorage = { + DEVICE_TYPE_WII_USB, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB, + (FN_MEDIUM_STARTUP)&__usbstorage_Startup, + (FN_MEDIUM_ISINSERTED)&__usbstorage_IsInserted, + (FN_MEDIUM_READSECTORS)&__usbstorage_ReadSectors, + (FN_MEDIUM_WRITESECTORS)&__usbstorage_WriteSectors, + (FN_MEDIUM_CLEARSTATUS)&__usbstorage_ClearStatus, + (FN_MEDIUM_SHUTDOWN)&__usbstorage_Shutdown +}; +