OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [CORTEX_LPC1768_GCC_RedSuite/] [src/] [LPCUSB/] [usbhw_lpc.c] - Blame information for rev 581

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 581 jeremybenn
/*
2
        LPCUSB, an USB device driver for LPC microcontrollers
3
        Copyright (C) 2006 Bertrik Sikken (bertrik@sikken.nl)
4
 
5
        Redistribution and use in source and binary forms, with or without
6
        modification, are permitted provided that the following conditions are met:
7
 
8
        1. Redistributions of source code must retain the above copyright
9
           notice, this list of conditions and the following disclaimer.
10
        2. Redistributions in binary form must reproduce the above copyright
11
           notice, this list of conditions and the following disclaimer in the
12
           documentation and/or other materials provided with the distribution.
13
        3. The name of the author may not be used to endorse or promote products
14
           derived from this software without specific prior written permission.
15
 
16
        THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
        IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
        OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
        IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
        INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
        NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
        DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
        THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
        (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
        THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
*/
27
 
28
 
29
/** @file
30
        USB hardware layer
31
 */
32
 
33
 
34
#include "usbdebug.h"
35
#include "usbhw_lpc.h"
36
#include "usbapi.h"
37
 
38
#ifdef DEBUG
39
// comment out the following line if you don't want to use debug LEDs
40
//#define DEBUG_LED
41
#endif
42
 
43
/** Installed device interrupt handler */
44
static TFnDevIntHandler *_pfnDevIntHandler = NULL;
45
/** Installed endpoint interrupt handlers */
46
static TFnEPIntHandler  *_apfnEPIntHandlers[16];
47
/** Installed frame interrupt handlers */
48
static TFnFrameHandler  *_pfnFrameHandler = NULL;
49
 
50
/** convert from endpoint address to endpoint index */
51
#define EP2IDX(bEP)     ((((bEP)&0xF)<<1)|(((bEP)&0x80)>>7))
52
/** convert from endpoint index to endpoint address */
53
#define IDX2EP(idx)     ((((idx)<<7)&0x80)|(((idx)>>1)&0xF))
54
 
55
 
56
 
57
/**
58
        Local function to wait for a device interrupt (and clear it)
59
 
60
        @param [in]     dwIntr          Bitmask of interrupts to wait for
61
 */
62
static void Wait4DevInt(unsigned long dwIntr)
63
{
64
        // wait for specific interrupt
65
        while ((LPC_USB->USBDevIntSt & dwIntr) != dwIntr);
66
        // clear the interrupt bits
67
        LPC_USB->USBDevIntClr = dwIntr;
68
}
69
 
70
 
71
/**
72
        Local function to send a command to the USB protocol engine
73
 
74
        @param [in]     bCmd            Command to send
75
 */
76
static void USBHwCmd(unsigned char bCmd)
77
{
78
        // clear CDFULL/CCEMTY
79
        LPC_USB->USBDevIntClr = CDFULL | CCEMTY;
80
        // write command code
81
        LPC_USB->USBCmdCode = 0x00000500 | (bCmd << 16);
82
        Wait4DevInt(CCEMTY);
83
}
84
 
85
 
86
/**
87
        Local function to send a command + data to the USB protocol engine
88
 
89
        @param [in]     bCmd            Command to send
90
        @param [in]     bData           Data to send
91
 */
92
static void USBHwCmdWrite(unsigned char bCmd, unsigned short bData)
93
{
94
        // write command code
95
        USBHwCmd(bCmd);
96
 
97
        // write command data
98
        LPC_USB->USBCmdCode = 0x00000100 | (bData << 16);
99
        Wait4DevInt(CCEMTY);
100
}
101
 
102
 
103
/**
104
        Local function to send a command to the USB protocol engine and read data
105
 
106
        @param [in]     bCmd            Command to send
107
 
108
        @return the data
109
 */
110
static unsigned char USBHwCmdRead(unsigned char bCmd)
111
{
112
        // write command code
113
        USBHwCmd(bCmd);
114
 
115
        // get data
116
        LPC_USB->USBCmdCode = 0x00000200 | (bCmd << 16);
117
        Wait4DevInt(CDFULL);
118
        return LPC_USB->USBCmdData;
119
}
120
 
121
 
122
/**
123
        'Realizes' an endpoint, meaning that buffer space is reserved for
124
        it. An endpoint needs to be realised before it can be used.
125
 
126
        From experiments, it appears that a USB reset causes USBReEP to
127
        re-initialise to 3 (= just the control endpoints).
128
        However, a USB bus reset does not disturb the USBMaxPSize settings.
129
 
130
        @param [in]     idx                     Endpoint index
131
        @param [in] wMaxPSize   Maximum packet size for this endpoint
132
 */
133
static void USBHwEPRealize(int idx, unsigned short wMaxPSize)
134
{
135
        LPC_USB->USBReEP |= (1 << idx);
136
        LPC_USB->USBEpInd = idx;
137
        LPC_USB->USBMaxPSize = wMaxPSize;
138
        Wait4DevInt(EP_RLZED);
139
}
140
 
141
 
142
/**
143
        Enables or disables an endpoint
144
 
145
        @param [in]     idx             Endpoint index
146
        @param [in]     fEnable TRUE to enable, FALSE to disable
147
 */
148
static void USBHwEPEnable(int idx, BOOL fEnable)
149
{
150
        USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fEnable ? 0 : EP_DA);
151
}
152
 
153
 
154
/**
155
        Configures an endpoint and enables it
156
 
157
        @param [in]     bEP                             Endpoint number
158
        @param [in]     wMaxPacketSize  Maximum packet size for this EP
159
 */
160
void USBHwEPConfig(unsigned char bEP, unsigned short wMaxPacketSize)
161
{
162
        int idx;
163
 
164
        idx = EP2IDX(bEP);
165
 
166
        // realise EP
167
        USBHwEPRealize(idx, wMaxPacketSize);
168
 
169
        // enable EP
170
        USBHwEPEnable(idx, TRUE);
171
}
172
 
173
 
174
/**
175
        Registers an endpoint event callback
176
 
177
        @param [in]     bEP                             Endpoint number
178
        @param [in]     pfnHandler              Callback function
179
 */
180
void USBHwRegisterEPIntHandler(unsigned char bEP, TFnEPIntHandler *pfnHandler)
181
{
182
        int idx;
183
 
184
        idx = EP2IDX(bEP);
185
 
186
        ASSERT(idx<32);
187
 
188
        /* add handler to list of EP handlers */
189
        _apfnEPIntHandlers[idx / 2] = pfnHandler;
190
 
191
        /* enable EP interrupt */
192
        LPC_USB->USBEpIntEn |= (1 << idx);
193
        LPC_USB->USBDevIntEn |= EP_SLOW;
194
 
195
        DBG("Registered handler for EP 0x%x\n", bEP);
196
}
197
 
198
 
199
/**
200
        Registers an device status callback
201
 
202
        @param [in]     pfnHandler      Callback function
203
 */
204
void USBHwRegisterDevIntHandler(TFnDevIntHandler *pfnHandler)
205
{
206
        _pfnDevIntHandler = pfnHandler;
207
 
208
        // enable device interrupt
209
        LPC_USB->USBDevIntEn |= DEV_STAT;
210
 
211
        DBG("Registered handler for device status\n");
212
}
213
 
214
 
215
/**
216
        Registers the frame callback
217
 
218
        @param [in]     pfnHandler      Callback function
219
 */
220
void USBHwRegisterFrameHandler(TFnFrameHandler *pfnHandler)
221
{
222
        _pfnFrameHandler = pfnHandler;
223
 
224
        // enable device interrupt
225
        LPC_USB->USBDevIntEn |= FRAME;
226
 
227
        DBG("Registered handler for frame\n");
228
}
229
 
230
 
231
/**
232
        Sets the USB address.
233
 
234
        @param [in]     bAddr           Device address to set
235
 */
236
void USBHwSetAddress(unsigned char bAddr)
237
{
238
        USBHwCmdWrite(CMD_DEV_SET_ADDRESS, DEV_EN | bAddr);
239
}
240
 
241
 
242
/**
243
        Connects or disconnects from the USB bus
244
 
245
        @param [in]     fConnect        If TRUE, connect, otherwise disconnect
246
 */
247
void USBHwConnect(BOOL fConnect)
248
{
249
        USBHwCmdWrite(CMD_DEV_STATUS, fConnect ? CON : 0);
250
}
251
 
252
 
253
/**
254
        Enables interrupt on NAK condition
255
 
256
        For IN endpoints a NAK is generated when the host wants to read data
257
        from the device, but none is available in the endpoint buffer.
258
        For OUT endpoints a NAK is generated when the host wants to write data
259
        to the device, but the endpoint buffer is still full.
260
 
261
        The endpoint interrupt handlers can distinguish regular (ACK) interrupts
262
        from NAK interrupt by checking the bits in their bEPStatus argument.
263
 
264
        @param [in]     bIntBits        Bitmap indicating which NAK interrupts to enable
265
 */
266
void USBHwNakIntEnable(unsigned char bIntBits)
267
{
268
        USBHwCmdWrite(CMD_DEV_SET_MODE, bIntBits);
269
}
270
 
271
 
272
/**
273
        Gets the status from a specific endpoint.
274
 
275
        @param [in]     bEP             Endpoint number
276
        @return Endpoint status byte (containing EP_STATUS_xxx bits)
277
 */
278
unsigned char   USBHwEPGetStatus(unsigned char bEP)
279
{
280
        int idx = EP2IDX(bEP);
281
 
282
        return USBHwCmdRead(CMD_EP_SELECT | idx);
283
}
284
 
285
 
286
/**
287
        Sets the stalled property of an endpoint
288
 
289
        @param [in]     bEP             Endpoint number
290
        @param [in]     fStall  TRUE to stall, FALSE to unstall
291
 */
292
void USBHwEPStall(unsigned char bEP, BOOL fStall)
293
{
294
        int idx = EP2IDX(bEP);
295
 
296
        USBHwCmdWrite(CMD_EP_SET_STATUS | idx, fStall ? EP_ST : 0);
297
}
298
 
299
 
300
/**
301
        Writes data to an endpoint buffer
302
 
303
        @param [in]     bEP             Endpoint number
304
        @param [in]     pbBuf   Endpoint data
305
        @param [in]     iLen    Number of bytes to write
306
 
307
        @return TRUE if the data was successfully written or <0 in case of error.
308
*/
309
int USBHwEPWrite(unsigned char bEP, unsigned char *pbBuf, int iLen)
310
{
311
        int idx;
312
 
313
        idx = EP2IDX(bEP);
314
 
315
        // set write enable for specific endpoint
316
        LPC_USB->USBCtrl = WR_EN | ((bEP & 0xF) << 2);
317
 
318
        // set packet length
319
        LPC_USB->USBTxPLen = iLen;
320
 
321
        // write data
322
        while (LPC_USB->USBCtrl & WR_EN) {
323
                LPC_USB->USBTxData = (pbBuf[3] << 24) | (pbBuf[2] << 16) | (pbBuf[1] << 8) | pbBuf[0];
324
                pbBuf += 4;
325
        }
326
 
327
        // select endpoint and validate buffer
328
        USBHwCmd(CMD_EP_SELECT | idx);
329
        USBHwCmd(CMD_EP_VALIDATE_BUFFER);
330
 
331
        return iLen;
332
}
333
 
334
 
335
/**
336
        Reads data from an endpoint buffer
337
 
338
        @param [in]     bEP             Endpoint number
339
        @param [in]     pbBuf   Endpoint data
340
        @param [in]     iMaxLen Maximum number of bytes to read
341
 
342
        @return the number of bytes available in the EP (possibly more than iMaxLen),
343
        or <0 in case of error.
344
 */
345
int USBHwEPRead(unsigned char bEP, unsigned char *pbBuf, int iMaxLen)
346
{
347
        int i, idx;
348
        unsigned long   dwData, dwLen;
349
 
350
        idx = EP2IDX(bEP);
351
 
352
        // set read enable bit for specific endpoint
353
        LPC_USB->USBCtrl = RD_EN | ((bEP & 0xF) << 2);
354
 
355
        // wait for PKT_RDY
356
        do {
357
                dwLen = LPC_USB->USBRxPLen;
358
        } while ((dwLen & PKT_RDY) == 0);
359
 
360
        // packet valid?
361
        if ((dwLen & DV) == 0) {
362
                return -1;
363
        }
364
 
365
        // get length
366
        dwLen &= PKT_LNGTH_MASK;
367
 
368
        // get data
369
        dwData = 0;
370
        for (i = 0; i < dwLen; i++) {
371
                if ((i % 4) == 0) {
372
                        dwData = LPC_USB->USBRxData;
373
                }
374
                if ((pbBuf != NULL) && (i < iMaxLen)) {
375
                        pbBuf[i] = dwData & 0xFF;
376
                }
377
                dwData >>= 8;
378
        }
379
 
380
        // make sure RD_EN is clear
381
        LPC_USB->USBCtrl = 0;
382
 
383
        // select endpoint and clear buffer
384
        USBHwCmd(CMD_EP_SELECT | idx);
385
        USBHwCmd(CMD_EP_CLEAR_BUFFER);
386
 
387
        return dwLen;
388
}
389
 
390
 
391
/**
392
        Sets the 'configured' state.
393
 
394
        All registered endpoints are 'realised' and enabled, and the
395
        'configured' bit is set in the device status register.
396
 
397
        @param [in]     fConfigured     If TRUE, configure device, else unconfigure
398
 */
399
void USBHwConfigDevice(BOOL fConfigured)
400
{
401
        // set configured bit
402
        USBHwCmdWrite(CMD_DEV_CONFIG, fConfigured ? CONF_DEVICE : 0);
403
}
404
 
405
 
406
/**
407
        USB interrupt handler
408
 
409
        @todo Get all 11 bits of frame number instead of just 8
410
 
411
        Endpoint interrupts are mapped to the slow interrupt
412
 */
413
void USBHwISR(void)
414
{
415
        unsigned long   dwStatus;
416
        unsigned long dwIntBit;
417
        unsigned char   bEPStat, bDevStat, bStat;
418
        int i;
419
        unsigned short  wFrame;
420
 
421
        // handle device interrupts
422
        dwStatus = LPC_USB->USBDevIntSt;
423
 
424
        // frame interrupt
425
        if (dwStatus & FRAME) {
426
                // clear int
427
                LPC_USB->USBDevIntClr = FRAME;
428
                // call handler
429
                if (_pfnFrameHandler != NULL) {
430
                        wFrame = USBHwCmdRead(CMD_DEV_READ_CUR_FRAME_NR);
431
                        _pfnFrameHandler(wFrame);
432
                }
433
        }
434
 
435
        // device status interrupt
436
        if (dwStatus & DEV_STAT) {
437
                /*      Clear DEV_STAT interrupt before reading DEV_STAT register.
438
                        This prevents corrupted device status reads, see
439
                        LPC2148 User manual revision 2, 25 july 2006.
440
                */
441
                LPC_USB->USBDevIntClr = DEV_STAT;
442
                bDevStat = USBHwCmdRead(CMD_DEV_STATUS);
443
                if (bDevStat & (CON_CH | SUS_CH | RST)) {
444
                        // convert device status into something HW independent
445
                        bStat = ((bDevStat & CON) ? DEV_STATUS_CONNECT : 0) |
446
                                        ((bDevStat & SUS) ? DEV_STATUS_SUSPEND : 0) |
447
                                        ((bDevStat & RST) ? DEV_STATUS_RESET : 0);
448
                        // call handler
449
                        if (_pfnDevIntHandler != NULL) {
450
                                _pfnDevIntHandler(bStat);
451
                        }
452
                }
453
        }
454
 
455
        // endpoint interrupt
456
        if (dwStatus & EP_SLOW) {
457
                // clear EP_SLOW
458
                LPC_USB->USBDevIntClr = EP_SLOW;
459
                // check all endpoints
460
                for (i = 0; i < 32; i++) {
461
                        dwIntBit = (1 << i);
462
                        if (LPC_USB->USBEpIntSt & dwIntBit) {
463
                                // clear int (and retrieve status)
464
                                LPC_USB->USBEpIntClr = dwIntBit;
465
                                Wait4DevInt(CDFULL);
466
                                bEPStat = LPC_USB->USBCmdData;
467
                                // convert EP pipe stat into something HW independent
468
                                bStat = ((bEPStat & EPSTAT_FE) ? EP_STATUS_DATA : 0) |
469
                                                ((bEPStat & EPSTAT_ST) ? EP_STATUS_STALLED : 0) |
470
                                                ((bEPStat & EPSTAT_STP) ? EP_STATUS_SETUP : 0) |
471
                                                ((bEPStat & EPSTAT_EPN) ? EP_STATUS_NACKED : 0) |
472
                                                ((bEPStat & EPSTAT_PO) ? EP_STATUS_ERROR : 0);
473
                                // call handler
474
                                if (_apfnEPIntHandlers[i / 2] != NULL) {
475
                                        _apfnEPIntHandlers[i / 2](IDX2EP(i), bStat);
476
                                }
477
                        }
478
                }
479
        }
480
}
481
 
482
 
483
 
484
/**
485
        Initialises the USB hardware
486
 
487
 
488
        @return TRUE if the hardware was successfully initialised
489
 */
490
BOOL USBHwInit(void)
491
{
492
        // P2.9 -> USB_CONNECT
493
        LPC_PINCON->PINSEL4 &= ~0x000C0000;
494
        LPC_PINCON->PINSEL4 |= 0x00040000;
495
 
496
        // P1.18 -> USB_UP_LED
497
        // P1.30 -> VBUS
498
        LPC_PINCON->PINSEL3 &= ~0x30000030;
499
        LPC_PINCON->PINSEL3 |= 0x20000010;
500
 
501
        // P0.29 -> USB_D+
502
        // P0.30 -> USB_D-
503
        LPC_PINCON->PINSEL1 &= ~0x3C000000;
504
        LPC_PINCON->PINSEL1 |= 0x14000000;
505
 
506
        // enable PUSB
507
        LPC_SC->PCONP |= (1 << 31);
508
 
509
        LPC_USB->OTGClkCtrl = 0x12;                       /* Dev clock, AHB clock enable  */
510
        while ((LPC_USB->OTGClkSt & 0x12) != 0x12);
511
 
512
        // disable/clear all interrupts for now
513
        LPC_USB->USBDevIntEn = 0;
514
        LPC_USB->USBDevIntClr = 0xFFFFFFFF;
515
        LPC_USB->USBDevIntPri = 0;
516
 
517
        LPC_USB->USBEpIntEn = 0;
518
        LPC_USB->USBEpIntClr = 0xFFFFFFFF;
519
        LPC_USB->USBEpIntPri = 0;
520
 
521
        // by default, only ACKs generate interrupts
522
        USBHwNakIntEnable(0);
523
 
524
        return TRUE;
525
}
526
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.