1 /*-------------------------------------------------------------
3 usbstorage.c -- Bulk-only USB mass storage support
6 Sven Peter (svpe) <svpe@gmx.net>
8 This software is provided 'as-is', without any express or implied
9 warranty. In no event will the authors be held liable for any
10 damages arising from the use of this software.
12 Permission is granted to anyone to use this software for any
13 purpose, including commercial applications, and to alter it and
14 redistribute it freely, subject to the following restrictions:
16 1. The origin of this software must not be misrepresented; you
17 must not claim that you wrote the original software. If you use
18 this software in a product, an acknowledgment in the product
19 documentation would be appreciated but is not required.
21 2. Altered source versions must be plainly marked as such, and
22 must not be misrepresented as being the original software.
24 3. This notice may not be removed or altered from any source
27 -------------------------------------------------------------*/
40 #include "processor.h"
43 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
45 #define HEAP_SIZE (32*1024)
46 #define TAG_START 0x0BADC0DE
49 #define CBW_SIGNATURE 0x43425355
50 #define CBW_IN (1 << 7)
54 #define CSW_SIGNATURE 0x53425355
56 #define SCSI_TEST_UNIT_READY 0x00
57 #define SCSI_REQUEST_SENSE 0x03
58 #define SCSI_READ_CAPACITY 0x25
59 #define SCSI_READ_10 0x28
60 #define SCSI_WRITE_10 0x2A
62 #define SCSI_SENSE_REPLY_SIZE 18
63 #define SCSI_SENSE_NOT_READY 0x02
64 #define SCSI_SENSE_MEDIUM_ERROR 0x03
65 #define SCSI_SENSE_HARDWARE_ERROR 0x04
67 #define USB_CLASS_MASS_STORAGE 0x08
68 #define MASS_STORAGE_SCSI_COMMANDS 0x06
69 #define MASS_STORAGE_BULK_ONLY 0x50
71 #define USBSTORAGE_GET_MAX_LUN 0xFE
72 #define USBSTORAGE_RESET 0xFF
74 #define USB_ENDPOINT_BULK 0x02
76 #define USBSTORAGE_CYCLE_RETRIES 3
78 #define MAX_TRANSFER_SIZE 4096
80 #define DEVLIST_MAXSIZE 8
82 static heap_cntrl __heap
;
83 static u8 __heap_created
= 0;
84 static lwpq_t __usbstorage_waitq
= 0;
87 The following is for implementing a DISC_INTERFACE
91 static usbstorage_handle __usbfd
;
93 static u8 __mounted
= 0;
97 static s32
__usbstorage_reset(usbstorage_handle
*dev
);
98 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
);
100 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
101 * but there's currently no other known way of doing this and it's in my humble
102 * opinion still better than having a function blocking forever while waiting
103 * for the USB data/IOS reply..
106 static s32
__usb_blkmsg_cb(s32 retval
, void *dummy
)
108 usbstorage_handle
*dev
= (usbstorage_handle
*)dummy
;
109 dev
->retval
= retval
;
110 SYS_CancelAlarm(dev
->alarm
);
111 LWP_ThreadBroadcast(__usbstorage_waitq
);
115 static s32
__usb_deviceremoved_cb(s32 retval
,void *arg
)
120 static void __usb_timeouthandler(syswd_t alarm
,void *cbarg
)
122 usbstorage_handle
*dev
= (usbstorage_handle
*)cbarg
;
123 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
124 LWP_ThreadBroadcast(__usbstorage_waitq
);
127 static void __usb_settimeout(usbstorage_handle
*dev
)
133 SYS_SetAlarm(dev
->alarm
,&ts
,__usb_timeouthandler
,dev
);
136 static s32
__USB_BlkMsgTimeout(usbstorage_handle
*dev
, u8 bEndpoint
, u16 wLength
, void *rpData
)
141 dev
->retval
= USBSTORAGE_PROCESSING
;
142 retval
= USB_WriteBlkMsgAsync(dev
->usb_fd
, bEndpoint
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
143 if(retval
< 0) return retval
;
145 __usb_settimeout(dev
);
147 _CPU_ISR_Disable(level
);
149 retval
= dev
->retval
;
150 if(retval
!=USBSTORAGE_PROCESSING
) break;
151 else LWP_ThreadSleep(__usbstorage_waitq
);
152 } while(retval
==USBSTORAGE_PROCESSING
);
153 _CPU_ISR_Restore(level
);
155 if(retval
==USBSTORAGE_ETIMEDOUT
) USBStorage_Close(dev
);
159 static s32
__USB_CtrlMsgTimeout(usbstorage_handle
*dev
, u8 bmRequestType
, u8 bmRequest
, u16 wValue
, u16 wIndex
, u16 wLength
, void *rpData
)
169 dev
->retval
= USBSTORAGE_PROCESSING
;
170 retval
= USB_WriteCtrlMsgAsync(dev
->usb_fd
, bmRequestType
, bmRequest
, wValue
, wIndex
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
171 if(retval
< 0) return retval
;
173 __usb_settimeout(dev
);
175 _CPU_ISR_Disable(level
);
177 retval
= dev
->retval
;
178 if(retval
!=USBSTORAGE_PROCESSING
) break;
179 else LWP_ThreadSleep(__usbstorage_waitq
);
180 } while(retval
==USBSTORAGE_PROCESSING
);
181 _CPU_ISR_Restore(level
);
183 if(retval
==USBSTORAGE_ETIMEDOUT
) USBStorage_Close(dev
);
187 s32
USBStorage_Initialize()
192 _CPU_ISR_Disable(level
);
193 if(__heap_created
!= 0) {
194 _CPU_ISR_Restore(level
);
198 LWP_InitQueue(&__usbstorage_waitq
);
200 ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
201 if((u32
)ptr
< (u32
)SYS_GetArena2Lo()) {
202 _CPU_ISR_Restore(level
);
206 SYS_SetArena2Hi(ptr
);
208 __lwp_heap_init(&__heap
, ptr
, HEAP_SIZE
, 32);
210 _CPU_ISR_Restore(level
);
216 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
218 s32 retval
= USBSTORAGE_OK
;
220 if(cbLen
== 0 || cbLen
> 16)
223 memset(dev
->buffer
, 0, CBW_SIZE
);
225 __stwbrx(dev
->buffer
, 0, CBW_SIGNATURE
);
226 __stwbrx(dev
->buffer
, 4, dev
->tag
);
227 __stwbrx(dev
->buffer
, 8, len
);
228 dev
->buffer
[12] = flags
;
229 dev
->buffer
[13] = lun
;
230 dev
->buffer
[14] = (cbLen
> 6 ? 0x10 : 6);
232 memcpy(dev
->buffer
+ 15, cb
, cbLen
);
234 if(dev
->suspended
== 1)
236 USB_ResumeDevice(dev
->usb_fd
);
240 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)dev
->buffer
);
242 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
243 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
248 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
)
250 s32 retval
= USBSTORAGE_OK
;
251 u32 signature
, tag
, _dataResidue
, _status
;
253 memset(dev
->buffer
, 0, CSW_SIZE
);
255 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, dev
->buffer
);
256 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
257 else if(retval
< 0) return retval
;
259 signature
= __lwbrx(dev
->buffer
, 0);
260 tag
= __lwbrx(dev
->buffer
, 4);
261 _dataResidue
= __lwbrx(dev
->buffer
, 8);
262 _status
= dev
->buffer
[12];
264 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
266 if(dataResidue
!= NULL
)
267 *dataResidue
= _dataResidue
;
271 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
274 return USBSTORAGE_OK
;
277 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
279 s32 retval
= USBSTORAGE_OK
;
285 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
287 LWP_MutexLock(dev
->lock
);
292 if(retval
== USBSTORAGE_ETIMEDOUT
)
297 retval
= __send_cbw(dev
, lun
, len
, CBW_OUT
, cb
, cbLen
);
298 if(retval
== USBSTORAGE_ETIMEDOUT
)
302 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
303 retval
= USBSTORAGE_ETIMEDOUT
;
308 thisLen
= len
> MAX_TRANSFER_SIZE
? MAX_TRANSFER_SIZE
: len
;
309 memset(dev
->buffer
, 0, MAX_TRANSFER_SIZE
);
310 memcpy(dev
->buffer
, buffer
, thisLen
);
311 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, thisLen
, dev
->buffer
);
313 if(retval
== USBSTORAGE_ETIMEDOUT
)
318 retval
= USBSTORAGE_EDATARESIDUE
;
323 if(retval
!= thisLen
&& len
> 0)
325 retval
= USBSTORAGE_EDATARESIDUE
;
334 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
335 retval
= USBSTORAGE_ETIMEDOUT
;
341 retval
= __send_cbw(dev
, lun
, len
, CBW_IN
, cb
, cbLen
);
343 if(retval
== USBSTORAGE_ETIMEDOUT
)
348 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
349 retval
= USBSTORAGE_ETIMEDOUT
;
354 thisLen
= len
> MAX_TRANSFER_SIZE
? MAX_TRANSFER_SIZE
: len
;
355 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, thisLen
, dev
->buffer
);
359 memcpy(buffer
, dev
->buffer
, retval
);
363 if(retval
!= thisLen
)
369 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
370 retval
= USBSTORAGE_ETIMEDOUT
;
375 retval
= __read_csw(dev
, &status
, &dataResidue
);
377 if(retval
== USBSTORAGE_ETIMEDOUT
)
382 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
383 retval
= USBSTORAGE_ETIMEDOUT
;
387 retval
= USBSTORAGE_OK
;
388 } while(retval
< 0 && retries
> 0);
390 if(retval
< 0 && retval
!= USBSTORAGE_ETIMEDOUT
)
392 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
393 retval
= USBSTORAGE_ETIMEDOUT
;
395 LWP_MutexUnlock(dev
->lock
);
400 if(_dataResidue
!= NULL
)
401 *_dataResidue
= dataResidue
;
406 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
410 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
413 memset(cmd
, 0, sizeof(cmd
));
414 cmd
[0] = SCSI_TEST_UNIT_READY
;
416 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
417 if(retval
< 0) return retval
;
421 cmd
[0] = SCSI_REQUEST_SENSE
;
423 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
425 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
426 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
427 if(retval
< 0) return retval
;
429 status
= sense
[2] & 0x0F;
430 if(status
== SCSI_SENSE_NOT_READY
|| status
== SCSI_SENSE_MEDIUM_ERROR
|| status
== SCSI_SENSE_HARDWARE_ERROR
) return USBSTORAGE_ESENSE
;
436 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
440 if(dev
->suspended
== 1)
442 USB_ResumeDevice(dev
->usb_fd
);
446 retval
= __USB_CtrlMsgTimeout(dev
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_CLASS
| USB_CTRLTYPE_REC_INTERFACE
), USBSTORAGE_RESET
, 0, dev
->interface
, 0, NULL
);
448 /* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
449 if(retval
< 0 && retval
!= -7004)
452 /* gives device enough time to process the reset */
455 retval
= USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);
458 retval
= USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);
464 s32
USBStorage_Open(usbstorage_handle
*dev
, const char *bus
, u16 vid
, u16 pid
)
467 u8 conf
,*max_lun
= NULL
;
468 u32 iConf
, iInterface
, iEp
;
470 usb_configurationdesc
*ucd
;
471 usb_interfacedesc
*uid
;
472 usb_endpointdesc
*ued
;
474 max_lun
= __lwp_heap_allocate(&__heap
, 1);
475 if(max_lun
==NULL
) return IPC_ENOMEM
;
477 memset(dev
, 0, sizeof(*dev
));
479 dev
->tag
= TAG_START
;
480 if(LWP_MutexInit(&dev
->lock
, false) < 0)
481 goto free_and_return
;
482 if(SYS_CreateAlarm(&dev
->alarm
)<0)
483 goto free_and_return
;
485 retval
= USB_OpenDevice(bus
, vid
, pid
, &dev
->usb_fd
);
487 goto free_and_return
;
489 retval
= USB_GetDescriptors(dev
->usb_fd
, &udd
);
491 goto free_and_return
;
493 for(iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++)
495 ucd
= &udd
.configurations
[iConf
];
496 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
498 uid
= &ucd
->interfaces
[iInterface
];
499 if(uid
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
&&
500 uid
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
&&
501 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
503 if(uid
->bNumEndpoints
< 2)
506 dev
->ep_in
= dev
->ep_out
= 0;
507 for(iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++)
509 ued
= &uid
->endpoints
[iEp
];
510 if(ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
513 if(ued
->bEndpointAddress
& USB_ENDPOINT_IN
)
514 dev
->ep_in
= ued
->bEndpointAddress
;
516 dev
->ep_out
= ued
->bEndpointAddress
;
518 if(dev
->ep_in
!= 0 && dev
->ep_out
!= 0)
520 dev
->configuration
= ucd
->bConfigurationValue
;
521 dev
->interface
= uid
->bInterfaceNumber
;
522 dev
->altInterface
= uid
->bAlternateSetting
;
529 USB_FreeDescriptors(&udd
);
530 retval
= USBSTORAGE_ENOINTERFACE
;
531 goto free_and_return
;
534 USB_FreeDescriptors(&udd
);
536 retval
= USBSTORAGE_EINIT
;
537 if(USB_GetConfiguration(dev
->usb_fd
, &conf
) < 0)
538 goto free_and_return
;
539 if(conf
!= dev
->configuration
&& USB_SetConfiguration(dev
->usb_fd
, dev
->configuration
) < 0)
540 goto free_and_return
;
541 if(dev
->altInterface
!= 0 && USB_SetAlternativeInterface(dev
->usb_fd
, dev
->interface
, dev
->altInterface
) < 0)
542 goto free_and_return
;
545 retval
= USBStorage_Reset(dev
);
547 goto free_and_return
;
549 LWP_MutexLock(dev
->lock
);
550 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
);
551 LWP_MutexUnlock(dev
->lock
);
555 dev
->max_lun
= *max_lun
;
558 if(retval
== USBSTORAGE_ETIMEDOUT
)
559 goto free_and_return
;
561 retval
= USBSTORAGE_OK
;
562 dev
->sector_size
= (u32
*)calloc(dev
->max_lun
, sizeof(u32
));
563 if(dev
->sector_size
== NULL
)
566 goto free_and_return
;
569 if(dev
->max_lun
== 0)
572 /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
574 * Some devices (i.e. Iomega Zip100) need this -- apparently
575 * the bulk pipes get STALLed when the GetMaxLUN request is
576 * processed. This is, in theory, harmless to all other devices
577 * (regardless of if they stall or not).
579 USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);
580 USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);
582 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE
);
584 if(dev
->buffer
== NULL
) retval
= IPC_ENOMEM
;
586 USB_DeviceRemovalNotifyAsync(dev
->usb_fd
,__usb_deviceremoved_cb
,dev
);
587 retval
= USBSTORAGE_OK
;
591 if(max_lun
!=NULL
) __lwp_heap_free(&__heap
, max_lun
);
594 USB_CloseDevice(&dev
->usb_fd
);
595 LWP_MutexDestroy(dev
->lock
);
596 SYS_RemoveAlarm(dev
->alarm
);
597 if(dev
->buffer
!= NULL
)
598 __lwp_heap_free(&__heap
, dev
->buffer
);
599 if(dev
->sector_size
!= NULL
)
600 free(dev
->sector_size
);
601 memset(dev
, 0, sizeof(*dev
));
607 s32
USBStorage_Close(usbstorage_handle
*dev
)
609 USB_CloseDevice(&dev
->usb_fd
);
610 LWP_MutexDestroy(dev
->lock
);
611 SYS_RemoveAlarm(dev
->alarm
);
612 if(dev
->sector_size
!=NULL
)
613 free(dev
->sector_size
);
614 if(dev
->buffer
!=NULL
)
615 __lwp_heap_free(&__heap
, dev
->buffer
);
616 memset(dev
, 0, sizeof(*dev
));
620 s32
USBStorage_Reset(usbstorage_handle
*dev
)
624 LWP_MutexLock(dev
->lock
);
625 retval
= __usbstorage_reset(dev
);
626 LWP_MutexUnlock(dev
->lock
);
631 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
636 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
640 if(lun
>= dev
->max_lun
)
643 retval
= __usbstorage_clearerrors(dev
, lun
);
647 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], NULL
);
651 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
654 u8 cmd
[] = {SCSI_READ_CAPACITY
, lun
<< 5};
657 retval
= __cycle(dev
, lun
, response
, 8, cmd
, 2, 0, NULL
, NULL
);
660 if(n_sectors
!= NULL
)
661 memcpy(n_sectors
, response
, 4);
662 if(sector_size
!= NULL
)
663 memcpy(sector_size
, response
+ 4, 4);
664 retval
= USBSTORAGE_OK
;
670 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, u8
*buffer
)
686 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
688 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
689 if(retval
> 0 && status
!= 0)
690 retval
= USBSTORAGE_ESTATUS
;
694 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
710 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
712 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
713 if(retval
> 0 && status
!= 0)
714 retval
= USBSTORAGE_ESTATUS
;
718 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
720 if(dev
->suspended
== 1)
721 return USBSTORAGE_OK
;
723 USB_SuspendDevice(dev
->usb_fd
);
726 return USBSTORAGE_OK
;
731 The following is for implementing a DISC_INTERFACE
735 static bool usb_inited
=false;
736 static bool __usbstorage_ReadSectors(u32
, u32
, void *);
738 static bool __usbstorage_IsInserted(void);
740 static bool __usbstorage_Startup(void)
744 USBStorage_Initialize();
745 return __usbstorage_IsInserted();
748 static bool __usbstorage_IsInserted(void)
761 USBStorage_Initialize();
764 __mounted
= 0; //reset it here and check if device is still attached
766 buffer
= __lwp_heap_allocate(&__heap
, DEVLIST_MAXSIZE
<< 3);
769 memset(buffer
, 0, DEVLIST_MAXSIZE
<< 3);
771 if(USB_GetDeviceList("/dev/usb/oh0", buffer
, DEVLIST_MAXSIZE
, 0, &dummy
) < 0)
773 if(__vid
!=0 || __pid
!=0)
775 USBStorage_Close(&__usbfd
);
776 memset(&__usbfd
, 0, sizeof(__usbfd
));
783 __lwp_heap_free(&__heap
,buffer
);
789 if(__vid
!=0 || __pid
!=0)
791 for(i
= 0; i
< DEVLIST_MAXSIZE
; i
++)
793 memcpy(&vid
, (buffer
+ (i
<< 3) + 4), 2);
794 memcpy(&pid
, (buffer
+ (i
<< 3) + 6), 2);
795 if(vid
!= 0 || pid
!= 0)
797 if( (vid
== __vid
) && (pid
== __pid
))
800 __lwp_heap_free(&__heap
,buffer
);
801 usleep(50); // I don't know why I have to wait but it's needed
806 USBStorage_Close(&__usbfd
);
807 memset(&__usbfd
, 0, sizeof(__usbfd
));
814 for(i
= 0; i
< DEVLIST_MAXSIZE
; i
++)
816 memcpy(&vid
, (buffer
+ (i
<< 3) + 4), 2);
817 memcpy(&pid
, (buffer
+ (i
<< 3) + 6), 2);
818 if(vid
== 0 || pid
== 0)
821 if(USBStorage_Open(&__usbfd
, "oh0", vid
, pid
) < 0)
824 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
825 for(j
= 0; j
< maxLun
; j
++)
827 retval
= USBStorage_MountLUN(&__usbfd
, j
);
829 if(retval
== USBSTORAGE_ETIMEDOUT
)
842 __lwp_heap_free(&__heap
,buffer
);
848 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
855 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
857 if(retval
== USBSTORAGE_ETIMEDOUT
)
865 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
872 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
874 if(retval
== USBSTORAGE_ETIMEDOUT
)
882 static bool __usbstorage_ClearStatus(void)
887 static bool __usbstorage_Shutdown(void)
889 if(__vid
!=0 || __pid
!=0)
891 USBStorage_Close(&__usbfd
);
892 memset(&__usbfd
, 0, sizeof(__usbfd
));
902 DISC_INTERFACE __io_usbstorage
= {
904 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
905 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
906 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
907 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
908 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
909 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
910 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown