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 -------------------------------------------------------------*/
32 #include "usbstorage.h"
34 #define HEAP_SIZE 4096
35 #define TAG_START 0x0BADC0DE
38 #define CBW_SIGNATURE 0x43425355
39 #define CBW_IN (1 << 7)
43 #define CSW_SIGNATURE 0x53425355
45 #define SCSI_TEST_UNIT_READY 0x00
46 #define SCSI_REQUEST_SENSE 0x03
47 #define SCSI_READ_CAPACITY 0x25
48 #define SCSI_READ_10 0x28
49 #define SCSI_WRITE_10 0x2A
51 #define SCSI_SENSE_REPLY_SIZE 18
55 #define TRACE printf(" %d@%s\n", __LINE__, __FUNCTION__);
62 s32
USBStorage_Initialize()
64 hId
= iosCreateHeap(HEAP_SIZE
);
73 s32
USBStorage_Deinitialize()
75 return iosDestroyHeap(hId
);
78 static inline void __write32(u8
*p
, u32 v
)
86 static inline u32
__read32(u8
*p
)
88 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
91 static s32
__send_cbw(usbstorage_handle
*dev
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
96 if(cbLen
== 0 || cbLen
> 16)
99 cbw
= iosAlloc(hId
, CBW_SIZE
);
103 retval
= IPC_ENOHEAP
;
104 goto free_and_return
;
107 memset(cbw
, 0, CBW_SIZE
);
109 __write32(cbw
, CBW_SIGNATURE
);
110 __write32(cbw
+ 4, dev
->tag
);
111 __write32(cbw
+ 8, len
);
113 cbw
[13] = 0; /* TODO: LUN */
116 memcpy(cbw
+ 15, cb
, cbLen
);
118 LWP_MutexLock(dev
->usb_fd
);
119 retval
= USB_WriteBlkMsg(dev
->usb_fd
, dev
->ep_out
, CBW_SIZE
, (void *)cbw
);
121 if(retval
== CBW_SIZE
)
123 else if(retval
> CBW_SIZE
)
132 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
)
136 u32 signature
, tag
, _dataResidue
, _status
;
138 csw
= iosAlloc(hId
, CSW_SIZE
);
142 retval
= IPC_ENOHEAP
;
143 goto free_and_return
;
146 memset(csw
, 0, CSW_SIZE
);
148 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, CSW_SIZE
, csw
);
149 if(retval
!= CSW_SIZE
)
154 goto free_and_return
;
157 signature
= __read32(csw
);
158 tag
= __read32(csw
+ 4);
159 _dataResidue
= __read32(csw
+ 8);
162 if(signature
!= CSW_SIGNATURE
)
166 goto free_and_return
;
169 if(dataResidue
!= NULL
)
170 *dataResidue
= _dataResidue
;
178 goto free_and_return
;
183 LWP_MutexUnlock(dev
->lock
);
191 static s32
__read_cycle(usbstorage_handle
*dev
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
)
199 bfr
= iosAlloc(hId
, dev
->ep_in_size
);
203 retval
= IPC_ENOHEAP
;
207 retval
= __send_cbw(dev
, len
, CBW_IN
, cb
, cbLen
);
214 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, dev
->ep_in_size
, bfr
);
221 memcpy(buffer
, bfr
, retval
);
225 if(retval
!= dev
->ep_in_size
)
229 retval
= __read_csw(dev
, &status
, &dataResidue
);
236 if(status
|| dataResidue
)
239 // TODO error handling
251 static s32
__write_cycle(usbstorage_handle
*dev
, const u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
)
260 bfr
= iosAlloc(hId
, dev
->ep_out_size
);
264 retval
= IPC_ENOHEAP
;
268 retval
= __send_cbw(dev
, len
, CBW_OUT
, cb
, cbLen
);
275 thisLen
= len
> dev
->ep_out_size
? dev
->ep_out_size
: len
;
276 memset(bfr
, 0, dev
->ep_out_size
);
277 memcpy(bfr
, buffer
, thisLen
);
278 retval
= USB_WriteBlkMsg(dev
->usb_fd
, dev
->ep_out
, thisLen
, bfr
);
288 if(retval
!= thisLen
&& len
> 0)
295 retval
= __read_csw(dev
, &status
, &dataResidue
);
302 if(status
|| dataResidue
)
305 // TODO error handling
317 usbstorage_handle
*USBStorage_Open(const char *bus
, u16 vid
, u16 pid
)
319 usbstorage_handle
*dev
= NULL
;
325 dev
= calloc(1, sizeof(*dev
));
329 goto free_and_return
;
332 dev
->tag
= TAG_START
;
333 if(LWP_MutexInit(&dev
->lock
, true) < 0)
334 goto free_and_return
;
335 LWP_MutexLock(dev
->lock
);
337 retval
= USB_OpenDevice(bus
, vid
, pid
, &dev
->usb_fd
);
339 goto free_and_return
;
341 sense
= iosAlloc(hId
, SCSI_SENSE_REPLY_SIZE
);
343 goto free_and_return
;
345 // TODO: parse descriptors here
347 dev
->ep_in_size
= 64;
349 dev
->ep_out_size
= 64;
351 memset(cmd
, 0, sizeof(cmd
));
352 cmd
[0] = SCSI_TEST_UNIT_READY
;
355 retval
= __send_cbw(dev
, 0, CBW_IN
, cmd
, 1);
362 goto free_and_return
;
365 /* some devices needs this to be fully working... */
366 retval
= __read_csw(dev
, &status
, NULL
);
370 cmd
[0] = SCSI_REQUEST_SENSE
;
371 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
373 retval
= __send_cbw(dev
, 0, CBW_IN
, cmd
, 6);
379 goto free_and_return
;
382 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
383 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, SCSI_SENSE_REPLY_SIZE
, sense
);
385 if(retval
< SCSI_SENSE_REPLY_SIZE
)
387 if(retval
< 0) /* this retruns 0 on one of my sticks.. :/ */
390 /* fatal error again */
393 goto free_and_return
;
396 retval
= __read_csw(dev
, NULL
, NULL
);
399 /* fatal error again */
402 goto free_and_return
;
406 memset(cmd
, 0, sizeof(cmd
));
408 cmd
[0] = SCSI_READ_CAPACITY
;
409 retval
= __read_cycle(dev
, sense
, 8, cmd
, 1);
413 goto free_and_return
;
415 memcpy(&dev
->n_sectors
, sense
, 4);
416 memcpy(&dev
->sector_size
, sense
+ 4, 4);
419 LWP_MutexUnlock(dev
->lock
);
425 LWP_MutexDestroy(dev
->lock
);
432 s32
USBStorage_Close(usbstorage_handle
*dev
)
434 USB_CloseDevice(&dev
->usb_fd
);
435 LWP_MutexDestroy(dev
->lock
);
436 memset(dev
, 0, sizeof(*dev
));
440 s32
USBStorage_Read(usbstorage_handle
*dev
, u32 sector
, u8
*buffer
, u16 n_sectors
)
454 return __read_cycle(dev
, buffer
, n_sectors
* dev
->sector_size
, cmd
, sizeof(cmd
));
458 s32
USBStorage_Write(usbstorage_handle
*dev
, u32 sector
, const u8
*buffer
, u16 n_sectors
)
472 return __write_cycle(dev
, buffer
, n_sectors
* dev
->sector_size
, cmd
, sizeof(cmd
));