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 -------------------------------------------------------------*/
43 #include "processor.h"
45 #include "lwp_watchdog.h"
47 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
49 #define HEAP_SIZE (18*1024)
50 #define TAG_START 0x0BADC0DE
53 #define CBW_SIGNATURE 0x43425355
54 #define CBW_IN (1 << 7)
58 #define CSW_SIGNATURE 0x53425355
60 #define SCSI_TEST_UNIT_READY 0x00
61 #define SCSI_REQUEST_SENSE 0x03
62 #define SCSI_INQUIRY 0x12
63 #define SCSI_START_STOP 0x1B
64 #define SCSI_READ_CAPACITY 0x25
65 #define SCSI_READ_10 0x28
66 #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 INVALID_LUN -2
92 #define MAX_TRANSFER_SIZE_V0 4096
93 #define MAX_TRANSFER_SIZE_V5 (16*1024)
95 #define DEVLIST_MAXSIZE 8
97 static heap_cntrl __heap
;
98 static bool __inited
= false;
99 static u64 usb_last_used
= 0;
100 static lwpq_t __usbstorage_waitq
= 0;
101 static u32 usbtimeout
= USBSTORAGE_TIMEOUT
;
104 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
);
117 s32
USBStorage_Inquiry(usbstorage_handle
*dev
, u8 lun
);
119 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
120 * but there's currently no other known way of doing this and it's in my humble
121 * opinion still better than having a function blocking forever while waiting
122 * for the USB data/IOS reply..
125 static s32
__usb_blkmsg_cb(s32 retval
, void *dummy
)
127 usbstorage_handle
*dev
= (usbstorage_handle
*)dummy
;
128 dev
->retval
= retval
;
129 SYS_CancelAlarm(dev
->alarm
);
130 LWP_ThreadBroadcast(__usbstorage_waitq
);
134 static s32
__usb_deviceremoved_cb(s32 retval
,void *arg
)
137 if(__vid
!= 0) USBStorage_Close(&__usbfd
);
141 static void __usb_timeouthandler(syswd_t alarm
,void *cbarg
)
143 usbstorage_handle
*dev
= (usbstorage_handle
*)cbarg
;
144 dev
->retval
= USBSTORAGE_ETIMEDOUT
;
145 LWP_ThreadBroadcast(__usbstorage_waitq
);
148 static void __usb_settimeout(usbstorage_handle
*dev
, u32 secs
)
154 SYS_SetAlarm(dev
->alarm
,&ts
,__usb_timeouthandler
,dev
);
157 static s32
__USB_BlkMsgTimeout(usbstorage_handle
*dev
, u8 bEndpoint
, u16 wLength
, void *rpData
, u32 timeout
)
161 dev
->retval
= USBSTORAGE_PROCESSING
;
162 retval
= USB_WriteBlkMsgAsync(dev
->usb_fd
, bEndpoint
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
163 if(retval
< 0) return retval
;
165 __usb_settimeout(dev
, timeout
);
168 retval
= dev
->retval
;
169 if(retval
!=USBSTORAGE_PROCESSING
) break;
170 else LWP_ThreadSleep(__usbstorage_waitq
);
171 } while(retval
==USBSTORAGE_PROCESSING
);
174 USB_ClearHalt(dev
->usb_fd
, bEndpoint
);
179 static s32
__USB_CtrlMsgTimeout(usbstorage_handle
*dev
, u8 bmRequestType
, u8 bmRequest
, u16 wValue
, u16 wIndex
, u16 wLength
, void *rpData
)
183 dev
->retval
= USBSTORAGE_PROCESSING
;
184 retval
= USB_WriteCtrlMsgAsync(dev
->usb_fd
, bmRequestType
, bmRequest
, wValue
, wIndex
, wLength
, rpData
, __usb_blkmsg_cb
, (void *)dev
);
185 if(retval
< 0) return retval
;
187 __usb_settimeout(dev
, usbtimeout
);
190 retval
= dev
->retval
;
191 if(retval
!=USBSTORAGE_PROCESSING
) break;
192 else LWP_ThreadSleep(__usbstorage_waitq
);
193 } while(retval
==USBSTORAGE_PROCESSING
);
198 static u8
*arena_ptr
=NULL
;
199 static u8
*cbw_buffer
=NULL
;
201 s32
USBStorage_Initialize()
208 _CPU_ISR_Disable(level
);
209 LWP_InitQueue(&__usbstorage_waitq
);
211 arena_ptr
= (u8
*)ROUNDDOWN32(((u32
)SYS_GetArena2Hi() - HEAP_SIZE
));
212 if((u32
)arena_ptr
< (u32
)SYS_GetArena2Lo()) {
213 _CPU_ISR_Restore(level
);
216 SYS_SetArena2Hi(arena_ptr
);
218 __lwp_heap_init(&__heap
, arena_ptr
, HEAP_SIZE
, 32);
219 cbw_buffer
=(u8
*)__lwp_heap_allocate(&__heap
, 32);
221 _CPU_ISR_Restore(level
);
225 static s32
__send_cbw(usbstorage_handle
*dev
, u8 lun
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
227 s32 retval
= USBSTORAGE_OK
;
229 if(cbLen
== 0 || cbLen
> 16)
232 memset(cbw_buffer
, 0, CBW_SIZE
);
234 __stwbrx(cbw_buffer
, 0, CBW_SIGNATURE
);
235 __stwbrx(cbw_buffer
, 4, ++dev
->tag
);
236 __stwbrx(cbw_buffer
, 8, len
);
237 cbw_buffer
[12] = flags
;
238 cbw_buffer
[13] = lun
;
239 cbw_buffer
[14] = (cbLen
> 6 ? 10 : 6);
241 memcpy(cbw_buffer
+ 15, cb
, cbLen
);
243 if(dev
->suspended
== 1)
245 USB_ResumeDevice(dev
->usb_fd
);
249 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_out
, CBW_SIZE
, (void *)cbw_buffer
, usbtimeout
);
251 if(retval
== CBW_SIZE
) return USBSTORAGE_OK
;
252 else if(retval
> 0) return USBSTORAGE_ESHORTWRITE
;
257 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
, u32 timeout
)
259 s32 retval
= USBSTORAGE_OK
;
260 u32 signature
, tag
, _dataResidue
, _status
;
262 memset(cbw_buffer
, 0, CSW_SIZE
);
264 retval
= __USB_BlkMsgTimeout(dev
, dev
->ep_in
, CSW_SIZE
, cbw_buffer
, timeout
);
265 if(retval
> 0 && retval
!= CSW_SIZE
) return USBSTORAGE_ESHORTREAD
;
266 else if(retval
< 0) return retval
;
268 signature
= __lwbrx(cbw_buffer
, 0);
269 tag
= __lwbrx(cbw_buffer
, 4);
270 _dataResidue
= __lwbrx(cbw_buffer
, 8);
271 _status
= cbw_buffer
[12];
273 if(signature
!= CSW_SIGNATURE
) return USBSTORAGE_ESIGNATURE
;
275 if(dataResidue
!= NULL
)
276 *dataResidue
= _dataResidue
;
280 if(tag
!= dev
->tag
) return USBSTORAGE_ETAG
;
282 return USBSTORAGE_OK
;
285 static s32
__cycle(usbstorage_handle
*dev
, u8 lun
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
, u8 write
, u8
*_status
, u32
*_dataResidue
)
287 s32 retval
= USBSTORAGE_OK
;
292 u8 ep
= write
? dev
->ep_out
: dev
->ep_in
;
293 s8 retries
= USBSTORAGE_CYCLE_RETRIES
+ 1;
296 max_size
=MAX_TRANSFER_SIZE_V5
;
298 max_size
=MAX_TRANSFER_SIZE_V0
;
300 LWP_MutexLock(dev
->lock
);
303 u8
*_buffer
= buffer
;
307 if(retval
== USBSTORAGE_ETIMEDOUT
)
310 retval
= __send_cbw(dev
, lun
, len
, (write
? CBW_OUT
:CBW_IN
), cb
, cbLen
);
312 while(_len
> 0 && retval
>= 0)
314 u32 thisLen
= _len
> max_size
? max_size
: _len
;
316 if ((u32
)_buffer
&0x1F || !((u32
)_buffer
&0x10000000)) {
317 if (write
) memcpy(dev
->buffer
, _buffer
, thisLen
);
318 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, dev
->buffer
, usbtimeout
);
319 if (!write
&& retval
> 0)
320 memcpy(_buffer
, dev
->buffer
, retval
);
322 retval
= __USB_BlkMsgTimeout(dev
, ep
, thisLen
, _buffer
, usbtimeout
);
324 if (retval
== thisLen
) {
328 else if (retval
!= USBSTORAGE_ETIMEDOUT
)
329 retval
= USBSTORAGE_EDATARESIDUE
;
333 retval
= __read_csw(dev
, &status
, &dataResidue
, usbtimeout
);
336 if (__usbstorage_reset(dev
) == USBSTORAGE_ETIMEDOUT
)
337 retval
= USBSTORAGE_ETIMEDOUT
;
339 } while (retval
< 0 && retries
> 0);
341 LWP_MutexUnlock(dev
->lock
);
345 if(_dataResidue
!= NULL
)
346 *_dataResidue
= dataResidue
;
351 static s32
__usbstorage_clearerrors(usbstorage_handle
*dev
, u8 lun
)
355 u8 sense
[SCSI_SENSE_REPLY_SIZE
];
358 memset(cmd
, 0, sizeof(cmd
));
359 cmd
[0] = SCSI_TEST_UNIT_READY
;
361 retval
= __cycle(dev
, lun
, NULL
, 0, cmd
, 1, 0, &status
, NULL
);
362 if (retval
< 0) return retval
;
366 cmd
[0] = SCSI_REQUEST_SENSE
;
368 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
369 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
370 retval
= __cycle(dev
, lun
, sense
, SCSI_SENSE_REPLY_SIZE
, cmd
, 6, 0, NULL
, NULL
);
372 switch (sense
[2]&0xF) {
373 case SCSI_SENSE_NOT_READY
:
374 return USBSTORAGE_EINIT
;
375 case SCSI_SENSE_MEDIUM_ERROR
:
376 case SCSI_SENSE_HARDWARE_ERROR
:
377 return USBSTORAGE_ESENSE
;
385 static s32
__usbstorage_reset(usbstorage_handle
*dev
)
389 s32 retval
= __USB_CtrlMsgTimeout(dev
, (USB_CTRLTYPE_DIR_HOST2DEVICE
| USB_CTRLTYPE_TYPE_CLASS
| USB_CTRLTYPE_REC_INTERFACE
), USBSTORAGE_RESET
, 0, dev
->interface
, 0, NULL
);
392 USB_ClearHalt(dev
->usb_fd
, dev
->ep_in
);usleep(10000); //from http://www.usb.org/developers/devclass_docs/usbmassbulk_10.pdf
393 USB_ClearHalt(dev
->usb_fd
, dev
->ep_out
);usleep(10000);
397 s32
USBStorage_Open(usbstorage_handle
*dev
, s32 device_id
, u16 vid
, u16 pid
)
402 u32 iConf
, iInterface
, iEp
;
404 usb_configurationdesc
*ucd
;
405 usb_interfacedesc
*uid
;
406 usb_endpointdesc
*ued
;
408 max_lun
= __lwp_heap_allocate(&__heap
, 1);
412 memset(dev
, 0, sizeof(*dev
));
415 dev
->tag
= TAG_START
;
417 if (LWP_MutexInit(&dev
->lock
, false) < 0)
418 goto free_and_return
;
420 if (SYS_CreateAlarm(&dev
->alarm
) < 0)
421 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->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS
437 || uid->bInterfaceSubClass == MASS_STORAGE_RBC_COMMANDS
438 || uid->bInterfaceSubClass == MASS_STORAGE_ATA_COMMANDS
439 || uid->bInterfaceSubClass == MASS_STORAGE_QIC_COMMANDS
440 || uid->bInterfaceSubClass == MASS_STORAGE_UFI_COMMANDS
441 || uid->bInterfaceSubClass == MASS_STORAGE_SFF8070_COMMANDS) &&*/
442 uid
->bInterfaceProtocol
== MASS_STORAGE_BULK_ONLY
)
445 if (uid
->bNumEndpoints
< 2)
448 dev
->ep_in
= dev
->ep_out
= 0;
449 for (iEp
= 0; iEp
< uid
->bNumEndpoints
; iEp
++) {
450 ued
= &uid
->endpoints
[iEp
];
451 if (ued
->bmAttributes
!= USB_ENDPOINT_BULK
)
454 if (ued
->bEndpointAddress
& USB_ENDPOINT_IN
) {
455 dev
->ep_in
= ued
->bEndpointAddress
;
458 dev
->ep_out
= ued
->bEndpointAddress
;
459 if(ued
->wMaxPacketSize
> 64 && (dev
->usb_fd
>=0x20 || dev
->usb_fd
<-1))
466 if (dev
->ep_in
!= 0 && dev
->ep_out
!= 0) {
467 dev
->configuration
= ucd
->bConfigurationValue
;
468 dev
->interface
= uid
->bInterfaceNumber
;
469 dev
->altInterface
= uid
->bAlternateSetting
;
476 USB_FreeDescriptors(&udd
);
477 retval
= USBSTORAGE_ENOINTERFACE
;
478 goto free_and_return
;
481 dev
->bInterfaceSubClass
= uid
->bInterfaceSubClass
;
483 USB_FreeDescriptors(&udd
);
485 retval
= USBSTORAGE_EINIT
;
486 // some devices return an error, ignore it
487 USB_GetConfiguration(dev
->usb_fd
, &conf
);
489 if (conf
!= dev
->configuration
) USB_SetConfiguration(dev
->usb_fd
, dev
->configuration
);
490 if (dev
->altInterface
!=0) USB_SetAlternativeInterface(dev
->usb_fd
, dev
->interface
, dev
->altInterface
);
493 retval
= USBStorage_Reset(dev
);
497 LWP_MutexLock(dev
->lock
);
498 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
);
499 LWP_MutexUnlock(dev
->lock
);
504 dev
->max_lun
= *max_lun
+ 1;
506 if (retval
== USBSTORAGE_ETIMEDOUT
)
507 goto free_and_return
;
509 retval
= USBSTORAGE_OK
;
510 dev
->sector_size
= (u32
*) calloc(dev
->max_lun
, sizeof(u32
));
511 if(!dev
->sector_size
) {
513 goto free_and_return
;
516 /* taken from linux usbstorage module (drivers/usb/storage/transport.c)
518 * Some devices (i.e. Iomega Zip100) need this -- apparently
519 * the bulk pipes get STALLed when the GetMaxLUN request is
520 * processed. This is, in theory, harmless to all other devices
521 * (regardless of if they stall or not).
523 * 8/9/10: If anyone wants to actually use a Zip100, they can add this back.
524 * But for now, it seems to be breaking things more than it is helping.
526 //USB_ClearHalt(dev->usb_fd, dev->ep_in);
527 //USB_ClearHalt(dev->usb_fd, dev->ep_out);
530 dev
->buffer
= __lwp_heap_allocate(&__heap
, MAX_TRANSFER_SIZE_V5
);
535 USB_DeviceRemovalNotifyAsync(dev
->usb_fd
,__usb_deviceremoved_cb
,dev
);
536 retval
= USBSTORAGE_OK
;
541 __lwp_heap_free(&__heap
, max_lun
);
544 USBStorage_Close(dev
);
551 s32
USBStorage_Close(usbstorage_handle
*dev
)
558 if (dev
->usb_fd
!= -1)
559 USB_CloseDevice(&dev
->usb_fd
);
561 LWP_MutexDestroy(dev
->lock
);
562 SYS_RemoveAlarm(dev
->alarm
);
565 free(dev
->sector_size
);
568 __lwp_heap_free(&__heap
, dev
->buffer
);
570 memset(dev
, 0, sizeof(*dev
));
575 s32
USBStorage_Reset(usbstorage_handle
*dev
)
579 LWP_MutexLock(dev
->lock
);
580 retval
= __usbstorage_reset(dev
);
581 LWP_MutexUnlock(dev
->lock
);
586 s32
USBStorage_GetMaxLUN(usbstorage_handle
*dev
)
591 s32
USBStorage_MountLUN(usbstorage_handle
*dev
, u8 lun
)
596 if(lun
>= dev
->max_lun
)
600 retval
= __usbstorage_clearerrors(dev
, lun
);
603 USBStorage_Reset(dev
);
604 retval
= __usbstorage_clearerrors(dev
, lun
);
607 retval
= USBStorage_Inquiry(dev
, lun
);
609 retval
= USBStorage_ReadCapacity(dev
, lun
, &dev
->sector_size
[lun
], &n_sectors
);
610 if(retval
>= 0 && (dev
->sector_size
[lun
]<512 || n_sectors
==0))
616 s32
USBStorage_Inquiry(usbstorage_handle
*dev
, u8 lun
)
620 u8 cmd
[] = {SCSI_INQUIRY
, lun
<< 5,0,0,36,0};
625 memset(response
,0,36);
627 retval
= __cycle(dev
, lun
, response
, 36, cmd
, 6, 0, NULL
, NULL
);
631 if(retval
>=0) retval
=*response
& 31;
637 // info from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
639 case 7: // optical memory device (e.g., some optical disks)
651 s32
USBStorage_ReadCapacity(usbstorage_handle
*dev
, u8 lun
, u32
*sector_size
, u32
*n_sectors
)
654 u8 cmd
[10] = {SCSI_READ_CAPACITY
, lun
<<5};
657 retval
= __cycle(dev
, lun
, response
, sizeof(response
), cmd
, sizeof(cmd
), 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_IsDVD()
672 u32 sectorsize
, numSectors
;
674 if(!__mounted
|| __usbfd
.sector_size
[__lun
] != 2048)
677 if(USBStorage_ReadCapacity(&__usbfd
, __lun
, §orsize
, &numSectors
) < 0)
680 if(sectorsize
== 2048)
685 /* lo_ej = load/eject, controls the tray
686 * start = start(1) or stop(0) the motor (or eject(0), load(1))
687 * imm = return before the command has completed
688 * it might be a good idea to call this before STM_ShutdownToStandby() so the USB HDD doesn't stay on
690 s32
USBStorage_StartStop(usbstorage_handle
*dev
, u8 lun
, u8 lo_ej
, u8 start
, u8 imm
)
693 s32 retval
= USBSTORAGE_OK
;
696 (lun
<< 5) | (imm
&1),
699 ((lo_ej
&1)<<1) | (start
&1),
703 if(lun
>= dev
->max_lun
)
706 LWP_MutexLock(dev
->lock
);
708 retval
= __send_cbw(dev
, lun
, 0, CBW_IN
, cmd
, sizeof(cmd
));
710 // if imm==0, wait up to 10secs for spinup to finish
712 retval
= __read_csw(dev
, &status
, NULL
, (imm
? USBSTORAGE_TIMEOUT
: 10));
714 LWP_MutexUnlock(dev
->lock
);
716 if(retval
>=0 && status
!= 0)
717 retval
= USBSTORAGE_ESTATUS
;
722 s32
USBStorage_Read(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, 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 USBStorage_MountLUN(dev
, lun
);
749 retval
= __cycle(dev
, lun
, buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 0, &status
, NULL
);
750 if(retval
> 0 && status
!= 0)
751 retval
= USBSTORAGE_ESTATUS
;
753 usb_last_used
= gettime();
754 usbtimeout
= USBSTORAGE_TIMEOUT
;
759 s32
USBStorage_Write(usbstorage_handle
*dev
, u8 lun
, u32 sector
, u16 n_sectors
, const u8
*buffer
)
776 if(lun
>= dev
->max_lun
|| dev
->sector_size
[lun
] == 0)
779 // more than 60s since last use - make sure drive is awake
780 if(ticks_to_secs(gettime() - usb_last_used
) > 60)
783 USBStorage_MountLUN(dev
, lun
);
786 retval
= __cycle(dev
, lun
, (u8
*)buffer
, n_sectors
* dev
->sector_size
[lun
], cmd
, sizeof(cmd
), 1, &status
, NULL
);
787 if(retval
> 0 && status
!= 0)
788 retval
= USBSTORAGE_ESTATUS
;
790 usb_last_used
= gettime();
791 usbtimeout
= USBSTORAGE_TIMEOUT
;
796 s32
USBStorage_Suspend(usbstorage_handle
*dev
)
798 if(dev
->suspended
== 1)
799 return USBSTORAGE_OK
;
801 USB_SuspendDevice(dev
->usb_fd
);
804 return USBSTORAGE_OK
;
808 The following is for implementing a DISC_INTERFACE
812 static bool __usbstorage_Startup(void)
814 if(USB_Initialize() < 0 || USBStorage_Initialize() < 0)
820 static bool __usbstorage_IsInserted(void)
822 usb_device_entry
*buffer
;
828 u32 sectorsize
, numSectors
;
832 // device is not a USB DVD drive - always return true
833 if (__usbfd
.sector_size
[__lun
] != 2048)
836 // check if DVD is inserted
837 if (USBStorage_ReadCapacity(&__usbfd
, __lun
, §orsize
, &numSectors
) < 0)
846 buffer
= (usb_device_entry
*)__lwp_heap_allocate(&__heap
, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
850 memset(buffer
, 0, DEVLIST_MAXSIZE
* sizeof(usb_device_entry
));
852 if (USB_GetDeviceList(buffer
, DEVLIST_MAXSIZE
, USB_CLASS_MASS_STORAGE
, &device_count
) < 0)
854 if (__vid
!= 0 || __pid
!= 0)
855 USBStorage_Close(&__usbfd
);
857 __lwp_heap_free(&__heap
, buffer
);
863 if (__vid
!= 0 || __pid
!= 0) {
864 for(i
= 0; i
< device_count
; i
++) {
867 if(vid
!= 0 || pid
!= 0) {
868 if((vid
== __vid
) && (pid
== __pid
)) {
870 __lwp_heap_free(&__heap
,buffer
);
871 usleep(50); // I don't know why I have to wait but it's needed
876 USBStorage_Close(&__usbfd
); // device changed or unplugged, return false the first time to notify to the client that he must unmount devices
877 __lwp_heap_free(&__heap
,buffer
);
880 for (i
= 0; i
< device_count
; i
++) {
883 if (vid
== 0 || pid
== 0)
886 if (vid
== 0x0b95 && pid
== 0x7720) // USB LAN
889 if (USBStorage_Open(&__usbfd
, buffer
[i
].device_id
, vid
, pid
) < 0)
892 maxLun
= USBStorage_GetMaxLUN(&__usbfd
);
893 for (j
= 0; j
< maxLun
; j
++) {
894 retval
= USBStorage_MountLUN(&__usbfd
, j
);
896 if (retval
== INVALID_LUN
)
901 __usbstorage_reset(&__usbfd
);
909 usb_last_used
= gettime()-secs_to_ticks(100);
917 USBStorage_Close(&__usbfd
);
919 __lwp_heap_free(&__heap
, buffer
);
924 static bool __usbstorage_ReadSectors(u32 sector
, u32 numSectors
, void *buffer
)
931 retval
= USBStorage_Read(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
936 static bool __usbstorage_WriteSectors(u32 sector
, u32 numSectors
, const void *buffer
)
943 retval
= USBStorage_Write(&__usbfd
, __lun
, sector
, numSectors
, buffer
);
948 static bool __usbstorage_ClearStatus(void)
953 static bool __usbstorage_Shutdown(void)
955 if (__vid
!= 0 || __pid
!= 0)
956 USBStorage_Close(&__usbfd
);
961 void USBStorage_Deinitialize()
963 __usbstorage_Shutdown();
964 LWP_CloseQueue(__usbstorage_waitq
);
968 int USBStorage_ioctl(int request
, ...)
972 va_start(ap
, request
);
976 case B_RAW_DEVICE_COMMAND
:
979 raw_device_command
*rdc
= va_arg(ap
, raw_device_command
*);
980 write
= (rdc
->flags
== B_RAW_DEVICE_DATA_IN
) ? 0 : 1;
981 retval
= __cycle(&__usbfd
, __lun
, rdc
->data
, rdc
->data_length
, rdc
->command
, rdc
->command_length
, write
, &rdc
->scsi_status
, NULL
);
994 DISC_INTERFACE __io_usbstorage
= {
996 FEATURE_MEDIUM_CANREAD
| FEATURE_MEDIUM_CANWRITE
| FEATURE_WII_USB
,
997 (FN_MEDIUM_STARTUP
)&__usbstorage_Startup
,
998 (FN_MEDIUM_ISINSERTED
)&__usbstorage_IsInserted
,
999 (FN_MEDIUM_READSECTORS
)&__usbstorage_ReadSectors
,
1000 (FN_MEDIUM_WRITESECTORS
)&__usbstorage_WriteSectors
,
1001 (FN_MEDIUM_CLEARSTATUS
)&__usbstorage_ClearStatus
,
1002 (FN_MEDIUM_SHUTDOWN
)&__usbstorage_Shutdown