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 -------------------------------------------------------------*/
41 #include "processor.h"
44 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
46 #define HEAP_SIZE (32*1024)
47 #define TAG_START 0x0BADC0DE
50 #define CBW_SIGNATURE 0x43425355
51 #define CBW_IN (1 << 7)
55 #define CSW_SIGNATURE 0x53425355
57 #define SCSI_TEST_UNIT_READY 0x00
58 #define SCSI_REQUEST_SENSE 0x03
59 #define SCSI_READ_CAPACITY 0x25
60 #define SCSI_READ_10 0x28
61 #define SCSI_WRITE_10 0x2A
63 #define SCSI_SENSE_REPLY_SIZE 18
64 #define SCSI_SENSE_NOT_READY 0x02
65 #define SCSI_SENSE_MEDIUM_ERROR 0x03
66 #define SCSI_SENSE_HARDWARE_ERROR 0x04
68 #define USB_CLASS_MASS_STORAGE 0x08
69 #define MASS_STORAGE_SCSI_COMMANDS 0x06
70 #define MASS_STORAGE_BULK_ONLY 0x50
72 #define USBSTORAGE_GET_MAX_LUN 0xFE
73 #define USBSTORAGE_RESET 0xFF
75 #define USB_ENDPOINT_BULK 0x02
77 #define USBSTORAGE_CYCLE_RETRIES 3
79 #define MAX_TRANSFER_SIZE 4096
81 #define DEVLIST_MAXSIZE 8
83 static heap_cntrl __heap
;
84 static u8 __heap_created
= 0;
86 static s32
__usbstorage_reset(usbstorage_handle
*dev
);
87 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
);
89 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
90 * but there's currently no other known way of doing this and it's in my humble
91 * opinion still better than having a function blocking forever while waiting
92 * for the USB data/IOS reply..
95 static s32
__usb_blkmsgtimeout_cb(s32 retval
, void *dummy
)
97 usbstorage_handle
*dev
= (usbstorage_handle
*)dummy
;
99 LWP_CondSignal(dev
->cond
);
103 static s32
__USB_BlkMsgTimeout(usbstorage_handle
*dev
, u8 bEndpoint
, u16 wLength
, void *rpData
)
112 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
113 retval
= USB_WriteBlkMsgAsync(dev
->usb_fd
, bEndpoint
, wLength
, rpData
, __usb_blkmsgtimeout_cb
, (void *)dev
);
117 retval
= LWP_CondTimedWait(dev
->cond
, dev
->lock
, &ts
);
119 if(retval
== ETIMEDOUT
)
121 USBStorage_Close(dev
);
122 return USBSTORAGE_ETIMEDOUT
;
125 retval
= dev
->retval
;
129 static s32
__USB_CtrlMsgTimeout(usbstorage_handle
*dev
, u8 bmRequestType
, u8 bmRequest
, u16 wValue
, u16 wIndex
, u16 wLength
, void *rpData
)
138 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
139 retval
= USB_WriteCtrlMsgAsync(dev
->usb_fd
, bmRequestType
, bmRequest
, wValue
, wIndex
, wLength
, rpData
, __usb_blkmsgtimeout_cb
, (void *)dev
);
143 retval
= LWP_CondTimedWait(dev
->cond
, dev
->lock
, &ts
);
145 if(retval
== ETIMEDOUT
)
147 USBStorage_Close(dev
);
148 return USBSTORAGE_ETIMEDOUT
;
151 retval
= dev
->retval
;
155 s32
USBStorage_Initialize()
160 _CPU_ISR_Disable(level
);
161 if(__heap_created
!= 0) {
162 _CPU_ISR_Restore(level
);
166 ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
167 if((u32
)ptr
< (u32
)SYS_GetArena2Lo()) {
168 _CPU_ISR_Restore(level
);
172 SYS_SetArena2Hi(ptr
);
174 __lwp_heap_init(&__heap
, ptr
, HEAP_SIZE
, 32);
176 _CPU_ISR_Restore(level
);
182 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
184 s32 retval
= USBSTORAGE_OK
;
186 if(cbLen
== 0 || cbLen
> 16)
189 memset(dev
->buffer
, 0, CBW_SIZE
);
191 __stwbrx(dev
->buffer
, 0, CBW_SIGNATURE
);
192 __stwbrx(dev
->buffer
, 4, dev
->tag
);
193 __stwbrx(dev
->buffer
, 8, len
);
194 dev
->buffer
[12] = flags
;
195 dev
->buffer
[13] = lun
;
196 dev
->buffer
[14] = (cbLen
> 6 ? 0x10 : 6);
198 memcpy(dev
->buffer
+ 15, cb
, cbLen
);
200 if(dev
->suspended
== 1)
202 USB_ResumeDevice(dev
->usb_fd
);
206 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)dev
->buffer
);
208 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
209 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
214 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
)
216 s32 retval
= USBSTORAGE_OK
;
217 u32 signature
, tag
, _dataResidue
, _status
;
219 memset(dev
->buffer
, 0, CSW_SIZE
);
221 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, dev
->buffer
);
222 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
223 else if(retval
< 0) return retval
;
225 signature
= __lwbrx(dev
->buffer
, 0);
226 tag
= __lwbrx(dev
->buffer
, 4);
227 _dataResidue
= __lwbrx(dev
->buffer
, 8);
228 _status
= dev
->buffer
[12];
230 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
232 if(dataResidue
!= NULL
)
233 *dataResidue
= _dataResidue
;
237 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
240 return USBSTORAGE_OK
;
243 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
245 s32 retval
= USBSTORAGE_OK
;
251 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
253 LWP_MutexLock(dev
->lock
);
258 if(retval
== USBSTORAGE_ETIMEDOUT
)
263 retval
= __send_cbw(dev
, lun
, len
, CBW_OUT
, cb
, cbLen
);
264 if(retval
== USBSTORAGE_ETIMEDOUT
)
268 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
269 retval
= USBSTORAGE_ETIMEDOUT
;
274 thisLen
= len
> MAX_TRANSFER_SIZE
? MAX_TRANSFER_SIZE
: len
;
275 memset(dev
->buffer
, 0, MAX_TRANSFER_SIZE
);
276 memcpy(dev
->buffer
, buffer
, thisLen
);
277 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, thisLen
, dev
->buffer
);
279 if(retval
== USBSTORAGE_ETIMEDOUT
)
284 retval
= USBSTORAGE_EDATARESIDUE
;
289 if(retval
!= thisLen
&& len
> 0)
291 retval
= USBSTORAGE_EDATARESIDUE
;
300 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
301 retval
= USBSTORAGE_ETIMEDOUT
;
307 retval
= __send_cbw(dev
, lun
, len
, CBW_IN
, cb
, cbLen
);
309 if(retval
== USBSTORAGE_ETIMEDOUT
)
314 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
315 retval
= USBSTORAGE_ETIMEDOUT
;
320 thisLen
= len
> MAX_TRANSFER_SIZE
? MAX_TRANSFER_SIZE
: len
;
321 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, thisLen
, dev
->buffer
);
325 memcpy(buffer
, dev
->buffer
, retval
);
329 if(retval
!= thisLen
)
335 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
336 retval
= USBSTORAGE_ETIMEDOUT
;
341 retval
= __read_csw(dev
, &status
, &dataResidue
);
343 if(retval
== USBSTORAGE_ETIMEDOUT
)
348 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
349 retval
= USBSTORAGE_ETIMEDOUT
;
353 retval
= USBSTORAGE_OK
;
354 } while(retval
< 0 && retries
> 0);
356 if(retval
< 0 && retval
!= USBSTORAGE_ETIMEDOUT
)
358 if(__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
359 retval
= USBSTORAGE_ETIMEDOUT
;
361 LWP_MutexUnlock(dev
->lock
);
366 if(_dataResidue
!= NULL
)
367 *_dataResidue
= dataResidue
;
372 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
376 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
379 memset(cmd
, 0, sizeof(cmd
));
380 cmd
[0] = SCSI_TEST_UNIT_READY
;
382 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
383 if(retval
< 0) return retval
;
387 cmd
[0] = SCSI_REQUEST_SENSE
;
389 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
391 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
392 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
393 if(retval
< 0) return retval
;
395 status
= sense
[2] & 0x0F;
396 if(status
== SCSI_SENSE_NOT_READY
|| status
== SCSI_SENSE_MEDIUM_ERROR
|| status
== SCSI_SENSE_HARDWARE_ERROR
) return USBSTORAGE_ESENSE
;
402 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
406 if(dev
->suspended
== 1)
408 USB_ResumeDevice(dev
->usb_fd
);
412 retval
= __USB_CtrlMsgTimeout(dev
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_CLASS
| USB_CTRLTYPE_REC_INTERFACE
), USBSTORAGE_RESET
, 0, dev
->interface
, 0, NULL
);
414 /* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
415 if(retval
< 0 && retval
!= -7004)
418 /* gives device enough time to process the reset */
421 retval
= USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);
424 retval
= USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);
430 s32
USBStorage_Open(usbstorage_handle
*dev
, const char *bus
, u16 vid
, u16 pid
)
433 u8 conf
,*max_lun
= NULL
;
434 u32 iConf
, iInterface
, iEp
;
436 usb_configurationdesc
*ucd
;
437 usb_interfacedesc
*uid
;
438 usb_endpointdesc
*ued
;
440 max_lun
= __lwp_heap_allocate(&__heap
, 1);
441 if(max_lun
==NULL
) return IPC_ENOMEM
;
443 memset(dev
, 0, sizeof(*dev
));
445 dev
->tag
= TAG_START
;
446 if(LWP_MutexInit(&dev
->lock
, false) < 0)
447 goto free_and_return
;
448 if(LWP_CondInit(&dev
->cond
) < 0)
449 goto free_and_return
;
451 retval
= USB_OpenDevice(bus
, vid
, pid
, &dev
->usb_fd
);
453 goto free_and_return
;
455 retval
= USB_GetDescriptors(dev
->usb_fd
, &udd
);
457 goto free_and_return
;
459 for(iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++)
461 ucd
= &udd
.configurations
[iConf
];
462 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
464 uid
= &ucd
->interfaces
[iInterface
];
465 if(uid
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
&&
466 uid
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
&&
467 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
469 if(uid
->bNumEndpoints
< 2)
472 dev
->ep_in
= dev
->ep_out
= 0;
473 for(iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++)
475 ued
= &uid
->endpoints
[iEp
];
476 if(ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
479 if(ued
->bEndpointAddress
& USB_ENDPOINT_IN
)
480 dev
->ep_in
= ued
->bEndpointAddress
;
482 dev
->ep_out
= ued
->bEndpointAddress
;
484 if(dev
->ep_in
!= 0 && dev
->ep_out
!= 0)
486 dev
->configuration
= ucd
->bConfigurationValue
;
487 dev
->interface
= uid
->bInterfaceNumber
;
488 dev
->altInterface
= uid
->bAlternateSetting
;
495 USB_FreeDescriptors(&udd
);
496 retval
= USBSTORAGE_ENOINTERFACE
;
497 goto free_and_return
;
500 USB_FreeDescriptors(&udd
);
502 retval
= USBSTORAGE_EINIT
;
503 if(USB_GetConfiguration(dev
->usb_fd
, &conf
) < 0)
504 goto free_and_return
;
505 if(conf
!= dev
->configuration
&& USB_SetConfiguration(dev
->usb_fd
, dev
->configuration
) < 0)
506 goto free_and_return
;
507 if(dev
->altInterface
!= 0 && USB_SetAlternativeInterface(dev
->usb_fd
, dev
->interface
, dev
->altInterface
) < 0)
508 goto free_and_return
;
511 retval
= USBStorage_Reset(dev
);
513 goto free_and_return
;
515 LWP_MutexLock(dev
->lock
);
516 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
);
517 LWP_MutexUnlock(dev
->lock
);
521 dev
->max_lun
= *max_lun
;
524 if(retval
== USBSTORAGE_ETIMEDOUT
)
525 goto free_and_return
;
527 retval
= USBSTORAGE_OK
;
528 dev
->sector_size
= (u32
*)calloc(dev
->max_lun
, sizeof(u32
));
529 if(dev
->sector_size
== NULL
)
532 goto free_and_return
;
535 if(dev
->max_lun
== 0)
538 /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
540 * Some devices (i.e. Iomega Zip100) need this -- apparently
541 * the bulk pipes get STALLed when the GetMaxLUN request is
542 * processed. This is, in theory, harmless to all other devices
543 * (regardless of if they stall or not).
545 USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);
546 USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);
548 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE
);
550 if(dev
->buffer
== NULL
) retval
= IPC_ENOMEM
;
551 else retval
= USBSTORAGE_OK
;
554 if(max_lun
!=NULL
) __lwp_heap_free(&__heap
, max_lun
);
557 USB_CloseDevice(&dev
->usb_fd
);
558 LWP_MutexDestroy(dev
->lock
);
559 LWP_CondDestroy(dev
->cond
);
560 if(dev
->buffer
!= NULL
)
561 __lwp_heap_free(&__heap
, dev
->buffer
);
562 if(dev
->sector_size
!= NULL
)
563 free(dev
->sector_size
);
564 memset(dev
, 0, sizeof(*dev
));
570 s32
USBStorage_Close(usbstorage_handle
*dev
)
572 USB_CloseDevice(&dev
->usb_fd
);
573 LWP_MutexDestroy(dev
->lock
);
574 LWP_CondDestroy(dev
->cond
);
575 if(dev
->sector_size
!=NULL
)
576 free(dev
->sector_size
);
577 if(dev
->buffer
!=NULL
)
578 __lwp_heap_free(&__heap
, dev
->buffer
);
579 memset(dev
, 0, sizeof(*dev
));
583 s32
USBStorage_Reset(usbstorage_handle
*dev
)
587 LWP_MutexLock(dev
->lock
);
588 retval
= __usbstorage_reset(dev
);
589 LWP_MutexUnlock(dev
->lock
);
594 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
599 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
603 if(lun
>= dev
->max_lun
)
606 retval
= __usbstorage_clearerrors(dev
, lun
);
610 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], NULL
);
614 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
617 u8 cmd
[] = {SCSI_READ_CAPACITY
, lun
<< 5};
620 retval
= __cycle(dev
, lun
, response
, 8, cmd
, 2, 0, NULL
, NULL
);
623 if(n_sectors
!= NULL
)
624 memcpy(n_sectors
, response
, 4);
625 if(sector_size
!= NULL
)
626 memcpy(sector_size
, response
+ 4, 4);
627 retval
= USBSTORAGE_OK
;
633 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, u8
*buffer
)
649 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
651 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
652 if(retval
> 0 && status
!= 0)
653 retval
= USBSTORAGE_ESTATUS
;
657 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
673 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
675 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
676 if(retval
> 0 && status
!= 0)
677 retval
= USBSTORAGE_ESTATUS
;
681 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
683 if(dev
->suspended
== 1)
684 return USBSTORAGE_OK
;
686 USB_SuspendDevice(dev
->usb_fd
);
689 return USBSTORAGE_OK
;
694 The following is for implementing a DISC_INTERFACE
698 static usbstorage_handle __usbfd
;
700 static u8 __mounted
= 0;
701 static u16 __vid
= 0;
702 static u16 __pid
= 0;
704 static bool __usbstorage_IsInserted(void);
706 static bool __usbstorage_Startup(void)
709 USBStorage_Initialize();
711 memset(&__usbfd, 0, sizeof(__usbfd));
716 return __usbstorage_IsInserted();
719 static bool __usbstorage_IsInserted(void)
728 __mounted
= 0; //reset it here and check if device is still attached
730 buffer
= memalign(32, DEVLIST_MAXSIZE
<< 3);
733 memset(buffer
, 0, DEVLIST_MAXSIZE
<< 3);
735 if(USB_GetDeviceList("/dev/usb/oh0", buffer
, DEVLIST_MAXSIZE
, 0, &dummy
) < 0)
737 if(__vid
!=0 || __pid
!=0) USBStorage_Close(&__usbfd
);
738 memset(&__usbfd
, 0, sizeof(__usbfd
));
747 if(__vid
!=0 || __pid
!=0)
749 for(i
= 0; i
< DEVLIST_MAXSIZE
; i
++)
751 memcpy(&vid
, (buffer
+ (i
<< 3) + 4), 2);
752 memcpy(&pid
, (buffer
+ (i
<< 3) + 6), 2);
753 if(vid
!= 0 || pid
!= 0)
756 if( (vid
== __vid
) && (pid
== __pid
))
760 usleep(50); // I don't know why I have to wait but it's needed
765 USBStorage_Close(&__usbfd
);
768 memset(&__usbfd
, 0, sizeof(__usbfd
));
773 for(i
= 0; i
< DEVLIST_MAXSIZE
; i
++)
775 memcpy(&vid
, (buffer
+ (i
<< 3) + 4), 2);
776 memcpy(&pid
, (buffer
+ (i
<< 3) + 6), 2);
777 if(vid
== 0 || pid
== 0)
780 if(USBStorage_Open(&__usbfd
, "oh0", vid
, pid
) < 0)
783 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
784 for(j
= 0; j
< maxLun
; j
++)
786 retval
= USBStorage_MountLUN(&__usbfd
, j
);
787 if(retval
== USBSTORAGE_ETIMEDOUT
)
809 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
816 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
817 if(retval
== USBSTORAGE_ETIMEDOUT
)
826 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
833 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
834 if(retval
== USBSTORAGE_ETIMEDOUT
)
843 static bool __usbstorage_ClearStatus(void)
848 static bool __usbstorage_Shutdown(void)
850 //if(__mounted == 1) USBStorage_Close(&__usbfd);
855 const DISC_INTERFACE __io_usbstorage
= {
857 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
858 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
859 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
860 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
861 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
862 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
863 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown