Statistics
| Branch: | Revision:

root / arduino-1.0 / hardware / arduino / cores / arduino / USBCore.cpp @ 58d82c77

History | View | Annotate | Download (12.4 KB)

1

    
2

    
3
/* Copyright (c) 2010, Peter Barrett  
4
**  
5
** Permission to use, copy, modify, and/or distribute this software for  
6
** any purpose with or without fee is hereby granted, provided that the  
7
** above copyright notice and this permission notice appear in all copies.  
8
** 
9
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL  
10
** WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED  
11
** WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR  
12
** BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES  
13
** OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,  
14
** WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,  
15
** ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS  
16
** SOFTWARE.  
17
*/
18

    
19
#include "Platform.h"
20
#include "USBAPI.h"
21
#include "USBDesc.h"
22

    
23
#if defined(USBCON)
24

    
25
#define EP_TYPE_CONTROL                                0x00
26
#define EP_TYPE_BULK_IN                                0x81
27
#define EP_TYPE_BULK_OUT                        0x80
28
#define EP_TYPE_INTERRUPT_IN                0xC1
29
#define EP_TYPE_INTERRUPT_OUT                0xC0
30
#define EP_TYPE_ISOCHRONOUS_IN                0x41
31
#define EP_TYPE_ISOCHRONOUS_OUT                0x40
32

    
33
/** Pulse generation counters to keep track of the number of milliseconds remaining for each pulse type */
34
#define TX_RX_LED_PULSE_MS 100
35
volatile u8 TxLEDPulse; /**< Milliseconds remaining for data Tx LED pulse */
36
volatile u8 RxLEDPulse; /**< Milliseconds remaining for data Rx LED pulse */
37

    
38
//==================================================================
39
//==================================================================
40

    
41
extern const u16 STRING_LANGUAGE[] PROGMEM;
42
extern const u16 STRING_IPRODUCT[] PROGMEM;
43
extern const u16 STRING_IMANUFACTURER[] PROGMEM;
44
extern const DeviceDescriptor USB_DeviceDescriptor PROGMEM;
45
extern const DeviceDescriptor USB_DeviceDescriptorA PROGMEM;
46

    
47
const u16 STRING_LANGUAGE[2] = {
48
        (3<<8) | (2+2),
49
        0x0409        // English
50
};
51

    
52
const u16 STRING_IPRODUCT[17] = {
53
        (3<<8) | (2+2*16),
54
#if USB_PID == USB_PID_LEONARDO        
55
        'A','r','d','u','i','n','o',' ','L','e','o','n','a','r','d','o'
56
#elif USB_PID == USB_PID_MICRO
57
        'A','r','d','u','i','n','o',' ','M','i','c','r','o',' ',' ',' '
58
#endif
59
};
60

    
61
const u16 STRING_IMANUFACTURER[12] = {
62
        (3<<8) | (2+2*11),
63
        'A','r','d','u','i','n','o',' ','L','L','C'
64
};
65

    
66
#ifdef CDC_ENABLED
67
#define DEVICE_CLASS 0x02
68
#else
69
#define DEVICE_CLASS 0x00
70
#endif
71

    
72
//        DEVICE DESCRIPTOR
73
const DeviceDescriptor USB_DeviceDescriptor =
74
        D_DEVICE(0x00,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);
75

    
76
const DeviceDescriptor USB_DeviceDescriptorA =
77
        D_DEVICE(DEVICE_CLASS,0x00,0x00,64,USB_VID,USB_PID,0x100,IMANUFACTURER,IPRODUCT,0,1);
78

    
79
//==================================================================
80
//==================================================================
81

    
82
volatile u8 _usbConfiguration = 0;
83

    
84
static inline void WaitIN(void)
85
{
86
        while (!(UEINTX & (1<<TXINI)));
87
}
88

    
89
static inline void ClearIN(void)
90
{
91
        UEINTX = ~(1<<TXINI);
92
}
93

    
94
static inline void WaitOUT(void)
95
{
96
        while (!(UEINTX & (1<<RXOUTI)))
97
                ;
98
}
99

    
100
static inline u8 WaitForINOrOUT()
101
{
102
        while (!(UEINTX & ((1<<TXINI)|(1<<RXOUTI))))
103
                ;
104
        return (UEINTX & (1<<RXOUTI)) == 0;
105
}
106

    
107
static inline void ClearOUT(void)
108
{
109
        UEINTX = ~(1<<RXOUTI);
110
}
111

    
112
void Recv(volatile u8* data, u8 count)
113
{
114
        while (count--)
115
                *data++ = UEDATX;
116
        
117
        RXLED1;                                        // light the RX LED
118
        RxLEDPulse = TX_RX_LED_PULSE_MS;        
119
}
120

    
121
static inline u8 Recv8()
122
{
123
        RXLED1;                                        // light the RX LED
124
        RxLEDPulse = TX_RX_LED_PULSE_MS;
125

    
126
        return UEDATX;        
127
}
128

    
129
static inline void Send8(u8 d)
130
{
131
        UEDATX = d;
132
}
133

    
134
static inline void SetEP(u8 ep)
135
{
136
        UENUM = ep;
137
}
138

    
139
static inline u8 FifoByteCount()
140
{
141
        return UEBCLX;
142
}
143

    
144
static inline u8 ReceivedSetupInt()
145
{
146
        return UEINTX & (1<<RXSTPI);
147
}
148

    
149
static inline void ClearSetupInt()
150
{
151
        UEINTX = ~((1<<RXSTPI) | (1<<RXOUTI) | (1<<TXINI));
152
}
153

    
154
static inline void Stall()
155
{
156
        UECONX = (1<<STALLRQ) | (1<<EPEN);
157
}
158

    
159
static inline u8 ReadWriteAllowed()
160
{
161
        return UEINTX & (1<<RWAL);
162
}
163

    
164
static inline u8 Stalled()
165
{
166
        return UEINTX & (1<<STALLEDI);
167
}
168

    
169
static inline u8 FifoFree()
170
{
171
        return UEINTX & (1<<FIFOCON);
172
}
173

    
174
static inline void ReleaseRX()
175
{
176
        UEINTX = 0x6B;        // FIFOCON=0 NAKINI=1 RWAL=1 NAKOUTI=0 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=1
177
}
178

    
179
static inline void ReleaseTX()
180
{
181
        UEINTX = 0x3A;        // FIFOCON=0 NAKINI=0 RWAL=1 NAKOUTI=1 RXSTPI=1 RXOUTI=0 STALLEDI=1 TXINI=0
182
}
183

    
184
static inline u8 FrameNumber()
185
{
186
        return UDFNUML;
187
}
188

    
189
//==================================================================
190
//==================================================================
191

    
192
u8 USBGetConfiguration(void)
193
{
194
        return _usbConfiguration;
195
}
196

    
197
#define USB_RECV_TIMEOUT
198
class LockEP
199
{
200
        u8 _sreg;
201
public:
202
        LockEP(u8 ep) : _sreg(SREG)
203
        {
204
                cli();
205
                SetEP(ep & 7);
206
        }
207
        ~LockEP()
208
        {
209
                SREG = _sreg;
210
        }
211
};
212

    
213
//        Number of bytes, assumes a rx endpoint
214
u8 USB_Available(u8 ep)
215
{
216
        LockEP lock(ep);
217
        return FifoByteCount();
218
}
219

    
220
//        Non Blocking receive
221
//        Return number of bytes read
222
int USB_Recv(u8 ep, void* d, int len)
223
{
224
        if (!_usbConfiguration || len < 0)
225
                return -1;
226
        
227
        LockEP lock(ep);
228
        u8 n = FifoByteCount();
229
        len = min(n,len);
230
        n = len;
231
        u8* dst = (u8*)d;
232
        while (n--)
233
                *dst++ = Recv8();
234
        if (len && !FifoByteCount())        // release empty buffer
235
                ReleaseRX();
236
        
237
        return len;
238
}
239

    
240
//        Recv 1 byte if ready
241
int USB_Recv(u8 ep)
242
{
243
        u8 c;
244
        if (USB_Recv(ep,&c,1) != 1)
245
                return -1;
246
        return c;
247
}
248

    
249
//        Space in send EP
250
u8 USB_SendSpace(u8 ep)
251
{
252
        LockEP lock(ep);
253
        if (!ReadWriteAllowed())
254
                return 0;
255
        return 64 - FifoByteCount();
256
}
257

    
258
//        Blocking Send of data to an endpoint
259
int USB_Send(u8 ep, const void* d, int len)
260
{
261
        if (!_usbConfiguration)
262
                return -1;
263

    
264
        int r = len;
265
        const u8* data = (const u8*)d;
266
        u8 zero = ep & TRANSFER_ZERO;
267
        u8 timeout = 250;                // 250ms timeout on send? TODO
268
        while (len)
269
        {
270
                u8 n = USB_SendSpace(ep);
271
                if (n == 0)
272
                {
273
                        if (!(--timeout))
274
                                return -1;
275
                        delay(1);
276
                        continue;
277
                }
278

    
279
                if (n > len)
280
                        n = len;
281
                len -= n;
282
                {
283
                        LockEP lock(ep);
284
                        if (ep & TRANSFER_ZERO)
285
                        {
286
                                while (n--)
287
                                        Send8(0);
288
                        }
289
                        else if (ep & TRANSFER_PGM)
290
                        {
291
                                while (n--)
292
                                        Send8(pgm_read_byte(data++));
293
                        }
294
                        else
295
                        {
296
                                while (n--)
297
                                        Send8(*data++);
298
                        }
299
                        if (!ReadWriteAllowed() || ((len == 0) && (ep & TRANSFER_RELEASE)))        // Release full buffer
300
                                ReleaseTX();
301
                }
302
        }
303
        TXLED1;                                        // light the TX LED
304
        TxLEDPulse = TX_RX_LED_PULSE_MS;
305
        return r;
306
}
307

    
308
extern const u8 _initEndpoints[] PROGMEM;
309
const u8 _initEndpoints[] = 
310
{
311
        0,
312
        
313
#ifdef CDC_ENABLED
314
        EP_TYPE_INTERRUPT_IN,                // CDC_ENDPOINT_ACM
315
        EP_TYPE_BULK_OUT,                        // CDC_ENDPOINT_OUT
316
        EP_TYPE_BULK_IN,                        // CDC_ENDPOINT_IN
317
#endif
318

    
319
#ifdef HID_ENABLED
320
        EP_TYPE_INTERRUPT_IN                // HID_ENDPOINT_INT
321
#endif
322
};
323

    
324
#define EP_SINGLE_64 0x32        // EP0
325
#define EP_DOUBLE_64 0x36        // Other endpoints
326

    
327
static
328
void InitEP(u8 index, u8 type, u8 size)
329
{
330
        UENUM = index;
331
        UECONX = 1;
332
        UECFG0X = type;
333
        UECFG1X = size;
334
}
335

    
336
static
337
void InitEndpoints()
338
{
339
        for (u8 i = 1; i < sizeof(_initEndpoints); i++)
340
        {
341
                UENUM = i;
342
                UECONX = 1;
343
                UECFG0X = pgm_read_byte(_initEndpoints+i);
344
                UECFG1X = EP_DOUBLE_64;
345
        }
346
        UERST = 0x7E;        // And reset them
347
        UERST = 0;
348
}
349

    
350
//        Handle CLASS_INTERFACE requests
351
static
352
bool ClassInterfaceRequest(Setup& setup)
353
{
354
        u8 i = setup.wIndex;
355

    
356
#ifdef CDC_ENABLED
357
        if (CDC_ACM_INTERFACE == i)
358
                return CDC_Setup(setup);
359
#endif
360

    
361
#ifdef HID_ENABLED
362
        if (HID_INTERFACE == i)
363
                return HID_Setup(setup);
364
#endif
365
        return false;
366
}
367

    
368
int _cmark;
369
int _cend;
370
void InitControl(int end)
371
{
372
        SetEP(0);
373
        _cmark = 0;
374
        _cend = end;
375
}
376

    
377
static
378
bool SendControl(u8 d)
379
{
380
        if (_cmark < _cend)
381
        {
382
                if (!WaitForINOrOUT())
383
                        return false;
384
                Send8(d);
385
                if (!((_cmark + 1) & 0x3F))
386
                        ClearIN();        // Fifo is full, release this packet
387
        }
388
        _cmark++;
389
        return true;
390
};
391

    
392
//        Clipped by _cmark/_cend
393
int USB_SendControl(u8 flags, const void* d, int len)
394
{
395
        int sent = len;
396
        const u8* data = (const u8*)d;
397
        bool pgm = flags & TRANSFER_PGM;
398
        while (len--)
399
        {
400
                u8 c = pgm ? pgm_read_byte(data++) : *data++;
401
                if (!SendControl(c))
402
                        return -1;
403
        }
404
        return sent;
405
}
406

    
407
//        Does not timeout or cross fifo boundaries
408
//        Will only work for transfers <= 64 bytes
409
//        TODO
410
int USB_RecvControl(void* d, int len)
411
{
412
        WaitOUT();
413
        Recv((u8*)d,len);
414
        ClearOUT();
415
        return len;
416
}
417

    
418
int SendInterfaces()
419
{
420
        int total = 0;
421
        u8 interfaces = 0;
422

    
423
#ifdef CDC_ENABLED
424
        total = CDC_GetInterface(&interfaces);
425
#endif
426

    
427
#ifdef HID_ENABLED
428
        total += HID_GetInterface(&interfaces);
429
#endif
430

    
431
        return interfaces;
432
}
433

    
434
//        Construct a dynamic configuration descriptor
435
//        This really needs dynamic endpoint allocation etc
436
//        TODO
437
static
438
bool SendConfiguration(int maxlen)
439
{
440
        //        Count and measure interfaces
441
        InitControl(0);        
442
        int interfaces = SendInterfaces();
443
        ConfigDescriptor config = D_CONFIG(_cmark + sizeof(ConfigDescriptor),interfaces);
444

    
445
        //        Now send them
446
        InitControl(maxlen);
447
        USB_SendControl(0,&config,sizeof(ConfigDescriptor));
448
        SendInterfaces();
449
        return true;
450
}
451

    
452
u8 _cdcComposite = 0;
453

    
454
static
455
bool SendDescriptor(Setup& setup)
456
{
457
        u8 t = setup.wValueH;
458
        if (USB_CONFIGURATION_DESCRIPTOR_TYPE == t)
459
                return SendConfiguration(setup.wLength);
460

    
461
        InitControl(setup.wLength);
462
#ifdef HID_ENABLED
463
        if (HID_REPORT_DESCRIPTOR_TYPE == t)
464
                return HID_GetDescriptor(t);
465
#endif
466

    
467
        u8 desc_length = 0;
468
        const u8* desc_addr = 0;
469
        if (USB_DEVICE_DESCRIPTOR_TYPE == t)
470
        {
471
                if (setup.wLength == 8)
472
                        _cdcComposite = 1;
473
                desc_addr = _cdcComposite ?  (const u8*)&USB_DeviceDescriptorA : (const u8*)&USB_DeviceDescriptor;
474
        }
475
        else if (USB_STRING_DESCRIPTOR_TYPE == t)
476
        {
477
                if (setup.wValueL == 0)
478
                        desc_addr = (const u8*)&STRING_LANGUAGE;
479
                else if (setup.wValueL == IPRODUCT) 
480
                        desc_addr = (const u8*)&STRING_IPRODUCT;
481
                else if (setup.wValueL == IMANUFACTURER)
482
                        desc_addr = (const u8*)&STRING_IMANUFACTURER;
483
                else
484
                        return false;
485
        }
486

    
487
        if (desc_addr == 0)
488
                return false;
489
        if (desc_length == 0)
490
                desc_length = pgm_read_byte(desc_addr);
491

    
492
        USB_SendControl(TRANSFER_PGM,desc_addr,desc_length);
493
        return true;
494
}
495

    
496
//        Endpoint 0 interrupt
497
ISR(USB_COM_vect)
498
{
499
    SetEP(0);
500
        if (!ReceivedSetupInt())
501
                return;
502

    
503
        Setup setup;
504
        Recv((u8*)&setup,8);
505
        ClearSetupInt();
506

    
507
        u8 requestType = setup.bmRequestType;
508
        if (requestType & REQUEST_DEVICETOHOST)
509
                WaitIN();
510
        else
511
                ClearIN();
512

    
513
    bool ok = true;
514
        if (REQUEST_STANDARD == (requestType & REQUEST_TYPE))
515
        {
516
                //        Standard Requests
517
                u8 r = setup.bRequest;
518
                if (GET_STATUS == r)
519
                {
520
                        Send8(0);                // TODO
521
                        Send8(0);
522
                }
523
                else if (CLEAR_FEATURE == r)
524
                {
525
                }
526
                else if (SET_FEATURE == r)
527
                {
528
                }
529
                else if (SET_ADDRESS == r)
530
                {
531
                        WaitIN();
532
                        UDADDR = setup.wValueL | (1<<ADDEN);
533
                }
534
                else if (GET_DESCRIPTOR == r)
535
                {
536
                        ok = SendDescriptor(setup);
537
                }
538
                else if (SET_DESCRIPTOR == r)
539
                {
540
                        ok = false;
541
                }
542
                else if (GET_CONFIGURATION == r)
543
                {
544
                        Send8(1);
545
                }
546
                else if (SET_CONFIGURATION == r)
547
                {
548
                        if (REQUEST_DEVICE == (requestType & REQUEST_RECIPIENT))
549
                        {
550
                                InitEndpoints();
551
                                _usbConfiguration = setup.wValueL;
552
                        } else
553
                                ok = false;
554
                }
555
                else if (GET_INTERFACE == r)
556
                {
557
                }
558
                else if (SET_INTERFACE == r)
559
                {
560
                }
561
        }
562
        else
563
        {
564
                InitControl(setup.wLength);                //        Max length of transfer
565
                ok = ClassInterfaceRequest(setup);
566
        }
567

    
568
        if (ok)
569
                ClearIN();
570
        else
571
        {
572
                Stall();
573
        }
574
}
575

    
576
void USB_Flush(u8 ep)
577
{
578
        SetEP(ep);
579
        if (FifoByteCount())
580
                ReleaseTX();
581
}
582

    
583
//        General interrupt
584
ISR(USB_GEN_vect)
585
{
586
        u8 udint = UDINT;
587
        UDINT = 0;
588

    
589
        //        End of Reset
590
        if (udint & (1<<EORSTI))
591
        {
592
                InitEP(0,EP_TYPE_CONTROL,EP_SINGLE_64);        // init ep0
593
                _usbConfiguration = 0;                        // not configured yet
594
                UEIENX = 1 << RXSTPE;                        // Enable interrupts for ep0
595
        }
596

    
597
        //        Start of Frame - happens every millisecond so we use it for TX and RX LED one-shot timing, too
598
        if (udint & (1<<SOFI))
599
        {
600
#ifdef CDC_ENABLED
601
                USB_Flush(CDC_TX);                                // Send a tx frame if found
602
#endif
603
                
604
                // check whether the one-shot period has elapsed.  if so, turn off the LED
605
                if (TxLEDPulse && !(--TxLEDPulse))
606
                        TXLED0;
607
                if (RxLEDPulse && !(--RxLEDPulse))
608
                        RXLED0;
609
        }
610
}
611

    
612
//        VBUS or counting frames
613
//        Any frame counting?
614
u8 USBConnected()
615
{
616
        u8 f = UDFNUML;
617
        delay(3);
618
        return f != UDFNUML;
619
}
620

    
621
//=======================================================================
622
//=======================================================================
623

    
624
USB_ USB;
625

    
626
USB_::USB_()
627
{
628
}
629

    
630
void USB_::attach()
631
{
632
        _usbConfiguration = 0;
633
        UHWCON = 0x01;                                                // power internal reg
634
        USBCON = (1<<USBE)|(1<<FRZCLK);                // clock frozen, usb enabled
635
        PLLCSR = 0x12;                                                // Need 16 MHz xtal
636
        while (!(PLLCSR & (1<<PLOCK)))                // wait for lock pll
637
                ;
638
        USBCON = ((1<<USBE)|(1<<OTGPADE));        // start USB clock
639
        UDIEN = (1<<EORSTE)|(1<<SOFE);                // Enable interrupts for EOR (End of Reset) and SOF (start of frame)
640
        UDCON = 0;                                                        // enable attach resistor
641
        
642
        TX_RX_LED_INIT;
643
}
644

    
645
void USB_::detach()
646
{
647
}
648

    
649
//        Check for interrupts
650
//        TODO: VBUS detection
651
bool USB_::configured()
652
{
653
        return _usbConfiguration;
654
}
655

    
656
void USB_::poll()
657
{
658
}
659

    
660
#endif /* if defined(USBCON) */