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

Subversion Repositories openrisc

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

powered by: WebSVN 2.1.0

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