forked from RfidResearchGroup/proxmark3
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathusb_cdc.c
1264 lines (1083 loc) · 44.9 KB
/
usb_cdc.c
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
//-----------------------------------------------------------------------------
// Copyright (C) Proxmark3 contributors. See AUTHORS.md for details.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// See LICENSE.txt for the text of the license.
//-----------------------------------------------------------------------------
// at91sam7s USB CDC device implementation
// based on the "Basic USB Example" from ATMEL (doc6123.pdf)
//-----------------------------------------------------------------------------
#include "usb_cdc.h"
#include "proxmark3_arm.h"
#include "usart_defs.h"
/*
AT91SAM7S256 USB Device Port
• Embedded 328-byte dual-port RAM for endpoints
• Four endpoints
– Endpoint 0: 8 bytes
– Endpoint 1 and 2: 64 bytes ping-pong
– Endpoint 3: 64 bytes
– Ping-pong Mode (two memory banks) for bulk endpoints
*/
//
#define AT91C_EP_CONTROL 0
#define AT91C_EP_OUT 1 // cfg bulk out
#define AT91C_EP_IN 2 // cfg bulk in
#define AT91C_EP_NOTIFY 3 // cfg cdc notification interrup
// The endpoint size is defined in usb_cdc.h
// Section: USB Descriptors
#define USB_DESCRIPTOR_DEVICE 0x01 // DescriptorType for a Device Descriptor.
#define USB_DESCRIPTOR_CONFIGURATION 0x02 // DescriptorType for a Configuration Descriptor.
#define USB_DESCRIPTOR_STRING 0x03 // DescriptorType for a String Descriptor.
#define USB_DESCRIPTOR_INTERFACE 0x04 // DescriptorType for an Interface Descriptor.
#define USB_DESCRIPTOR_ENDPOINT 0x05 // DescriptorType for an Endpoint Descriptor.
#define USB_DESCRIPTOR_DEVICE_QUALIFIER 0x06 // DescriptorType for a Device Qualifier.
#define USB_DESCRIPTOR_OTHER_SPEED 0x07 // DescriptorType for a Other Speed Configuration.
#define USB_DESCRIPTOR_INTERFACE_POWER 0x08 // DescriptorType for Interface Power.
#define USB_DESCRIPTOR_OTG 0x09 // DescriptorType for an OTG Descriptor.
#define USB_DESCRIPTOR_IAD 0x0B // DescriptorType for a Interface Association Descriptor
#define USB_DESCRIPTOR_TYPE_BO 0x0F // DescriptorType for a BOS Descriptor.
/* Configuration Attributes */
#define _DEFAULT (0x01<<7) //Default Value (Bit 7 is set)
#define _SELF (0x01<<6) //Self-powered (Supports if set)
#define _RWU (0x01<<5) //Remote Wakeup (Supports if set)
#define _HNP (0x01 << 1) //HNP (Supports if set)
#define _SRP (0x01) //SRP (Supports if set)
/* Endpoint Transfer Type */
#define _CTRL 0x00 //Control Transfer
#define _ISO 0x01 //Isochronous Transfer
#define _BULK 0x02 //Bulk Transfer
#define _INTERRUPT 0x03 //Interrupt Transfer
// (bit7 | 0 = OUT, 1 = IN)
#define _EP_IN 0x80
#define _EP_OUT 0x00
#define _EP01_OUT 0x01
#define _EP01_IN 0x81
#define _EP02_OUT 0x02
#define _EP02_IN 0x82
#define _EP03_OUT 0x03
#define _EP03_IN 0x83
/* WCID specific Request Code */
#define MS_OS_DESCRIPTOR_INDEX 0xEE
#define MS_VENDOR_CODE 0x1C
#define MS_EXTENDED_COMPAT_ID 0x04
#define MS_EXTENDED_PROPERTIES 0x05
#define MS_WCID_GET_DESCRIPTOR 0xC0
#define MS_WCID_GET_FEATURE_DESCRIPTOR 0xC1
/* USB standard request code */
#define STD_GET_STATUS_ZERO 0x0080
#define STD_GET_STATUS_INTERFACE 0x0081
#define STD_GET_STATUS_ENDPOINT 0x0082
#define STD_CLEAR_FEATURE_ZERO 0x0100
#define STD_CLEAR_FEATURE_INTERFACE 0x0101
#define STD_CLEAR_FEATURE_ENDPOINT 0x0102
#define STD_SET_FEATURE_ZERO 0x0300
#define STD_SET_FEATURE_INTERFACE 0x0301
#define STD_SET_FEATURE_ENDPOINT 0x0302
#define STD_SET_ADDRESS 0x0500
#define STD_GET_DESCRIPTOR 0x0680
#define STD_SET_DESCRIPTOR 0x0700
#define STD_GET_CONFIGURATION 0x0880
#define STD_SET_CONFIGURATION 0x0900
#define STD_GET_INTERFACE 0x0A81
#define STD_SET_INTERFACE 0x0B01
#define STD_SYNCH_FRAME 0x0C82
/* CDC Class Specific Request Code */
#define GET_LINE_CODING 0x21A1
#define SET_LINE_CODING 0x2021
#define SET_CONTROL_LINE_STATE 0x2221
static bool isAsyncRequestFinished = false;
static AT91PS_UDP pUdp = AT91C_BASE_UDP;
static uint8_t btConfiguration = 0;
static uint8_t btConnection = 0;
static uint8_t btReceiveBank = AT91C_UDP_RX_DATA_BK0;
static const char devDescriptor[] = {
/* Device descriptor */
0x12, // Length
USB_DESCRIPTOR_DEVICE, // Descriptor Type (DEVICE)
0x00, 0x02, // Complies with USB Spec. Release (0200h = release 2.00) 0210 == release 2.10
2, // Device Class: Communication Device Class
0, // Device Subclass: CDC class sub code ACM [ice 0x02 = win10 virtual comport ]
0, // Device Protocol: CDC Device protocol (unused)
AT91C_USB_EP_CONTROL_SIZE, // MaxPacketSize0
0xc4, 0x9a, // Vendor ID [0x9ac4 = J. Westhues]
0x8f, 0x4b, // Product ID [0x4b8f = Proxmark-3 RFID Instrument]
0x00, 0x01, // BCD Device release number (1.00)
1, // index Manufacturer
2, // index Product
3, // index SerialNumber
1 // Number of Configs
};
static const char cfgDescriptor[] = {
/* Configuration 1 descriptor */
// -----------------------------
9, // Length
USB_DESCRIPTOR_CONFIGURATION, // Descriptor Type
(9 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 7), 0, // Total Length 2 EP + Control
2, // Number of Interfaces
1, // Index value of this Configuration (used in SetConfiguration from Host)
0, // Configuration string index
_DEFAULT, // Attributes 0xA0
0xFA, // Max Power consumption
// IAD to associate the one CDC interface
// --------------------------------------
/*
8, // Length
USB_DESCRIPTOR_IAD, // IAD_DESCRIPTOR (0x0B)
0, // CDC_INT_INTERFACE NUMBER (
2, // IAD INTERFACE COUNT (two interfaces)
2, // Function Class: CDC_CLASS
2, // Function SubClass: ACM
1, // Function Protocol: v.25term
0, // iInterface
*/
/* Interface 0 Descriptor */
/* CDC Communication Class Interface Descriptor Requirement for Notification*/
// -----------------------------------------------------------
9, // Length
USB_DESCRIPTOR_INTERFACE, // Descriptor Type
0, // Interface Number
0, // Alternate Setting
1, // Number of Endpoints in this interface
2, // Interface Class code (Communication Interface Class)
2, // Interface Subclass code (Abstract Control Model)
1, // InterfaceProtocol (Common AT Commands, V.25term)
0, // iInterface
/* Header Functional Descriptor */
5, // Function Length
0x24, // Descriptor type: CS_INTERFACE
0, // Descriptor subtype: Header Functional Descriptor
0x10, 0x01, // bcd CDC:1.1
/* ACM Functional Descriptor */
4, // Function Length
0x24, // Descriptor Type: CS_INTERFACE
2, // Descriptor Subtype: Abstract Control Management Functional Descriptor
2, // Capabilities D1, Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
/* Union Functional Descriptor */
5, // Function Length
0x24, // Descriptor Type: CS_INTERFACE
6, // Descriptor Subtype: Union Functional Descriptor
0, // MasterInterface: Communication Class Interface
1, // SlaveInterface0: Data Class Interface
/* Call Management Functional Descriptor */
5, // Function Length
0x24, // Descriptor Type: CS_INTERFACE
1, // Descriptor Subtype: Call Management Functional Descriptor
0, // Capabilities: Device sends/receives call management information only over the Communication Class interface. Device does not handle call management itself
1, // Data Interface: Data Class Interface
/* Protocol Functional Descriptor */
/*
6,
0x24, // Descriptor Type: CS_INTERFACE
0x0B, // Descriptor Subtype: Protocol Unit functional Descriptor
0xDD, // constant uniq ID of unit
0xFE, // protocol
*/
/* CDC Notification Endpoint descriptor */
// ---------------------------------------
7, // Length
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP03_IN, // EndpointAddress: Endpoint 03 - IN
_INTERRUPT, // Attributes
AT91C_USB_EP_CONTROL_SIZE, 0x00, // MaxPacket Size: EP0 - 8
0xFF, // Interval polling
/* Interface 1 Descriptor */
/* CDC Data Class Interface 1 Descriptor Requirement */
9, // Length
USB_DESCRIPTOR_INTERFACE, // Descriptor Type
1, // Interface Number
0, // Alternate Setting
2, // Number of Endpoints
0x0A, // Interface Class: CDC Data interface class
0, // Interface Subclass: not used
0, // Interface Protocol: No class specific protocol required (usb spec)
0, // Interface
/* Endpoint descriptor */
7, // Length
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP01_OUT, // Endpoint Address: Endpoint 01 - OUT
_BULK, // Attributes: BULK
AT91C_USB_EP_OUT_SIZE, 0x00, // MaxPacket Size: 64 bytes
0, // Interval: ignored for bulk
/* Endpoint descriptor */
7, // Length
USB_DESCRIPTOR_ENDPOINT, // Descriptor Type
_EP02_IN, // Endpoint Address: Endpoint 02 - IN
_BULK, // Attribute: BULK
AT91C_USB_EP_IN_SIZE, 0x00, // MaxPacket Size: 64 bytes
0 // Interval: ignored for bulk
};
// BOS descriptor
static const char bosDescriptor[] = {
0x5,
USB_DESCRIPTOR_TYPE_BO,
0xC,
0x0,
0x1, // 1 device capability
0x7,
0x10, // USB_DEVICE_CAPABITY_TYPE,
0x2,
0x2, // LPM capability bit set
0x0,
0x0,
0x0
};
// Microsoft OS Extended Configuration Compatible ID Descriptor
/*
static const char CompatIDFeatureDescriptor[] = {
0x28, 0x00, 0x00, 0x00, // Descriptor Length 40bytes (0x28)
0x00, 0x01, // Version ('1.0')
MS_EXTENDED_COMPAT_ID, 0x00, // Compatibility ID Descriptor Index 0x0004
0x01, // Number of sections. 0x1
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved (7bytes)
// -----function section 1------
0x00, // Interface Number #0
0x01, // reserved (0x1)
0x57, 0x49, 0x4E, 0x55, 0x53, 0x42, 0x00, 0x00, // Compatible ID ('WINUSB\0\0') (8bytes)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Sub-Compatible ID (8byte)
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved (6bytes)
};
*/
// Microsoft Extended Properties Feature Descriptor
/*
static const char OSprop[] = {
// u32 Descriptor Length (10+132+64+102 == 308
0x34, 0x01, 0, 0,
// u16 Version ('1.0')
0, 1,
// u16 wIndex
MS_EXTENDED_PROPERTIES, 0,
// u16 wCount -- three section
3, 0,
// -----property section 1------
// u32 size ( 14+40+78 == 132)
132, 0, 0, 0,
// u32 type
1, 0, 0, 0, // unicode string
// u16 namelen (20*2 = 40)
40, 0,
// name DeviceInterfaceGUID
'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0,'t',0,'e',0,'r',0,'f',0,'a',0,'c',0,'e',0,'G',0,'U',0,'I',0,'D',0,0,0,
// u32 datalen (39*2 = 78)
78, 0, 0, 0,
// data {4D36E978-E325-11CE-BFC1-08002BE10318}
'{',0,'4',0,'d',0,'3',0,'6',0,'e',0,'9',0,'7',0,'8',0,'-',0,'e',0,'3',0,'2',0,'5',0,
'-',0,'1',0,'1',0,'c',0,'e',0,'-',0,'b',0,'f',0,'c',0,'1',0,'-',0,'0',0,'8',0,'0',0,
'0',0,'2',0,'b',0,'e',0,'1',0,'0',0,'3',0,'1',0,'8',0,'}',0,0,0,
// -----property section 2------
// u32 size ( 14+12+38 == 64)
64, 0, 0, 0,
// u32 type
1, 0, 0, 0, // unicode string
// u16 namelen (12)
12, 0,
// name Label
'L',0,'a',0,'b',0,'e',0,'l',0,0,0,
// u32 datalen ( 19*2 = 38 )
38, 0, 0, 0,
// data 'Awesome PM3 Device'
'A',0,'w',0,'e',0,'s',0,'o',0,'m',0,'e',0,' ',0,'P',0,'M',0,'3',0,' ',0,'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,0,0,
// -----property section 3------
// u32 size ( 14+12+76 == 102)
102, 0, 0, 0,
// u32 type
2, 0, 0, 0, //Unicode string with environment variables
// u16 namelen (12)
12, 0,
// name Icons
'I',0,'c',0,'o',0,'n',0,'s',0,0,0,
// u32 datalen ( 38*2 == 76)
76, 0, 0, 0,
// data '%SystemRoot%\\system32\\Shell32.dll,-13'
'%',0,'S',0,'y',0,'s',0,'t',0,'e',0,'m',0,'R',0,'o',0,'o',0,'t',0,'%',0,
'\\',0,'s',0,'y',0,'s',0,'t',0,'e',0,'m',0,'3',0,'2',0,'\\',0,
'S',0,'h',0,'e',0,'l',0,'l',0,'3',0,'2',0,'.',0,'d',0,'l',0,'l',0,',',0,
'-',0,'1',0,'3',0,0,0
};
*/
static const char StrLanguageCodes[] = {
4, // Length
0x03, // Type is string
0x09, 0x04 // supported language Code 0 = 0x0409 (English)
};
// Note: ModemManager (Linux) ignores Proxmark3 devices by matching the
// manufacturer string "proxmark.org". Don't change this.
// or use the blacklisting file.
static const char StrManufacturer[] = {
26, // Length
0x03, // Type is string
'p', 0, 'r', 0, 'o', 0, 'x', 0, 'm', 0, 'a', 0, 'r', 0, 'k', 0, '.', 0, 'o', 0, 'r', 0, 'g', 0,
};
static const char StrProduct[] = {
20, // Length
0x03, // Type is string
'p', 0, 'r', 0, 'o', 0, 'x', 0, 'm', 0, 'a', 0, 'r', 0, 'k', 0, '3', 0
};
#ifndef WITH_FLASH
static const char StrSerialNumber[] = {
14, // Length
0x03, // Type is string
'i', 0, 'c', 0, 'e', 0, 'm', 0, 'a', 0, 'n', 0
};
#else // WITH_FLASH is defined
// Manually calculated size of descriptor with unique ID:
// offset 0, lengt h 1: total length field
// offset 1, length 1: descriptor type field
// offset 2, length 12: 6x unicode chars (original string)
// offset 14, length 4: 2x unicode chars (underscores) [[ to avoid descriptor being (size % 8) == 0, OS bug workaround ]]
// offset 18, length 32: 16x unicode chars (8-byte serial as hex characters)
// ============================
// total: 50 bytes
#define USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH 50
char StrSerialNumber[] = {
14, // Length is initially identical to non-unique version ... The length updated at boot, if unique serial is available
0x03, // Type is string
'i', 0, 'c', 0, 'e', 0, 'm', 0, 'a', 0, 'n', 0,
'_', 0, '_', 0,
'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0,
'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0, 'x', 0,
};
void usb_update_serial(uint64_t newSerialNumber) {
static bool configured = false; // TODO: enable by setting to false here...
if (configured) {
return;
}
// run this only once per boot... even if it fails to find serial number
configured = true;
// reject serial number if all-zero or all-ones
if ((newSerialNumber == 0x0000000000000000) || (newSerialNumber == 0xFFFFFFFFFFFFFFFF)) {
return;
}
// Descriptor is, effectively, initially identical to non-unique serial
// number because it reports the shorter length in the first byte.
// Convert uniqueID's eight bytes to 16 unicode characters in the
// descriptor and, finally, update the descriptor's length, which
// causes the serial number to become visible.
for (uint8_t i = 0; i < 8; i++) {
// order of nibbles chosen to match display order from `hw status`
uint8_t nibble1 = (newSerialNumber >> ((8 * i) + 4)) & 0xFu; // bitmasks [0xF0, 0xF000, 0xF00000, ... 0xF000000000000000]
uint8_t nibble2 = (newSerialNumber >> ((8 * i) + 0)) & 0xFu; // bitmasks [0x0F, 0x0F00, 0x0F0000, ... 0x0F00000000000000]
char c1 = nibble1 < 10 ? '0' + nibble1 : 'A' + (nibble1 - 10);
char c2 = nibble2 < 10 ? '0' + nibble2 : 'A' + (nibble2 - 10);
StrSerialNumber[18 + (4 * i) + 0] = c1; // [ 18, 22, .., 42, 46 ]
StrSerialNumber[18 + (4 * i) + 2] = c2; // [ 20, 24, .., 44, 48 ]
}
StrSerialNumber[0] = USB_STRING_DESCRIPTOR_SERIAL_NUMBER_LENGTH;
}
#endif
// size includes their own field.
static const char StrMS_OSDescriptor[] = {
18, // length 0x12
0x03, // Type is string
'M', 0, 'S', 0, 'F', 0, 'T', 0, '1', 0, '0', 0, '0', 0, MS_VENDOR_CODE, 0
};
static const char *getStringDescriptor(uint8_t idx) {
switch (idx) {
case 0:
return StrLanguageCodes;
case 1:
return StrManufacturer;
case 2:
return StrProduct;
case 3:
return StrSerialNumber;
case MS_OS_DESCRIPTOR_INDEX:
return StrMS_OSDescriptor;
default:
return (NULL);
}
}
// Bitmap for all status bits in CSR which must be written as 1 to cause no effect
#define REG_NO_EFFECT_1_ALL AT91C_UDP_RX_DATA_BK0 | AT91C_UDP_RX_DATA_BK1 \
|AT91C_UDP_STALLSENT | AT91C_UDP_RXSETUP \
|AT91C_UDP_TXCOMP
// Clear flags in the UDP_CSR register and waits for synchronization
#define UDP_CLEAR_EP_FLAGS(endpoint, flags) { \
volatile unsigned int reg; \
reg = pUdp->UDP_CSR[(endpoint)]; \
reg |= REG_NO_EFFECT_1_ALL; \
reg &= ~(flags); \
pUdp->UDP_CSR[(endpoint)] = reg; \
}
// reset flags in the UDP_CSR register and waits for synchronization
#define UDP_SET_EP_FLAGS(endpoint, flags) { \
volatile unsigned int reg; \
reg = pUdp->UDP_CSR[(endpoint)]; \
reg |= REG_NO_EFFECT_1_ALL; \
reg |= (flags); \
pUdp->UDP_CSR[(endpoint)] = reg; \
}
typedef struct {
uint32_t BitRate;
uint8_t Format;
uint8_t ParityType;
uint8_t DataBits;
} AT91S_CDC_LINE_CODING, *AT91PS_CDC_LINE_CODING;
static AT91S_CDC_LINE_CODING line = { // purely informative, actual values don't matter
USART_BAUD_RATE, // baudrate
0, // 1 Stop Bit
0, // None Parity
8 // 8 Data bits
};
// timer counts in 21.3us increments (1024/48MHz), rounding applies
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
static void SpinDelayUs(int us) {
int ticks = ((MCK / 1000000) * us + 512) >> 10;
// Borrow a PWM unit for my real-time clock
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
// 48 MHz / 1024 gives 46.875 kHz
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(10); // Channel Mode Register
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xffff; // Channel Period Register
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
for (;;) {
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
if (now == (uint16_t)(start + ticks))
return;
WDT_HIT();
}
}
/*
*----------------------------------------------------------------------------
* \fn usb_disable
* \brief This function deactivates the USB device
*----------------------------------------------------------------------------
*/
void usb_disable(void) {
// Disconnect the USB device
AT91C_BASE_PIOA->PIO_ODR = GPIO_USB_PU;
// Clear all lingering interrupts
if (pUdp->UDP_ISR & AT91C_UDP_ENDBUSRES) {
pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;
}
}
/*
*----------------------------------------------------------------------------
* \fn usb_enable
* \brief This function Activates the USB device
*----------------------------------------------------------------------------
*/
void usb_enable(void) {
// Set the PLL USB Divider
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// Specific Chip USB Initialisation
// Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
AT91C_BASE_PMC->PMC_SCER |= AT91C_PMC_UDP;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
AT91C_BASE_UDP->UDP_FADDR = 0;
AT91C_BASE_UDP->UDP_GLBSTATE = 0;
// Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
// Set in PIO mode and Configure in Output
AT91C_BASE_PIOA->PIO_PER = GPIO_USB_PU; // Set in PIO mode
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU; // Configure as Output
// Clear for set the Pullup resistor
AT91C_BASE_PIOA->PIO_CODR = GPIO_USB_PU;
// Disconnect and reconnect USB controller for 100ms
usb_disable();
SpinDelayUs(100 * 1000);
// Wait for a short while
//for (volatile size_t i=0; i<0x100000; i++) {};
// Reconnect USB reconnect
AT91C_BASE_PIOA->PIO_SODR = GPIO_USB_PU;
AT91C_BASE_PIOA->PIO_OER = GPIO_USB_PU;
}
/*
*----------------------------------------------------------------------------
* \fn usb_check
* \brief Test if the device is configured and handle enumeration
*----------------------------------------------------------------------------
*/
static int usb_reconnect = 0;
static int usb_configured = 0;
void SetUSBreconnect(int value) {
usb_reconnect = value;
}
int GetUSBreconnect(void) {
return usb_reconnect;
}
void SetUSBconfigured(int value) {
usb_configured = value;
}
int GetUSBconfigured(void) {
return usb_configured;
}
bool usb_check(void) {
/*
// reconnected ONCE and
if ( !USB_ATTACHED() ){
usb_reconnect = 1;
return false;
}
// only one time after USB been disengaged and re-engaged
if ( USB_ATTACHED() && usb_reconnect == 1 ) {
if ( usb_configured == 0) {
usb_disable();
usb_enable();
AT91F_CDC_Enumerate();
usb_configured = 1;
return false;
}
}
*/
// interrupt status register
AT91_REG isr = pUdp->UDP_ISR;
// end of bus reset
if (isr & AT91C_UDP_ENDBUSRES) {
pUdp->UDP_ICR = AT91C_UDP_ENDBUSRES;
// reset all endpoints
pUdp->UDP_RSTEP = (unsigned int) - 1;
pUdp->UDP_RSTEP = 0;
// Enable the function
pUdp->UDP_FADDR = AT91C_UDP_FEN;
// Configure endpoint 0 (enable control endpoint)
pUdp->UDP_CSR[AT91C_EP_CONTROL] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
} else if (isr & AT91C_UDP_EPINT0) {
pUdp->UDP_ICR = AT91C_UDP_EPINT0;
AT91F_CDC_Enumerate();
}
/*
else if (isr & AT91C_UDP_EPINT3 ) {
pUdp->UDP_ICR = AT91C_UDP_EPINT3;
AT91F_CDC_Enumerate();
//pUdp->UDP_ICR |= AT91C_UDP_EPINT3;
}
*/
return (btConfiguration) ? true : false;
}
bool usb_poll(void) {
if (usb_check() == false) {
return false;
}
return (pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank);
}
inline uint16_t usb_available_length(void) {
return (((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) & 0x7FF);
}
/**
In github PR #129, some users appears to get a false positive from
usb_poll, which returns true, but the usb_read operation
still returns 0.
This check is basically the same as above, but also checks
that the length available to read is non-zero, thus hopefully fixes the
bug.
**/
bool usb_poll_validate_length(void) {
if (usb_check() == false) {
return false;
}
if (!(pUdp->UDP_CSR[AT91C_EP_OUT] & btReceiveBank)) {
return false;
}
return (((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) > 0);
}
/*
*----------------------------------------------------------------------------
* \fn usb_read
* \brief Read available data from Endpoint 1 OUT (host to device)
*----------------------------------------------------------------------------
*/
uint32_t usb_read(uint8_t *data, size_t len) {
if (len == 0) {
return 0;
}
uint8_t bank = btReceiveBank;
uint16_t packetSize, nbBytesRcv = 0;
uint16_t time_out = 0;
while (len) {
if (usb_check() == false) {
break;
}
if (pUdp->UDP_CSR[AT91C_EP_OUT] & bank) {
packetSize = (((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) & 0x7FF);
packetSize = MIN(packetSize, len);
len -= packetSize;
while (packetSize--) {
data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];
}
// flip bank
UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank)
if (bank == AT91C_UDP_RX_DATA_BK0) {
bank = AT91C_UDP_RX_DATA_BK1;
} else {
bank = AT91C_UDP_RX_DATA_BK0;
}
}
if (time_out++ == 0x1FFF) {
break;
}
}
btReceiveBank = bank;
return nbBytesRcv;
}
static uint8_t usb_read_ng_buffer[64] = {0};
static uint8_t usb_read_ng_bufoffset = 0;
static uint8_t usb_read_ng_buflen = 0;
uint32_t usb_read_ng(uint8_t *data, size_t len) {
if (len == 0) {
return 0;
}
uint8_t bank = btReceiveBank;
uint16_t packetSize, nbBytesRcv = 0;
uint16_t time_out = 0;
// take first from local buffer
if (len <= usb_read_ng_buflen) {
// if local buffer has all data
for (uint8_t i = 0; i < len; i++) {
data[nbBytesRcv++] = usb_read_ng_buffer[usb_read_ng_bufoffset + i];
}
usb_read_ng_buflen -= len;
if (usb_read_ng_buflen == 0) {
usb_read_ng_bufoffset = 0;
} else {
usb_read_ng_bufoffset += len;
}
return nbBytesRcv;
} else {
// take all data from local buffer, then read from usb
for (uint8_t i = 0; i < usb_read_ng_buflen; i++) {
data[nbBytesRcv++] = usb_read_ng_buffer[usb_read_ng_bufoffset + i];
}
len -= usb_read_ng_buflen;
usb_read_ng_buflen = 0;
usb_read_ng_bufoffset = 0;
}
while (len) {
if (usb_check() == false) {
break;
}
if ((pUdp->UDP_CSR[AT91C_EP_OUT] & bank)) {
uint16_t available = (((pUdp->UDP_CSR[AT91C_EP_OUT] & AT91C_UDP_RXBYTECNT) >> 16) & 0x7FF);
packetSize = MIN(available, len);
available -= packetSize;
len -= packetSize;
while (packetSize--) {
data[nbBytesRcv++] = pUdp->UDP_FDR[AT91C_EP_OUT];
}
// fill the local buffer with the remaining bytes
for (uint16_t i = 0; i < available; i++) {
usb_read_ng_buffer[i] = pUdp->UDP_FDR[AT91C_EP_OUT];
}
// update number of available bytes in local bytes
usb_read_ng_buflen = available;
// flip bank
UDP_CLEAR_EP_FLAGS(AT91C_EP_OUT, bank)
if (bank == AT91C_UDP_RX_DATA_BK0) {
bank = AT91C_UDP_RX_DATA_BK1;
} else {
bank = AT91C_UDP_RX_DATA_BK0;
}
}
if (time_out++ == 0x1FFF) {
break;
}
}
btReceiveBank = bank;
return nbBytesRcv;
}
/*
*----------------------------------------------------------------------------
* \fn usb_write
* \brief Send through endpoint 2 (device to host)
*----------------------------------------------------------------------------
*/
int usb_write(const uint8_t *data, const size_t len) {
if (len == 0) {
return PM3_EINVARG;
}
if (usb_check() == false) {
return PM3_EIO;
}
// can we write?
if ((pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) != 0) {
return PM3_EIO;
}
size_t length = len;
uint32_t cpt = 0;
// send first chunk
cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt;
while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
}
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) {};
while (length) {
// Send next chunk
cpt = MIN(length, AT91C_USB_EP_IN_SIZE);
length -= cpt;
while (cpt--) {
pUdp->UDP_FDR[AT91C_EP_IN] = *data++;
}
// Wait for previous chunk to be sent
// (iceman) when is the bankswapping done?
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
if (usb_check() == false) {
return PM3_EIO;
}
}
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) {};
}
// Wait for the end of transfer
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
if (usb_check() == false) {
return PM3_EIO;
}
}
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
if (len % AT91C_USB_EP_IN_SIZE == 0) {
// like AT91F_USB_SendZlp(), in non ping-pong mode
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {};
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
}
return PM3_SUCCESS;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_start
* \brief Start async write process
* \return PM3_EIO if USB is invalid, PM3_SUCCESS if it is ready for write
*
* This function checks if the USB is connected, and wait until the FIFO
* is ready to be filled.
*
* Warning: usb_write() should not be called between
* async_usb_write_start() and async_usb_write_stop().
*----------------------------------------------------------------------------
*/
int async_usb_write_start(void) {
if (usb_check() == false) {
return PM3_EIO;
}
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
if (usb_check() == false) {
return PM3_EIO;
}
}
isAsyncRequestFinished = false;
return PM3_SUCCESS;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_pushByte
* \brief Push one byte to the FIFO of IN endpoint (time-critical)
*
* This function simply push a byte to the FIFO of IN endpoint.
* The FIFO size is AT91C_USB_EP_IN_SIZE. Make sure this function is not called
* over AT91C_USB_EP_IN_SIZE times between each async_usb_write_requestWrite().
*----------------------------------------------------------------------------
*/
inline void async_usb_write_pushByte(uint8_t data) {
pUdp->UDP_FDR[AT91C_EP_IN] = data;
isAsyncRequestFinished = false;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_requestWrite
* \brief Request a write operation (time-critical)
* \return false if the last write request is not finished, true if success
*
* This function requests a write operation from FIFO to the USB bus,
* and switch the internal banks of FIFO. It doesn't wait for the end of
* transmission from FIFO to the USB bus.
*
* Note: This function doesn't check if the usb is valid, as it is
* time-critical.
*----------------------------------------------------------------------------
*/
inline bool async_usb_write_requestWrite(void) {
// check if last request is finished
if (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
return false;
}
// clear transmission completed flag
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
// start of transmission
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
// hack: no need to wait if UDP_CSR and UDP_FDR are not used immediately.
// while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY)) {};
isAsyncRequestFinished = true;
return true;
}
/*
*----------------------------------------------------------------------------
* \fn async_usb_write_stop
* \brief Stop async write process
* \return PM3_EIO if USB is invalid, PM3_SUCCESS if data is written
*
* This function makes sure the data left in the FIFO is written to the
* USB bus.
*
* Warning: usb_write() should not be called between
* async_usb_write_start() and async_usb_write_stop().
*----------------------------------------------------------------------------
*/
int async_usb_write_stop(void) {
// Wait for the end of transfer
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXPKTRDY) {
if (usb_check() == false) {
return PM3_EIO;
}
}
// clear transmission completed flag
UDP_CLEAR_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXCOMP);
while (pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP) {};
// FIFO is not empty, request a write in non-ping-pong mode
if (isAsyncRequestFinished == false) {
UDP_SET_EP_FLAGS(AT91C_EP_IN, AT91C_UDP_TXPKTRDY);
while (!(pUdp->UDP_CSR[AT91C_EP_IN] & AT91C_UDP_TXCOMP)) {
if (usb_check() == false) {
return PM3_EIO;
}
}