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

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [PC/] [serial/] [serial.c] - Blame information for rev 675

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 586 jeremybenn
/*
2
        This serial port driver is borrowed heavily from DZComm.  I have
3
        simplified it by removing a lot of the functionality (hardware
4
        flow control, etc.).  For more details and the full version see
5
        http://dzcomm.sourceforge.net
6
*/
7
 
8
/*
9
    FreeRTOS V6.1.1 - Copyright (C) 2011 Real Time Engineers Ltd.
10
 
11
    ***************************************************************************
12
    *                                                                         *
13
    * If you are:                                                             *
14
    *                                                                         *
15
    *    + New to FreeRTOS,                                                   *
16
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
17
    *    + Looking for basic training,                                        *
18
    *    + Wanting to improve your FreeRTOS skills and productivity           *
19
    *                                                                         *
20
    * then take a look at the FreeRTOS books - available as PDF or paperback  *
21
    *                                                                         *
22
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
23
    *                  http://www.FreeRTOS.org/Documentation                  *
24
    *                                                                         *
25
    * A pdf reference manual is also available.  Both are usually delivered   *
26
    * to your inbox within 20 minutes to two hours when purchased between 8am *
27
    * and 8pm GMT (although please allow up to 24 hours in case of            *
28
    * exceptional circumstances).  Thank you for your support!                *
29
    *                                                                         *
30
    ***************************************************************************
31
 
32
    This file is part of the FreeRTOS distribution.
33
 
34
    FreeRTOS is free software; you can redistribute it and/or modify it under
35
    the terms of the GNU General Public License (version 2) as published by the
36
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
37
    ***NOTE*** The exception to the GPL is included to allow you to distribute
38
    a combined work that includes FreeRTOS without being obliged to provide the
39
    source code for proprietary components outside of the FreeRTOS kernel.
40
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
41
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
42
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
43
    more details. You should have received a copy of the GNU General Public
44
    License and the FreeRTOS license exception along with FreeRTOS; if not it
45
    can be viewed here: http://www.freertos.org/a00114.html and also obtained
46
    by writing to Richard Barry, contact details for whom are available on the
47
    FreeRTOS WEB site.
48
 
49
    1 tab == 4 spaces!
50
 
51
    http://www.FreeRTOS.org - Documentation, latest information, license and
52
    contact details.
53
 
54
    http://www.SafeRTOS.com - A version that is certified for use in safety
55
    critical systems.
56
 
57
    http://www.OpenRTOS.com - Commercial support, development, porting,
58
    licensing and training services.
59
*/
60
 
61
 
62
 
63
#include <stdlib.h>
64
#include <dos.h>
65
#include "FreeRTOS.h"
66
#include "queue.h"
67
#include "task.h"
68
#include "semphr.h"
69
#include "portasm.h"
70
 
71
#define serMAX_IRQs                                             ( 16 )
72
#define serTRANSMIT_HOLD_EMPTY_INT              ( 0x02 )
73
#define serCOM1_STANDARD_IRQ                    ( ( unsigned char ) 4 )
74
#define serCOM2_STANDARD_IRQ                    ( ( unsigned char ) 3 )
75
 
76
 
77
#define serIMR_8259_0                                   ( ( unsigned char ) 0x21 )
78
#define serIMR_8259_1                                   ( ( unsigned char ) 0xa1 )
79
#define serISR_8259_0                                   ( ( unsigned char ) 0x20 )
80
#define serISR_8259_1                                   ( ( unsigned char ) 0xa0 )
81
#define serALL_COMS_INTERRUPTS                  ( ( unsigned char ) 0x0f )
82
#define serALL_MODEM_CTRL_INTERRUPTS    ( ( unsigned char ) 0x0f )
83
 
84
#define serTRANSMIT_HOLD_OFFSET                                 ( 0 )
85
#define serRECEIVE_DATA_OFFSET                                  ( 0 )
86
#define serBAUD_RATE_DIVISOR_LOW_OFFSET                 ( 0 )
87
#define serBAUD_RATE_DIVISOR_HIGH_OFFSET                ( 1 )
88
#define serINTERRUPT_ENABLE_OFFSET                              ( 1 )
89
#define serINTERRUPT_ID_OFFSET                                  ( 2 )
90
#define serFIFO_CTRL_OFFSET                                             ( 2 )
91
#define serLINE_CTRL_OFFSET                                             ( 3 )
92
#define serMODEM_CTRL_OFFSET                                    ( 4 )
93
#define serLINE_STATUS_OFFSET                                   ( 5 )
94
#define serMODEM_STATUS_OFFSET                                  ( 6 )
95
#define serSCR_OFFSET                                                   ( 7 )
96
 
97
#define serMAX_BAUD                     ( ( unsigned long ) 115200UL )
98
 
99
#define serNO_INTERRUPTS        ( 0x00 )
100
 
101
#define vInterruptOn( pxPort, ucInterrupt )                                                                             \
102
{                                                                                                                                                               \
103
        unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg );    \
104
        if( !( ucIn & ucInterrupt ) )                                                                                           \
105
        {                                                                                                                                                       \
106
                portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn | ucInterrupt );    \
107
        }                                                                                                                                                       \
108
}
109
/*-----------------------------------------------------------*/
110
 
111
#define vInterruptOff( pxPort, ucInterrupt )                                                                    \
112
{                                                                                                                                                               \
113
        unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg );    \
114
        if( ucIn & ucInterrupt )                                                                                                        \
115
        {                                                                                                                                                       \
116
                portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn & ~ucInterrupt);    \
117
        }                                                                                                                                                       \
118
}
119
/*-----------------------------------------------------------*/
120
 
121
typedef enum
122
{
123
        serCOM1,
124
        serCOM2,
125
        serCOM3,
126
        serCOM4,
127
        serCOM5,
128
        serCOM6,
129
        serCOM7,
130
        serCOM8
131
} eCOMPort;
132
 
133
typedef enum
134
{
135
        serNO_PARITY,
136
        serODD_PARITY,
137
        serEVEN_PARITY,
138
        serMARK_PARITY,
139
        serSPACE_PARITY
140
} eParity;
141
 
142
typedef enum
143
{
144
        serSTOP_1,
145
        serSTOP_2
146
} eStopBits;
147
 
148
typedef enum
149
{
150
        serBITS_5,
151
        serBITS_6,
152
        serBITS_7,
153
        serBITS_8
154
} eDataBits;
155
 
156
typedef enum
157
{
158
        ser50,
159
        ser75,
160
        ser110,
161
        ser134,
162
        ser150,
163
        ser200,
164
        ser300,
165
        ser600,
166
        ser1200,
167
        ser1800,
168
        ser2400,
169
        ser4800,
170
        ser9600,
171
        ser19200,
172
        ser38400,
173
        ser57600,
174
        ser115200
175
} eBaud;
176
 
177
/* This *MUST* match the order in the eBaud definition. */
178
unsigned long ulBaudFromEnum[] =
179
{
180
        ( unsigned long ) 50,
181
        ( unsigned long ) 75,
182
        ( unsigned long ) 110,
183
        ( unsigned long ) 134,
184
        ( unsigned long ) 150,
185
        ( unsigned long ) 200,
186
        ( unsigned long ) 300,
187
        ( unsigned long ) 600,
188
        ( unsigned long ) 1200,
189
        ( unsigned long ) 1800,
190
        ( unsigned long ) 2400,
191
        ( unsigned long ) 4800,
192
        ( unsigned long ) 9600,
193
        ( unsigned long ) 19200,
194
        ( unsigned long ) 38400UL,
195
        ( unsigned long ) 57600UL,
196
        ( unsigned long ) 115200UL
197
};
198
 
199
typedef struct xCOM_PORT
200
{
201
        unsigned short sPort;   /* comm port address eg. 0x3f8    */
202
        unsigned char ucIRQ;    /* comm IRQ eg. 3                 */
203
 
204
        /* Next two fields used for setting up the IRQ routine and
205
        * (un)masking the interrupt in certain circumstances.
206
        */
207
        unsigned short usIRQVector;
208
        unsigned char ucInterruptEnableMast;
209
 
210
        /* Read/Write buffers. */
211
        xQueueHandle xRxedChars;
212
        xQueueHandle xCharsForTx;
213
 
214
        /* This lot are set up to minimise CPU time where accessing the comm
215
        * port's registers.
216
        */
217
        unsigned short usTransmitHoldReg;
218
        unsigned short usReceiveDataRegister;
219
        unsigned short usBaudRateDivisorLow;
220
        unsigned short usBaudRateDivisorHigh;
221
        unsigned short usInterruptEnableReg;
222
        unsigned short usInterruptIDReg;
223
        unsigned short usFIFOCtrlReg;
224
        unsigned short usLineCtrlReg;
225
        unsigned short usModemCtrlReg;
226
        unsigned short usLineStatusReg;
227
        unsigned short usModemStatusReg;
228
        unsigned short usSCRReg;
229
        unsigned short us8259InterruptServiceReg;
230
        unsigned short us8259InterruptMaskReg;
231
 
232
        /* This semaphore does nothing useful except test a feature of the
233
        scheduler. */
234
        xSemaphoreHandle xTestSem;
235
 
236
} xComPort;
237
 
238
typedef xComPort *xComPortHandle;
239
 
240
/* A xComPort structure can be associated with each IRQ.  Initially none
241
are create/installed. */
242
xComPort *xPortStatus[ serMAX_IRQs ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
243
 
244
/*-----------------------------------------------------------*/
245
 
246
/* These prototypes are repeated here so we don't have to include the serial header.  This allows
247
the xComPortHandle structure details to be private to this file. */
248
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
249
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
250
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
251
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
252
 
253
static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits );
254
static short sComPortISR( const xComPort * const pxPort );
255
 
256
/*-----------------------------------------------------------*/
257
 
258
/* Define an interrupt handler for each slot in the xPortStatus array. */
259
 
260
#define COM_IRQ_WRAPPER(N)                                                                              \
261
        static void __interrupt COM_IRQ##N##_WRAPPER( void )            \
262
        {                                                                                                                       \
263
                portDISABLE_INTERRUPTS();                                                               \
264
                if( sComPortISR( xPortStatus[##N##] ) )                                 \
265
                {                                                                                                               \
266
                        portSWITCH_CONTEXT();                                                           \
267
                }                                                                                                               \
268
        }
269
 
270
COM_IRQ_WRAPPER( 0 )
271
COM_IRQ_WRAPPER( 1 )
272
COM_IRQ_WRAPPER( 2 )
273
COM_IRQ_WRAPPER( 3 )
274
COM_IRQ_WRAPPER( 4 )
275
COM_IRQ_WRAPPER( 5 )
276
COM_IRQ_WRAPPER( 6 )
277
COM_IRQ_WRAPPER( 7 )
278
COM_IRQ_WRAPPER( 8 )
279
COM_IRQ_WRAPPER( 9 )
280
COM_IRQ_WRAPPER( 10 )
281
COM_IRQ_WRAPPER( 11 )
282
COM_IRQ_WRAPPER( 12 )
283
COM_IRQ_WRAPPER( 13 )
284
COM_IRQ_WRAPPER( 14 )
285
COM_IRQ_WRAPPER( 15 )
286
 
287
static pxISR xISRs[ serMAX_IRQs ] =
288
{
289
        COM_IRQ0_WRAPPER,
290
        COM_IRQ1_WRAPPER,
291
        COM_IRQ2_WRAPPER,
292
        COM_IRQ3_WRAPPER,
293
        COM_IRQ4_WRAPPER,
294
        COM_IRQ5_WRAPPER,
295
        COM_IRQ6_WRAPPER,
296
        COM_IRQ7_WRAPPER,
297
        COM_IRQ8_WRAPPER,
298
        COM_IRQ9_WRAPPER,
299
        COM_IRQ10_WRAPPER,
300
        COM_IRQ11_WRAPPER,
301
        COM_IRQ12_WRAPPER,
302
        COM_IRQ13_WRAPPER,
303
        COM_IRQ14_WRAPPER,
304
        COM_IRQ15_WRAPPER
305
};
306
 
307
static pxISR xOldISRs[ serMAX_IRQs ] = { NULL };
308
 
309
/*-----------------------------------------------------------*/
310
 
311
 
312
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
313
{
314
xComPort *pxPort;
315
 
316
        /* Create a structure to handle this port. */
317
        pxPort = ( xComPort * ) pvPortMalloc( sizeof( xComPort ) );
318
 
319
        if( pxPort != NULL )
320
        {
321
                /* Create the queues used by the comtest task. */
322
                pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
323
                pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
324
 
325
                /* Create the test semaphore.  This does nothing useful except test a feature of the scheduler. */
326
                vSemaphoreCreateBinary( pxPort->xTestSem );
327
 
328
                prvSetupPortHardware( pxPort, ePort, eWantedBaud, eWantedParity, eWantedDataBits, eWantedStopBits );
329
 
330
                return pxPort;
331
        }
332
 
333
        return NULL;
334
}
335
/*-----------------------------------------------------------*/
336
 
337
static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits )
338
{
339
short sIn;
340
unsigned long ulDivisor;
341
unsigned char ucDivisorLow;
342
unsigned char ucDivisorHigh;
343
unsigned char ucCommParam;
344
 
345
        /* IRQ numbers - standard */
346
        if( ( ePort == serCOM1 ) || ( ePort == serCOM3 ) || ( ePort == serCOM5 ) || ( ePort == serCOM7 ) )
347
        {
348
                pxPort->ucIRQ = serCOM1_STANDARD_IRQ;
349
                pxPort->sPort = 0x3f8;
350
        }
351
        else
352
        {
353
                pxPort->ucIRQ = serCOM2_STANDARD_IRQ;
354
                pxPort->sPort = 0x2f8;
355
        }
356
 
357
        /* Set up variables in port making it easy to see which sIn/o address is which */
358
        pxPort->usTransmitHoldReg = pxPort->sPort + serTRANSMIT_HOLD_OFFSET;
359
        pxPort->usReceiveDataRegister = pxPort->sPort + serRECEIVE_DATA_OFFSET;
360
        pxPort->usBaudRateDivisorLow = pxPort->sPort + serBAUD_RATE_DIVISOR_LOW_OFFSET;
361
        pxPort->usBaudRateDivisorHigh = pxPort->sPort + serBAUD_RATE_DIVISOR_HIGH_OFFSET;
362
        pxPort->usInterruptEnableReg = pxPort->sPort + serINTERRUPT_ENABLE_OFFSET;
363
        pxPort->usInterruptIDReg = pxPort->sPort + serINTERRUPT_ID_OFFSET;
364
        pxPort->usFIFOCtrlReg = pxPort->sPort + serFIFO_CTRL_OFFSET;
365
        pxPort->usLineCtrlReg = pxPort->sPort + serLINE_CTRL_OFFSET;
366
        pxPort->usModemCtrlReg = pxPort->sPort + serMODEM_CTRL_OFFSET;
367
        pxPort->usLineStatusReg = pxPort->sPort + serLINE_STATUS_OFFSET;
368
        pxPort->usModemStatusReg = pxPort->sPort + serMODEM_STATUS_OFFSET;
369
        pxPort->usSCRReg = pxPort->sPort + serSCR_OFFSET;
370
 
371
        /* Set communication parameters. */
372
        ulDivisor = serMAX_BAUD / ulBaudFromEnum[ eWantedBaud ];
373
        ucDivisorLow = ( unsigned char ) ulDivisor & ( unsigned char ) 0xff;
374
        ucDivisorHigh = ( unsigned char ) ( ( ( unsigned short ) ulDivisor >> 8 ) & 0xff );
375
 
376
        switch( eWantedParity )
377
        {
378
                case serNO_PARITY:              ucCommParam = 0x00;
379
                                                                break;
380
                case serODD_PARITY:             ucCommParam = 0x08;
381
                                                                break;
382
                case serEVEN_PARITY:    ucCommParam = 0x18;
383
                                                                break;
384
                case serMARK_PARITY:    ucCommParam = 0x28;
385
                                                                break;
386
                case serSPACE_PARITY:   ucCommParam = 0x38;
387
                                                                break;
388
                default:                                ucCommParam = 0x00;
389
                                                                break;
390
        }
391
 
392
        switch ( eWantedDataBits )
393
        {
394
                case serBITS_5: ucCommParam |= 0x00;
395
                                                break;
396
                case serBITS_6: ucCommParam |= 0x01;
397
                                                break;
398
                case serBITS_7: ucCommParam |= 0x02;
399
                                                break;
400
                case serBITS_8: ucCommParam |= 0x03;
401
                                                break;
402
                default:                ucCommParam |= 0x03;
403
                                                break;
404
        }
405
 
406
        if( eWantedStopBits == serSTOP_2 )
407
        {
408
                ucCommParam |= 0x04;
409
        }
410
 
411
        /* Reset UART into known state - Thanks to Bradley Town */
412
        portOUTPUT_BYTE( pxPort->usLineCtrlReg, 0x00 );                 /* Access usTransmitHoldReg/RBR/usInterruptEnableReg */
413
        portOUTPUT_BYTE( pxPort->usInterruptEnableReg, 0x00 );  /* Disable interrupts from UART */
414
        portOUTPUT_BYTE( pxPort->usModemCtrlReg, 0x04 );                /* Enable some multi-port cards */
415
 
416
        /* Code based on stuff from SVAsync lib. Clear UART Status and data registers
417
        setting up FIFO if possible */
418
        sIn = portINPUT_BYTE( pxPort->usSCRReg );
419
        portOUTPUT_BYTE( pxPort->usSCRReg, 0x55 );
420
 
421
        if( portINPUT_BYTE( pxPort->usSCRReg ) == 0x55 )
422
        {
423
                /* The chip is better than an 8250 */
424
                portOUTPUT_BYTE( pxPort->usSCRReg, sIn );       /* Set usSCRReg back to what it was before */
425
                portINPUT_BYTE( pxPort->usSCRReg);                      /* Give slow motherboards a chance */
426
 
427
                /* Try and start the FIFO. It appears that some chips need a two call
428
                protocol, but those that don't seem to work even if you do start it twice.
429
                The first call is simply to start it, the second starts it and sets an 8
430
                byte FIFO trigger level. */
431
                portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x01 );
432
                portINPUT_BYTE( pxPort->usFIFOCtrlReg );                        /* Give slow motherboards a chance to catch up */
433
                portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x87 );
434
 
435
                /* Check that the FIFO initialised */
436
                if( ( portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0xc0 ) != 0xc0 )
437
                {
438
                        /* It didn't so we assume it isn't there but disable it to be on the
439
                        safe side. */
440
                        portOUTPUT_BYTE( pxPort->usInterruptIDReg, 0xfe );
441
                }
442
        }
443
 
444
        /* End of (modified) SVAsync code.
445
        Set interrupt parameters calculating mask for 8259 controller's
446
        IMR and number of interrupt handler for given irq level  */
447
        if (pxPort->ucIRQ <= 7)
448
        {
449
                /* if 0<=irq<=7 first IMR address used */
450
                pxPort->ucInterruptEnableMast = ~(0x01 << pxPort->ucIRQ);
451
                pxPort->usIRQVector = pxPort->ucIRQ + 8;
452
                pxPort->us8259InterruptMaskReg = serIMR_8259_0;
453
                pxPort->us8259InterruptServiceReg = serISR_8259_0;
454
        }
455
        else
456
        {
457
                pxPort->ucInterruptEnableMast = ~( 0x01 << ( pxPort->ucIRQ % 8 ) );
458
                pxPort->usIRQVector = 0x70 + ( pxPort->ucIRQ - 8) ;
459
                pxPort->us8259InterruptMaskReg = serIMR_8259_1;
460
                pxPort->us8259InterruptServiceReg = serISR_8259_1;
461
        }
462
 
463
        /* Set Port Toggle to usBaudRateDivisorLow/usBaudRateDivisorHigh registers
464
        to set baud rate */
465
        portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam | 0x80 );
466
        portOUTPUT_BYTE( pxPort->usBaudRateDivisorLow, ucDivisorLow );
467
        portOUTPUT_BYTE( pxPort->usBaudRateDivisorHigh, ucDivisorHigh );
468
 
469
        /* reset usLineCtrlReg and Port Toggleout */
470
        portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam & 0x7F );
471
 
472
        portENTER_CRITICAL();
473
 
474
        if( xPortStatus[ pxPort->ucIRQ ] == NULL )
475
        {
476
                xPortStatus[ pxPort->ucIRQ ] = pxPort;
477
        }
478
 
479
        xOldISRs[ pxPort->ucIRQ ] = _dos_getvect( pxPort->usIRQVector );
480
        _dos_setvect( pxPort->usIRQVector, xISRs[ pxPort->ucIRQ ] );
481
 
482
        /* enable interrupt pxPort->ucIRQ level */
483
        portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
484
 
485
        /* And allow interrupts again now the hairy bit's done */
486
        portEXIT_CRITICAL();
487
 
488
        /* This version does not allow flow control. */
489
        portOUTPUT_BYTE( pxPort->usModemCtrlReg, serALL_MODEM_CTRL_INTERRUPTS );
490
 
491
        /* enable all communication's interrupts */
492
        portOUTPUT_BYTE( pxPort->usInterruptEnableReg, serALL_COMS_INTERRUPTS );
493
}
494
/*-----------------------------------------------------------*/
495
 
496
static short sComPortISR( const xComPort * const pxPort )
497
{
498
short sInterruptID;
499
char cIn, cOut;
500
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
501
extern void vComTestUnsuspendTask( void );
502
 
503
        portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, ( portINPUT_BYTE( pxPort->us8259InterruptMaskReg) | ~pxPort->ucInterruptEnableMast ) );
504
 
505
        /* Decide which UART has issued the interrupt */
506
        sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg );
507
 
508
        /* service whatever requests the calling UART may have. The top 4 bits are
509
        either unused or indicate the presence of a functioning FIFO, which we don't
510
        need to know. So trim them off to simplify the switch statement below. */
511
        sInterruptID &= 0x0f;
512
        do
513
        {
514
                switch( sInterruptID )
515
                {
516
                        case 0x0c:      /* Timeout
517
                                                Called when FIFO not up to trigger level but no activity for
518
                                                a while. Handled exactly as RDAINT, see below for
519
                                                description. */
520
                                                do
521
                                                {
522
                                                        cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
523
                                                        xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
524
 
525
                                                        /* Also release the semaphore - this does nothing interesting and is just a test.
526
                                                        We first attempt to unsuspend the task to check the scheduler correctely detects
527
                                                        this as an invalid call, then give the semaphore for real. */
528
                                                        vComTestUnsuspendTask();
529
                                                        xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
530
 
531
                                                } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
532
                                                break;
533
 
534
                        case 0x06:      /* LSINT */
535
                                                portINPUT_BYTE( pxPort->usLineStatusReg );
536
                                                break;
537
 
538
                        case 0x04:      /* RDAINT */
539
                                                /* The usInterruptIDReg flag tested above stops when the
540
                                                FIFO is below the trigger level rather than empty, whereas
541
                                                this flag allows one to empty it: (do loop because there
542
                                                must be at least one to read by virtue of having got here.) */
543
                                                do
544
                                                {
545
                                                        cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
546
                                                        xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
547
 
548
                                                        /* Also release the semaphore - this does nothing interesting and is just a test.
549
                                                        We first attempt to unsuspend the task to check the scheduler correctely detects
550
                                                        this as an invalid call, then give the semaphore for real. */
551
                                                        vComTestUnsuspendTask();
552
                                                        xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
553
 
554
                                                } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
555
                                                break;
556
 
557
                        case 0x02:      /* serTRANSMIT_HOLD_EMPTY_INT */
558
                                                if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cOut, &xHigherPriorityTaskWoken ) != pdTRUE )
559
                                                {
560
                                                        /* Queue empty, nothing to send */
561
                                                        vInterruptOff( pxPort, serTRANSMIT_HOLD_EMPTY_INT);
562
                                                }
563
                                                else
564
                                                {
565
                                                        portOUTPUT_BYTE( pxPort->usTransmitHoldReg, ( short ) cOut );
566
                                                }
567
                                                break;
568
 
569
                        case 0x00:      /* MSINT */
570
                                                portINPUT_BYTE( pxPort->usModemStatusReg );
571
                                                break;
572
                }
573
 
574
                /* Get the next instruction, trimming as above */
575
                sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0x0f;
576
 
577
        } while( !( sInterruptID & 0x01 ) );
578
 
579
        if( pxPort->ucIRQ > 7 )
580
        {
581
                portOUTPUT_BYTE( 0xA0, 0x60 + ( pxPort->ucIRQ & 0x07 ) );
582
                portOUTPUT_BYTE( 0x20, 0x62);
583
        }
584
        else
585
        {
586
                portOUTPUT_BYTE( 0x20, 0x60 + pxPort->ucIRQ );
587
        }
588
 
589
        portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
590
 
591
        /* If posting any of the characters to a queue woke a task that was blocked on
592
        the queue we may want to return to the task just woken (depending on its
593
        priority relative to the task this ISR interrupted. */
594
        return xHigherPriorityTaskWoken;
595
}
596
/*-----------------------------------------------------------*/
597
 
598
portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
599
{
600
        /* Get the next character from the buffer, note that this routine is only
601
        called having checked that the is (at least) one to get */
602
        if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
603
        {
604
                return pdTRUE;
605
        }
606
        else
607
        {
608
                return pdFALSE;
609
        }
610
}
611
/*-----------------------------------------------------------*/
612
 
613
portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
614
{
615
        if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
616
        {
617
                return pdFAIL;
618
        }
619
 
620
        vInterruptOn( pxPort, serTRANSMIT_HOLD_EMPTY_INT );
621
 
622
        return pdPASS;
623
}
624
/*-----------------------------------------------------------*/
625
 
626
void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
627
{
628
char * pcNextChar;
629
const portTickType xNoBlock = ( portTickType ) 0;
630
 
631
        /* Stop warnings. */
632
        ( void ) usStringLength;
633
 
634
        pcNextChar = ( char * ) pcString;
635
        while( *pcNextChar )
636
        {
637
                xSerialPutChar( pxPort, *pcNextChar, xNoBlock );
638
                pcNextChar++;
639
        }
640
}
641
/*-----------------------------------------------------------*/
642
 
643
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
644
{
645
const portTickType xBlockTime = ( portTickType ) 0xffff;
646
 
647
        /* This function does nothing interesting, but test the
648
        semaphore from ISR mechanism. */
649
        return xSemaphoreTake( xPort->xTestSem, xBlockTime );
650
}
651
/*-----------------------------------------------------------*/
652
 
653
void vSerialClose( xComPortHandle xPort )
654
{
655
        portENTER_CRITICAL();
656
 
657
        /* Turn off the interrupts. */
658
        portOUTPUT_BYTE( xPort->usModemCtrlReg, serNO_INTERRUPTS );
659
        portOUTPUT_BYTE( xPort->usInterruptEnableReg, serNO_INTERRUPTS );
660
 
661
        /* Put back the original ISR. */
662
        _dos_setvect( xPort->usIRQVector, xOldISRs[ xPort->ucIRQ ] );
663
 
664
        /* Remove the reference in the array of xComPort structures. */
665
        xPortStatus[ xPort->ucIRQ ] = NULL;
666
 
667
        /* Delete the queues. */
668
        vQueueDelete( xPort->xRxedChars );
669
        vQueueDelete( xPort->xCharsForTx );
670
 
671
        vPortFree( ( void * ) xPort );
672
 
673
        portEXIT_CRITICAL();
674
}
675
 

powered by: WebSVN 2.1.0

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