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 static inline s32
__usb_getdesc(s32 fd
, u8
*buffer
, u8 type
, u8 index
, u8 size
)
64 return USB_WriteCtrlMsg(fd
, USB_ENDPOINT_IN
, USB_REQ_GETDESCRIPTOR
, (type
<< 8) | index
, 0, size
, buffer
);
67 s32
USB_GetDescriptors(s32 fd
, _usb_devdesc
*udd
)
71 usb_configurationdesc
*ucd
= NULL
;
72 usb_interfacedesc
*uid
= NULL
;
73 usb_endpointdesc
*ued
= NULL
;
75 u32 iConf
, iInterface
, iEndpoint
;
77 buffer
= iosAlloc(hId
, sizeof(*udd
));
84 retval
= __usb_getdesc(fd
, buffer
, USB_DT_DEVICE
, 0, USB_DT_DEVICE_SIZE
);
87 memcpy(udd
, buffer
, USB_DT_DEVICE_SIZE
);
90 udd
->bcdUSB
= bswap16(udd
->bcdUSB
);
91 udd
->idVendor
= bswap16(udd
->idVendor
);
92 udd
->idProduct
= bswap16(udd
->idProduct
);
93 udd
->bcdDevice
= bswap16(udd
->bcdDevice
);
95 udd
->configurations
= calloc(udd
->bNumConfigurations
, sizeof(*udd
->configurations
));
96 if(udd
->configurations
== NULL
)
101 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
103 buffer
= iosAlloc(hId
, USB_DT_CONFIG_SIZE
);
106 retval
= IPC_ENOHEAP
;
110 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, USB_DT_CONFIG_SIZE
);
111 ucd
= &udd
->configurations
[iConf
];
112 memcpy(ucd
, buffer
, USB_DT_CONFIG_SIZE
);
113 iosFree(hId
, buffer
);
115 ucd
->wTotalLength
= bswap16(ucd
->wTotalLength
);
116 buffer
= iosAlloc(hId
, ucd
->wTotalLength
);
119 retval
= IPC_ENOHEAP
;
123 retval
= __usb_getdesc(fd
, buffer
, USB_DT_CONFIG
, iConf
, ucd
->wTotalLength
);
131 ucd
->interfaces
= calloc(ucd
->bNumInterfaces
, sizeof(*ucd
->interfaces
));
132 if(ucd
->interfaces
== NULL
)
134 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
136 uid
= &ucd
->interfaces
[iInterface
];
137 memcpy(uid
, ptr
, USB_DT_INTERFACE_SIZE
);
140 uid
->endpoints
= calloc(uid
->bNumEndpoints
, sizeof(*uid
->endpoints
));
141 if(uid
->endpoints
== NULL
)
143 for(iEndpoint
= 0; iEndpoint
< uid
->bNumEndpoints
; iEndpoint
++)
145 ued
= &uid
->endpoints
[iEndpoint
];
146 memcpy(ued
, ptr
, USB_DT_ENDPOINT_SIZE
);
148 ued
->wMaxPacketSize
= bswap16(ued
->wMaxPacketSize
);
158 iosFree(hId
, buffer
);
160 USB_FreeDescriptors(udd
);
164 void USB_FreeDescriptors(_usb_devdesc
*udd
)
166 int iConf
, iInterface
;
167 usb_configurationdesc
*ucd
;
168 usb_interfacedesc
*uid
;
169 if(udd
->configurations
!= NULL
)
171 for(iConf
= 0; iConf
< udd
->bNumConfigurations
; iConf
++)
173 ucd
= &udd
->configurations
[iConf
];
174 if(ucd
->interfaces
!= NULL
)
176 for(iInterface
= 0; iInterface
< ucd
->bNumInterfaces
; iInterface
++)
178 uid
= &ucd
->interfaces
[iInterface
];
179 if(uid
->endpoints
!= NULL
)
180 free(uid
->endpoints
);
182 free(ucd
->interfaces
);
185 free(udd
->configurations
);
189 s32
USBStorage_Initialize()
191 hId
= iosCreateHeap(HEAP_SIZE
);
200 s32
USBStorage_Deinitialize()
202 return iosDestroyHeap(hId
);
205 static inline void __write32(u8
*p
, u32 v
)
213 static inline u32
__read32(u8
*p
)
215 return p
[0] | (p
[1] << 8) | (p
[2] << 16) | (p
[3] << 24);
218 static s32
__send_cbw(usbstorage_handle
*dev
, u32 len
, u8 flags
, const u8
*cb
, u8 cbLen
)
223 if(cbLen
== 0 || cbLen
> 16)
226 cbw
= iosAlloc(hId
, CBW_SIZE
);
230 retval
= IPC_ENOHEAP
;
231 goto free_and_return
;
234 memset(cbw
, 0, CBW_SIZE
);
236 __write32(cbw
, CBW_SIGNATURE
);
237 __write32(cbw
+ 4, dev
->tag
);
238 __write32(cbw
+ 8, len
);
240 cbw
[13] = 0; /* TODO: LUN */
243 memcpy(cbw
+ 15, cb
, cbLen
);
245 LWP_MutexLock(dev
->usb_fd
);
246 retval
= USB_WriteBlkMsg(dev
->usb_fd
, dev
->ep_out
, CBW_SIZE
, (void *)cbw
);
248 if(retval
== CBW_SIZE
)
250 else if(retval
> CBW_SIZE
)
259 static s32
__read_csw(usbstorage_handle
*dev
, u8
*status
, u32
*dataResidue
)
263 u32 signature
, tag
, _dataResidue
, _status
;
265 csw
= iosAlloc(hId
, CSW_SIZE
);
269 retval
= IPC_ENOHEAP
;
270 goto free_and_return
;
273 memset(csw
, 0, CSW_SIZE
);
275 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, CSW_SIZE
, csw
);
276 if(retval
!= CSW_SIZE
)
281 goto free_and_return
;
284 signature
= __read32(csw
);
285 tag
= __read32(csw
+ 4);
286 _dataResidue
= __read32(csw
+ 8);
289 if(signature
!= CSW_SIGNATURE
)
293 goto free_and_return
;
296 if(dataResidue
!= NULL
)
297 *dataResidue
= _dataResidue
;
305 goto free_and_return
;
310 LWP_MutexUnlock(dev
->lock
);
318 static s32
__read_cycle(usbstorage_handle
*dev
, u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
)
326 bfr
= iosAlloc(hId
, dev
->ep_in_size
);
330 retval
= IPC_ENOHEAP
;
334 retval
= __send_cbw(dev
, len
, CBW_IN
, cb
, cbLen
);
341 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, dev
->ep_in_size
, bfr
);
348 memcpy(buffer
, bfr
, retval
);
352 if(retval
!= dev
->ep_in_size
)
356 retval
= __read_csw(dev
, &status
, &dataResidue
);
363 if(status
|| dataResidue
)
366 // TODO error handling
378 static s32
__write_cycle(usbstorage_handle
*dev
, const u8
*buffer
, u32 len
, u8
*cb
, u8 cbLen
)
387 bfr
= iosAlloc(hId
, dev
->ep_out_size
);
391 retval
= IPC_ENOHEAP
;
395 retval
= __send_cbw(dev
, len
, CBW_OUT
, cb
, cbLen
);
402 thisLen
= len
> dev
->ep_out_size
? dev
->ep_out_size
: len
;
403 memset(bfr
, 0, dev
->ep_out_size
);
404 memcpy(bfr
, buffer
, thisLen
);
405 retval
= USB_WriteBlkMsg(dev
->usb_fd
, dev
->ep_out
, thisLen
, bfr
);
415 if(retval
!= thisLen
&& len
> 0)
422 retval
= __read_csw(dev
, &status
, &dataResidue
);
429 if(status
|| dataResidue
)
432 // TODO error handling
444 usbstorage_handle
*USBStorage_Open(const char *bus
, u16 vid
, u16 pid
)
446 usbstorage_handle
*dev
= NULL
;
452 dev
= calloc(1, sizeof(*dev
));
456 goto free_and_return
;
459 dev
->tag
= TAG_START
;
460 if(LWP_MutexInit(&dev
->lock
, true) < 0)
461 goto free_and_return
;
462 LWP_MutexLock(dev
->lock
);
464 retval
= USB_OpenDevice(bus
, vid
, pid
, &dev
->usb_fd
);
466 goto free_and_return
;
468 sense
= iosAlloc(hId
, SCSI_SENSE_REPLY_SIZE
);
470 goto free_and_return
;
472 // TODO: parse descriptors here
474 dev
->ep_in_size
= 64;
476 dev
->ep_out_size
= 64;
478 /* some devices needs this (TEST_UNIT_READY -> REQUEST_SENSE
479 * to be working... */
480 memset(cmd
, 0, sizeof(cmd
));
481 cmd
[0] = SCSI_TEST_UNIT_READY
;
484 retval
= __send_cbw(dev
, 0, CBW_IN
, cmd
, 1);
491 goto free_and_return
;
494 retval
= __read_csw(dev
, &status
, NULL
);
498 cmd
[0] = SCSI_REQUEST_SENSE
;
499 cmd
[4] = SCSI_SENSE_REPLY_SIZE
;
501 retval
= __send_cbw(dev
, 0, CBW_IN
, cmd
, 6);
507 goto free_and_return
;
510 memset(sense
, 0, SCSI_SENSE_REPLY_SIZE
);
511 retval
= USB_ReadBlkMsg(dev
->usb_fd
, dev
->ep_in
, SCSI_SENSE_REPLY_SIZE
, sense
);
513 if(retval
< SCSI_SENSE_REPLY_SIZE
)
515 if(retval
< 0) /* this retruns 0 on one of my sticks.. :/ */
518 /* fatal error again */
521 goto free_and_return
;
524 retval
= __read_csw(dev
, NULL
, NULL
);
527 /* fatal error again */
530 goto free_and_return
;
534 memset(cmd
, 0, sizeof(cmd
));
536 cmd
[0] = SCSI_READ_CAPACITY
;
537 retval
= __read_cycle(dev
, sense
, 8, cmd
, 1);
541 goto free_and_return
;
543 memcpy(&dev
->n_sectors
, sense
, 4);
544 memcpy(&dev
->sector_size
, sense
+ 4, 4);
547 LWP_MutexUnlock(dev
->lock
);
553 LWP_MutexDestroy(dev
->lock
);
560 s32
USBStorage_Close(usbstorage_handle
*dev
)
562 USB_CloseDevice(&dev
->usb_fd
);
563 LWP_MutexDestroy(dev
->lock
);
568 s32
USBStorage_Read(usbstorage_handle
*dev
, u32 sector
, u8
*buffer
, u16 n_sectors
)
582 return __read_cycle(dev
, buffer
, n_sectors
* dev
->sector_size
, cmd
, sizeof(cmd
));
586 s32
USBStorage_Write(usbstorage_handle
*dev
, u32 sector
, const u8
*buffer
, u16 n_sectors
)
600 return __write_cycle(dev
, buffer
, n_sectors
* dev
->sector_size
, cmd
, sizeof(cmd
));