-
Notifications
You must be signed in to change notification settings - Fork 5
/
otg.cpp
6138 lines (5366 loc) · 195 KB
/
otg.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* In this file in this order:
* - usbhost.cpp
* - ff.cpp
*/
#include "otg.h"
// ==== otg.cpp ==========================================================
int uhgogo;
char otgbufrd[512];
char otgbufwr[512];
void otgfill(char *buf, int pat);
int otgBlRead(int slot, int block, int pat);
int otgBlWrite(int slot,int block, int pat);
int otgBlTest(int slot, int n);
extern char otgbufrd[512];
extern char otgbufwr[512];
#ifdef USEFATFS
FATFS fatfs;
void otgFsRead(char *fname);
void otgFsWrite(char *s);
void otgFsLs(char *s);
#endif // USEFATFS
// cmdServer()
// read a command from Rs232
// execute the command
extern void (*gpf_isr)(void);
#define CMDLINEFULL 80
char cmdline[CMDLINEFULL+2];
int cmdlinepp;
void
cmdServer()
{ char *s= cmdline;
int i, j;
if (cmdlinepp==0) memset(cmdline, 0, sizeof(cmdline));
if (Serial.available()>0){
i= Serial.read();
if ((i>=' ')&& (cmdlinepp < CMDLINEFULL))
cmdline[cmdlinepp++]= i;
if ((i=='\n') && (cmdlinepp>0))
cmdlinepp= CMDLINEFULL;
}
if (cmdlinepp< CMDLINEFULL)
return; // and loop
printf("> %s\n", cmdline);
cmdlinepp= 0;
if (strcmp(s, "go")==0){ // go
printf("start uh server\n");
uhgogo= 1;
return;
}
if (strncmp(s, "v=", 2)==0){ // v= <verbose>
i= strtol(s+2, 0, 10);
uhstate.verbose= i;
printf("verbose=%d\n", i);
return;
}
if (strncmp(s, "blrd ", 5)==0){ // blrd <lba>
i= strtol(s+5, &s, 10);
j= strtol(s, 0, 16);
otgBlRead(0, i, j<=0? -1: j);
return;
}
if (strncmp(s, "blwr ", 5)==0){ // blwr <lba> <pat>
i= strtol(s+5, &s, 10);
j= strtol(s, 0, 16);
otgBlWrite(0, i, j);
return;
}
if (strncmp(s, "bltst", 5)==0){ // bltst <cnt>
i= strtol(s+5, &s, 10);
otgBlTest(0, i);
return;
}
if (strcmp(s, "u")==0){ // u
uhDump();
return;
}
#ifdef USEFATFS
if (strcmp(s, "ls")==0){ // ls
otgFsLs(s+3);
return;
}
if (strncmp(s, "rd ", 3)==0){ // rd <filename>
otgFsRead(s+3);
return;
}
if (strncmp(s, "wr ", 3)==0){ // wr <filename> <n> <pat>
otgFsWrite(s+3);
return;
}
#endif // USEFATFS
printf("ERROR unknown cmd <%s>\n", cmdline);
}
#define VERBOSE1 if (uhstate.verbose)
#define VERBOSE2 if (uhstate.verbose>1)
void
uhServer()
{ static u64 t0init; // no more than 1 per 2s
static int ostat= UHSTAT_NULL;
static int fs=0;
int st;
if (ostat== UHSTAT_NULL)
uhInit(); // init driver
st= uhstate.state;
if (st<UHSTAT_DEV)
t0init= 0;
if (st!=ostat) // stat changed
VERBOSE1 uhPrintState();
if ((st>=UHSTAT_DEV) && (st<UHSTAT_READY) && ((millis()-t0init)>2000)){
uhInit(); // silent
fs= 0;
t0init= millis();
}
if ((st>= UHSTAT_READY)&& (fs==0)){
#ifdef USEFATFS
memset (&fatfs, 0, sizeof(fatfs));
f_mount(0, &fatfs);
#endif // USEFATFS
fs= 1;
}
ostat= st;
}
// pattern -2 no compare, no dump
// -1 no compare, dump
// 0.. compare, dump if error
// return <0 error
// 0 rd ok, compare error
// >0 ok, compare ok
//
void
otgfill(char *buf, int pat)
{ int i;
for (i=0; i<512; i++, buf++)
*buf= pat++;
}
int
otgBlRead(int slot, int block, int pat)
{
(void)slot;
int i;
VERBOSE1 if (pat!=-2) printf("read %d %0x\n", block, pat==-1? 0: pat);
otgfill(otgbufwr, pat);
if ((i= mscReadBlock(block, otgbufrd))< 0){
printf("read failed %d\n", i);
return i;
}
if (memcmp(otgbufrd, otgbufwr, 512)==0){
return 1;
}
if (pat>=0)
printf("read %d %0x compare failed\n", block, pat);
if (pat!=-2)
dumphex(otgbufrd, 0, 512);
if (pat>=0){
printf("pattern: %d %d\n", block, pat);
dumphex(otgbufwr, 0, 512);
}
return 0;
}
int
otgBlWrite(int slot,int block, int pat)
{
(void)slot;
int i;
VERBOSE1 printf("write %d %0x\n", block, pat);
otgfill(otgbufwr, pat);
if ((i= mscWriteBlock( block, otgbufwr))!= 0){
printf("write failed %d\n", i);
return 0;
}
return 1;
}
const int otgdt[]= { 13,0x55, 177,0x33, 1333,0x12, 117,0x00, 888,0x88, 300, 0x33,
73,0xCC, 155,0xAF, 1404,0xE2, 1488,0x99, 999,0xFF, 257, 0xA5,
0 };
int
otgBlTest(int slot, int n)
{ const int *p;
if (n<1) n=1;
for (;n>0; n--){
for (p= otgdt; *p>0; p+=2 )
if (otgBlWrite(slot, *p, p[1]+n)==0)
return 0;
for (p= otgdt; *p>0; p+=2 )
if (otgBlRead(slot, *p, p[1]+n)==0)
return 0;
}
printf("Test finished ok\n");
return 1;
}
#ifdef USEFATFS
void
otgFsLs(char *s)
{ DIR dir; int i; char at;
FILINFO fin;
char lfn[_MAX_LFN+1];
#if _USE_LFN
fin.lfname= lfn;
fin.lfsize= sizeof(lfn);
#endif
if ((i=f_opendir(&dir, "/"))!=0){
printf("ERROR f_opendir %d\n", i);
return;
}
for (i=0; i<100; i++){
memset(lfn, 0, sizeof(lfn));
if (f_readdir(&dir, &fin)!=0)
break;
if (fin.fname[0]==0) break; // problem f_readdir() !
if (lfn[0]!=0)
printf("< %-20s", lfn);
else
printf("< %-20s", fin.fname);
at=' ';
if (fin.fattrib&AM_DIR) at='/';
printf(" %c %d\n", at, fin.fsize);
}
}
void
otgFsRead(char *fname)
{ int i;
FIL fd;
char buf[80];
if ((i=f_open(&fd, fname, FA_READ))!=0){
printf("ERROR f_open <%s> %d\n", fname, i);
return;
}
while (f_gets( buf, sizeof(buf), &fd)!=0){
printf("< %s", buf);
}
printf("\nEOF\n", buf);
f_close(&fd);
}
void
otgFsWrite(char *s)
{ int i, lmax;
FIL fd;
char *fname=s;
char buf[80];
while (*s>' ') s++;
if (*s!=0) *s++= 0;
lmax= strtol(s, &s, 10);
while (*s==' ') s++;
if (lmax<=0) lmax=10;
if ((i=f_open(&fd, fname, FA_WRITE|FA_CREATE_ALWAYS))!=0){
printf("ERROR f_open <%s> %d\n", fname, i);
return;
}
for (i=1; i<= lmax; i++){
sprintf(buf,"line %d ", i);
f_puts(buf, &fd);
f_puts(s, &fd);
f_puts("\n", &fd);
}
f_close(&fd);
printf("write %s %d lines done\n", fname, lmax);
}
#endif // USEFATFS
// +++ usbhost() driver integration
void
uhStatServer() // display stat on LED
{
#if 0
if (uhstate.state>= UHSTAT_READY)
digitalWrite(13, HIGH); // turn led on
else digitalWrite(13, LOW); // turn led off
PIOA->PIO_CODR= LEDBIT2;
else PIOA->PIO_SODR= LEDBIT2;
#endif
}
void
uhWaitMs(int n)
{
uhStatServer();
delay(n);
uhStatServer();
}
void
uhSwitch()
{
uhStatServer();
// switch to other task
uhStatServer();
}
#ifdef USEFATFS
#
// +++ fatfs integration
struct billstime {
u32 sec:5, // seconds/2 0-29
min: 6, // minutes 0-59
hour: 5, // hour 0-23 (gmt)
day:5, // dd 1-31
month: 4, // MM 1-12
year: 7; // yyyy-1980
};
DWORD
get_fattime()
{ union {
DWORD d;
struct billstime b;
} u;
u.d= 0;
u.b.year= 2017-1980;
u.b.month= 7;
u.b.day= 24;
u.b.hour= 16;
u.b.min= 44;
return u.d;
}
#if _USE_LFN
WCHAR
ff_convert(WCHAR x, UINT mode)
{ return x;
}
WCHAR
ff_wtoupper(WCHAR x)
{ return x;
}
#endif // _USE_LFN
// +++ fatfs -> usbhost interface
// ff -> usbhost interface
DSTATUS
disk_initialize (BYTE lun)
{
if (uhstate.state== UHSTAT_READY)
return RES_OK;
return RES_ERROR;
}
DSTATUS
disk_status (BYTE lun)
{
if (uhstate.state== UHSTAT_READY)
return RES_OK;
return RES_ERROR;
}
DRESULT
disk_read (BYTE lun, BYTE *buf, DWORD lba, BYTE cnt)
{ int i;
for (;cnt>0; lba++, buf+=512, cnt--){
VERBOSE2 printf("disk_read lba=%d\n", lba);
if ((i=mscReadBlock(lba, (char *)buf))<0)
return RES_ERROR;
}
return RES_OK;
}
DRESULT
disk_write (BYTE lun, const BYTE *buf, DWORD lba, BYTE cnt)
{ int i;
for (;cnt>0; lba++, buf+=512, cnt--){
VERBOSE2 printf("disk_write lba=%d\n", lba);
if ((i=mscWriteBlock(lba, (char *)buf))<0)
return RES_ERROR;
}
return RES_OK;
}
DRESULT
disk_ioctl (BYTE lun, BYTE cmd, void* p)
{
VERBOSE1 printf("disk_ioctl %d\n", cmd);
switch (cmd) {
case GET_SECTOR_SIZE:
case GET_BLOCK_SIZE:
* ((DWORD *)p)= 512;
return RES_OK;
case GET_SECTOR_COUNT:
* ((DWORD *)p)= uhstate.capacity;
return RES_OK;
case CTRL_SYNC:
return RES_OK;
}
VERBOSE1 printf("ERROR disk_ioctl %d\n", cmd);
return RES_ERROR;
}
#endif // USEFATFS
// +++ suppport and debug functions
void
dumphex(const char *p, u32 addr, int cnt)
{ int i; uchar c; u32 *pp;
const char tohex[]="0123456789ABCDEF";
for (;cnt >0; cnt-=16, p+=16, addr+=16) {
printf("%08X:", addr);
for (i=0; i<16; i++){
c= p[i];
if ((i%4)==0)
printf(" ");
if (i < cnt)
printf("%c%c", tohex[(c>>4)&0xF], tohex[c&0xF]);
else printf(" ");
}
printf(" /");
for (i=0; i<16; i++){
c= p[i];
if ((i < cnt)&& (c>=' ') && (c<0x7F))
printf("%c", c);
else printf(" ");
}
printf("/");
#if 1
if ((((u32)p)&0x3)==0){ // 32bit alligned
pp= (u32*) p;
for (i=0; i<16; i+=4, pp++)
if (i<cnt)
printf(" %08X", *pp);
}
#endif
printf("\n");
}
}
// ==== usbhost.cpp ======================================================
/*
This code is in the public domain.
Created by Andreas Meyer controlord/at/controlord/dot/fr
Version 201712 (dec 2017)
*/
//#include "duedue.h"
//#include "usbhost.h"
void uhSetState(int i); // only down!
void uhSetStateUp(int i); // down or up 1
void uhSetStateXXX(int i);
const char *uhStatAsc();
void uhInit();
void uhInitx(char *s);
void uhInitPipe(int pipe, int token);
void uhInitPipeToken(int pipe, int token);
void uhInitAllocDpram();
void uhInitPeriph();
int uhInitResetUsb(int n, int inix);
int uhInitEnum();
void uhEnumSaveDescr(u8 *d);
void uhEnumPrintDescr(u8 *d, int tlng);
int uhEnumConfig(u8 *d, int tlng);
void uhResetDevEndpointIn();
const char * uhErrorAsc(int ecode);
int uhSendPipe(int pipe, u8 *buf, int lng);
int uhReceivePipe(int pipe, u8 *buf, int lng);
extern void udd_interrupt();
void uhInterrupt();
void uhInterruptPipe(int pipe);
extern void (*gpf_isr)(void);
void mscInit();
int mscTstUnitReady();
int mscInquiry();
int mscReadCapacity();
int mscRequestSense();
int mscReceiveWrapper(int pipe, u32 stall);
int mscReadBlock(u32 lba, char *buf);
int mscWriteBlock(u32 lba, char *buf);
const char *scsi2asc(int code);
void uhDumpx(int pipe, const char *pre, int destr);
int uhStepFrom, uhStepTo;
#define VERBOSE0 // severe internal errors, "can not happen"
#define VERBOSE1 if (uhstate.verbose)
#define VERBOSE2 if (uhstate.verbose>1)
#define VERBOSE3 if (uhstate.verbose>2)
// +++ usbhost, msc, scsi ***********
// +++ usb host + enumeration
#define UHLOG if (0) uhramlog
void uhramlog(const char *fmt, ...); // debug support
#define UHPIPE_CTRL 0
#define UHPIPE_IN 1
#define UHPIPE_OUT 2
#define UHPIPES 10 // just for arrays
//#define UOTGHS_DPRAM 0x20180000
#define UOTGHS_DPRAM UOTGHS_RAM_ADDR
//struct _uhstate {
// volatile int state; // off, enumeration, ready
// u32 capacity; // total number of blocks
// u16 idVendor; // enumeration
// u16 idProduct;
// u8 vendor_id[8+1];
// u8 product_id[16+1];
// u8 product_rev[4+1];
// u16 maxPower;
//};
struct _uhstate uhstate;
struct _uhx { // internals
struct _cnt {
u32 sof; // count sof events
u32 pipeint;
u32 connect;
u32 disconnect;
u32 stall;
u32 tout;
u32 errs[10]; // -1...
u32 mscErrors; // signal msc rd/wr error
} cnt;
u8 *uhDmaStartaddress;
char *fifoaddr[UHPIPES];
int devpipein; // device endpoint
int devpipeout; // device endpoint
int devpipeoutLng; // endpoint max package size
u32 msctag;
struct _it {
volatile u32 pipe;
volatile u32 mask;
volatile u32 isr;
volatile int done; // 0=waiting for, >0: ok, <0: UHERROR_
} it; // uhx.it.
} uhx;
const char *
uhStatAsc()
{ switch(uhstate.state){
case UHSTAT_NULL: return "";
case UHSTAT_NODEV: return "NODEV";
case UHSTAT_DEV: return "DEV";
case UHSTAT_ENUM: return "ENUM";
case UHSTAT_READY: return "READY";
default: return "??? stat unknown";
}
}
#define UHERROR_NOTREADY -1
#define UHERROR_TIMEOUT -2
#define UHERROR_STALL -3 // not really an error
#define UHERROR_REPLY -4
#define UHERROR_INTERN -5
#define UHERROR_IO -6
#define UHTIMEOUT 1000 // ms
#define UHTIMEOUTSENSER 5000 // ms senserequest ?????
const char *uhAscErrors[]= { "notready", "timeout", "stall", "reply",
"intern", "io"};
const char *
uhErrorAsc(int ecode)
{ switch(ecode){
default: return "";
case UHERROR_NOTREADY: return "ERROR: NOT READY";
case UHERROR_TIMEOUT: return "ERROR: TIMEOUT";
case UHERROR_STALL: return "ERROR: STALL";
case UHERROR_REPLY: return "ERROR: REPLY";
case UHERROR_INTERN: return "ERROR: INTERN";
case UHERROR_IO: return "ERROR: IO";
}
}
// usb device setup request
typedef struct _usb_request {
u8 urRequestType;
u8 urRequest;
u16 urValue;
u16 urIndex;
u16 urLeng;
} usb_request;
#define USBREQUESTLNG 8
#define urFill(t, rq, v, ix, lng) \
memset(&ur, 0, sizeof(ur));\
ur.urRequestType= t; \
ur.urRequest= rq; \
ur.urValue= v; \
ur.urIndex= ix; \
ur.urLeng= lng;
// urRequestType
#define USB_REQ_DIR_OUT (0<<7) //!< Host to device
#define USB_REQ_DIR_IN (1<<7) //!< Device to host
#define USB_REQ_TYPE_STANDARD (0<<5) //!< Standard request
//#define USB_REQ_TYPE_CLASS (1<<5) //!< Class-specific request
//#define USB_REQ_TYPE_VENDOR (2<<5) //!< Vendor-specific request
#define USB_REQ_RECIP_DEVICE (0<<0) //!< Recipient device
//#define USB_REQ_RECIP_INTERFACE (1<<0) //!< Recipient interface
#define USB_REQ_RECIP_ENDPOINT (2<<0) //!< Recipient endpoint
//#define USB_REQ_RECIP_OTHER (3<<0) //!< Recipient other
//#define USB_REQ_RECIP_MASK (0x1F) //!< Mask
// urRequest
//efine USB_REQ_GET_STATUS 0
#define USB_REQ_CLEAR_FEATURE 1
//efine USB_REQ_SET_FEATURE 3
#define USB_REQ_SET_ADDRESS 5
#define USB_REQ_GET_DESCRIPTOR 6
//efine USB_REQ_SET_DESCRIPTOR 7
//efine USB_REQ_GET_CONFIGURATION 8
#define USB_REQ_SET_CONFIGURATION 9
//efine USB_REQ_GET_INTERFACE 10
//efine USB_REQ_SET_INTERFACE 11
//efine USB_REQ_SYNCH_FRAME 12
#define USB_EP_FEATURE_HALT 0 // endpoint feature
#define USB_DT_DEVICE 1
#define USB_DT_CONFIGURATION 2
#define USB_DT_INTERFACE 4
#define USB_DT_ENDPOINT 5
// USB device descriptor s
typedef struct _usb_devdesr{ // devioce descr
u8 bLength; // 0:
u8 bDescriptorType; // 1:
u16 bcdUSB; // 2:
u8 bDeviceClass; // 4:
u8 bDeviceSubClass; // 5:
u8 bDeviceProtocol; // 6:
u8 bMaxPacketSize0; // 7:
u16 idVendor; // 8:
u16 idProduct; // A:
u16 bcdDevice; // C:
u8 iManufacturer; // E:
u8 iProduct; // F:
u8 iSerialNumber; // 10:
u8 bNumConfigurations; // 11: total: 18 bytes
} usb_devdescr;
typedef struct { // configuration decr
u8 bLength;
u8 bDescriptorType;
u16 wTotalLength;
u8 bNumInterfaces;
u8 bConfigurationValue;
u8 iConfiguration;
u8 bmAttributes; // 0x40= self powered
u8 bMaxPower; // *2mA lng=9
u8 stuff[46]; // 23= 1 interface(9) + 2 epdescr(7)
} usb_confdescr;
#define CONFDESCRLNG 9
typedef struct { // interface descr.
u8 bLength;
u8 bDescriptorType;
u8 bInterfaceNumber;
u8 bAlternateSetting;
u8 bNumEndpoints;
u8 bInterfaceClass; // need MSC_CLASS
u8 bInterfaceSubClass;
u8 bInterfaceProtocol;
u8 iInterface;
} usb_ifacedescr;
#define MSC_CLASS 0x08
#define MSC_SUBCLASS_TRANSPARENT 0x06
#define MSC_PROTOCOL_BULK 0x50
typedef struct { // endpoint descr
u8 bLength;
u8 bDescriptorType;
u8 bEndpointAddress;
u8 bmAttributes;
u8 wMaxPacketSize[2];
u8 bInterval;
} usb_epdescr;
#define USB_EP_DIR_IN 0x80
#define USB_EP_DIR_OUT 0x00
#define USB_EP_TYPE_BULK 2
void
uhSetState(int i) // only down!
{ if (i< uhstate.state)
uhstate.state= i;
uhStatServer();
}
void
uhSetStateUp(int i) // down or up 1
{ if (i< uhstate.state)
uhstate.state= i;
if (i== uhstate.state+1)
uhstate.state= i;
uhStatServer();
}
void
uhSetStateXXX(int i) // set uncondiotioned (debug only)
{ uhstate.state= i;
uhStatServer();
}
int
uhError(int e)
{ int i;
i= -1-e; // -1->0 -2->1 ...
if ((i>=0) && (i<10)) uhx.cnt.errs[i]++;
UHLOG("error %d", e);
// uhSetState(sowhat);
// set last error ?;
return e;
}
void
uhPrintState()
{ const char *speed;
switch ((UOTGHS->UOTGHS_SR & UOTGHS_SR_SPEED_Msk)>>UOTGHS_SR_SPEED_Pos){
case 0: speed= "full"; break;
case 1: speed= "high"; break;
case 2: speed= "low" ; break;
default: speed="???" ; break;
}
printf("%s %s speed",
uhStatAsc(), speed);
if (uhstate.verbose)
printf(" v=%d", uhstate.verbose);
if (uhstate.state>= UHSTAT_READY)
printf(" vendor= %04X %s product= %04X %s curr= %dmA"
" mem= %dGB",
uhstate.idVendor, uhstate.vendor_id, uhstate.idProduct,
uhstate.product_id,
uhstate.maxPower,
(uhstate.capacity/2000+300)/1000);
printf("\n");
}
// uhInit():
// uhInitPeriph() init usb host -> UHSTAT_NODEV
// wait for dev to connect -> UHSTAT_DEV
// uhInitEnum() enumeration phase -> UHSTAT_ENUM
// mscInit() int msc/sci interface, get device infos -> UHSTAT_READY
//
// ATmel:
// step1 0: reset
// step2 11: 20ms
// step3 32: reset
// step4 43: 100ms
// step5 143: get device descr
// step6 143: 20ms
// step7 163: reset
// step8 174: 100ms
// step9 274: set address
// step10 274: 20ms
// step11 294: new adrress, get dev descriptor
void
uhInit()
{ uhInitx((char *)""); }
void
uhInitx(char *s)
{
uhStepFrom= strtol(s, &s, 10);
if (*s==',') s++;
uhStepTo= strtol(s, &s, 10);
if (uhStepTo<=0) uhStepTo= 9999;
uhInitAllocDpram();
if (uhstate.state== UHSTAT_NULL){
uhSetStateUp(UHSTAT_NODEV); // stat _NULL -> _NODEV
uhInitPeriph();
u64 t0;
for (t0=millis(); millis()< (t0+500);){
uhSwitch();
if (uhstate.state== UHSTAT_DEV)
break;
}
VERBOSE2 printf("%s dev after %d ms\n",
uhstate.state== UHSTAT_DEV? "": "no", (int)(millis()-t0));
}
if (uhStepTo<3) // uhin ,2 -> stop
goto end;
if (uhstate.state== UHSTAT_DEV)
uhInitEnum();
if (uhStepTo<100) // uhin ,99 -> stop
goto end;
if (uhstate.state== UHSTAT_ENUM)
mscInit();
end:
VERBOSE2 printf("uhInit status= %d %s\n", uhstate.state, uhStatAsc());
}
// seems to be ok (?)
// same70: PLL=600 HCLK=300 MCK=150MHz
// sam3x: PLL=168 HCLK= 84 MCK= 84
// UPLLCK = 480 MHz
#define USBDIV (10-1) // UPLLCK / 10 --> 48 MHz
void
usbclkInit(int on)
{
(void)on;
volatile Pmc *pmc= PMC;
PMC->CKGR_UCKR= CKGR_UCKR_UPLLCOUNT(0x3Fu) | CKGR_UCKR_UPLLEN;
while ( !(PMC->PMC_SR & PMC_SR_LOCKU) );
pmc->PMC_USB= PMC_USB_USBDIV(USBDIV)|PMC_USB_USBS; // UPLLCK /10
// pmc->PMC_SCER= PMC_SCER_USBCLK; // enable usb clock
pmc->PMC_SCER= PMC_SCER_UOTGCLK; // enable usb clock NYI ???
}
void
uhInitPeriph()
{ volatile Uotghs *usb= UOTGHS;
u64 t0;
VERBOSE2 printf("uhInitPeriph\n");
#define UOTGVBOF (1<<10)
PIOB->PIO_PER= UOTGVBOF;
PIOB->PIO_OER= UOTGVBOF;
PIOB->PIO_SODR= UOTGVBOF; // ext-power-> usb-power
usb->UOTGHS_CTRL = // host mode, unfreeze
UOTGHS_CTRL_USBE| // enable usb
UOTGHS_CTRL_VBUSHWC;
//NYI perClockEnable(ID_UOTGHS, 1);
usbclkInit(1);
//NYI NVIC_SetPriority((IRQn_Type) ID_UOTGHS, 5);
//NYI NVIC_EnableIRQ((IRQn_Type) ID_UOTGHS);
gpf_isr= uhInterrupt;
usb->UOTGHS_CTRL = // host mode, unfreeze
UOTGHS_CTRL_USBE| // enable usb
UOTGHS_CTRL_VBUSHWC;
usb->UOTGHS_HSTCTRL= 0;
for (t0=millis()+1000; t0>millis();){
uhSwitch();
if (usb->UOTGHS_SR& UOTGHS_SR_CLKUSABLE)
goto uhp1;
}
VERBOSE0 printf("uhInitPerph failed (clk usable)\n");
return;
uhp1:
usb->UOTGHS_HSTICR= 0x7F; // clear all it
usb->UOTGHS_SFR = UOTGHS_SFR_VBUSRQS; // enable vbus (must)
usb->UOTGHS_HSTIER=
UOTGHS_HSTIER_DCONNIES|
UOTGHS_HSTIER_DDISCIES|
0; // UOTGHS_HSTIER_HSOFIES; // remove SOF ???
}
#define XX 1 // normal delay timing
// atmel reset proc step3:
int
uhInitResetUsb(int n, int inix) // reset usb
{ volatile Uotghs *usb= UOTGHS;
u64 t0; int ret=0;
u32 hstier= usb->UOTGHS_HSTIMR;
uhInitPeriph();
UHLOG("reset usb");
usb->UOTGHS_HSTIDR= 0xFFFFFFFF;
usb->UOTGHS_HSTCTRL= 0;
usb->UOTGHS_HSTCTRL= UOTGHS_HSTCTRL_RESET; // reset usb
for (t0=millis(); millis()<t0+ 5000;){ // 500 !!!
uhSwitch();
if (usb->UOTGHS_HSTISR& UOTGHS_HSTISR_RSTI)
goto uhp2;
}
VERBOSE1 printf("uhInitReset failed (reset %d)\n", n);
ret= UHERROR_NOTREADY;
uhp2:
VERBOSE2 printf("reset in %d ms\n", (int)(millis()-t0));
uhWaitMs(30*XX);
usb->UOTGHS_HSTCTRL= 0;
usb->UOTGHS_HSTICR= UOTGHS_HSTICR_RSTIC;
usb->UOTGHS_HSTCTRL= UOTGHS_HSTCTRL_SOFE; // sof enable, needed!
uhWaitMs(20*XX);
if (inix==0)
goto ier;
uhWaitMs(100*XX);
usb->UOTGHS_HSTCTRL= UOTGHS_HSTCTRL_SOFE; // sof enable, needed!
uhWaitMs(3*XX);
uhInitPipe(UHPIPE_CTRL, -1);
uhWaitMs(10*XX);
ier:
usb->UOTGHS_HSTICR= 0x7F; // clear all ints
usb->UOTGHS_HSTIER= hstier; // restore hst int mask
return ret;
}
int
uhInitEnum() // uhin
{ volatile Uotghs *usb= UOTGHS;
int i, redocnt=0, lng=100;
usb_request ur;
usb_devdescr udev;
usb_confdescr uconf;
u8 confno;
VERBOSE2 printf("uhInitEnum\n");
switch (uhStepFrom){
case 5: goto step5; // uhin 5
case 6: goto step6;
case 7: goto step7;
case 13: goto step13;
}
uhWaitMs(50*XX); // essentiel needs this
if ((i=uhInitResetUsb(1, 0))<0) // reset usb
return i;
if ((i=uhInitResetUsb(2, 1))<0) // reset usb
return i;
usb->UOTGHS_HSTADDR1= (0<<16)|(0<<8)|(0<<0);
if (uhStepTo<= 5) return 0; // uhin ,5
step5:
VERBOSE2 printf("Step5 get dev descr\n"); // step5 get devdescr
VERBOSE3 uhDumpx(-1, "", 1);
UHLOG("step5 get dev descr");
urFill( USB_REQ_RECIP_DEVICE|USB_REQ_TYPE_STANDARD|USB_REQ_DIR_IN,
USB_REQ_GET_DESCRIPTOR,
USB_DT_DEVICE<<8,
0,
8);
if ((i=uhSendPipe(UHPIPE_CTRL, (u8 *)&ur, USBREQUESTLNG))<0) // step5
return i;
if (uhStepTo<= 6) return 0; // uhin ,6
step6:
if ((i=uhReceivePipe(UHPIPE_CTRL, (u8 *)&udev, sizeof(udev)))<0)
return i;
if (uhStepTo<= 7) return 0; // uhin ,7
uhWaitMs(20*XX);
step7:
if ((i=uhInitResetUsb(3, 1))<0) // reset usb step7
return i;
VERBOSE2 printf("Step9 set addr\n"); // step9 set address
UHLOG("step9 set addr");
urFill( USB_REQ_RECIP_DEVICE|USB_REQ_TYPE_STANDARD|USB_REQ_DIR_OUT,
USB_REQ_SET_ADDRESS, // set address
1, // new address
0,
0);
if ((i=uhSendPipe(UHPIPE_CTRL, (u8 *)&ur, USBREQUESTLNG))<0)
return i;
if ((i=uhReceivePipe(UHPIPE_CTRL, 0, 0))<0)
return i;
uhWaitMs(20*XX);
VERBOSE2 printf("Step11 get dev descr\n"); // step11 new ad, get dev descr
UHLOG("step11 get dev descr");
usb->UOTGHS_HSTADDR1= (1<<16)|(1<<8)|(1<<0);
urFill( USB_REQ_RECIP_DEVICE|USB_REQ_TYPE_STANDARD|USB_REQ_DIR_IN,
USB_REQ_GET_DESCRIPTOR, // get descriptor
USB_DT_DEVICE<<8,
0,
sizeof(usb_devdescr));
if ((i=uhSendPipe(UHPIPE_CTRL, (u8 *)&ur, USBREQUESTLNG))<0)
return i;
if ((i=uhReceivePipe(UHPIPE_CTRL, (u8 *)&udev, sizeof(udev)))<0)
return i;
uhEnumSaveDescr((u8 *) &udev);
VERBOSE2 uhEnumPrintDescr((u8 *) &udev, 0);
VERBOSE2 printf("Step12 get conf descr\n"); // step12 get config descr
UHLOG("step12 get conf descr");
urFill( USB_REQ_RECIP_DEVICE|USB_REQ_TYPE_STANDARD|USB_REQ_DIR_IN,
USB_REQ_GET_DESCRIPTOR, // get descriptor
USB_DT_CONFIGURATION<<8,
0,
CONFDESCRLNG);
if ((i=uhSendPipe(UHPIPE_CTRL, (u8 *)&ur, USBREQUESTLNG))<0)