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_START_STOP 0x1B
62 #define SCSI_READ_CAPACITY 0x25
63 #define SCSI_READ_10 0x28
64 #define SCSI_WRITE_10 0x2A
66 #define SCSI_SENSE_REPLY_SIZE 18
67 #define SCSI_SENSE_NOT_READY 0x02
68 #define SCSI_SENSE_MEDIUM_ERROR 0x03
69 #define SCSI_SENSE_HARDWARE_ERROR 0x04
71 #define USB_CLASS_MASS_STORAGE 0x08
72 #define MASS_STORAGE_RBC_COMMANDS 0x01
73 #define MASS_STORAGE_ATA_COMMANDS 0x02
74 #define MASS_STORAGE_QIC_COMMANDS 0x03
75 #define MASS_STORAGE_UFI_COMMANDS 0x04
76 #define MASS_STORAGE_SFF8070_COMMANDS 0x05
77 #define MASS_STORAGE_SCSI_COMMANDS 0x06
78 #define MASS_STORAGE_BULK_ONLY 0x50
80 #define USBSTORAGE_GET_MAX_LUN 0xFE
81 #define USBSTORAGE_RESET 0xFF
83 #define USB_ENDPOINT_BULK 0x02
85 #define USBSTORAGE_CYCLE_RETRIES 3
86 #define USBSTORAGE_TIMEOUT 2
88 #define MAX_TRANSFER_SIZE_V0 4096
89 #define MAX_TRANSFER_SIZE_V5 (16*1024)
91 #define DEVLIST_MAXSIZE 8
96 static heap_cntrl __heap
;
97 static bool __inited
= false;
98 static u64 usb_last_used
= 0;
99 static lwpq_t __usbstorage_waitq
= 0;
100 static u32 usbtimeout
= USBSTORAGE_TIMEOUT
;
103 The following is for implementing a DISC_INTERFACE
108 static usbstorage_handle __usbfd
;
110 static bool __mounted
= false;
111 static u16 __vid
= 0;
112 static u16 __pid
= 0;
113 static bool usb2_mode
=true;
115 static s32
__usbstorage_reset(usbstorage_handle
*dev
);
116 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
);
118 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
119 * but there's currently no other known way of doing this and it's in my humble
120 * opinion still better than having a function blocking forever while waiting
121 * for the USB data/IOS reply..
124 static s32
__usb_blkmsg_cb(s32 retval
, void *dummy
)
126 usbstorage_handle
*dev
= (usbstorage_handle
*)dummy
;
127 dev
->retval
= retval
;
128 SYS_CancelAlarm(dev
->alarm
);
129 LWP_ThreadBroadcast(__usbstorage_waitq
);
133 static s32
__usb_deviceremoved_cb(s32 retval
,void *arg
)
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 s32
USBStorage_Initialize()
204 _CPU_ISR_Disable(level
);
205 LWP_InitQueue(&__usbstorage_waitq
);
207 ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
208 if((u32
)ptr
< (u32
)SYS_GetArena2Lo()) {
209 _CPU_ISR_Restore(level
);
213 SYS_SetArena2Hi(ptr
);
214 __lwp_heap_init(&__heap
, ptr
, HEAP_SIZE
, 32);
216 _CPU_ISR_Restore(level
);
220 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
222 s32 retval
= USBSTORAGE_OK
;
224 if(cbLen
== 0 || cbLen
> 16)
227 memset(dev
->buffer
, 0, CBW_SIZE
);
229 __stwbrx(dev
->buffer
, 0, CBW_SIGNATURE
);
230 __stwbrx(dev
->buffer
, 4, ++dev
->tag
);
231 __stwbrx(dev
->buffer
, 8, len
);
232 dev
->buffer
[12] = flags
;
233 dev
->buffer
[13] = lun
;
234 dev
->buffer
[14] = (cbLen
> 6 ? 10 : 6);
236 memcpy(dev
->buffer
+ 15, cb
, cbLen
);
238 if(dev
->suspended
== 1)
240 USB_ResumeDevice(dev
->usb_fd
);
244 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)dev
->buffer
, usbtimeout
);
246 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
247 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
252 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
, u32 timeout
)
254 s32 retval
= USBSTORAGE_OK
;
255 u32 signature
, tag
, _dataResidue
, _status
;
257 memset(dev
->buffer
, 0, CSW_SIZE
);
259 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, dev
->buffer
, timeout
);
260 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
261 else if(retval
< 0) return retval
;
263 signature
= __lwbrx(dev
->buffer
, 0);
264 tag
= __lwbrx(dev
->buffer
, 4);
265 _dataResidue
= __lwbrx(dev
->buffer
, 8);
266 _status
= dev
->buffer
[12];
268 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
270 if(dataResidue
!= NULL
)
271 *dataResidue
= _dataResidue
;
275 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
277 return USBSTORAGE_OK
;
280 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
282 s32 retval
= USBSTORAGE_OK
;
287 u8 ep
= write
? dev
->ep_out
: dev
->ep_in
;
288 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
291 max_size
=MAX_TRANSFER_SIZE_V5
;
293 max_size
=MAX_TRANSFER_SIZE_V0
;
295 LWP_MutexLock(dev
->lock
);
298 u8
*_buffer
= buffer
;
302 if(retval
== USBSTORAGE_ETIMEDOUT
)
305 retval
= __send_cbw(dev
, lun
, len
, (write
? CBW_OUT
:CBW_IN
), cb
, cbLen
);
307 while(_len
> 0 && retval
>= 0)
309 u32 thisLen
= _len
> max_size
? max_size
: _len
;
311 if ((u32
)_buffer
&0x1F || !((u32
)_buffer
&0x10000000)) {
312 if (write
) memcpy(dev
->buffer
, _buffer
, thisLen
);
313 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, dev
->buffer
, usbtimeout
);
314 if (!write
&& retval
> 0)
315 memcpy(_buffer
, dev
->buffer
, retval
);
317 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, _buffer
, usbtimeout
);
319 if (retval
== thisLen
) {
323 else if (retval
!= USBSTORAGE_ETIMEDOUT
)
324 retval
= USBSTORAGE_EDATARESIDUE
;
328 __read_csw(dev
, &status
, &dataResidue
, usbtimeout
);
331 if (__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
332 retval
= USBSTORAGE_ETIMEDOUT
;
335 } while (retval
< 0 && retries
> 0);
337 LWP_MutexUnlock(dev
->lock
);
341 if(_dataResidue
!= NULL
)
342 *_dataResidue
= dataResidue
;
347 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
351 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
354 memset(cmd
, 0, sizeof(cmd
));
355 cmd
[0] = SCSI_TEST_UNIT_READY
;
357 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
358 if (retval
< 0) return retval
;
362 cmd
[0] = SCSI_REQUEST_SENSE
;
364 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
365 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
366 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
368 switch (sense
[2]&0xF) {
369 case SCSI_SENSE_NOT_READY
:
370 return USBSTORAGE_EINIT
;
371 case SCSI_SENSE_MEDIUM_ERROR
:
372 case SCSI_SENSE_HARDWARE_ERROR
:
373 return USBSTORAGE_ESENSE
;
381 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
385 s32 retval
= __USB_CtrlMsgTimeout(dev
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_CLASS
| USB_CTRLTYPE_REC_INTERFACE
), USBSTORAGE_RESET
, 0, dev
->interface
, 0, NULL
);
391 s32
USBStorage_Open(usbstorage_handle
*dev
, s32 device_id
, u16 vid
, u16 pid
)
396 u32 iConf
, iInterface
, iEp
;
398 usb_configurationdesc
*ucd
;
399 usb_interfacedesc
*uid
;
400 usb_endpointdesc
*ued
;
401 bool reset_flag
= false;
403 max_lun
= __lwp_heap_allocate(&__heap
, 1);
407 memset(dev
, 0, sizeof(*dev
));
410 dev
->tag
= TAG_START
;
412 if (LWP_MutexInit(&dev
->lock
, false) < 0)
413 goto free_and_return
;
415 if (SYS_CreateAlarm(&dev
->alarm
) < 0)
416 goto free_and_return
;
420 retval
= USB_OpenDevice(device_id
, vid
, pid
, &dev
->usb_fd
);
422 goto free_and_return
;
424 retval
= USB_GetDescriptors(dev
->usb_fd
, &udd
);
426 goto free_and_return
;
428 for (iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++) {
429 ucd
= &udd
.configurations
[iConf
];
430 for (iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++) {
431 uid
= &ucd
->interfaces
[iInterface
];
432 if(uid
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
&&
433 (uid
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
434 || uid
->bInterfaceSubClass
== MASS_STORAGE_RBC_COMMANDS
435 || uid
->bInterfaceSubClass
== MASS_STORAGE_ATA_COMMANDS
436 || uid
->bInterfaceSubClass
== MASS_STORAGE_QIC_COMMANDS
437 || uid
->bInterfaceSubClass
== MASS_STORAGE_UFI_COMMANDS
438 || uid
->bInterfaceSubClass
== MASS_STORAGE_SFF8070_COMMANDS
) &&
439 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
441 if (uid
->bNumEndpoints
< 2)
445 dev
->ep_in
= dev
->ep_out
= 0;
446 for (iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++) {
447 ued
= &uid
->endpoints
[iEp
];
448 if (ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
451 if (ued
->bEndpointAddress
& USB_ENDPOINT_IN
) {
452 dev
->ep_in
= ued
->bEndpointAddress
;
455 dev
->ep_out
= ued
->bEndpointAddress
;
456 if(ued
->wMaxPacketSize
> 64 && (dev
->usb_fd
>=0x20 || dev
->usb_fd
<-1))
463 if (dev
->ep_in
!= 0 && dev
->ep_out
!= 0) {
464 dev
->configuration
= ucd
->bConfigurationValue
;
465 dev
->interface
= uid
->bInterfaceNumber
;
466 dev
->altInterface
= uid
->bAlternateSetting
;
474 USB_FreeDescriptors(&udd
);
475 retval
= USBSTORAGE_ENOINTERFACE
;
476 goto free_and_return
;
479 dev
->bInterfaceSubClass
= uid
->bInterfaceSubClass
;
481 USB_FreeDescriptors(&udd
);
483 retval
= USBSTORAGE_EINIT
;
484 // some devices return an error, ignore it
485 USB_GetConfiguration(dev
->usb_fd
, &conf
);
487 if (conf
!= dev
->configuration
&& USB_SetConfiguration(dev
->usb_fd
, dev
->configuration
) < 0)
488 goto free_and_return
;
490 if (dev
->altInterface
!=0 && USB_SetAlternativeInterface(dev
->usb_fd
, dev
->interface
, dev
->altInterface
) < 0)
491 goto free_and_return
;
495 if(!reset_flag
&& dev
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
)
498 retval
= USBStorage_Reset(dev
);
501 USB_CloseDevice(&dev
->usb_fd
);
506 LWP_MutexLock(dev
->lock
);
507 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
);
508 LWP_MutexUnlock(dev
->lock
);
513 dev
->max_lun
= *max_lun
+ 1;
515 if (retval
== USBSTORAGE_ETIMEDOUT
)
516 goto free_and_return
;
518 retval
= USBSTORAGE_OK
;
519 dev
->sector_size
= (u32
*) calloc(dev
->max_lun
, sizeof(u32
));
520 if(!dev
->sector_size
) {
522 goto free_and_return
;
525 /* taken from linux usbstorage module (drivers/usb/storage/transport.c)
527 * Some devices (i.e. Iomega Zip100) need this -- apparently
528 * the bulk pipes get STALLed when the GetMaxLUN request is
529 * processed. This is, in theory, harmless to all other devices
530 * (regardless of if they stall or not).
532 * 8/9/10: If anyone wants to actually use a Zip100, they can add this back.
533 * But for now, it seems to be breaking things more than it is helping.
535 //USB_ClearHalt(dev->usb_fd, dev->ep_in);
536 //USB_ClearHalt(dev->usb_fd, dev->ep_out);
539 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE_V5
);
544 USB_DeviceRemovalNotifyAsync(dev
->usb_fd
,__usb_deviceremoved_cb
,dev
);
545 retval
= USBSTORAGE_OK
;
550 __lwp_heap_free(&__heap
, max_lun
);
553 USBStorage_Close(dev
);
560 s32
USBStorage_Close(usbstorage_handle
*dev
)
567 if (dev
->usb_fd
!= -1)
568 USB_CloseDevice(&dev
->usb_fd
);
570 LWP_MutexDestroy(dev
->lock
);
571 SYS_RemoveAlarm(dev
->alarm
);
574 free(dev
->sector_size
);
577 __lwp_heap_free(&__heap
, dev
->buffer
);
579 memset(dev
, 0, sizeof(*dev
));
584 s32
USBStorage_Reset(usbstorage_handle
*dev
)
588 LWP_MutexLock(dev
->lock
);
589 retval
= __usbstorage_reset(dev
);
590 LWP_MutexUnlock(dev
->lock
);
595 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
600 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
604 if(lun
>= dev
->max_lun
)
607 retval
= __usbstorage_clearerrors(dev
, lun
);
611 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], NULL
);
616 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
619 u8 cmd
[10] = {SCSI_READ_CAPACITY
, lun
<<5};
622 retval
= __cycle(dev
, lun
, response
, sizeof(response
), cmd
, sizeof(cmd
), 0, NULL
, NULL
);
625 if(n_sectors
!= NULL
)
626 memcpy(n_sectors
, response
, 4);
627 if(sector_size
!= NULL
)
628 memcpy(sector_size
, response
+ 4, 4);
629 retval
= USBSTORAGE_OK
;
635 /* lo_ej = load/eject, controls the tray
636 * start = start(1) or stop(0) the motor (or eject(0), load(1))
637 * imm = return before the command has completed
638 * it might be a good idea to call this before STM_ShutdownToStandby() so the USB HDD doesn't stay on
640 s32
USBStorage_StartStop(usbstorage_handle
*dev
, u8 lun
, u8 lo_ej
, u8 start
, u8 imm
)
643 s32 retval
= USBSTORAGE_OK
;
646 (lun
<< 5) | (imm
&1),
649 ((lo_ej
&1)<<1) | (start
&1),
653 if(lun
>= dev
->max_lun
)
656 LWP_MutexLock(dev
->lock
);
658 retval
= __send_cbw(dev
, lun
, 0, CBW_IN
, cmd
, sizeof(cmd
));
660 // if imm==0, wait up to 10secs for spinup to finish
662 retval
= __read_csw(dev
, &status
, NULL
, (imm
? USBSTORAGE_TIMEOUT
: 10));
664 LWP_MutexUnlock(dev
->lock
);
666 if(retval
>=0 && status
!= 0)
667 retval
= USBSTORAGE_ESTATUS
;
672 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, u8
*buffer
)
689 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
692 // more than 60s since last use - make sure drive is awake
693 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
696 USB_ResumeDevice(dev
->usb_fd
);
698 if(dev
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
)
700 retval
= __usbstorage_clearerrors(dev
, lun
);
705 retval
= USBStorage_StartStop(dev
, lun
, 0, 1, 0);
712 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
713 if(retval
> 0 && status
!= 0)
714 retval
= USBSTORAGE_ESTATUS
;
716 usb_last_used
= gettime();
717 usbtimeout
= USBSTORAGE_TIMEOUT
;
722 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
739 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
742 // more than 60s since last use - make sure drive is awake
743 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
746 USB_ResumeDevice(dev
->usb_fd
);
748 if(dev
->bInterfaceSubClass
== MASS_STORAGE_SCSI_COMMANDS
)
750 retval
= __usbstorage_clearerrors(dev
, lun
);
754 retval
= USBStorage_StartStop(dev
, lun
, 0, 1, 0);
761 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
762 if(retval
> 0 && status
!= 0)
763 retval
= USBSTORAGE_ESTATUS
;
765 usb_last_used
= gettime();
766 usbtimeout
= USBSTORAGE_TIMEOUT
;
771 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
773 if(dev
->suspended
== 1)
774 return USBSTORAGE_OK
;
776 USB_SuspendDevice(dev
->usb_fd
);
779 return USBSTORAGE_OK
;
783 The following is for implementing a DISC_INTERFACE
787 static bool __usbstorage_Startup(void)
789 if(USB_Initialize() < 0 || USBStorage_Initialize() < 0)
795 static bool __usbstorage_IsInserted(void)
797 usb_device_entry
*buffer
;
810 buffer
= (usb_device_entry
*)__lwp_heap_allocate(&__heap
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
814 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
816 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_MASS_STORAGE
, &device_count
) < 0)
818 if (__vid
!= 0 || __pid
!= 0)
819 USBStorage_Close(&__usbfd
);
821 __lwp_heap_free(&__heap
, buffer
);
827 if (__vid
!= 0 || __pid
!= 0) {
828 for(i
= 0; i
< device_count
; i
++) {
831 if(vid
!= 0 || pid
!= 0) {
832 if((vid
== __vid
) && (pid
== __pid
)) {
834 __lwp_heap_free(&__heap
,buffer
);
835 usleep(50); // I don't know why I have to wait but it's needed
840 USBStorage_Close(&__usbfd
);
841 __lwp_heap_free(&__heap
,buffer
);
845 for (i
= 0; i
< device_count
; i
++) {
848 if (vid
== 0 || pid
== 0)
851 if (USBStorage_Open(&__usbfd
, buffer
[i
].device_id
, vid
, pid
) < 0)
854 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
855 for (j
= 0; j
< maxLun
; j
++) {
856 retval
= USBStorage_MountLUN(&__usbfd
, j
);
858 if (retval
== USBSTORAGE_ETIMEDOUT
)
868 usb_last_used
= gettime()-secs_to_ticks(100);
876 USBStorage_Close(&__usbfd
);
878 __lwp_heap_free(&__heap
, buffer
);
882 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
889 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
894 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
901 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
906 static bool __usbstorage_ClearStatus(void)
911 static bool __usbstorage_Shutdown(void)
913 if (__vid
!= 0 || __pid
!= 0)
914 USBStorage_Close(&__usbfd
);
919 DISC_INTERFACE __io_usbstorage
= {
921 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
922 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
923 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
924 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
925 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
926 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
927 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown