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
67 #define SCSI_SENSE_REPLY_SIZE 18
68 #define SCSI_SENSE_NOT_READY 0x02
69 #define SCSI_SENSE_MEDIUM_ERROR 0x03
70 #define SCSI_SENSE_HARDWARE_ERROR 0x04
72 #define USB_CLASS_MASS_STORAGE 0x08
73 #define MASS_STORAGE_RBC_COMMANDS 0x01
74 #define MASS_STORAGE_ATA_COMMANDS 0x02
75 #define MASS_STORAGE_QIC_COMMANDS 0x03
76 #define MASS_STORAGE_UFI_COMMANDS 0x04
77 #define MASS_STORAGE_SFF8070_COMMANDS 0x05
78 #define MASS_STORAGE_SCSI_COMMANDS 0x06
79 #define MASS_STORAGE_BULK_ONLY 0x50
81 #define USBSTORAGE_GET_MAX_LUN 0xFE
82 #define USBSTORAGE_RESET 0xFF
84 #define USB_ENDPOINT_BULK 0x02
86 #define USBSTORAGE_CYCLE_RETRIES 3
87 #define USBSTORAGE_TIMEOUT 2
89 #define INVALID_LUN -2
91 #define MAX_TRANSFER_SIZE_V0 4096
92 #define MAX_TRANSFER_SIZE_V5 (16*1024)
94 #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
107 static usbstorage_handle __usbfd
;
109 static bool __mounted
= false;
110 static u16 __vid
= 0;
111 static u16 __pid
= 0;
112 static bool usb2_mode
=true;
114 static s32
__usbstorage_reset(usbstorage_handle
*dev
);
115 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
);
116 s32
USBStorage_Inquiry(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
)
136 if(__vid
!= 0) USBStorage_Close(&__usbfd
);
140 static void __usb_timeouthandler(syswd_t alarm
,void *cbarg
)
142 usbstorage_handle
*dev
= (usbstorage_handle
*)cbarg
;
143 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
144 LWP_ThreadBroadcast(__usbstorage_waitq
);
147 static void __usb_settimeout(usbstorage_handle
*dev
, u32 secs
)
153 SYS_SetAlarm(dev
->alarm
,&ts
,__usb_timeouthandler
,dev
);
156 static s32
__USB_BlkMsgTimeout(usbstorage_handle
*dev
, u8 bEndpoint
, u16 wLength
, void *rpData
, u32 timeout
)
160 dev
->retval
= USBSTORAGE_PROCESSING
;
161 retval
= USB_WriteBlkMsgAsync(dev
->usb_fd
, bEndpoint
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
162 if(retval
< 0) return retval
;
164 __usb_settimeout(dev
, timeout
);
167 retval
= dev
->retval
;
168 if(retval
!=USBSTORAGE_PROCESSING
) break;
169 else LWP_ThreadSleep(__usbstorage_waitq
);
170 } while(retval
==USBSTORAGE_PROCESSING
);
173 USB_ClearHalt(dev
->usb_fd
, bEndpoint
);
178 static s32
__USB_CtrlMsgTimeout(usbstorage_handle
*dev
, u8 bmRequestType
, u8 bmRequest
, u16 wValue
, u16 wIndex
, u16 wLength
, void *rpData
)
182 dev
->retval
= USBSTORAGE_PROCESSING
;
183 retval
= USB_WriteCtrlMsgAsync(dev
->usb_fd
, bmRequestType
, bmRequest
, wValue
, wIndex
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
184 if(retval
< 0) return retval
;
186 __usb_settimeout(dev
, usbtimeout
);
189 retval
= dev
->retval
;
190 if(retval
!=USBSTORAGE_PROCESSING
) break;
191 else LWP_ThreadSleep(__usbstorage_waitq
);
192 } while(retval
==USBSTORAGE_PROCESSING
);
197 static u8
*arena_ptr
=NULL
;
198 static u8
*cbw_buffer
=NULL
;
200 s32
USBStorage_Initialize()
207 _CPU_ISR_Disable(level
);
208 LWP_InitQueue(&__usbstorage_waitq
);
210 arena_ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
211 if((u32
)arena_ptr
< (u32
)SYS_GetArena2Lo()) {
212 _CPU_ISR_Restore(level
);
215 SYS_SetArena2Hi(arena_ptr
);
217 __lwp_heap_init(&__heap
, arena_ptr
, HEAP_SIZE
, 32);
218 cbw_buffer
=(u8
*)__lwp_heap_allocate(&__heap
, 32);
220 _CPU_ISR_Restore(level
);
224 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
226 s32 retval
= USBSTORAGE_OK
;
228 if(cbLen
== 0 || cbLen
> 16)
231 memset(cbw_buffer
, 0, CBW_SIZE
);
233 __stwbrx(cbw_buffer
, 0, CBW_SIGNATURE
);
234 __stwbrx(cbw_buffer
, 4, ++dev
->tag
);
235 __stwbrx(cbw_buffer
, 8, len
);
236 cbw_buffer
[12] = flags
;
237 cbw_buffer
[13] = lun
;
238 cbw_buffer
[14] = (cbLen
> 6 ? 10 : 6);
240 memcpy(cbw_buffer
+ 15, cb
, cbLen
);
242 if(dev
->suspended
== 1)
244 USB_ResumeDevice(dev
->usb_fd
);
248 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)cbw_buffer
, usbtimeout
);
250 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
251 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
256 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
, u32 timeout
)
258 s32 retval
= USBSTORAGE_OK
;
259 u32 signature
, tag
, _dataResidue
, _status
;
261 memset(cbw_buffer
, 0, CSW_SIZE
);
263 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, cbw_buffer
, timeout
);
264 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
265 else if(retval
< 0) return retval
;
267 signature
= __lwbrx(cbw_buffer
, 0);
268 tag
= __lwbrx(cbw_buffer
, 4);
269 _dataResidue
= __lwbrx(cbw_buffer
, 8);
270 _status
= cbw_buffer
[12];
272 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
274 if(dataResidue
!= NULL
)
275 *dataResidue
= _dataResidue
;
279 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
281 return USBSTORAGE_OK
;
284 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
286 s32 retval
= USBSTORAGE_OK
;
291 u8 ep
= write
? dev
->ep_out
: dev
->ep_in
;
292 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
295 max_size
=MAX_TRANSFER_SIZE_V5
;
297 max_size
=MAX_TRANSFER_SIZE_V0
;
299 LWP_MutexLock(dev
->lock
);
302 u8
*_buffer
= buffer
;
306 if(retval
== USBSTORAGE_ETIMEDOUT
)
309 retval
= __send_cbw(dev
, lun
, len
, (write
? CBW_OUT
:CBW_IN
), cb
, cbLen
);
311 while(_len
> 0 && retval
>= 0)
313 u32 thisLen
= _len
> max_size
? max_size
: _len
;
315 if ((u32
)_buffer
&0x1F || !((u32
)_buffer
&0x10000000)) {
316 if (write
) memcpy(dev
->buffer
, _buffer
, thisLen
);
317 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, dev
->buffer
, usbtimeout
);
318 if (!write
&& retval
> 0)
319 memcpy(_buffer
, dev
->buffer
, retval
);
321 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, _buffer
, usbtimeout
);
323 if (retval
== thisLen
) {
327 else if (retval
!= USBSTORAGE_ETIMEDOUT
)
328 retval
= USBSTORAGE_EDATARESIDUE
;
332 retval
= __read_csw(dev
, &status
, &dataResidue
, usbtimeout
);
335 if (__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
336 retval
= USBSTORAGE_ETIMEDOUT
;
338 } while (retval
< 0 && retries
> 0);
340 LWP_MutexUnlock(dev
->lock
);
344 if(_dataResidue
!= NULL
)
345 *_dataResidue
= dataResidue
;
350 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
354 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
357 memset(cmd
, 0, sizeof(cmd
));
358 cmd
[0] = SCSI_TEST_UNIT_READY
;
360 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
361 if (retval
< 0) return retval
;
365 cmd
[0] = SCSI_REQUEST_SENSE
;
367 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
368 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
369 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
371 switch (sense
[2]&0xF) {
372 case SCSI_SENSE_NOT_READY
:
373 return USBSTORAGE_EINIT
;
374 case SCSI_SENSE_MEDIUM_ERROR
:
375 case SCSI_SENSE_HARDWARE_ERROR
:
376 return USBSTORAGE_ESENSE
;
384 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
388 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 USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);usleep(10000); //from http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
392 USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);usleep(10000);
396 s32
USBStorage_Open(usbstorage_handle
*dev
, s32 device_id
, u16 vid
, u16 pid
)
401 u32 iConf
, iInterface
, iEp
;
403 usb_configurationdesc
*ucd
;
404 usb_interfacedesc
*uid
;
405 usb_endpointdesc
*ued
;
407 max_lun
= __lwp_heap_allocate(&__heap
, 1);
411 memset(dev
, 0, sizeof(*dev
));
414 dev
->tag
= TAG_START
;
416 if (LWP_MutexInit(&dev
->lock
, false) < 0)
417 goto free_and_return
;
419 if (SYS_CreateAlarm(&dev
->alarm
) < 0)
420 goto free_and_return
;
422 retval
= USB_OpenDevice(device_id
, vid
, pid
, &dev
->usb_fd
);
424 goto free_and_return
;
426 retval
= USB_GetDescriptors(dev
->usb_fd
, &udd
);
428 goto free_and_return
;
430 for (iConf
= 0; iConf
< udd
.bNumConfigurations
; iConf
++) {
431 ucd
= &udd
.configurations
[iConf
];
432 for (iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++) {
433 uid
= &ucd
->interfaces
[iInterface
];
434 if(uid
->bInterfaceClass
== USB_CLASS_MASS_STORAGE
&& /*
435 (uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS
436 || uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS
437 || uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS
438 || uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS
439 || uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS
440 || uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) &&*/
441 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
444 if (uid
->bNumEndpoints
< 2)
447 dev
->ep_in
= dev
->ep_out
= 0;
448 for (iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++) {
449 ued
= &uid
->endpoints
[iEp
];
450 if (ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
453 if (ued
->bEndpointAddress
& USB_ENDPOINT_IN
) {
454 dev
->ep_in
= ued
->bEndpointAddress
;
457 dev
->ep_out
= ued
->bEndpointAddress
;
458 if(ued
->wMaxPacketSize
> 64 && (dev
->usb_fd
>=0x20 || dev
->usb_fd
<-1))
465 if (dev
->ep_in
!= 0 && dev
->ep_out
!= 0) {
466 dev
->configuration
= ucd
->bConfigurationValue
;
467 dev
->interface
= uid
->bInterfaceNumber
;
468 dev
->altInterface
= uid
->bAlternateSetting
;
475 USB_FreeDescriptors(&udd
);
476 retval
= USBSTORAGE_ENOINTERFACE
;
477 goto free_and_return
;
480 dev
->bInterfaceSubClass
= uid
->bInterfaceSubClass
;
482 USB_FreeDescriptors(&udd
);
484 retval
= USBSTORAGE_EINIT
;
485 // some devices return an error, ignore it
486 USB_GetConfiguration(dev
->usb_fd
, &conf
);
488 if (conf
!= dev
->configuration
) USB_SetConfiguration(dev
->usb_fd
, dev
->configuration
);
489 if (dev
->altInterface
!=0) USB_SetAlternativeInterface(dev
->usb_fd
, dev
->interface
, dev
->altInterface
);
492 retval
= USBStorage_Reset(dev
);
496 LWP_MutexLock(dev
->lock
);
497 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
);
498 LWP_MutexUnlock(dev
->lock
);
503 dev
->max_lun
= *max_lun
+ 1;
505 if (retval
== USBSTORAGE_ETIMEDOUT
)
506 goto free_and_return
;
508 retval
= USBSTORAGE_OK
;
509 dev
->sector_size
= (u32
*) calloc(dev
->max_lun
, sizeof(u32
));
510 if(!dev
->sector_size
) {
512 goto free_and_return
;
515 /* taken from linux usbstorage module (drivers/usb/storage/transport.c)
517 * Some devices (i.e. Iomega Zip100) need this -- apparently
518 * the bulk pipes get STALLed when the GetMaxLUN request is
519 * processed. This is, in theory, harmless to all other devices
520 * (regardless of if they stall or not).
522 * 8/9/10: If anyone wants to actually use a Zip100, they can add this back.
523 * But for now, it seems to be breaking things more than it is helping.
525 //USB_ClearHalt(dev->usb_fd, dev->ep_in);
526 //USB_ClearHalt(dev->usb_fd, dev->ep_out);
529 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE_V5
);
534 USB_DeviceRemovalNotifyAsync(dev
->usb_fd
,__usb_deviceremoved_cb
,dev
);
535 retval
= USBSTORAGE_OK
;
540 __lwp_heap_free(&__heap
, max_lun
);
543 USBStorage_Close(dev
);
550 s32
USBStorage_Close(usbstorage_handle
*dev
)
557 if (dev
->usb_fd
!= -1)
558 USB_CloseDevice(&dev
->usb_fd
);
560 LWP_MutexDestroy(dev
->lock
);
561 SYS_RemoveAlarm(dev
->alarm
);
564 free(dev
->sector_size
);
567 __lwp_heap_free(&__heap
, dev
->buffer
);
569 memset(dev
, 0, sizeof(*dev
));
574 s32
USBStorage_Reset(usbstorage_handle
*dev
)
578 LWP_MutexLock(dev
->lock
);
579 retval
= __usbstorage_reset(dev
);
580 LWP_MutexUnlock(dev
->lock
);
585 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
590 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
595 if(lun
>= dev
->max_lun
)
599 retval
= __usbstorage_clearerrors(dev
, lun
);
602 USBStorage_Reset(dev
);
603 retval
= __usbstorage_clearerrors(dev
, lun
);
606 retval
= USBStorage_Inquiry(dev
, lun
);
608 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], &n_sectors
);
609 if(retval
>= 0 && (dev
->sector_size
[lun
]<512 || n_sectors
==0))
615 s32
USBStorage_Inquiry(usbstorage_handle
*dev
, u8 lun
)
619 u8 cmd
[] = {SCSI_INQUIRY
, lun
<< 5,0,0,36,0};
624 memset(response
,0,36);
626 retval
= __cycle(dev
, lun
, response
, 36, cmd
, 6, 0, NULL
, NULL
);
630 if(retval
>=0) retval
=*response
& 31;
636 // info from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
638 case 7: // optical memory device (e.g., some optical disks)
650 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
653 u8 cmd
[10] = {SCSI_READ_CAPACITY
, lun
<<5};
656 retval
= __cycle(dev
, lun
, response
, sizeof(response
), cmd
, sizeof(cmd
), 0, NULL
, NULL
);
659 if(n_sectors
!= NULL
)
660 memcpy(n_sectors
, response
, 4);
661 if(sector_size
!= NULL
)
662 memcpy(sector_size
, response
+ 4, 4);
663 retval
= USBSTORAGE_OK
;
669 s32
USBStorage_IsDVD()
671 u32 sectorsize
, numSectors
;
673 if(!__mounted
|| __usbfd
.sector_size
[__lun
] != 2048)
676 if(USBStorage_ReadCapacity(&__usbfd
, __lun
, §orsize
, &numSectors
) < 0)
679 if(sectorsize
== 2048)
684 /* lo_ej = load/eject, controls the tray
685 * start = start(1) or stop(0) the motor (or eject(0), load(1))
686 * imm = return before the command has completed
687 * it might be a good idea to call this before STM_ShutdownToStandby() so the USB HDD doesn't stay on
689 s32
USBStorage_StartStop(usbstorage_handle
*dev
, u8 lun
, u8 lo_ej
, u8 start
, u8 imm
)
692 s32 retval
= USBSTORAGE_OK
;
695 (lun
<< 5) | (imm
&1),
698 ((lo_ej
&1)<<1) | (start
&1),
702 if(lun
>= dev
->max_lun
)
705 LWP_MutexLock(dev
->lock
);
707 retval
= __send_cbw(dev
, lun
, 0, CBW_IN
, cmd
, sizeof(cmd
));
709 // if imm==0, wait up to 10secs for spinup to finish
711 retval
= __read_csw(dev
, &status
, NULL
, (imm
? USBSTORAGE_TIMEOUT
: 10));
713 LWP_MutexUnlock(dev
->lock
);
715 if(retval
>=0 && status
!= 0)
716 retval
= USBSTORAGE_ESTATUS
;
721 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, u8
*buffer
)
738 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
741 // more than 60s since last use - make sure drive is awake
742 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
745 USBStorage_MountLUN(dev
, lun
);
748 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
749 if(retval
> 0 && status
!= 0)
750 retval
= USBSTORAGE_ESTATUS
;
752 usb_last_used
= gettime();
753 usbtimeout
= USBSTORAGE_TIMEOUT
;
758 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
775 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
778 // more than 60s since last use - make sure drive is awake
779 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
782 USBStorage_MountLUN(dev
, lun
);
785 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
786 if(retval
> 0 && status
!= 0)
787 retval
= USBSTORAGE_ESTATUS
;
789 usb_last_used
= gettime();
790 usbtimeout
= USBSTORAGE_TIMEOUT
;
795 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
797 if(dev
->suspended
== 1)
798 return USBSTORAGE_OK
;
800 USB_SuspendDevice(dev
->usb_fd
);
803 return USBSTORAGE_OK
;
807 The following is for implementing a DISC_INTERFACE
811 static bool __usbstorage_Startup(void)
813 if(USB_Initialize() < 0 || USBStorage_Initialize() < 0)
819 static bool __usbstorage_IsInserted(void)
821 usb_device_entry
*buffer
;
834 buffer
= (usb_device_entry
*)__lwp_heap_allocate(&__heap
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
838 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
840 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_MASS_STORAGE
, &device_count
) < 0)
842 if (__vid
!= 0 || __pid
!= 0)
843 USBStorage_Close(&__usbfd
);
845 __lwp_heap_free(&__heap
, buffer
);
851 if (__vid
!= 0 || __pid
!= 0) {
852 for(i
= 0; i
< device_count
; i
++) {
855 if(vid
!= 0 || pid
!= 0) {
856 if((vid
== __vid
) && (pid
== __pid
)) {
858 __lwp_heap_free(&__heap
,buffer
);
859 usleep(50); // I don't know why I have to wait but it's needed
864 USBStorage_Close(&__usbfd
); // device changed or unplugged, return false the first time to notify to the client that he must unmount devices
865 __lwp_heap_free(&__heap
,buffer
);
868 for (i
= 0; i
< device_count
; i
++) {
871 if (vid
== 0 || pid
== 0)
874 if (USBStorage_Open(&__usbfd
, buffer
[i
].device_id
, vid
, pid
) < 0)
877 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
878 for (j
= 0; j
< maxLun
; j
++) {
879 retval
= USBStorage_MountLUN(&__usbfd
, j
);
881 if (retval
== INVALID_LUN
)
886 __usbstorage_reset(&__usbfd
);
894 usb_last_used
= gettime()-secs_to_ticks(100);
902 USBStorage_Close(&__usbfd
);
904 __lwp_heap_free(&__heap
, buffer
);
909 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
916 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
921 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
928 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
933 static bool __usbstorage_ClearStatus(void)
938 static bool __usbstorage_Shutdown(void)
940 if (__vid
!= 0 || __pid
!= 0)
941 USBStorage_Close(&__usbfd
);
946 void USBStorage_Deinitialize()
948 __usbstorage_Shutdown();
949 LWP_CloseQueue(__usbstorage_waitq
);
953 DISC_INTERFACE __io_usbstorage
= {
955 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
956 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
957 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
958 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
959 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
960 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
961 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown