1 /*-------------------------------------------------------------
3 usbstorage.c -- Bulk-only USB mass storage support
6 Sven Peter (svpe) <svpe@gmx.net>
7 Copyright (C) 2009-2010
8 tueidj, rodries, Tantric
10 This software is provided 'as-is', without any express or implied
11 warranty. In no event will the authors be held liable for any
12 damages arising from the use of this software.
14 Permission is granted to anyone to use this software for any
15 purpose, including commercial applications, and to alter it and
16 redistribute it freely, subject to the following restrictions:
18 1. The origin of this software must not be misrepresented; you
19 must not claim that you wrote the original software. If you use
20 this software in a product, an acknowledgment in the product
21 documentation would be appreciated but is not required.
23 2. Altered source versions must be plainly marked as such, and
24 must not be misrepresented as being the original software.
26 3. This notice may not be removed or altered from any source
29 -------------------------------------------------------------*/
42 #include "processor.h"
44 #include "lwp_watchdog.h"
46 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
48 #define HEAP_SIZE (18*1024)
49 #define TAG_START 0x0BADC0DE
52 #define CBW_SIGNATURE 0x43425355
53 #define CBW_IN (1 << 7)
57 #define CSW_SIGNATURE 0x53425355
59 #define SCSI_TEST_UNIT_READY 0x00
60 #define SCSI_REQUEST_SENSE 0x03
61 #define SCSI_INQUIRY 0x12
62 #define SCSI_START_STOP 0x1B
63 #define SCSI_READ_CAPACITY 0x25
64 #define SCSI_READ_10 0x28
65 #define SCSI_WRITE_10 0x2A
68 #define SCSI_SENSE_REPLY_SIZE 18
69 #define SCSI_SENSE_NOT_READY 0x02
70 #define SCSI_SENSE_MEDIUM_ERROR 0x03
71 #define SCSI_SENSE_HARDWARE_ERROR 0x04
73 #define USB_CLASS_MASS_STORAGE 0x08
74 #define MASS_STORAGE_RBC_COMMANDS 0x01
75 #define MASS_STORAGE_ATA_COMMANDS 0x02
76 #define MASS_STORAGE_QIC_COMMANDS 0x03
77 #define MASS_STORAGE_UFI_COMMANDS 0x04
78 #define MASS_STORAGE_SFF8070_COMMANDS 0x05
79 #define MASS_STORAGE_SCSI_COMMANDS 0x06
80 #define MASS_STORAGE_BULK_ONLY 0x50
82 #define USBSTORAGE_GET_MAX_LUN 0xFE
83 #define USBSTORAGE_RESET 0xFF
85 #define USB_ENDPOINT_BULK 0x02
87 #define USBSTORAGE_CYCLE_RETRIES 3
88 #define USBSTORAGE_TIMEOUT 2
90 #define MAX_TRANSFER_SIZE_V0 4096
91 #define MAX_TRANSFER_SIZE_V5 (16*1024)
93 #define DEVLIST_MAXSIZE 8
95 static heap_cntrl __heap
;
96 static bool __inited
= false;
97 static u64 usb_last_used
= 0;
98 static lwpq_t __usbstorage_waitq
= 0;
99 static u32 usbtimeout
= USBSTORAGE_TIMEOUT
;
102 The following is for implementing a DISC_INTERFACE
106 static usbstorage_handle __usbfd
;
108 static bool __mounted
= false;
109 static u16 __vid
= 0;
110 static u16 __pid
= 0;
111 static bool usb2_mode
=true;
113 static s32
__usbstorage_reset(usbstorage_handle
*dev
);
114 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
);
115 s32
USBStorage_Inquiry(usbstorage_handle
*dev
, u8 lun
);
117 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
118 * but there's currently no other known way of doing this and it's in my humble
119 * opinion still better than having a function blocking forever while waiting
120 * for the USB data/IOS reply..
123 static s32
__usb_blkmsg_cb(s32 retval
, void *dummy
)
125 usbstorage_handle
*dev
= (usbstorage_handle
*)dummy
;
126 dev
->retval
= retval
;
127 SYS_CancelAlarm(dev
->alarm
);
128 LWP_ThreadBroadcast(__usbstorage_waitq
);
132 static s32
__usb_deviceremoved_cb(s32 retval
,void *arg
)
135 if(__vid
!= 0) USBStorage_Close(&__usbfd
);
139 static void __usb_timeouthandler(syswd_t alarm
,void *cbarg
)
141 usbstorage_handle
*dev
= (usbstorage_handle
*)cbarg
;
142 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
143 LWP_ThreadBroadcast(__usbstorage_waitq
);
146 static void __usb_settimeout(usbstorage_handle
*dev
, u32 secs
)
152 SYS_SetAlarm(dev
->alarm
,&ts
,__usb_timeouthandler
,dev
);
155 static s32
__USB_BlkMsgTimeout(usbstorage_handle
*dev
, u8 bEndpoint
, u16 wLength
, void *rpData
, u32 timeout
)
159 dev
->retval
= USBSTORAGE_PROCESSING
;
160 retval
= USB_WriteBlkMsgAsync(dev
->usb_fd
, bEndpoint
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
161 if(retval
< 0) return retval
;
163 __usb_settimeout(dev
, timeout
);
166 retval
= dev
->retval
;
167 if(retval
!=USBSTORAGE_PROCESSING
) break;
168 else LWP_ThreadSleep(__usbstorage_waitq
);
169 } while(retval
==USBSTORAGE_PROCESSING
);
172 USB_ClearHalt(dev
->usb_fd
, bEndpoint
);
177 static s32
__USB_CtrlMsgTimeout(usbstorage_handle
*dev
, u8 bmRequestType
, u8 bmRequest
, u16 wValue
, u16 wIndex
, u16 wLength
, void *rpData
)
181 dev
->retval
= USBSTORAGE_PROCESSING
;
182 retval
= USB_WriteCtrlMsgAsync(dev
->usb_fd
, bmRequestType
, bmRequest
, wValue
, wIndex
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
183 if(retval
< 0) return retval
;
185 __usb_settimeout(dev
, usbtimeout
);
188 retval
= dev
->retval
;
189 if(retval
!=USBSTORAGE_PROCESSING
) break;
190 else LWP_ThreadSleep(__usbstorage_waitq
);
191 } while(retval
==USBSTORAGE_PROCESSING
);
196 static u8
*arena_ptr
=NULL
;
198 s32
USBStorage_Initialize()
205 _CPU_ISR_Disable(level
);
206 LWP_InitQueue(&__usbstorage_waitq
);
208 arena_ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
209 if((u32
)arena_ptr
< (u32
)SYS_GetArena2Lo()) {
210 _CPU_ISR_Restore(level
);
213 SYS_SetArena2Hi(arena_ptr
);
215 __lwp_heap_init(&__heap
, arena_ptr
, HEAP_SIZE
, 32);
217 _CPU_ISR_Restore(level
);
221 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
223 s32 retval
= USBSTORAGE_OK
;
225 if(cbLen
== 0 || cbLen
> 16)
228 memset(dev
->buffer
, 0, CBW_SIZE
);
230 __stwbrx(dev
->buffer
, 0, CBW_SIGNATURE
);
231 __stwbrx(dev
->buffer
, 4, ++dev
->tag
);
232 __stwbrx(dev
->buffer
, 8, len
);
233 dev
->buffer
[12] = flags
;
234 dev
->buffer
[13] = lun
;
235 dev
->buffer
[14] = (cbLen
> 6 ? 10 : 6);
237 memcpy(dev
->buffer
+ 15, cb
, cbLen
);
239 if(dev
->suspended
== 1)
241 USB_ResumeDevice(dev
->usb_fd
);
245 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)dev
->buffer
, usbtimeout
);
247 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
248 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
253 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
, u32 timeout
)
255 s32 retval
= USBSTORAGE_OK
;
256 u32 signature
, tag
, _dataResidue
, _status
;
258 memset(dev
->buffer
, 0, CSW_SIZE
);
260 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, dev
->buffer
, timeout
);
261 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
262 else if(retval
< 0) return retval
;
264 signature
= __lwbrx(dev
->buffer
, 0);
265 tag
= __lwbrx(dev
->buffer
, 4);
266 _dataResidue
= __lwbrx(dev
->buffer
, 8);
267 _status
= dev
->buffer
[12];
269 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
271 if(dataResidue
!= NULL
)
272 *dataResidue
= _dataResidue
;
276 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
278 return USBSTORAGE_OK
;
281 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
283 s32 retval
= USBSTORAGE_OK
;
288 u8 ep
= write
? dev
->ep_out
: dev
->ep_in
;
289 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
292 max_size
=MAX_TRANSFER_SIZE_V5
;
294 max_size
=MAX_TRANSFER_SIZE_V0
;
296 LWP_MutexLock(dev
->lock
);
299 u8
*_buffer
= buffer
;
303 if(retval
== USBSTORAGE_ETIMEDOUT
)
306 retval
= __send_cbw(dev
, lun
, len
, (write
? CBW_OUT
:CBW_IN
), cb
, cbLen
);
308 while(_len
> 0 && retval
>= 0)
310 u32 thisLen
= _len
> max_size
? max_size
: _len
;
312 if ((u32
)_buffer
&0x1F || !((u32
)_buffer
&0x10000000)) {
313 if (write
) memcpy(dev
->buffer
, _buffer
, thisLen
);
314 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, dev
->buffer
, usbtimeout
);
315 if (!write
&& retval
> 0)
316 memcpy(_buffer
, dev
->buffer
, retval
);
318 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, _buffer
, usbtimeout
);
320 if (retval
== thisLen
) {
324 else if (retval
!= USBSTORAGE_ETIMEDOUT
)
325 retval
= USBSTORAGE_EDATARESIDUE
;
329 __read_csw(dev
, &status
, &dataResidue
, usbtimeout
);
332 if (__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
333 retval
= USBSTORAGE_ETIMEDOUT
;
336 } while (retval
< 0 && retries
> 0);
338 LWP_MutexUnlock(dev
->lock
);
342 if(_dataResidue
!= NULL
)
343 *_dataResidue
= dataResidue
;
348 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
352 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
355 memset(cmd
, 0, sizeof(cmd
));
356 cmd
[0] = SCSI_TEST_UNIT_READY
;
358 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
359 if (retval
< 0) return retval
;
363 cmd
[0] = SCSI_REQUEST_SENSE
;
365 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
366 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
367 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
369 switch (sense
[2]&0xF) {
370 case SCSI_SENSE_NOT_READY
:
371 return USBSTORAGE_EINIT
;
372 case SCSI_SENSE_MEDIUM_ERROR
:
373 case SCSI_SENSE_HARDWARE_ERROR
:
374 return USBSTORAGE_ESENSE
;
382 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
386 s32 retval
= __USB_CtrlMsgTimeout(dev
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_CLASS
| USB_CTRLTYPE_REC_INTERFACE
), USBSTORAGE_RESET
, 0, dev
->interface
, 0, NULL
);
389 USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);usleep(100); //from http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
390 USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);usleep(100);
394 s32
USBStorage_Open(usbstorage_handle
*dev
, s32 device_id
, u16 vid
, u16 pid
)
399 u32 iConf
, iInterface
, iEp
;
401 usb_configurationdesc
*ucd
;
402 usb_interfacedesc
*uid
;
403 usb_endpointdesc
*ued
;
404 bool reset_flag
= false;
406 max_lun
= __lwp_heap_allocate(&__heap
, 1);
410 memset(dev
, 0, sizeof(*dev
));
413 dev
->tag
= TAG_START
;
415 if (LWP_MutexInit(&dev
->lock
, false) < 0)
416 goto free_and_return
;
418 if (SYS_CreateAlarm(&dev
->alarm
) < 0)
419 goto free_and_return
;
423 retval
= USB_OpenDevice(device_id
, vid
, pid
, &dev
->usb_fd
);
425 goto free_and_return
;
427 retval
= USB_GetDescriptors(dev
->usb_fd
, &udd
);
429 goto free_and_return
;
431 for (iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++) {
432 ucd
= &udd
.configurations
[iConf
];
433 for (iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++) {
434 uid
= &ucd
->interfaces
[iInterface
];
435 if(uid
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
&&
436 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
438 if (uid
->bNumEndpoints
< 2)
441 dev
->ep_in
= dev
->ep_out
= 0;
442 for (iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++) {
443 ued
= &uid
->endpoints
[iEp
];
444 if (ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
447 if (ued
->bEndpointAddress
& USB_ENDPOINT_IN
) {
448 dev
->ep_in
= ued
->bEndpointAddress
;
451 dev
->ep_out
= ued
->bEndpointAddress
;
452 if(ued
->wMaxPacketSize
> 64 && (dev
->usb_fd
>=0x20 || dev
->usb_fd
<-1))
459 if (dev
->ep_in
!= 0 && dev
->ep_out
!= 0) {
460 dev
->configuration
= ucd
->bConfigurationValue
;
461 dev
->interface
= uid
->bInterfaceNumber
;
462 dev
->altInterface
= uid
->bAlternateSetting
;
469 USB_FreeDescriptors(&udd
);
470 retval
= USBSTORAGE_ENOINTERFACE
;
471 goto free_and_return
;
474 dev
->bInterfaceSubClass
= uid
->bInterfaceSubClass
;
476 USB_FreeDescriptors(&udd
);
478 retval
= USBSTORAGE_EINIT
;
479 // some devices return an error, ignore it
480 USB_GetConfiguration(dev
->usb_fd
, &conf
);
483 retval
= USBStorage_Reset(dev
);
487 LWP_MutexLock(dev
->lock
);
488 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
);
489 LWP_MutexUnlock(dev
->lock
);
494 dev
->max_lun
= *max_lun
+ 1;
496 if (retval
== USBSTORAGE_ETIMEDOUT
)
497 goto free_and_return
;
499 retval
= USBSTORAGE_OK
;
500 dev
->sector_size
= (u32
*) calloc(dev
->max_lun
, sizeof(u32
));
501 if(!dev
->sector_size
) {
503 goto free_and_return
;
506 /* taken from linux usbstorage module (drivers/usb/storage/transport.c)
508 * Some devices (i.e. Iomega Zip100) need this -- apparently
509 * the bulk pipes get STALLed when the GetMaxLUN request is
510 * processed. This is, in theory, harmless to all other devices
511 * (regardless of if they stall or not).
513 * 8/9/10: If anyone wants to actually use a Zip100, they can add this back.
514 * But for now, it seems to be breaking things more than it is helping.
516 //USB_ClearHalt(dev->usb_fd, dev->ep_in);
517 //USB_ClearHalt(dev->usb_fd, dev->ep_out);
520 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE_V5
);
525 USB_DeviceRemovalNotifyAsync(dev
->usb_fd
,__usb_deviceremoved_cb
,dev
);
526 retval
= USBSTORAGE_OK
;
531 __lwp_heap_free(&__heap
, max_lun
);
534 USBStorage_Close(dev
);
541 s32
USBStorage_Close(usbstorage_handle
*dev
)
548 if (dev
->usb_fd
!= -1)
549 USB_CloseDevice(&dev
->usb_fd
);
551 LWP_MutexDestroy(dev
->lock
);
552 SYS_RemoveAlarm(dev
->alarm
);
555 free(dev
->sector_size
);
558 __lwp_heap_free(&__heap
, dev
->buffer
);
560 memset(dev
, 0, sizeof(*dev
));
565 s32
USBStorage_Reset(usbstorage_handle
*dev
)
569 LWP_MutexLock(dev
->lock
);
570 retval
= __usbstorage_reset(dev
);
571 LWP_MutexUnlock(dev
->lock
);
576 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
581 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
585 if(lun
>= dev
->max_lun
)
589 retval
= __usbstorage_clearerrors(dev
, lun
);
592 USBStorage_Reset(dev
);
593 retval
= __usbstorage_clearerrors(dev
, lun
);
596 retval
= USBStorage_Inquiry(dev
, lun
);
597 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], NULL
);
601 s32
USBStorage_Inquiry(usbstorage_handle
*dev
, u8 lun
)
605 u8 cmd
[] = {SCSI_INQUIRY
, lun
<< 5,0,0,36,0};
610 memset(response
,0,36);
611 retval
= __cycle(dev
, lun
, response
, 36, cmd
, 6, 0, NULL
, NULL
);
614 if(retval
>=0) retval
=*response
& 31;
618 switch(*response & 31)
620 // info from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
622 case 7: // optical memory device (e.g., some optical disks)
634 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
637 u8 cmd
[10] = {SCSI_READ_CAPACITY
, lun
<<5};
640 retval
= __cycle(dev
, lun
, response
, sizeof(response
), cmd
, sizeof(cmd
), 0, NULL
, NULL
);
643 if(n_sectors
!= NULL
)
644 memcpy(n_sectors
, response
, 4);
645 if(sector_size
!= NULL
)
646 memcpy(sector_size
, response
+ 4, 4);
647 retval
= USBSTORAGE_OK
;
653 /* lo_ej = load/eject, controls the tray
654 * start = start(1) or stop(0) the motor (or eject(0), load(1))
655 * imm = return before the command has completed
656 * it might be a good idea to call this before STM_ShutdownToStandby() so the USB HDD doesn't stay on
658 s32
USBStorage_StartStop(usbstorage_handle
*dev
, u8 lun
, u8 lo_ej
, u8 start
, u8 imm
)
661 s32 retval
= USBSTORAGE_OK
;
664 (lun
<< 5) | (imm
&1),
667 ((lo_ej
&1)<<1) | (start
&1),
671 if(lun
>= dev
->max_lun
)
674 LWP_MutexLock(dev
->lock
);
676 retval
= __send_cbw(dev
, lun
, 0, CBW_IN
, cmd
, sizeof(cmd
));
678 // if imm==0, wait up to 10secs for spinup to finish
680 retval
= __read_csw(dev
, &status
, NULL
, (imm
? USBSTORAGE_TIMEOUT
: 10));
682 LWP_MutexUnlock(dev
->lock
);
684 if(retval
>=0 && status
!= 0)
685 retval
= USBSTORAGE_ESTATUS
;
690 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, u8
*buffer
)
707 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
710 // more than 60s since last use - make sure drive is awake
711 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
716 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
718 if(retval
> 0 && status
!= 0)
719 retval
= USBSTORAGE_ESTATUS
;
721 usb_last_used
= gettime();
722 usbtimeout
= USBSTORAGE_TIMEOUT
;
727 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
744 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
747 // more than 60s since last use - make sure drive is awake
748 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
753 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
754 if(retval
> 0 && status
!= 0)
755 retval
= USBSTORAGE_ESTATUS
;
757 usb_last_used
= gettime();
758 usbtimeout
= USBSTORAGE_TIMEOUT
;
763 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
765 if(dev
->suspended
== 1)
766 return USBSTORAGE_OK
;
768 USB_SuspendDevice(dev
->usb_fd
);
771 return USBSTORAGE_OK
;
775 The following is for implementing a DISC_INTERFACE
779 static bool __usbstorage_Startup(void)
781 if(USB_Initialize() < 0 || USBStorage_Initialize() < 0)
787 static bool __usbstorage_IsInserted(void)
789 usb_device_entry
*buffer
;
802 buffer
= (usb_device_entry
*)__lwp_heap_allocate(&__heap
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
806 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
808 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_MASS_STORAGE
, &device_count
) < 0)
810 if (__vid
!= 0 || __pid
!= 0)
811 USBStorage_Close(&__usbfd
);
813 __lwp_heap_free(&__heap
, buffer
);
819 if (__vid
!= 0 || __pid
!= 0) {
820 for(i
= 0; i
< device_count
; i
++) {
823 if(vid
!= 0 || pid
!= 0) {
824 if((vid
== __vid
) && (pid
== __pid
)) {
826 __lwp_heap_free(&__heap
,buffer
);
827 usleep(50); // I don't know why I have to wait but it's needed
832 USBStorage_Close(&__usbfd
);
833 __lwp_heap_free(&__heap
,buffer
);
836 for (i
= 0; i
< device_count
; i
++) {
839 if (vid
== 0 || pid
== 0)
842 if (USBStorage_Open(&__usbfd
, buffer
[i
].device_id
, vid
, pid
) < 0)
845 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
847 for (j
= 0; j
< maxLun
; j
++) {
848 retval
= USBStorage_MountLUN(&__usbfd
, j
);
852 __usbstorage_reset(&__usbfd
);
860 usb_last_used
= gettime()-secs_to_ticks(100);
868 USBStorage_Close(&__usbfd
);
870 __lwp_heap_free(&__heap
, buffer
);
874 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
881 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
886 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
893 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
898 static bool __usbstorage_ClearStatus(void)
903 static bool __usbstorage_Shutdown(void)
905 if (__vid
!= 0 || __pid
!= 0)
906 USBStorage_Close(&__usbfd
);
911 void USBStorage_Deinitialize()
913 __usbstorage_Shutdown();
914 LWP_CloseQueue(__usbstorage_waitq
);
918 DISC_INTERFACE __io_usbstorage
= {
920 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
921 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
922 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
923 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
924 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
925 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
926 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown