- head deinitialization removed from sdio_Deintialize. Only close the file descriptor.
[libogc.git] / libogc / usbstorage.c
blob4e4751e85f7cbff77f5d59bae651e1ea3d1fb515
1 /*-------------------------------------------------------------
3 usbstorage.c -- Bulk-only USB mass storage support
5 Copyright (C) 2008
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
25 distribution.
27 -------------------------------------------------------------*/
28 #if defined(HW_RVL)
30 #include <gccore.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <sys/time.h>
35 #include <ogc/cond.h>
36 #include <errno.h>
37 #include <lwp_heap.h>
38 #include <malloc.h>
40 #include "asm.h"
41 #include "processor.h"
42 #include "disc_io.h"
44 #define ROUNDDOWN32(v) (((u32)(v)-0x1f)&~0x1f)
46 #define HEAP_SIZE (32*1024)
47 #define TAG_START 0x0BADC0DE
49 #define CBW_SIZE 31
50 #define CBW_SIGNATURE 0x43425355
51 #define CBW_IN (1 << 7)
52 #define CBW_OUT 0
54 #define CSW_SIZE 13
55 #define CSW_SIGNATURE 0x53425355
57 #define SCSI_TEST_UNIT_READY 0x00
58 #define SCSI_REQUEST_SENSE 0x03
59 #define SCSI_READ_CAPACITY 0x25
60 #define SCSI_READ_10 0x28
61 #define SCSI_WRITE_10 0x2A
63 #define SCSI_SENSE_REPLY_SIZE 18
64 #define SCSI_SENSE_NOT_READY 0x02
65 #define SCSI_SENSE_MEDIUM_ERROR 0x03
66 #define SCSI_SENSE_HARDWARE_ERROR 0x04
68 #define USB_CLASS_MASS_STORAGE 0x08
69 #define MASS_STORAGE_SCSI_COMMANDS 0x06
70 #define MASS_STORAGE_BULK_ONLY 0x50
72 #define USBSTORAGE_GET_MAX_LUN 0xFE
73 #define USBSTORAGE_RESET 0xFF
75 #define USB_ENDPOINT_BULK 0x02
77 #define USBSTORAGE_CYCLE_RETRIES 3
79 #define MAX_TRANSFER_SIZE 4096
81 #define DEVLIST_MAXSIZE 8
83 static heap_cntrl __heap;
84 static u8 __heap_created = 0;
86 static s32 __usbstorage_reset(usbstorage_handle *dev);
87 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
89 /* XXX: this is a *really* dirty and ugly way to send a bulkmessage with a timeout
90 * but there's currently no other known way of doing this and it's in my humble
91 * opinion still better than having a function blocking forever while waiting
92 * for the USB data/IOS reply..
95 static s32 __usb_blkmsgtimeout_cb(s32 retval, void *dummy)
97 usbstorage_handle *dev = (usbstorage_handle *)dummy;
98 dev->retval = retval;
99 LWP_CondSignal(dev->cond);
100 return 0;
103 static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData)
105 s32 retval;
106 struct timespec ts;
108 ts.tv_sec = 2;
109 ts.tv_nsec = 0;
112 dev->retval = USBSTORAGE_ETIMEDOUT;
113 retval = USB_WriteBlkMsgAsync(dev->usb_fd, bEndpoint, wLength, rpData, __usb_blkmsgtimeout_cb, (void *)dev);
114 if(retval < 0)
115 return retval;
117 retval = LWP_CondTimedWait(dev->cond, dev->lock, &ts);
119 if(retval == ETIMEDOUT)
121 USBStorage_Close(dev);
122 return USBSTORAGE_ETIMEDOUT;
125 retval = dev->retval;
126 return retval;
129 static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
131 s32 retval;
132 struct timespec ts;
134 ts.tv_sec = 2;
135 ts.tv_nsec = 0;
138 dev->retval = USBSTORAGE_ETIMEDOUT;
139 retval = USB_WriteCtrlMsgAsync(dev->usb_fd, bmRequestType, bmRequest, wValue, wIndex, wLength, rpData, __usb_blkmsgtimeout_cb, (void *)dev);
140 if(retval < 0)
141 return retval;
143 retval = LWP_CondTimedWait(dev->cond, dev->lock, &ts);
145 if(retval == ETIMEDOUT)
147 USBStorage_Close(dev);
148 return USBSTORAGE_ETIMEDOUT;
151 retval = dev->retval;
152 return retval;
155 s32 USBStorage_Initialize()
157 u8 *ptr;
158 u32 level;
160 _CPU_ISR_Disable(level);
161 if(__heap_created != 0) {
162 _CPU_ISR_Restore(level);
163 return IPC_OK;
166 ptr = (u8*)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - HEAP_SIZE));
167 if((u32)ptr < (u32)SYS_GetArena2Lo()) {
168 _CPU_ISR_Restore(level);
169 return IPC_ENOMEM;
172 SYS_SetArena2Hi(ptr);
174 __lwp_heap_init(&__heap, ptr, HEAP_SIZE, 32);
175 __heap_created = 1;
176 _CPU_ISR_Restore(level);
178 return IPC_OK;
182 static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
184 s32 retval = USBSTORAGE_OK;
186 if(cbLen == 0 || cbLen > 16)
187 return IPC_EINVAL;
189 memset(dev->buffer, 0, CBW_SIZE);
191 __stwbrx(dev->buffer, 0, CBW_SIGNATURE);
192 __stwbrx(dev->buffer, 4, dev->tag);
193 __stwbrx(dev->buffer, 8, len);
194 dev->buffer[12] = flags;
195 dev->buffer[13] = lun;
196 dev->buffer[14] = (cbLen > 6 ? 0x10 : 6);
198 memcpy(dev->buffer + 15, cb, cbLen);
200 if(dev->suspended == 1)
202 USB_ResumeDevice(dev->usb_fd);
203 dev->suspended = 0;
206 retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
208 if(retval == CBW_SIZE) return USBSTORAGE_OK;
209 else if(retval > 0) return USBSTORAGE_ESHORTWRITE;
211 return retval;
214 static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
216 s32 retval = USBSTORAGE_OK;
217 u32 signature, tag, _dataResidue, _status;
219 memset(dev->buffer, 0, CSW_SIZE);
221 retval = __USB_BlkMsgTimeout(dev, dev->ep_in, CSW_SIZE, dev->buffer);
222 if(retval > 0 && retval != CSW_SIZE) return USBSTORAGE_ESHORTREAD;
223 else if(retval < 0) return retval;
225 signature = __lwbrx(dev->buffer, 0);
226 tag = __lwbrx(dev->buffer, 4);
227 _dataResidue = __lwbrx(dev->buffer, 8);
228 _status = dev->buffer[12];
230 if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE;
232 if(dataResidue != NULL)
233 *dataResidue = _dataResidue;
234 if(status != NULL)
235 *status = _status;
237 if(tag != dev->tag) return USBSTORAGE_ETAG;
238 dev->tag++;
240 return USBSTORAGE_OK;
243 static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue)
245 s32 retval = USBSTORAGE_OK;
247 u8 status = 0;
248 u32 dataResidue = 0;
249 u32 thisLen;
251 s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
253 LWP_MutexLock(dev->lock);
256 retries--;
258 if(retval == USBSTORAGE_ETIMEDOUT)
259 break;
261 if(write)
263 retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
264 if(retval == USBSTORAGE_ETIMEDOUT)
265 break;
266 if(retval < 0)
268 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
269 retval = USBSTORAGE_ETIMEDOUT;
270 continue;
272 while(len > 0)
274 thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len;
275 memset(dev->buffer, 0, MAX_TRANSFER_SIZE);
276 memcpy(dev->buffer, buffer, thisLen);
277 retval = __USB_BlkMsgTimeout(dev, dev->ep_out, thisLen, dev->buffer);
279 if(retval == USBSTORAGE_ETIMEDOUT)
280 break;
282 if(retval < 0)
284 retval = USBSTORAGE_EDATARESIDUE;
285 break;
289 if(retval != thisLen && len > 0)
291 retval = USBSTORAGE_EDATARESIDUE;
292 break;
294 len -= retval;
295 buffer += retval;
298 if(retval < 0)
300 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
301 retval = USBSTORAGE_ETIMEDOUT;
302 continue;
305 else
307 retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
309 if(retval == USBSTORAGE_ETIMEDOUT)
310 break;
312 if(retval < 0)
314 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
315 retval = USBSTORAGE_ETIMEDOUT;
316 continue;
318 while(len > 0)
320 thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len;
321 retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, dev->buffer);
322 if(retval < 0)
323 break;
325 memcpy(buffer, dev->buffer, retval);
326 len -= retval;
327 buffer += retval;
329 if(retval != thisLen)
330 break;
333 if(retval < 0)
335 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
336 retval = USBSTORAGE_ETIMEDOUT;
337 continue;
341 retval = __read_csw(dev, &status, &dataResidue);
343 if(retval == USBSTORAGE_ETIMEDOUT)
344 break;
346 if(retval < 0)
348 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
349 retval = USBSTORAGE_ETIMEDOUT;
350 continue;
353 retval = USBSTORAGE_OK;
354 } while(retval < 0 && retries > 0);
356 if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT)
358 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
359 retval = USBSTORAGE_ETIMEDOUT;
361 LWP_MutexUnlock(dev->lock);
364 if(_status != NULL)
365 *_status = status;
366 if(_dataResidue != NULL)
367 *_dataResidue = dataResidue;
369 return retval;
372 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
374 s32 retval;
375 u8 cmd[16];
376 u8 sense[SCSI_SENSE_REPLY_SIZE];
377 u8 status = 0;
379 memset(cmd, 0, sizeof(cmd));
380 cmd[0] = SCSI_TEST_UNIT_READY;
382 retval = __cycle(dev, lun, NULL, 0, cmd, 1, 0, &status, NULL);
383 if(retval < 0) return retval;
385 if(status != 0)
387 cmd[0] = SCSI_REQUEST_SENSE;
388 cmd[1] = lun << 5;
389 cmd[4] = SCSI_SENSE_REPLY_SIZE;
390 cmd[5] = 0;
391 memset(sense, 0, SCSI_SENSE_REPLY_SIZE);
392 retval = __cycle(dev, lun, sense, SCSI_SENSE_REPLY_SIZE, cmd, 6, 0, NULL, NULL);
393 if(retval < 0) return retval;
395 status = sense[2] & 0x0F;
396 if(status == SCSI_SENSE_NOT_READY || status == SCSI_SENSE_MEDIUM_ERROR || status == SCSI_SENSE_HARDWARE_ERROR) return USBSTORAGE_ESENSE;
399 return retval;
402 static s32 __usbstorage_reset(usbstorage_handle *dev)
404 s32 retval;
406 if(dev->suspended == 1)
408 USB_ResumeDevice(dev->usb_fd);
409 dev->suspended = 0;
412 retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
414 /* FIXME?: some devices return -7004 here which definitely violates the usb ms protocol but they still seem to be working... */
415 if(retval < 0 && retval != -7004)
416 goto end;
418 /* gives device enough time to process the reset */
419 usleep(60);
421 retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
422 if(retval < 0)
423 goto end;
424 retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
426 end:
427 return retval;
430 s32 USBStorage_Open(usbstorage_handle *dev, const char *bus, u16 vid, u16 pid)
432 s32 retval = -1;
433 u8 conf,*max_lun = NULL;
434 u32 iConf, iInterface, iEp;
435 usb_devdesc udd;
436 usb_configurationdesc *ucd;
437 usb_interfacedesc *uid;
438 usb_endpointdesc *ued;
440 max_lun = __lwp_heap_allocate(&__heap, 1);
441 if(max_lun==NULL) return IPC_ENOMEM;
443 memset(dev, 0, sizeof(*dev));
445 dev->tag = TAG_START;
446 if(LWP_MutexInit(&dev->lock, false) < 0)
447 goto free_and_return;
448 if(LWP_CondInit(&dev->cond) < 0)
449 goto free_and_return;
451 retval = USB_OpenDevice(bus, vid, pid, &dev->usb_fd);
452 if(retval < 0)
453 goto free_and_return;
455 retval = USB_GetDescriptors(dev->usb_fd, &udd);
456 if(retval < 0)
457 goto free_and_return;
459 for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
461 ucd = &udd.configurations[iConf];
462 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
464 uid = &ucd->interfaces[iInterface];
465 if(uid->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
466 uid->bInterfaceSubClass == MASS_STORAGE_SCSI_COMMANDS &&
467 uid->bInterfaceProtocol == MASS_STORAGE_BULK_ONLY)
469 if(uid->bNumEndpoints < 2)
470 continue;
472 dev->ep_in = dev->ep_out = 0;
473 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
475 ued = &uid->endpoints[iEp];
476 if(ued->bmAttributes != USB_ENDPOINT_BULK)
477 continue;
479 if(ued->bEndpointAddress & USB_ENDPOINT_IN)
480 dev->ep_in = ued->bEndpointAddress;
481 else
482 dev->ep_out = ued->bEndpointAddress;
484 if(dev->ep_in != 0 && dev->ep_out != 0)
486 dev->configuration = ucd->bConfigurationValue;
487 dev->interface = uid->bInterfaceNumber;
488 dev->altInterface = uid->bAlternateSetting;
489 goto found;
495 USB_FreeDescriptors(&udd);
496 retval = USBSTORAGE_ENOINTERFACE;
497 goto free_and_return;
499 found:
500 USB_FreeDescriptors(&udd);
502 retval = USBSTORAGE_EINIT;
503 if(USB_GetConfiguration(dev->usb_fd, &conf) < 0)
504 goto free_and_return;
505 if(conf != dev->configuration && USB_SetConfiguration(dev->usb_fd, dev->configuration) < 0)
506 goto free_and_return;
507 if(dev->altInterface != 0 && USB_SetAlternativeInterface(dev->usb_fd, dev->interface, dev->altInterface) < 0)
508 goto free_and_return;
509 dev->suspended = 0;
511 retval = USBStorage_Reset(dev);
512 if(retval < 0)
513 goto free_and_return;
515 LWP_MutexLock(dev->lock);
516 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);
517 LWP_MutexUnlock(dev->lock);
518 if(retval < 0)
519 dev->max_lun = 1;
520 else
521 dev->max_lun = *max_lun;
524 if(retval == USBSTORAGE_ETIMEDOUT)
525 goto free_and_return;
527 retval = USBSTORAGE_OK;
528 dev->sector_size = (u32 *)calloc(dev->max_lun, sizeof(u32));
529 if(dev->sector_size == NULL)
531 retval = IPC_ENOMEM;
532 goto free_and_return;
535 if(dev->max_lun == 0)
536 dev->max_lun++;
538 /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
540 * Some devices (i.e. Iomega Zip100) need this -- apparently
541 * the bulk pipes get STALLed when the GetMaxLUN request is
542 * processed. This is, in theory, harmless to all other devices
543 * (regardless of if they stall or not).
545 USB_ClearHalt(dev->usb_fd, dev->ep_in);
546 USB_ClearHalt(dev->usb_fd, dev->ep_out);
548 dev->buffer = __lwp_heap_allocate(&__heap, MAX_TRANSFER_SIZE);
550 if(dev->buffer == NULL) retval = IPC_ENOMEM;
551 else retval = USBSTORAGE_OK;
553 free_and_return:
554 if(max_lun!=NULL) __lwp_heap_free(&__heap, max_lun);
555 if(retval < 0)
557 USB_CloseDevice(&dev->usb_fd);
558 LWP_MutexDestroy(dev->lock);
559 LWP_CondDestroy(dev->cond);
560 if(dev->buffer != NULL)
561 __lwp_heap_free(&__heap, dev->buffer);
562 if(dev->sector_size != NULL)
563 free(dev->sector_size);
564 memset(dev, 0, sizeof(*dev));
565 return retval;
567 return 0;
570 s32 USBStorage_Close(usbstorage_handle *dev)
572 USB_CloseDevice(&dev->usb_fd);
573 LWP_MutexDestroy(dev->lock);
574 LWP_CondDestroy(dev->cond);
575 if(dev->sector_size!=NULL)
576 free(dev->sector_size);
577 if(dev->buffer!=NULL)
578 __lwp_heap_free(&__heap, dev->buffer);
579 memset(dev, 0, sizeof(*dev));
580 return 0;
583 s32 USBStorage_Reset(usbstorage_handle *dev)
585 s32 retval;
587 LWP_MutexLock(dev->lock);
588 retval = __usbstorage_reset(dev);
589 LWP_MutexUnlock(dev->lock);
591 return retval;
594 s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
596 return dev->max_lun;
599 s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
601 s32 retval;
603 if(lun >= dev->max_lun)
604 return IPC_EINVAL;
606 retval = __usbstorage_clearerrors(dev, lun);
607 if(retval < 0)
608 return retval;
610 retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], NULL);
611 return retval;
614 s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
616 s32 retval;
617 u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
618 u8 response[8];
620 retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL);
621 if(retval >= 0)
623 if(n_sectors != NULL)
624 memcpy(n_sectors, response, 4);
625 if(sector_size != NULL)
626 memcpy(sector_size, response + 4, 4);
627 retval = USBSTORAGE_OK;
630 return retval;
633 s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
635 u8 status = 0;
636 s32 retval;
637 u8 cmd[] = {
638 SCSI_READ_10,
639 lun << 5,
640 sector >> 24,
641 sector >> 16,
642 sector >> 8,
643 sector,
645 n_sectors >> 8,
646 n_sectors,
649 if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
650 return IPC_EINVAL;
651 retval = __cycle(dev, lun, buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 0, &status, NULL);
652 if(retval > 0 && status != 0)
653 retval = USBSTORAGE_ESTATUS;
654 return retval;
657 s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
659 u8 status = 0;
660 s32 retval;
661 u8 cmd[] = {
662 SCSI_WRITE_10,
663 lun << 5,
664 sector >> 24,
665 sector >> 16,
666 sector >> 8,
667 sector,
669 n_sectors >> 8,
670 n_sectors,
673 if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
674 return IPC_EINVAL;
675 retval = __cycle(dev, lun, (u8 *)buffer, n_sectors * dev->sector_size[lun], cmd, sizeof(cmd), 1, &status, NULL);
676 if(retval > 0 && status != 0)
677 retval = USBSTORAGE_ESTATUS;
678 return retval;
681 s32 USBStorage_Suspend(usbstorage_handle *dev)
683 if(dev->suspended == 1)
684 return USBSTORAGE_OK;
686 USB_SuspendDevice(dev->usb_fd);
687 dev->suspended = 1;
689 return USBSTORAGE_OK;
694 The following is for implementing a DISC_INTERFACE
695 as used by libfat
698 static usbstorage_handle __usbfd;
699 static u8 __lun = 0;
700 static u8 __mounted = 0;
701 static u16 __vid = 0;
702 static u16 __pid = 0;
704 static bool __usbstorage_IsInserted(void);
706 static bool __usbstorage_Startup(void)
708 USB_Initialize();
709 USBStorage_Initialize();
711 memset(&__usbfd, 0, sizeof(__usbfd));
712 __lun = 0;
713 __mounted = 0;
716 return __usbstorage_IsInserted();
719 static bool __usbstorage_IsInserted(void)
721 u8 *buffer;
722 u8 dummy;
723 u8 i, j;
724 u16 vid, pid;
725 s32 maxLun;
726 s32 retval;
728 __mounted = 0; //reset it here and check if device is still attached
730 buffer = memalign(32, DEVLIST_MAXSIZE << 3);
731 if(buffer == NULL)
732 return false;
733 memset(buffer, 0, DEVLIST_MAXSIZE << 3);
735 if(USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0)
737 if(__vid!=0 || __pid!=0) USBStorage_Close(&__usbfd);
738 memset(&__usbfd, 0, sizeof(__usbfd));
739 __lun = 0;
740 __vid = 0;
741 __pid = 0;
743 free(buffer);
744 return false;
747 if(__vid!=0 || __pid!=0)
749 for(i = 0; i < DEVLIST_MAXSIZE; i++)
751 memcpy(&vid, (buffer + (i << 3) + 4), 2);
752 memcpy(&pid, (buffer + (i << 3) + 6), 2);
753 if(vid != 0 || pid != 0)
756 if( (vid == __vid) && (pid == __pid))
758 __mounted = 1;
759 free(buffer);
760 usleep(50); // I don't know why I have to wait but it's needed
761 return true;
765 USBStorage_Close(&__usbfd);
768 memset(&__usbfd, 0, sizeof(__usbfd));
769 __lun = 0;
770 __vid = 0;
771 __pid = 0;
773 for(i = 0; i < DEVLIST_MAXSIZE; i++)
775 memcpy(&vid, (buffer + (i << 3) + 4), 2);
776 memcpy(&pid, (buffer + (i << 3) + 6), 2);
777 if(vid == 0 || pid == 0)
778 continue;
780 if(USBStorage_Open(&__usbfd, "oh0", vid, pid) < 0)
781 continue;
783 maxLun = USBStorage_GetMaxLUN(&__usbfd);
784 for(j = 0; j < maxLun; j++)
786 retval = USBStorage_MountLUN(&__usbfd, j);
787 if(retval == USBSTORAGE_ETIMEDOUT)
789 break;
792 if(retval < 0)
793 continue;
795 __mounted = 1;
796 __lun = j;
797 __vid = vid;
798 __pid = pid;
799 i = DEVLIST_MAXSIZE;
800 break;
803 free(buffer);
804 if(__mounted == 1)
805 return true;
806 return false;
809 static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer)
811 s32 retval;
813 if(__mounted != 1)
814 return false;
816 retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
817 if(retval == USBSTORAGE_ETIMEDOUT)
819 __mounted = 0;
821 if(retval < 0)
822 return false;
823 return true;
826 static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer)
828 s32 retval;
830 if(__mounted != 1)
831 return false;
833 retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
834 if(retval == USBSTORAGE_ETIMEDOUT)
836 __mounted = 0;
838 if(retval < 0)
839 return false;
840 return true;
843 static bool __usbstorage_ClearStatus(void)
845 return true;
848 static bool __usbstorage_Shutdown(void)
850 //if(__mounted == 1) USBStorage_Close(&__usbfd);
851 __mounted = 0;
852 return true;
855 const DISC_INTERFACE __io_usbstorage = {
856 DEVICE_TYPE_WII_USB,
857 FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_USB,
858 (FN_MEDIUM_STARTUP)&__usbstorage_Startup,
859 (FN_MEDIUM_ISINSERTED)&__usbstorage_IsInserted,
860 (FN_MEDIUM_READSECTORS)&__usbstorage_ReadSectors,
861 (FN_MEDIUM_WRITESECTORS)&__usbstorage_WriteSectors,
862 (FN_MEDIUM_CLEARSTATUS)&__usbstorage_ClearStatus,
863 (FN_MEDIUM_SHUTDOWN)&__usbstorage_Shutdown
866 #endif /* HW_RVL */