2 This serial port driver is borrowed heavily from DZComm. I have
\r
3 simplified it by removing a lot of the functionality (hardware
\r
4 flow control, etc.). For more details and the full version see
\r
5 http://dzcomm.sourceforge.net
\r
9 FreeRTOS V7.5.2 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
11 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
13 ***************************************************************************
\r
15 * FreeRTOS provides completely free yet professionally developed, *
\r
16 * robust, strictly quality controlled, supported, and cross *
\r
17 * platform software that has become a de facto standard. *
\r
19 * Help yourself get started quickly and support the FreeRTOS *
\r
20 * project by purchasing a FreeRTOS tutorial book, reference *
\r
21 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
25 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
33 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
34 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
35 >>! the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
41 link: http://www.freertos.org/a00114.html
\r
45 ***************************************************************************
\r
47 * Having a problem? Start by reading the FAQ "My application does *
\r
48 * not run, what could be wrong?" *
\r
50 * http://www.FreeRTOS.org/FAQHelp.html *
\r
52 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
55 license and Real Time Engineers Ltd. contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
59 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
61 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
62 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
63 licenses offer ticketed support, indemnification and middleware.
\r
65 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
66 engineered and independently SIL3 certified version for use in safety and
\r
67 mission critical applications that require provable dependability.
\r
76 #include "FreeRTOS.h"
\r
80 #include "portasm.h"
\r
82 #define serMAX_IRQs ( 16 )
\r
83 #define serTRANSMIT_HOLD_EMPTY_INT ( 0x02 )
\r
84 #define serCOM1_STANDARD_IRQ ( ( unsigned char ) 4 )
\r
85 #define serCOM2_STANDARD_IRQ ( ( unsigned char ) 3 )
\r
88 #define serIMR_8259_0 ( ( unsigned char ) 0x21 )
\r
89 #define serIMR_8259_1 ( ( unsigned char ) 0xa1 )
\r
90 #define serISR_8259_0 ( ( unsigned char ) 0x20 )
\r
91 #define serISR_8259_1 ( ( unsigned char ) 0xa0 )
\r
92 #define serALL_COMS_INTERRUPTS ( ( unsigned char ) 0x0f )
\r
93 #define serALL_MODEM_CTRL_INTERRUPTS ( ( unsigned char ) 0x0f )
\r
95 #define serTRANSMIT_HOLD_OFFSET ( 0 )
\r
96 #define serRECEIVE_DATA_OFFSET ( 0 )
\r
97 #define serBAUD_RATE_DIVISOR_LOW_OFFSET ( 0 )
\r
98 #define serBAUD_RATE_DIVISOR_HIGH_OFFSET ( 1 )
\r
99 #define serINTERRUPT_ENABLE_OFFSET ( 1 )
\r
100 #define serINTERRUPT_ID_OFFSET ( 2 )
\r
101 #define serFIFO_CTRL_OFFSET ( 2 )
\r
102 #define serLINE_CTRL_OFFSET ( 3 )
\r
103 #define serMODEM_CTRL_OFFSET ( 4 )
\r
104 #define serLINE_STATUS_OFFSET ( 5 )
\r
105 #define serMODEM_STATUS_OFFSET ( 6 )
\r
106 #define serSCR_OFFSET ( 7 )
\r
108 #define serMAX_BAUD ( ( unsigned long ) 115200UL )
\r
110 #define serNO_INTERRUPTS ( 0x00 )
\r
112 #define vInterruptOn( pxPort, ucInterrupt ) \
\r
114 unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
\r
115 if( !( ucIn & ucInterrupt ) ) \
\r
117 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn | ucInterrupt ); \
\r
120 /*-----------------------------------------------------------*/
\r
122 #define vInterruptOff( pxPort, ucInterrupt ) \
\r
124 unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
\r
125 if( ucIn & ucInterrupt ) \
\r
127 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn & ~ucInterrupt); \
\r
130 /*-----------------------------------------------------------*/
\r
188 /* This *MUST* match the order in the eBaud definition. */
\r
189 unsigned long ulBaudFromEnum[] =
\r
191 ( unsigned long ) 50,
\r
192 ( unsigned long ) 75,
\r
193 ( unsigned long ) 110,
\r
194 ( unsigned long ) 134,
\r
195 ( unsigned long ) 150,
\r
196 ( unsigned long ) 200,
\r
197 ( unsigned long ) 300,
\r
198 ( unsigned long ) 600,
\r
199 ( unsigned long ) 1200,
\r
200 ( unsigned long ) 1800,
\r
201 ( unsigned long ) 2400,
\r
202 ( unsigned long ) 4800,
\r
203 ( unsigned long ) 9600,
\r
204 ( unsigned long ) 19200,
\r
205 ( unsigned long ) 38400UL,
\r
206 ( unsigned long ) 57600UL,
\r
207 ( unsigned long ) 115200UL
\r
210 typedef struct xCOM_PORT
\r
212 unsigned short sPort; /* comm port address eg. 0x3f8 */
\r
213 unsigned char ucIRQ; /* comm IRQ eg. 3 */
\r
215 /* Next two fields used for setting up the IRQ routine and
\r
216 * (un)masking the interrupt in certain circumstances.
\r
218 unsigned short usIRQVector;
\r
219 unsigned char ucInterruptEnableMast;
\r
221 /* Read/Write buffers. */
\r
222 xQueueHandle xRxedChars;
\r
223 xQueueHandle xCharsForTx;
\r
225 /* This lot are set up to minimise CPU time where accessing the comm
\r
226 * port's registers.
\r
228 unsigned short usTransmitHoldReg;
\r
229 unsigned short usReceiveDataRegister;
\r
230 unsigned short usBaudRateDivisorLow;
\r
231 unsigned short usBaudRateDivisorHigh;
\r
232 unsigned short usInterruptEnableReg;
\r
233 unsigned short usInterruptIDReg;
\r
234 unsigned short usFIFOCtrlReg;
\r
235 unsigned short usLineCtrlReg;
\r
236 unsigned short usModemCtrlReg;
\r
237 unsigned short usLineStatusReg;
\r
238 unsigned short usModemStatusReg;
\r
239 unsigned short usSCRReg;
\r
240 unsigned short us8259InterruptServiceReg;
\r
241 unsigned short us8259InterruptMaskReg;
\r
243 /* This semaphore does nothing useful except test a feature of the
\r
245 xSemaphoreHandle xTestSem;
\r
249 typedef xComPort *xComPortHandle;
\r
251 /* A xComPort structure can be associated with each IRQ. Initially none
\r
252 are create/installed. */
\r
253 xComPort *xPortStatus[ serMAX_IRQs ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
\r
255 /*-----------------------------------------------------------*/
\r
257 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
258 the xComPortHandle structure details to be private to this file. */
\r
259 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
260 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
\r
261 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
\r
262 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
\r
264 static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits );
\r
265 static short sComPortISR( const xComPort * const pxPort );
\r
267 /*-----------------------------------------------------------*/
\r
269 /* Define an interrupt handler for each slot in the xPortStatus array. */
\r
271 #define COM_IRQ_WRAPPER(N) \
\r
272 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
274 portDISABLE_INTERRUPTS(); \
\r
275 if( sComPortISR( xPortStatus[##N##] ) ) \
\r
277 portSWITCH_CONTEXT(); \
\r
281 COM_IRQ_WRAPPER( 0 )
\r
282 COM_IRQ_WRAPPER( 1 )
\r
283 COM_IRQ_WRAPPER( 2 )
\r
284 COM_IRQ_WRAPPER( 3 )
\r
285 COM_IRQ_WRAPPER( 4 )
\r
286 COM_IRQ_WRAPPER( 5 )
\r
287 COM_IRQ_WRAPPER( 6 )
\r
288 COM_IRQ_WRAPPER( 7 )
\r
289 COM_IRQ_WRAPPER( 8 )
\r
290 COM_IRQ_WRAPPER( 9 )
\r
291 COM_IRQ_WRAPPER( 10 )
\r
292 COM_IRQ_WRAPPER( 11 )
\r
293 COM_IRQ_WRAPPER( 12 )
\r
294 COM_IRQ_WRAPPER( 13 )
\r
295 COM_IRQ_WRAPPER( 14 )
\r
296 COM_IRQ_WRAPPER( 15 )
\r
298 static pxISR xISRs[ serMAX_IRQs ] =
\r
310 COM_IRQ10_WRAPPER,
\r
311 COM_IRQ11_WRAPPER,
\r
312 COM_IRQ12_WRAPPER,
\r
313 COM_IRQ13_WRAPPER,
\r
318 static pxISR xOldISRs[ serMAX_IRQs ] = { NULL };
\r
320 /*-----------------------------------------------------------*/
\r
323 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
327 /* Create a structure to handle this port. */
\r
328 pxPort = ( xComPort * ) pvPortMalloc( sizeof( xComPort ) );
\r
330 if( pxPort != NULL )
\r
332 /* Create the queues used by the comtest task. */
\r
333 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
334 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
336 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
337 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
339 prvSetupPortHardware( pxPort, ePort, eWantedBaud, eWantedParity, eWantedDataBits, eWantedStopBits );
\r
346 /*-----------------------------------------------------------*/
\r
348 static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits )
\r
351 unsigned long ulDivisor;
\r
352 unsigned char ucDivisorLow;
\r
353 unsigned char ucDivisorHigh;
\r
354 unsigned char ucCommParam;
\r
356 /* IRQ numbers - standard */
\r
357 if( ( ePort == serCOM1 ) || ( ePort == serCOM3 ) || ( ePort == serCOM5 ) || ( ePort == serCOM7 ) )
\r
359 pxPort->ucIRQ = serCOM1_STANDARD_IRQ;
\r
360 pxPort->sPort = 0x3f8;
\r
364 pxPort->ucIRQ = serCOM2_STANDARD_IRQ;
\r
365 pxPort->sPort = 0x2f8;
\r
368 /* Set up variables in port making it easy to see which sIn/o address is which */
\r
369 pxPort->usTransmitHoldReg = pxPort->sPort + serTRANSMIT_HOLD_OFFSET;
\r
370 pxPort->usReceiveDataRegister = pxPort->sPort + serRECEIVE_DATA_OFFSET;
\r
371 pxPort->usBaudRateDivisorLow = pxPort->sPort + serBAUD_RATE_DIVISOR_LOW_OFFSET;
\r
372 pxPort->usBaudRateDivisorHigh = pxPort->sPort + serBAUD_RATE_DIVISOR_HIGH_OFFSET;
\r
373 pxPort->usInterruptEnableReg = pxPort->sPort + serINTERRUPT_ENABLE_OFFSET;
\r
374 pxPort->usInterruptIDReg = pxPort->sPort + serINTERRUPT_ID_OFFSET;
\r
375 pxPort->usFIFOCtrlReg = pxPort->sPort + serFIFO_CTRL_OFFSET;
\r
376 pxPort->usLineCtrlReg = pxPort->sPort + serLINE_CTRL_OFFSET;
\r
377 pxPort->usModemCtrlReg = pxPort->sPort + serMODEM_CTRL_OFFSET;
\r
378 pxPort->usLineStatusReg = pxPort->sPort + serLINE_STATUS_OFFSET;
\r
379 pxPort->usModemStatusReg = pxPort->sPort + serMODEM_STATUS_OFFSET;
\r
380 pxPort->usSCRReg = pxPort->sPort + serSCR_OFFSET;
\r
382 /* Set communication parameters. */
\r
383 ulDivisor = serMAX_BAUD / ulBaudFromEnum[ eWantedBaud ];
\r
384 ucDivisorLow = ( unsigned char ) ulDivisor & ( unsigned char ) 0xff;
\r
385 ucDivisorHigh = ( unsigned char ) ( ( ( unsigned short ) ulDivisor >> 8 ) & 0xff );
\r
387 switch( eWantedParity )
\r
389 case serNO_PARITY: ucCommParam = 0x00;
\r
391 case serODD_PARITY: ucCommParam = 0x08;
\r
393 case serEVEN_PARITY: ucCommParam = 0x18;
\r
395 case serMARK_PARITY: ucCommParam = 0x28;
\r
397 case serSPACE_PARITY: ucCommParam = 0x38;
\r
399 default: ucCommParam = 0x00;
\r
403 switch ( eWantedDataBits )
\r
405 case serBITS_5: ucCommParam |= 0x00;
\r
407 case serBITS_6: ucCommParam |= 0x01;
\r
409 case serBITS_7: ucCommParam |= 0x02;
\r
411 case serBITS_8: ucCommParam |= 0x03;
\r
413 default: ucCommParam |= 0x03;
\r
417 if( eWantedStopBits == serSTOP_2 )
\r
419 ucCommParam |= 0x04;
\r
422 /* Reset UART into known state - Thanks to Bradley Town */
\r
423 portOUTPUT_BYTE( pxPort->usLineCtrlReg, 0x00 ); /* Access usTransmitHoldReg/RBR/usInterruptEnableReg */
\r
424 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, 0x00 ); /* Disable interrupts from UART */
\r
425 portOUTPUT_BYTE( pxPort->usModemCtrlReg, 0x04 ); /* Enable some multi-port cards */
\r
427 /* Code based on stuff from SVAsync lib. Clear UART Status and data registers
\r
428 setting up FIFO if possible */
\r
429 sIn = portINPUT_BYTE( pxPort->usSCRReg );
\r
430 portOUTPUT_BYTE( pxPort->usSCRReg, 0x55 );
\r
432 if( portINPUT_BYTE( pxPort->usSCRReg ) == 0x55 )
\r
434 /* The chip is better than an 8250 */
\r
435 portOUTPUT_BYTE( pxPort->usSCRReg, sIn ); /* Set usSCRReg back to what it was before */
\r
436 portINPUT_BYTE( pxPort->usSCRReg); /* Give slow motherboards a chance */
\r
438 /* Try and start the FIFO. It appears that some chips need a two call
\r
439 protocol, but those that don't seem to work even if you do start it twice.
\r
440 The first call is simply to start it, the second starts it and sets an 8
\r
441 byte FIFO trigger level. */
\r
442 portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x01 );
\r
443 portINPUT_BYTE( pxPort->usFIFOCtrlReg ); /* Give slow motherboards a chance to catch up */
\r
444 portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x87 );
\r
446 /* Check that the FIFO initialised */
\r
447 if( ( portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0xc0 ) != 0xc0 )
\r
449 /* It didn't so we assume it isn't there but disable it to be on the
\r
451 portOUTPUT_BYTE( pxPort->usInterruptIDReg, 0xfe );
\r
455 /* End of (modified) SVAsync code.
\r
456 Set interrupt parameters calculating mask for 8259 controller's
\r
457 IMR and number of interrupt handler for given irq level */
\r
458 if (pxPort->ucIRQ <= 7)
\r
460 /* if 0<=irq<=7 first IMR address used */
\r
461 pxPort->ucInterruptEnableMast = ~(0x01 << pxPort->ucIRQ);
\r
462 pxPort->usIRQVector = pxPort->ucIRQ + 8;
\r
463 pxPort->us8259InterruptMaskReg = serIMR_8259_0;
\r
464 pxPort->us8259InterruptServiceReg = serISR_8259_0;
\r
468 pxPort->ucInterruptEnableMast = ~( 0x01 << ( pxPort->ucIRQ % 8 ) );
\r
469 pxPort->usIRQVector = 0x70 + ( pxPort->ucIRQ - 8) ;
\r
470 pxPort->us8259InterruptMaskReg = serIMR_8259_1;
\r
471 pxPort->us8259InterruptServiceReg = serISR_8259_1;
\r
474 /* Set Port Toggle to usBaudRateDivisorLow/usBaudRateDivisorHigh registers
\r
475 to set baud rate */
\r
476 portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam | 0x80 );
\r
477 portOUTPUT_BYTE( pxPort->usBaudRateDivisorLow, ucDivisorLow );
\r
478 portOUTPUT_BYTE( pxPort->usBaudRateDivisorHigh, ucDivisorHigh );
\r
480 /* reset usLineCtrlReg and Port Toggleout */
\r
481 portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam & 0x7F );
\r
483 portENTER_CRITICAL();
\r
485 if( xPortStatus[ pxPort->ucIRQ ] == NULL )
\r
487 xPortStatus[ pxPort->ucIRQ ] = pxPort;
\r
490 xOldISRs[ pxPort->ucIRQ ] = _dos_getvect( pxPort->usIRQVector );
\r
491 _dos_setvect( pxPort->usIRQVector, xISRs[ pxPort->ucIRQ ] );
\r
493 /* enable interrupt pxPort->ucIRQ level */
\r
494 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
\r
496 /* And allow interrupts again now the hairy bit's done */
\r
497 portEXIT_CRITICAL();
\r
499 /* This version does not allow flow control. */
\r
500 portOUTPUT_BYTE( pxPort->usModemCtrlReg, serALL_MODEM_CTRL_INTERRUPTS );
\r
502 /* enable all communication's interrupts */
\r
503 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, serALL_COMS_INTERRUPTS );
\r
505 /*-----------------------------------------------------------*/
\r
507 static short sComPortISR( const xComPort * const pxPort )
\r
509 short sInterruptID;
\r
511 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
512 extern void vComTestUnsuspendTask( void );
\r
514 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, ( portINPUT_BYTE( pxPort->us8259InterruptMaskReg) | ~pxPort->ucInterruptEnableMast ) );
\r
516 /* Decide which UART has issued the interrupt */
\r
517 sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg );
\r
519 /* service whatever requests the calling UART may have. The top 4 bits are
\r
520 either unused or indicate the presence of a functioning FIFO, which we don't
\r
521 need to know. So trim them off to simplify the switch statement below. */
\r
522 sInterruptID &= 0x0f;
\r
525 switch( sInterruptID )
\r
527 case 0x0c: /* Timeout
\r
528 Called when FIFO not up to trigger level but no activity for
\r
529 a while. Handled exactly as RDAINT, see below for
\r
533 cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
\r
534 xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
\r
536 /* Also release the semaphore - this does nothing interesting and is just a test.
\r
537 We first attempt to unsuspend the task to check the scheduler correctely detects
\r
538 this as an invalid call, then give the semaphore for real. */
\r
539 vComTestUnsuspendTask();
\r
540 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
542 } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
\r
545 case 0x06: /* LSINT */
\r
546 portINPUT_BYTE( pxPort->usLineStatusReg );
\r
549 case 0x04: /* RDAINT */
\r
550 /* The usInterruptIDReg flag tested above stops when the
\r
551 FIFO is below the trigger level rather than empty, whereas
\r
552 this flag allows one to empty it: (do loop because there
\r
553 must be at least one to read by virtue of having got here.) */
\r
556 cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
\r
557 xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
\r
559 /* Also release the semaphore - this does nothing interesting and is just a test.
\r
560 We first attempt to unsuspend the task to check the scheduler correctely detects
\r
561 this as an invalid call, then give the semaphore for real. */
\r
562 vComTestUnsuspendTask();
\r
563 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
565 } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
\r
568 case 0x02: /* serTRANSMIT_HOLD_EMPTY_INT */
\r
569 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cOut, &xHigherPriorityTaskWoken ) != pdTRUE )
\r
571 /* Queue empty, nothing to send */
\r
572 vInterruptOff( pxPort, serTRANSMIT_HOLD_EMPTY_INT);
\r
576 portOUTPUT_BYTE( pxPort->usTransmitHoldReg, ( short ) cOut );
\r
580 case 0x00: /* MSINT */
\r
581 portINPUT_BYTE( pxPort->usModemStatusReg );
\r
585 /* Get the next instruction, trimming as above */
\r
586 sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0x0f;
\r
588 } while( !( sInterruptID & 0x01 ) );
\r
590 if( pxPort->ucIRQ > 7 )
\r
592 portOUTPUT_BYTE( 0xA0, 0x60 + ( pxPort->ucIRQ & 0x07 ) );
\r
593 portOUTPUT_BYTE( 0x20, 0x62);
\r
597 portOUTPUT_BYTE( 0x20, 0x60 + pxPort->ucIRQ );
\r
600 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
\r
602 /* If posting any of the characters to a queue woke a task that was blocked on
\r
603 the queue we may want to return to the task just woken (depending on its
\r
604 priority relative to the task this ISR interrupted. */
\r
605 return xHigherPriorityTaskWoken;
\r
607 /*-----------------------------------------------------------*/
\r
609 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
\r
611 /* Get the next character from the buffer, note that this routine is only
\r
612 called having checked that the is (at least) one to get */
\r
613 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
622 /*-----------------------------------------------------------*/
\r
624 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
\r
626 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
631 vInterruptOn( pxPort, serTRANSMIT_HOLD_EMPTY_INT );
\r
635 /*-----------------------------------------------------------*/
\r
637 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
640 const portTickType xNoBlock = ( portTickType ) 0;
\r
642 /* Stop warnings. */
\r
643 ( void ) usStringLength;
\r
645 pcNextChar = ( char * ) pcString;
\r
646 while( *pcNextChar )
\r
648 xSerialPutChar( pxPort, *pcNextChar, xNoBlock );
\r
652 /*-----------------------------------------------------------*/
\r
654 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
656 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
658 /* This function does nothing interesting, but test the
\r
659 semaphore from ISR mechanism. */
\r
660 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
662 /*-----------------------------------------------------------*/
\r
664 void vSerialClose( xComPortHandle xPort )
\r
666 portENTER_CRITICAL();
\r
668 /* Turn off the interrupts. */
\r
669 portOUTPUT_BYTE( xPort->usModemCtrlReg, serNO_INTERRUPTS );
\r
670 portOUTPUT_BYTE( xPort->usInterruptEnableReg, serNO_INTERRUPTS );
\r
672 /* Put back the original ISR. */
\r
673 _dos_setvect( xPort->usIRQVector, xOldISRs[ xPort->ucIRQ ] );
\r
675 /* Remove the reference in the array of xComPort structures. */
\r
676 xPortStatus[ xPort->ucIRQ ] = NULL;
\r
678 /* Delete the queues. */
\r
679 vQueueDelete( xPort->xRxedChars );
\r
680 vQueueDelete( xPort->xCharsForTx );
\r
682 vPortFree( ( void * ) xPort );
\r
684 portEXIT_CRITICAL();
\r