/* * 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. * * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * Neither the name of the FH Augsburg nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "../../core/core.h" #include "../../core/usb.h" #include "../../usbspec/usb11spec.h" #include "../../../malloc.h" #include "../../../string.h" #include "../../../irq.h" #include "storage.h" #define MAX_DEVICES 2 void usb_storage_probe(); void usb_storage_check(); struct usb_device *massstorage[MAX_DEVICES]; u16 sectorsize[MAX_DEVICES]; u8 massstorage_in_use; 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); } void usb_storage_probe() { // schaue ob aktuell enumeriertes geraet ein storage ist #if DEBUG core.stdout("Probe: Storage\r\n"); #endif /* 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; } } void usb_storage_check() { // wird periodisch augerufen // da ein mass storage aber keinen interrupt oder isochronen endpunkt // hat passiert hier nichts } 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; 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; } 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) { 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 #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.. */ static s32 __usb_deviceremoved_cb(s32 retval,void *arg) { return 0; } static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData) { s32 retval; dev->retval = USBSTORAGE_PROCESSING; retval = USB_WriteBlkMsgAsync(dev->usb_fd, bEndpoint, wLength, rpData, (void *)dev); dev->retval = retval; if(retval==USBSTORAGE_ETIMEDOUT) USBStorage_Close(dev); return retval; } 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) { s32 retval = USBSTORAGE_OK; u32 signature, tag, _dataResidue, _status; memset(dev->buffer, 0, CSW_SIZE); 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; signature = __lwbrx(dev->buffer, 0); tag = __lwbrx(dev->buffer, 4); _dataResidue = __lwbrx(dev->buffer, 8); _status = dev->buffer[12]; if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE; 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; } static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun) { 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; } 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; } 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); return retval; } s32 USBStorage_GetMaxLUN(usbstorage_handle *dev) { return dev->max_lun; } s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun) { s32 retval; if(lun >= dev->max_lun) return IPC_EINVAL; retval = __usbstorage_clearerrors(dev, lun); if(retval < 0) return retval; 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; } s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer) { 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; } 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; } /* The following is for implementing a DISC_INTERFACE as used by libfat */ static BOOL __usbstorage_IsInserted(void); static BOOL __usbstorage_Startup(void) { USB_Initialize(); USBStorage_Initialize(); return __usbstorage_IsInserted(); } 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 };