2 * storage.c -- Bulk-only USB mass storage support
4 * Copyright (c) 2007, Benedikt Sauter <sauter@ixbat.de>
5 * Copyright (C) 2008, Sven Peter (svpe) <svpe@gmx.net>
6 * Copyright (C) 2010, Bernhard Urban <lewurm@gmx.net>
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
14 * * Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * * Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
20 * * Neither the name of the FH Augsburg nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 #include "../../core/core.h"
38 #include "../../core/usb.h"
39 #include "../../usbspec/usb11spec.h"
40 #include "../../../malloc.h"
47 void usb_storage_probe();
48 void usb_storage_check();
50 struct usb_device *massstorage[MAX_DEVICES];
51 u16 sectorsize[MAX_DEVICES];
52 u8 massstorage_in_use;
54 struct usb_driver storage = {
56 .probe = usb_storage_probe,
57 .check = usb_storage_check,
61 void usb_storage_init()
63 massstorage_in_use = 0;
64 usb_register_driver(&storage);
68 void usb_storage_probe()
70 // schaue ob aktuell enumeriertes geraet ein storage ist
72 core.stdout("Probe: Storage\r\n");
75 /* read interface descriptor for class code */
78 struct usb_device* dev;
79 struct element * iterator = core.devices->head;
81 while(iterator != NULL) {
82 dev = (struct usb_device*)iterator->data;
84 /* get interface descriptor */
85 usb_control_msg(dev, 0x80, GET_DESCRIPTOR,2, 0, 32, buf, 0);
87 if(buf[14]==MASS_STORAGE_CLASSCODE){
88 massstorage[massstorage_in_use] = dev;
91 core.stdout("Storage: Found Storage Device\r\n");
94 /* here is only my lib driver test */
96 usb_storage_inquiry(0);
97 usb_storage_read_capacity(0);
99 //char * buf = (char*)malloc(512);
102 //usb_storage_read_sector(0,1,buf);
104 /* end of driver test */
107 iterator=iterator->next;
112 void usb_storage_check()
114 // wird periodisch augerufen
115 // da ein mass storage aber keinen interrupt oder isochronen endpunkt
116 // hat passiert hier nichts
121 u8 usb_storage_inquiry(u8 device)
123 /* send cwb "usbc" */
125 usb_storage_cbw *cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw));
126 cbw->dCBWSignature= 0x43425355;
127 cbw->dCBWTag=0x826A6008;
128 cbw->dCBWDataTransferLength=0x00000024;
131 cbw->bCBWCBLength=0x01;
137 cbw->CBWCB[0]=0x12; // 0x12 = INQUIRY
139 usb_bulk_write(massstorage[device], 2, (u8*)cbw, 31, 0);
140 usb_bulk_read(massstorage[device], 1, (u8*)cbw, 36, 0);
141 usb_bulk_read(massstorage[device], 1, (u8*)cbw, 13, 0);
149 u8 usb_storage_read_capacity(u8 device)
151 /* send cwb "usbc" */
155 usb_storage_cbw * cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw));
157 usb_control_msg(massstorage[device], 0x02,1,0, 0x8100, 0,tmp, 0);
159 cbw->dCBWSignature= 0x43425355;
160 cbw->dCBWTag=0x826A6008;
161 cbw->dCBWDataTransferLength=0x00000008;
164 cbw->bCBWCBLength=0x0A;
169 cbw->CBWCB[0]=0x25; // 0x12 = INQUIRY
171 usb_bulk_write(massstorage[device], 2, (u8*)cbw, 31, 0);
172 usb_bulk_read(massstorage[device], 1, (u8*)cbw, 8, 0);
173 usb_bulk_read(massstorage[device], 1, (u8*)cbw, 13, 0);
181 u8 usb_storage_read_sector(u8 device, u32 sector, char * buf)
183 /* send cwb "usbc" */
184 u8 tmpbuf[] = {0x55,0x53,0x42,0x43,0x08,
185 0xE0,0x63,0x82,0x00,0x02,
186 0x00,0x00,0x80,0x00,0x0A,
187 0x28,0x00,0x00,0x00,0x00,
188 0x00,0x00,0x00,0x01,0x00,
189 0x00,0x00,0x00,0x00,0x00,
191 0x00,0x00,0x00,0x00,0x00};
193 usb_bulk_write(massstorage[device], 2, tmpbuf, 31, 0);
194 //usb_bulk_read(massstorage[device], 1, buf,64,0);
195 //usb_bulk_read(massstorage[device], 1, buf, 13, 0);
202 u8 usb_storage_write_sector(u8 device, u32 sector, char * buf)
212 #include <sys/time.h>
214 #include <lwp_heap.h>
218 #include "processor.h"
221 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
223 #define HEAP_SIZE (32*1024)
224 #define TAG_START 0x0BADC0DE
227 #define CBW_SIGNATURE 0x43425355
228 #define CBW_IN (1 << 7)
232 #define CSW_SIGNATURE 0x53425355
234 #define SCSI_TEST_UNIT_READY 0x00
235 #define SCSI_REQUEST_SENSE 0x03
236 #define SCSI_READ_CAPACITY 0x25
237 #define SCSI_READ_10 0x28
238 #define SCSI_WRITE_10 0x2A
240 #define SCSI_SENSE_REPLY_SIZE 18
241 #define SCSI_SENSE_NOT_READY 0x02
242 #define SCSI_SENSE_MEDIUM_ERROR 0x03
243 #define SCSI_SENSE_HARDWARE_ERROR 0x04
245 #define USB_CLASS_MASS_STORAGE 0x08
246 #define MASS_STORAGE_SCSI_COMMANDS 0x06
247 #define MASS_STORAGE_BULK_ONLY 0x50
249 #define USBSTORAGE_GET_MAX_LUN 0xFE
250 #define USBSTORAGE_RESET 0xFF
252 #define USB_ENDPOINT_BULK 0x02
254 #define USBSTORAGE_CYCLE_RETRIES 3
256 #define MAX_TRANSFER_SIZE 4096
258 #define DEVLIST_MAXSIZE 8
260 static heap_cntrl __heap;
261 static u8 __heap_created = 0;
262 static lwpq_t __usbstorage_waitq = 0;
265 The following is for implementing a DISC_INTERFACE
269 static usbstorage_handle __usbfd;
271 static u8 __mounted = 0;
272 static u16 __vid = 0;
273 static u16 __pid = 0;
275 static s32 __usbstorage_reset(usbstorage_handle *dev);
276 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
278 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
279 * but there's currently no other known way of doing this and it's in my humble
280 * opinion still better than having a function blocking forever while waiting
281 * for the USB data/IOS reply..
284 static s32 __usb_blkmsg_cb(s32 retval, void *dummy)
286 usbstorage_handle *dev = (usbstorage_handle *)dummy;
287 dev->retval = retval;
288 SYS_CancelAlarm(dev->alarm);
289 LWP_ThreadBroadcast(__usbstorage_waitq);
293 static s32 __usb_deviceremoved_cb(s32 retval,void *arg)
298 static void __usb_timeouthandler(syswd_t alarm,void *cbarg)
300 usbstorage_handle *dev = (usbstorage_handle*)cbarg;
301 dev->retval = USBSTORAGE_ETIMEDOUT;
302 LWP_ThreadBroadcast(__usbstorage_waitq);
305 static void __usb_settimeout(usbstorage_handle *dev)
311 SYS_SetAlarm(dev->alarm,&ts,__usb_timeouthandler,dev);
314 static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData)
319 dev->retval = USBSTORAGE_PROCESSING;
320 retval = USB_WriteBlkMsgAsync(dev->usb_fd, bEndpoint, wLength, rpData, __usb_blkmsg_cb, (void *)dev);
321 if(retval < 0) return retval;
323 __usb_settimeout(dev);
325 _CPU_ISR_Disable(level);
327 retval = dev->retval;
328 if(retval!=USBSTORAGE_PROCESSING) break;
329 else LWP_ThreadSleep(__usbstorage_waitq);
330 } while(retval==USBSTORAGE_PROCESSING);
331 _CPU_ISR_Restore(level);
333 if(retval==USBSTORAGE_ETIMEDOUT) USBStorage_Close(dev);
337 static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
347 dev->retval = USBSTORAGE_PROCESSING;
348 retval = USB_WriteCtrlMsgAsync(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData, __usb_blkmsg_cb, (void *)dev);
349 if(retval < 0) return retval;
351 __usb_settimeout(dev);
353 _CPU_ISR_Disable(level);
355 retval = dev->retval;
356 if(retval!=USBSTORAGE_PROCESSING) break;
357 else LWP_ThreadSleep(__usbstorage_waitq);
358 } while(retval==USBSTORAGE_PROCESSING);
359 _CPU_ISR_Restore(level);
361 if(retval==USBSTORAGE_ETIMEDOUT) USBStorage_Close(dev);
365 s32 USBStorage_Initialize()
370 _CPU_ISR_Disable(level);
371 if(__heap_created != 0) {
372 _CPU_ISR_Restore(level);
376 LWP_InitQueue(&__usbstorage_waitq);
378 ptr = (u8*)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - HEAP_SIZE));
379 if((u32)ptr < (u32)SYS_GetArena2Lo()) {
380 _CPU_ISR_Restore(level);
384 SYS_SetArena2Hi(ptr);
386 __lwp_heap_init(&__heap, ptr, HEAP_SIZE, 32);
388 _CPU_ISR_Restore(level);
394 static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
396 s32 retval = USBSTORAGE_OK;
398 if(cbLen == 0 || cbLen > 16)
401 memset(dev->buffer, 0, CBW_SIZE);
403 __stwbrx(dev->buffer, 0, CBW_SIGNATURE);
404 __stwbrx(dev->buffer, 4, dev->tag);
405 __stwbrx(dev->buffer, 8, len);
406 dev->buffer[12] = flags;
407 dev->buffer[13] = lun;
408 dev->buffer[14] = (cbLen > 6 ? 0x10 : 6);
410 memcpy(dev->buffer + 15, cb, cbLen);
412 if(dev->suspended == 1)
414 USB_ResumeDevice(dev->usb_fd);
418 retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
420 if(retval == CBW_SIZE) return USBSTORAGE_OK;
421 else if(retval > 0) return USBSTORAGE_ESHORTWRITE;
426 static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
428 s32 retval = USBSTORAGE_OK;
429 u32 signature, tag, _dataResidue, _status;
431 memset(dev->buffer, 0, CSW_SIZE);
433 retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer);
434 if(retval > 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD;
435 else if(retval < 0) return retval;
437 signature = __lwbrx(dev->buffer, 0);
438 tag = __lwbrx(dev->buffer, 4);
439 _dataResidue = __lwbrx(dev->buffer, 8);
440 _status = dev->buffer[12];
442 if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE;
444 if(dataResidue != NULL)
445 *dataResidue = _dataResidue;
449 if(tag != dev->tag) return USBSTORAGE_ETAG;
452 return USBSTORAGE_OK;
455 static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue)
457 s32 retval = USBSTORAGE_OK;
463 s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
465 LWP_MutexLock(dev->lock);
470 if(retval == USBSTORAGE_ETIMEDOUT)
475 retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
476 if(retval == USBSTORAGE_ETIMEDOUT)
480 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
481 retval = USBSTORAGE_ETIMEDOUT;
486 thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len;
487 memset(dev->buffer, 0, MAX_TRANSFER_SIZE);
488 memcpy(dev->buffer, buffer, thisLen);
489 retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, dev->buffer);
491 if(retval == USBSTORAGE_ETIMEDOUT)
496 retval = USBSTORAGE_EDATARESIDUE;
501 if(retval != thisLen && len > 0)
503 retval = USBSTORAGE_EDATARESIDUE;
512 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
513 retval = USBSTORAGE_ETIMEDOUT;
519 retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
521 if(retval == USBSTORAGE_ETIMEDOUT)
526 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
527 retval = USBSTORAGE_ETIMEDOUT;
532 thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len;
533 retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, dev->buffer);
537 memcpy(buffer, dev->buffer, retval);
541 if(retval != thisLen)
547 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
548 retval = USBSTORAGE_ETIMEDOUT;
553 retval = __read_csw(dev, &status, &dataResidue);
555 if(retval == USBSTORAGE_ETIMEDOUT)
560 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
561 retval = USBSTORAGE_ETIMEDOUT;
565 retval = USBSTORAGE_OK;
566 } while(retval < 0 && retries > 0);
568 if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT)
570 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
571 retval = USBSTORAGE_ETIMEDOUT;
573 LWP_MutexUnlock(dev->lock);
578 if(_dataResidue != NULL)
579 *_dataResidue = dataResidue;
584 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
588 u8 sense[SCSI_SENSE_REPLY_SIZE];
591 memset(cmd, 0, sizeof(cmd));
592 cmd[0] = SCSI_TEST_UNIT_READY;
594 retval = __cycle(dev, lun, NULL, 0, cmd, 1, 0, &status, NULL);
595 if(retval < 0) return retval;
599 cmd[0] = SCSI_REQUEST_SENSE;
601 cmd[4] = SCSI_SENSE_REPLY_SIZE;
603 memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
604 retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL);
605 if(retval < 0) return retval;
607 status = sense[2] & 0x0F;
608 if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR) return USBSTORAGE_ESENSE;
614 static s32 __usbstorage_reset(usbstorage_handle *dev)
618 if(dev->suspended == 1)
620 USB_ResumeDevice(dev->usb_fd);
624 retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
626 /* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
627 if(retval < 0 && retval != -7004)
630 /* gives device enough time to process the reset */
633 retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
636 retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
642 s32 USBStorage_Open(usbstorage_handle *dev, const char *bus, u16 vid, u16 pid)
645 u8 conf,*max_lun = NULL;
646 u32 iConf, iInterface, iEp;
648 usb_configurationdesc *ucd;
649 usb_interfacedesc *uid;
650 usb_endpointdesc *ued;
652 max_lun = __lwp_heap_allocate(&__heap, 1);
653 if(max_lun==NULL) return IPC_ENOMEM;
655 memset(dev, 0, sizeof(*dev));
657 dev->tag = TAG_START;
658 if(LWP_MutexInit(&dev->lock, false) < 0)
659 goto free_and_return;
660 if(SYS_CreateAlarm(&dev->alarm)<0)
661 goto free_and_return;
663 retval = USB_OpenDevice(bus, vid, pid, &dev->usb_fd);
665 goto free_and_return;
667 retval = USB_GetDescriptors(dev->usb_fd, &udd);
669 goto free_and_return;
671 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
673 ucd = &udd.configurations[iConf];
674 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
676 uid = &ucd->interfaces[iInterface];
677 if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
678 uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS &&
679 uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
681 if(uid->bNumEndpoints < 2)
684 dev->ep_in = dev->ep_out = 0;
685 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
687 ued = &uid->endpoints[iEp];
688 if(ued->bmAttributes != USB_ENDPOINT_BULK)
691 if(ued->bEndpointAddress & USB_ENDPOINT_IN)
692 dev->ep_in = ued->bEndpointAddress;
694 dev->ep_out = ued->bEndpointAddress;
696 if(dev->ep_in != 0 && dev->ep_out != 0)
698 dev->configuration = ucd->bConfigurationValue;
699 dev->interface = uid->bInterfaceNumber;
700 dev->altInterface = uid->bAlternateSetting;
707 USB_FreeDescriptors(&udd);
708 retval = USBSTORAGE_ENOINTERFACE;
709 goto free_and_return;
712 USB_FreeDescriptors(&udd);
714 retval = USBSTORAGE_EINIT;
715 if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
716 goto free_and_return;
717 if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
718 goto free_and_return;
719 if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
720 goto free_and_return;
723 retval = USBStorage_Reset(dev);
725 goto free_and_return;
727 LWP_MutexLock(dev->lock);
728 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);
729 LWP_MutexUnlock(dev->lock);
733 dev->max_lun = *max_lun;
736 if(retval == USBSTORAGE_ETIMEDOUT)
737 goto free_and_return;
739 retval = USBSTORAGE_OK;
740 dev->sector_size = (u32 *)calloc(dev->max_lun, sizeof(u32));
741 if(dev->sector_size == NULL)
744 goto free_and_return;
747 if(dev->max_lun == 0)
750 /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
752 * Some devices (i.e. Iomega Zip100) need this -- apparently
753 * the bulk pipes get STALLed when the GetMaxLUN request is
754 * processed. This is, in theory, harmless to all other devices
755 * (regardless of if they stall or not).
757 USB_ClearHalt(dev->usb_fd, dev->ep_in);
758 USB_ClearHalt(dev->usb_fd, dev->ep_out);
760 dev->buffer = __lwp_heap_allocate(&__heap, MAX_TRANSFER_SIZE);
762 if(dev->buffer == NULL) retval = IPC_ENOMEM;
764 USB_DeviceRemovalNotifyAsync(dev->usb_fd,__usb_deviceremoved_cb,dev);
765 retval = USBSTORAGE_OK;
769 if(max_lun!=NULL) __lwp_heap_free(&__heap, max_lun);
772 USB_CloseDevice(&dev->usb_fd);
773 LWP_MutexDestroy(dev->lock);
774 SYS_RemoveAlarm(dev->alarm);
775 if(dev->buffer != NULL)
776 __lwp_heap_free(&__heap, dev->buffer);
777 if(dev->sector_size != NULL)
778 free(dev->sector_size);
779 memset(dev, 0, sizeof(*dev));
785 s32 USBStorage_Close(usbstorage_handle *dev)
787 USB_CloseDevice(&dev->usb_fd);
788 LWP_MutexDestroy(dev->lock);
789 SYS_RemoveAlarm(dev->alarm);
790 if(dev->sector_size!=NULL)
791 free(dev->sector_size);
792 if(dev->buffer!=NULL)
793 __lwp_heap_free(&__heap, dev->buffer);
794 memset(dev, 0, sizeof(*dev));
798 s32 USBStorage_Reset(usbstorage_handle *dev)
802 LWP_MutexLock(dev->lock);
803 retval = __usbstorage_reset(dev);
804 LWP_MutexUnlock(dev->lock);
809 s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
814 s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
818 if(lun >= dev->max_lun)
821 retval = __usbstorage_clearerrors(dev, lun);
825 retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], NULL);
829 s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
832 u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
835 retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL);
838 if(n_sectors != NULL)
839 memcpy(n_sectors, response, 4);
840 if(sector_size != NULL)
841 memcpy(sector_size, response + 4, 4);
842 retval = USBSTORAGE_OK;
848 s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
864 if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
866 retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL);
867 if(retval > 0 && status != 0)
868 retval = USBSTORAGE_ESTATUS;
872 s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
888 if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
890 retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL);
891 if(retval > 0 && status != 0)
892 retval = USBSTORAGE_ESTATUS;
896 s32 USBStorage_Suspend(usbstorage_handle *dev)
898 if(dev->suspended == 1)
899 return USBSTORAGE_OK;
901 USB_SuspendDevice(dev->usb_fd);
904 return USBSTORAGE_OK;
909 The following is for implementing a DISC_INTERFACE
913 static bool __usbstorage_IsInserted(void);
915 static bool __usbstorage_Startup(void)
918 USBStorage_Initialize();
919 return __usbstorage_IsInserted();
922 static bool __usbstorage_IsInserted(void)
931 __mounted = 0; //reset it here and check if device is still attached
933 buffer = __lwp_heap_allocate(&__heap, DEVLIST_MAXSIZE << 3);
936 memset(buffer, 0, DEVLIST_MAXSIZE << 3);
938 if(USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0)
940 if(__vid!=0 || __pid!=0) USBStorage_Close(&__usbfd);
941 memset(&__usbfd, 0, sizeof(__usbfd));
946 __lwp_heap_free(&__heap,buffer);
950 if(__vid!=0 || __pid!=0)
952 for(i = 0; i < DEVLIST_MAXSIZE; i++)
954 memcpy(&vid, (buffer + (i << 3) + 4), 2);
955 memcpy(&pid, (buffer + (i << 3) + 6), 2);
956 if(vid != 0 || pid != 0)
959 if( (vid == __vid) && (pid == __pid))
962 __lwp_heap_free(&__heap,buffer);
963 usleep(50); // I don't know why I have to wait but it's needed
968 USBStorage_Close(&__usbfd);
971 memset(&__usbfd, 0, sizeof(__usbfd));
976 for(i = 0; i < DEVLIST_MAXSIZE; i++)
978 memcpy(&vid, (buffer + (i << 3) + 4), 2);
979 memcpy(&pid, (buffer + (i << 3) + 6), 2);
980 if(vid == 0 || pid == 0)
983 if(USBStorage_Open(&__usbfd, "oh0", vid, pid) < 0)
986 maxLun = USBStorage_GetMaxLUN(&__usbfd);
987 for(j = 0; j < maxLun; j++)
989 retval = USBStorage_MountLUN(&__usbfd, j);
990 if(retval == USBSTORAGE_ETIMEDOUT)
1002 i = DEVLIST_MAXSIZE;
1006 __lwp_heap_free(&__heap,buffer);
1012 static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer)
1019 retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
1020 if(retval == USBSTORAGE_ETIMEDOUT)
1029 static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer)
1036 retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
1037 if(retval == USBSTORAGE_ETIMEDOUT)
1046 static bool __usbstorage_ClearStatus(void)
1051 static bool __usbstorage_Shutdown(void)
1053 //if(__mounted == 1) USBStorage_Close(&__usbfd);
1058 const DISC_INTERFACE __io_usbstorage = {
1059 DEVICE_TYPE_WII_USB,
1060 FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB,
1061 (FN_MEDIUM_STARTUP)&__usbstorage_Startup,
1062 (FN_MEDIUM_ISINSERTED)&__usbstorage_IsInserted,
1063 (FN_MEDIUM_READSECTORS)&__usbstorage_ReadSectors,
1064 (FN_MEDIUM_WRITESECTORS)&__usbstorage_WriteSectors,
1065 (FN_MEDIUM_CLEARSTATUS)&__usbstorage_ClearStatus,
1066 (FN_MEDIUM_SHUTDOWN)&__usbstorage_Shutdown