0bc39e3c05ac8492cc72ec06156e4b6503967e09
[ppcskel.git] / usb / drivers / class / storage.c
1 /*
2  * storage.c -- Bulk-only USB mass storage support
3  *
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>
7  * All rights reserved.
8  *
9  *
10  * Redistribution and use in source and binary forms, with or without 
11  * modification, are permitted provided that the following conditions 
12  * are met:
13  *
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.
23  *
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.
35  */
36
37 #include "../../core/core.h"
38 #include "../../core/usb.h"
39 #include "../../usbspec/usb11spec.h"
40 #include "../../../malloc.h"
41
42 #include "storage.h"
43
44
45 #define MAX_DEVICES 2
46
47 void usb_storage_probe();
48 void usb_storage_check();
49
50 struct usb_device *massstorage[MAX_DEVICES];
51 u16 sectorsize[MAX_DEVICES];
52 u8 massstorage_in_use;
53
54 struct usb_driver storage = {
55         .name     = "storage",
56         .probe  = usb_storage_probe,
57         .check  = usb_storage_check,
58         .data     = NULL
59 };
60
61 void usb_storage_init()
62 {
63         massstorage_in_use = 0;
64         usb_register_driver(&storage);  
65 }
66
67
68 void usb_storage_probe()
69 {
70         // schaue ob aktuell enumeriertes geraet ein storage ist
71         #if DEBUG
72         core.stdout("Probe: Storage\r\n");
73         #endif
74  
75         /* read interface descriptor for class code */
76         u8 buf[32];
77         
78         struct usb_device* dev;
79         struct element * iterator = core.devices->head;
80         
81         while(iterator != NULL) {
82                 dev = (struct usb_device*)iterator->data;
83
84                 /* get interface descriptor */
85                 usb_control_msg(dev, 0x80, GET_DESCRIPTOR,2, 0, 32, buf, 0);
86
87                 if(buf[14]==MASS_STORAGE_CLASSCODE){
88                         massstorage[massstorage_in_use] = dev;
89                         massstorage_in_use++;
90                         #if DEBUG
91                         core.stdout("Storage: Found Storage Device\r\n");
92                         #endif 
93
94                         /* here is only my lib driver test */
95                         usb_storage_open(0);
96                         usb_storage_inquiry(0);
97                         usb_storage_read_capacity(0);
98
99                         //char * buf = (char*)malloc(512);
100                         //free(buf);
101                         //char buf[512];
102                         //usb_storage_read_sector(0,1,buf);
103
104                         /* end of driver test */
105                 }
106
107                 iterator=iterator->next;
108         }
109 }
110
111
112 void usb_storage_check()
113 {
114         // wird periodisch augerufen
115         // da ein mass storage aber keinen interrupt oder isochronen endpunkt
116         // hat passiert hier nichts
117 }
118
119
120
121 u8 usb_storage_inquiry(u8 device)
122 {
123         /* send cwb "usbc" */
124         
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;
129         cbw->bCWDFlags=0x80;
130         cbw->bCBWLun=0x00;
131         cbw->bCBWCBLength=0x01;
132
133         u8 i;
134         for(i=0;i<16;i++)
135                 cbw->CBWCB[i]=0x00;
136
137         cbw->CBWCB[0]=0x12; // 0x12 = INQUIRY
138
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); 
142
143         free(cbw);
144
145         return 0;
146 }
147
148
149 u8 usb_storage_read_capacity(u8 device)
150 {
151         /* send cwb "usbc" */
152
153         u8 tmp[8];
154         u8 i;
155         usb_storage_cbw  * cbw = (usb_storage_cbw*)malloc(sizeof(usb_storage_cbw));
156
157         usb_control_msg(massstorage[device], 0x02,1,0, 0x8100, 0,tmp, 0);
158
159         cbw->dCBWSignature= 0x43425355;
160         cbw->dCBWTag=0x826A6008;
161         cbw->dCBWDataTransferLength=0x00000008;
162         cbw->bCWDFlags=0x80;
163         cbw->bCBWLun=0x00;
164         cbw->bCBWCBLength=0x0A;
165
166         for(i=0;i<16;i++)
167                 cbw->CBWCB[i]=0x00;
168
169         cbw->CBWCB[0]=0x25; // 0x12 = INQUIRY
170
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); 
174
175         free(cbw);
176
177         return 0;
178 }
179
180
181 u8 usb_storage_read_sector(u8 device, u32 sector, char * buf)
182 {
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,
190                 0x00,
191                 0x00,0x00,0x00,0x00,0x00};
192
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); 
196
197         
198         return 0;
199 }
200
201
202 u8 usb_storage_write_sector(u8 device, u32 sector, char * buf)
203 {
204
205         return 0;
206 }
207
208 #include <gccore.h>
209 #include <stdlib.h>
210 #include <string.h>
211 #include <unistd.h>
212 #include <sys/time.h>
213 #include <errno.h>
214 #include <lwp_heap.h>
215 #include <malloc.h>
216
217 #include "asm.h"
218 #include "processor.h"
219 #include "disc_io.h"
220
221 #define ROUNDDOWN32(v)                          (((u32)(v)-0x1f)&~0x1f)
222
223 #define HEAP_SIZE                       (32*1024)
224 #define TAG_START                       0x0BADC0DE
225
226 #define CBW_SIZE                        31
227 #define CBW_SIGNATURE                   0x43425355
228 #define CBW_IN                          (1 << 7)
229 #define CBW_OUT                         0
230
231 #define CSW_SIZE                        13
232 #define CSW_SIGNATURE                   0x53425355
233
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
239
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
244
245 #define USB_CLASS_MASS_STORAGE          0x08
246 #define MASS_STORAGE_SCSI_COMMANDS      0x06
247 #define MASS_STORAGE_BULK_ONLY          0x50
248
249 #define USBSTORAGE_GET_MAX_LUN          0xFE
250 #define USBSTORAGE_RESET                0xFF
251
252 #define USB_ENDPOINT_BULK               0x02
253
254 #define USBSTORAGE_CYCLE_RETRIES        3
255
256 #define MAX_TRANSFER_SIZE                       4096
257
258 #define DEVLIST_MAXSIZE    8
259
260 static heap_cntrl __heap;
261 static u8 __heap_created = 0;
262 static lwpq_t __usbstorage_waitq = 0;
263
264 /*
265 The following is for implementing a DISC_INTERFACE 
266 as used by libfat
267 */
268
269 static usbstorage_handle __usbfd;
270 static u8 __lun = 0;
271 static u8 __mounted = 0;
272 static u16 __vid = 0;
273 static u16 __pid = 0;
274
275 static s32 __usbstorage_reset(usbstorage_handle *dev);
276 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun);
277
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..
282  */
283
284 static s32 __usb_blkmsg_cb(s32 retval, void *dummy)
285 {
286         usbstorage_handle *dev = (usbstorage_handle *)dummy;
287         dev->retval = retval;
288         SYS_CancelAlarm(dev->alarm);
289         LWP_ThreadBroadcast(__usbstorage_waitq);
290         return 0;
291 }
292
293 static s32 __usb_deviceremoved_cb(s32 retval,void *arg)
294 {
295         return 0;
296 }
297
298 static void __usb_timeouthandler(syswd_t alarm,void *cbarg)
299 {
300         usbstorage_handle *dev = (usbstorage_handle*)cbarg;
301         dev->retval = USBSTORAGE_ETIMEDOUT;
302         LWP_ThreadBroadcast(__usbstorage_waitq);
303 }
304
305 static void __usb_settimeout(usbstorage_handle *dev)
306 {
307         struct timespec ts;
308
309         ts.tv_sec = 2;
310         ts.tv_nsec = 0;
311         SYS_SetAlarm(dev->alarm,&ts,__usb_timeouthandler,dev);
312 }
313
314 static s32 __USB_BlkMsgTimeout(usbstorage_handle *dev, u8 bEndpoint, u16 wLength, void *rpData)
315 {
316         u32 level;
317         s32 retval;
318
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;
322
323         __usb_settimeout(dev);
324
325         _CPU_ISR_Disable(level);
326         do {
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);
332
333         if(retval==USBSTORAGE_ETIMEDOUT) USBStorage_Close(dev);
334         return retval;
335 }
336
337 static s32 __USB_CtrlMsgTimeout(usbstorage_handle *dev, u8 bmRequestType, u8 bmRequest, u16 wValue, u16 wIndex, u16 wLength, void *rpData)
338 {
339         u32 level;
340         s32 retval;
341         struct timespec ts;
342
343         ts.tv_sec = 2;
344         ts.tv_nsec = 0;
345
346
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;
350
351         __usb_settimeout(dev);
352
353         _CPU_ISR_Disable(level);
354         do {
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);
360
361         if(retval==USBSTORAGE_ETIMEDOUT) USBStorage_Close(dev);
362         return retval;
363 }
364
365 s32 USBStorage_Initialize()
366 {
367         u8 *ptr;
368         u32 level;
369
370         _CPU_ISR_Disable(level);
371         if(__heap_created != 0) {
372                 _CPU_ISR_Restore(level);
373                 return IPC_OK;
374         }
375         
376         LWP_InitQueue(&__usbstorage_waitq);
377
378         ptr = (u8*)ROUNDDOWN32(((u32)SYS_GetArena2Hi() - HEAP_SIZE));
379         if((u32)ptr < (u32)SYS_GetArena2Lo()) {
380                 _CPU_ISR_Restore(level);
381                 return IPC_ENOMEM;
382         }
383
384         SYS_SetArena2Hi(ptr);
385
386         __lwp_heap_init(&__heap, ptr, HEAP_SIZE, 32);
387         __heap_created = 1;
388         _CPU_ISR_Restore(level);
389
390         return IPC_OK;
391
392 }
393
394 static s32 __send_cbw(usbstorage_handle *dev, u8 lun, u32 len, u8 flags, const u8 *cb, u8 cbLen)
395 {
396         s32 retval = USBSTORAGE_OK;
397
398         if(cbLen == 0 || cbLen > 16)
399                 return IPC_EINVAL;
400         
401         memset(dev->buffer, 0, CBW_SIZE);
402
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);
409
410         memcpy(dev->buffer + 15, cb, cbLen);
411
412         if(dev->suspended == 1)
413         {
414                 USB_ResumeDevice(dev->usb_fd);
415                 dev->suspended = 0;
416         }
417
418         retval = __USB_BlkMsgTimeout(dev, dev->ep_out, CBW_SIZE, (void *)dev->buffer);
419
420         if(retval == CBW_SIZE) return USBSTORAGE_OK;
421         else if(retval > 0) return USBSTORAGE_ESHORTWRITE;
422
423         return retval;
424 }
425
426 static s32 __read_csw(usbstorage_handle *dev, u8 *status, u32 *dataResidue)
427 {
428         s32 retval = USBSTORAGE_OK;
429         u32 signature, tag, _dataResidue, _status;
430
431         memset(dev->buffer, 0, CSW_SIZE);
432
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;
436
437         signature = __lwbrx(dev->buffer, 0);
438         tag = __lwbrx(dev->buffer, 4);
439         _dataResidue = __lwbrx(dev->buffer, 8);
440         _status = dev->buffer[12];
441
442         if(signature != CSW_SIGNATURE) return USBSTORAGE_ESIGNATURE;
443
444         if(dataResidue != NULL)
445                 *dataResidue = _dataResidue;
446         if(status != NULL)
447                 *status = _status;
448
449         if(tag != dev->tag) return USBSTORAGE_ETAG;
450         dev->tag++;
451
452         return USBSTORAGE_OK;
453 }
454
455 static s32 __cycle(usbstorage_handle *dev, u8 lun, u8 *buffer, u32 len, u8 *cb, u8 cbLen, u8 write, u8 *_status, u32 *_dataResidue)
456 {
457         s32 retval = USBSTORAGE_OK;
458
459         u8 status = 0;
460         u32 dataResidue = 0;
461         u32 thisLen;
462
463         s8 retries = USBSTORAGE_CYCLE_RETRIES + 1;
464
465         LWP_MutexLock(dev->lock);
466         do
467         {
468                 retries--;
469
470                 if(retval == USBSTORAGE_ETIMEDOUT)
471                         break;
472
473                 if(write)
474                 {
475                         retval = __send_cbw(dev, lun, len, CBW_OUT, cb, cbLen);
476                         if(retval == USBSTORAGE_ETIMEDOUT)
477                                 break;
478                         if(retval < 0)
479                         {
480                                 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
481                                         retval = USBSTORAGE_ETIMEDOUT;
482                                 continue;
483                         }
484                         while(len > 0)
485                         {
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);
490
491                                 if(retval == USBSTORAGE_ETIMEDOUT)
492                                         break;
493
494                                 if(retval < 0)
495                                 {
496                                         retval = USBSTORAGE_EDATARESIDUE;
497                                         break;
498                                 }
499
500
501                                 if(retval != thisLen && len > 0)
502                                 {
503                                         retval = USBSTORAGE_EDATARESIDUE;
504                                         break;
505                                 }
506                                 len -= retval;
507                                 buffer += retval;
508                         }
509
510                         if(retval < 0)
511                         {
512                                 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
513                                         retval = USBSTORAGE_ETIMEDOUT;
514                                 continue;
515                         }
516                 }
517                 else
518                 {
519                         retval = __send_cbw(dev, lun, len, CBW_IN, cb, cbLen);
520
521                         if(retval == USBSTORAGE_ETIMEDOUT)
522                                 break;
523
524                         if(retval < 0)
525                         {
526                                 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
527                                         retval = USBSTORAGE_ETIMEDOUT;
528                                 continue;
529                         }
530                         while(len > 0)
531                         {
532                                 thisLen = len > MAX_TRANSFER_SIZE ? MAX_TRANSFER_SIZE : len;
533                                 retval = __USB_BlkMsgTimeout(dev, dev->ep_in, thisLen, dev->buffer);
534                                 if(retval < 0)
535                                         break;
536
537                                 memcpy(buffer, dev->buffer, retval);
538                                 len -= retval;
539                                 buffer += retval;
540
541                                 if(retval != thisLen)
542                                         break;
543                         }
544
545                         if(retval < 0)
546                         {
547                                 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
548                                         retval = USBSTORAGE_ETIMEDOUT;
549                                 continue;
550                         }
551                 }
552
553                 retval = __read_csw(dev, &status, &dataResidue);
554
555                 if(retval == USBSTORAGE_ETIMEDOUT)
556                         break;
557
558                 if(retval < 0)
559                 {
560                         if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
561                                 retval = USBSTORAGE_ETIMEDOUT;
562                         continue;
563                 }
564
565                 retval = USBSTORAGE_OK;
566         } while(retval < 0 && retries > 0);
567
568         if(retval < 0 && retval != USBSTORAGE_ETIMEDOUT)
569         {
570                 if(__usbstorage_reset(dev) == USBSTORAGE_ETIMEDOUT)
571                         retval = USBSTORAGE_ETIMEDOUT;
572         }
573         LWP_MutexUnlock(dev->lock);
574
575
576         if(_status != NULL)
577                 *_status = status;
578         if(_dataResidue != NULL)
579                 *_dataResidue = dataResidue;
580
581         return retval;
582 }
583
584 static s32 __usbstorage_clearerrors(usbstorage_handle *dev, u8 lun)
585 {
586         s32 retval;
587         u8 cmd[16];
588         u8 sense[SCSI_SENSE_REPLY_SIZE];
589         u8 status = 0;
590
591         memset(cmd, 0, sizeof(cmd));
592         cmd[0] = SCSI_TEST_UNIT_READY;
593
594         retval = __cycle(dev, lun, NULL, 0, cmd, 1, 0, &status, NULL);
595         if(retval < 0) return retval;
596
597         if(status != 0)
598         {
599                 cmd[0] = SCSI_REQUEST_SENSE;
600                 cmd[1] = lun << 5;
601                 cmd[4] = SCSI_SENSE_REPLY_SIZE;
602                 cmd[5] = 0;
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;
606
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;
609         }
610
611         return retval;
612 }
613
614 static s32 __usbstorage_reset(usbstorage_handle *dev)
615 {
616         s32 retval;
617
618         if(dev->suspended == 1)
619         {
620                 USB_ResumeDevice(dev->usb_fd);
621                 dev->suspended = 0;
622         }
623
624         retval = __USB_CtrlMsgTimeout(dev, (USB_CTRLTYPE_DIR_HOST2DEVICE | USB_CTRLTYPE_TYPE_CLASS | USB_CTRLTYPE_REC_INTERFACE), USBSTORAGE_RESET, 0, dev->interface, 0, NULL);
625
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)
628                 goto end;
629
630         /* gives device enough time to process the reset */
631         usleep(60);
632
633         retval = USB_ClearHalt(dev->usb_fd, dev->ep_in);
634         if(retval < 0)
635                 goto end;
636         retval = USB_ClearHalt(dev->usb_fd, dev->ep_out);
637
638 end:
639         return retval;
640 }
641
642 s32 USBStorage_Open(usbstorage_handle *dev, const char *bus, u16 vid, u16 pid)
643 {
644         s32 retval = -1;
645         u8 conf,*max_lun = NULL;
646         u32 iConf, iInterface, iEp;
647         usb_devdesc udd;
648         usb_configurationdesc *ucd;
649         usb_interfacedesc *uid;
650         usb_endpointdesc *ued;
651
652         max_lun = __lwp_heap_allocate(&__heap, 1);
653         if(max_lun==NULL) return IPC_ENOMEM;
654
655         memset(dev, 0, sizeof(*dev));
656
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;
662
663         retval = USB_OpenDevice(bus, vid, pid, &dev->usb_fd);
664         if(retval < 0)
665                 goto free_and_return;
666
667         retval = USB_GetDescriptors(dev->usb_fd, &udd);
668         if(retval < 0)
669                 goto free_and_return;
670
671         for(iConf = 0; iConf < udd.bNumConfigurations; iConf++)
672         {
673                 ucd = &udd.configurations[iConf];               
674                 for(iInterface = 0; iInterface < ucd->bNumInterfaces; iInterface++)
675                 {
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)
680                         {
681                                 if(uid->bNumEndpoints < 2)
682                                         continue;
683
684                                 dev->ep_in = dev->ep_out = 0;
685                                 for(iEp = 0; iEp < uid->bNumEndpoints; iEp++)
686                                 {
687                                         ued = &uid->endpoints[iEp];
688                                         if(ued->bmAttributes != USB_ENDPOINT_BULK)
689                                                 continue;
690
691                                         if(ued->bEndpointAddress & USB_ENDPOINT_IN)
692                                                 dev->ep_in = ued->bEndpointAddress;
693                                         else
694                                                 dev->ep_out = ued->bEndpointAddress;
695                                 }
696                                 if(dev->ep_in != 0 && dev->ep_out != 0)
697                                 {
698                                         dev->configuration = ucd->bConfigurationValue;
699                                         dev->interface = uid->bInterfaceNumber;
700                                         dev->altInterface = uid->bAlternateSetting;
701                                         goto found;
702                                 }
703                         }
704                 }
705         }
706
707         USB_FreeDescriptors(&udd);
708         retval = USBSTORAGE_ENOINTERFACE;
709         goto free_and_return;
710
711 found:
712         USB_FreeDescriptors(&udd);
713
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;
721         dev->suspended = 0;
722
723         retval = USBStorage_Reset(dev);
724         if(retval < 0)
725                 goto free_and_return;
726
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);
730         if(retval < 0)
731                 dev->max_lun = 1;
732         else
733                 dev->max_lun = *max_lun;
734
735         
736         if(retval == USBSTORAGE_ETIMEDOUT)
737                 goto free_and_return;
738
739         retval = USBSTORAGE_OK;
740         dev->sector_size = (u32 *)calloc(dev->max_lun, sizeof(u32));
741         if(dev->sector_size == NULL)
742         {
743                 retval = IPC_ENOMEM;
744                 goto free_and_return;
745         }
746
747         if(dev->max_lun == 0)
748                 dev->max_lun++;
749
750         /* taken from linux usbstorage module (drivers/usb/storage/transport.c) */
751         /*
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).
756          */
757         USB_ClearHalt(dev->usb_fd, dev->ep_in);
758         USB_ClearHalt(dev->usb_fd, dev->ep_out);
759
760         dev->buffer = __lwp_heap_allocate(&__heap, MAX_TRANSFER_SIZE);
761         
762         if(dev->buffer == NULL) retval = IPC_ENOMEM;
763         else {
764                 USB_DeviceRemovalNotifyAsync(dev->usb_fd,__usb_deviceremoved_cb,dev);
765                 retval = USBSTORAGE_OK;
766         }
767
768 free_and_return:
769         if(max_lun!=NULL) __lwp_heap_free(&__heap, max_lun);
770         if(retval < 0)
771         {
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));
780                 return retval;
781         }
782         return 0;
783 }
784
785 s32 USBStorage_Close(usbstorage_handle *dev)
786 {
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));
795         return 0;
796 }
797
798 s32 USBStorage_Reset(usbstorage_handle *dev)
799 {
800         s32 retval;
801
802         LWP_MutexLock(dev->lock);
803         retval = __usbstorage_reset(dev);
804         LWP_MutexUnlock(dev->lock);
805
806         return retval;
807 }
808
809 s32 USBStorage_GetMaxLUN(usbstorage_handle *dev)
810 {
811         return dev->max_lun;
812 }
813
814 s32 USBStorage_MountLUN(usbstorage_handle *dev, u8 lun)
815 {
816         s32 retval;
817
818         if(lun >= dev->max_lun)
819                 return IPC_EINVAL;
820
821         retval = __usbstorage_clearerrors(dev, lun);
822         if(retval < 0)
823                 return retval;
824
825         retval = USBStorage_ReadCapacity(dev, lun, &dev->sector_size[lun], NULL);
826         return retval;
827 }
828
829 s32 USBStorage_ReadCapacity(usbstorage_handle *dev, u8 lun, u32 *sector_size, u32 *n_sectors)
830 {
831         s32 retval;
832         u8 cmd[] = {SCSI_READ_CAPACITY, lun << 5};
833         u8 response[8];
834
835         retval = __cycle(dev, lun, response, 8, cmd, 2, 0, NULL, NULL);
836         if(retval >= 0)
837         {
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;
843         }
844
845         return retval;
846 }
847
848 s32 USBStorage_Read(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, u8 *buffer)
849 {
850         u8 status = 0;
851         s32 retval;
852         u8 cmd[] = {
853                 SCSI_READ_10,
854                 lun << 5,
855                 sector >> 24,
856                 sector >> 16,
857                 sector >>  8,
858                 sector,
859                 0,
860                 n_sectors >> 8,
861                 n_sectors,
862                 0
863                 };
864         if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
865                 return IPC_EINVAL;
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;
869         return retval;
870 }
871
872 s32 USBStorage_Write(usbstorage_handle *dev, u8 lun, u32 sector, u16 n_sectors, const u8 *buffer)
873 {
874         u8 status = 0;
875         s32 retval;
876         u8 cmd[] = {
877                 SCSI_WRITE_10,
878                 lun << 5,
879                 sector >> 24,
880                 sector >> 16,
881                 sector >> 8,
882                 sector,
883                 0,
884                 n_sectors >> 8,
885                 n_sectors,
886                 0
887                 };
888         if(lun >= dev->max_lun || dev->sector_size[lun] == 0)
889                 return IPC_EINVAL;
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;
893         return retval;
894 }
895
896 s32 USBStorage_Suspend(usbstorage_handle *dev)
897 {
898         if(dev->suspended == 1)
899                 return USBSTORAGE_OK;
900
901         USB_SuspendDevice(dev->usb_fd);
902         dev->suspended = 1;
903
904         return USBSTORAGE_OK;
905
906 }
907
908 /*
909 The following is for implementing a DISC_INTERFACE 
910 as used by libfat
911 */
912
913 static bool __usbstorage_IsInserted(void);
914
915 static bool __usbstorage_Startup(void)
916 {
917         USB_Initialize();
918         USBStorage_Initialize();
919         return __usbstorage_IsInserted();
920 }
921
922 static bool __usbstorage_IsInserted(void)
923 {
924    u8 *buffer;
925    u8 dummy;
926    u8 i, j;
927    u16 vid, pid;
928    s32 maxLun;
929    s32 retval;
930
931    __mounted = 0;               //reset it here and check if device is still attached
932
933    buffer = __lwp_heap_allocate(&__heap, DEVLIST_MAXSIZE << 3);
934    if(buffer == NULL)
935        return false;
936    memset(buffer, 0, DEVLIST_MAXSIZE << 3);
937
938    if(USB_GetDeviceList("/dev/usb/oh0", buffer, DEVLIST_MAXSIZE, 0, &dummy) < 0)
939    {
940        if(__vid!=0 || __pid!=0) USBStorage_Close(&__usbfd);
941        memset(&__usbfd, 0, sizeof(__usbfd));
942        __lun = 0;
943        __vid = 0;
944        __pid = 0;
945
946        __lwp_heap_free(&__heap,buffer);
947        return false;
948    }
949
950    if(__vid!=0 || __pid!=0)
951    {
952        for(i = 0; i < DEVLIST_MAXSIZE; i++)
953        {
954            memcpy(&vid, (buffer + (i << 3) + 4), 2);
955            memcpy(&pid, (buffer + (i << 3) + 6), 2);
956            if(vid != 0 || pid != 0)
957            {
958
959                if( (vid == __vid) && (pid == __pid))
960                {
961                    __mounted = 1;
962                                    __lwp_heap_free(&__heap,buffer);
963                    usleep(50); // I don't know why I have to wait but it's needed
964                    return true;
965                }
966            }
967        }
968        USBStorage_Close(&__usbfd);
969    }
970
971    memset(&__usbfd, 0, sizeof(__usbfd));
972    __lun = 0;
973    __vid = 0;
974    __pid = 0;
975
976    for(i = 0; i < DEVLIST_MAXSIZE; i++)
977    {
978        memcpy(&vid, (buffer + (i << 3) + 4), 2);
979        memcpy(&pid, (buffer + (i << 3) + 6), 2);
980        if(vid == 0 || pid == 0)
981            continue;
982
983        if(USBStorage_Open(&__usbfd, "oh0", vid, pid) < 0)
984            continue;
985
986        maxLun = USBStorage_GetMaxLUN(&__usbfd);
987        for(j = 0; j < maxLun; j++)
988        {
989            retval = USBStorage_MountLUN(&__usbfd, j);
990            if(retval == USBSTORAGE_ETIMEDOUT)
991            {
992                break;
993            }
994
995            if(retval < 0)
996                continue;
997
998            __mounted = 1;
999            __lun = j;
1000            __vid = vid;
1001            __pid = pid;
1002            i = DEVLIST_MAXSIZE;
1003            break;
1004        }
1005    }
1006    __lwp_heap_free(&__heap,buffer);
1007    if(__mounted == 1)
1008        return true;
1009    return false;
1010 }
1011
1012 static bool __usbstorage_ReadSectors(u32 sector, u32 numSectors, void *buffer)
1013 {
1014    s32 retval;
1015
1016    if(__mounted != 1)
1017        return false;
1018
1019    retval = USBStorage_Read(&__usbfd, __lun, sector, numSectors, buffer);
1020    if(retval == USBSTORAGE_ETIMEDOUT)
1021    {
1022        __mounted = 0;
1023    }
1024    if(retval < 0)
1025        return false;
1026    return true;
1027 }
1028
1029 static bool __usbstorage_WriteSectors(u32 sector, u32 numSectors, const void *buffer)
1030 {
1031    s32 retval;
1032
1033    if(__mounted != 1)
1034        return false;
1035
1036    retval = USBStorage_Write(&__usbfd, __lun, sector, numSectors, buffer);
1037    if(retval == USBSTORAGE_ETIMEDOUT)
1038    {
1039        __mounted = 0;
1040    }
1041    if(retval < 0)
1042        return false;
1043    return true;
1044 }
1045
1046 static bool __usbstorage_ClearStatus(void)
1047 {
1048    return true;
1049 }
1050
1051 static bool __usbstorage_Shutdown(void)
1052 {
1053    //if(__mounted == 1) USBStorage_Close(&__usbfd);
1054    __mounted = 0;
1055    return true;
1056 }
1057
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
1067 };
1068
1069 #endif /* HW_RVL */