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.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
12 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
14 ***************************************************************************
\r
16 * FreeRTOS provides completely free yet professionally developed, *
\r
17 * robust, strictly quality controlled, supported, and cross *
\r
18 * platform software that has become a de facto standard. *
\r
20 * Help yourself get started quickly and support the FreeRTOS *
\r
21 * project by purchasing a FreeRTOS tutorial book, reference *
\r
22 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
26 ***************************************************************************
\r
28 This file is part of the FreeRTOS distribution.
\r
30 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
31 the terms of the GNU General Public License (version 2) as published by the
\r
32 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
34 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
35 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
36 >>! the source code for proprietary components outside of the FreeRTOS
\r
39 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
40 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
41 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
42 link: http://www.freertos.org/a00114.html
\r
46 ***************************************************************************
\r
48 * Having a problem? Start by reading the FAQ "My application does *
\r
49 * not run, what could be wrong?" *
\r
51 * http://www.FreeRTOS.org/FAQHelp.html *
\r
53 ***************************************************************************
\r
55 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
56 license and Real Time Engineers Ltd. contact details.
\r
58 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
59 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
60 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
62 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
63 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
64 licenses offer ticketed support, indemnification and middleware.
\r
66 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
67 engineered and independently SIL3 certified version for use in safety and
\r
68 mission critical applications that require provable dependability.
\r
77 #include "FreeRTOS.h"
\r
81 #include "portasm.h"
\r
83 #define serMAX_IRQs ( 16 )
\r
84 #define serTRANSMIT_HOLD_EMPTY_INT ( 0x02 )
\r
85 #define serCOM1_STANDARD_IRQ ( ( unsigned char ) 4 )
\r
86 #define serCOM2_STANDARD_IRQ ( ( unsigned char ) 3 )
\r
89 #define serIMR_8259_0 ( ( unsigned char ) 0x21 )
\r
90 #define serIMR_8259_1 ( ( unsigned char ) 0xa1 )
\r
91 #define serISR_8259_0 ( ( unsigned char ) 0x20 )
\r
92 #define serISR_8259_1 ( ( unsigned char ) 0xa0 )
\r
93 #define serALL_COMS_INTERRUPTS ( ( unsigned char ) 0x0f )
\r
94 #define serALL_MODEM_CTRL_INTERRUPTS ( ( unsigned char ) 0x0f )
\r
96 #define serTRANSMIT_HOLD_OFFSET ( 0 )
\r
97 #define serRECEIVE_DATA_OFFSET ( 0 )
\r
98 #define serBAUD_RATE_DIVISOR_LOW_OFFSET ( 0 )
\r
99 #define serBAUD_RATE_DIVISOR_HIGH_OFFSET ( 1 )
\r
100 #define serINTERRUPT_ENABLE_OFFSET ( 1 )
\r
101 #define serINTERRUPT_ID_OFFSET ( 2 )
\r
102 #define serFIFO_CTRL_OFFSET ( 2 )
\r
103 #define serLINE_CTRL_OFFSET ( 3 )
\r
104 #define serMODEM_CTRL_OFFSET ( 4 )
\r
105 #define serLINE_STATUS_OFFSET ( 5 )
\r
106 #define serMODEM_STATUS_OFFSET ( 6 )
\r
107 #define serSCR_OFFSET ( 7 )
\r
109 #define serMAX_BAUD ( ( unsigned long ) 115200UL )
\r
111 #define serNO_INTERRUPTS ( 0x00 )
\r
113 #define vInterruptOn( pxPort, ucInterrupt ) \
\r
115 unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
\r
116 if( !( ucIn & ucInterrupt ) ) \
\r
118 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn | ucInterrupt ); \
\r
121 /*-----------------------------------------------------------*/
\r
123 #define vInterruptOff( pxPort, ucInterrupt ) \
\r
125 unsigned char ucIn = portINPUT_BYTE( pxPort->usInterruptEnableReg ); \
\r
126 if( ucIn & ucInterrupt ) \
\r
128 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, ucIn & ~ucInterrupt); \
\r
131 /*-----------------------------------------------------------*/
\r
189 /* This *MUST* match the order in the eBaud definition. */
\r
190 unsigned long ulBaudFromEnum[] =
\r
192 ( unsigned long ) 50,
\r
193 ( unsigned long ) 75,
\r
194 ( unsigned long ) 110,
\r
195 ( unsigned long ) 134,
\r
196 ( unsigned long ) 150,
\r
197 ( unsigned long ) 200,
\r
198 ( unsigned long ) 300,
\r
199 ( unsigned long ) 600,
\r
200 ( unsigned long ) 1200,
\r
201 ( unsigned long ) 1800,
\r
202 ( unsigned long ) 2400,
\r
203 ( unsigned long ) 4800,
\r
204 ( unsigned long ) 9600,
\r
205 ( unsigned long ) 19200,
\r
206 ( unsigned long ) 38400UL,
\r
207 ( unsigned long ) 57600UL,
\r
208 ( unsigned long ) 115200UL
\r
211 typedef struct xCOM_PORT
\r
213 unsigned short sPort; /* comm port address eg. 0x3f8 */
\r
214 unsigned char ucIRQ; /* comm IRQ eg. 3 */
\r
216 /* Next two fields used for setting up the IRQ routine and
\r
217 * (un)masking the interrupt in certain circumstances.
\r
219 unsigned short usIRQVector;
\r
220 unsigned char ucInterruptEnableMast;
\r
222 /* Read/Write buffers. */
\r
223 xQueueHandle xRxedChars;
\r
224 xQueueHandle xCharsForTx;
\r
226 /* This lot are set up to minimise CPU time where accessing the comm
\r
227 * port's registers.
\r
229 unsigned short usTransmitHoldReg;
\r
230 unsigned short usReceiveDataRegister;
\r
231 unsigned short usBaudRateDivisorLow;
\r
232 unsigned short usBaudRateDivisorHigh;
\r
233 unsigned short usInterruptEnableReg;
\r
234 unsigned short usInterruptIDReg;
\r
235 unsigned short usFIFOCtrlReg;
\r
236 unsigned short usLineCtrlReg;
\r
237 unsigned short usModemCtrlReg;
\r
238 unsigned short usLineStatusReg;
\r
239 unsigned short usModemStatusReg;
\r
240 unsigned short usSCRReg;
\r
241 unsigned short us8259InterruptServiceReg;
\r
242 unsigned short us8259InterruptMaskReg;
\r
244 /* This semaphore does nothing useful except test a feature of the
\r
246 xSemaphoreHandle xTestSem;
\r
250 typedef xComPort *xComPortHandle;
\r
252 /* A xComPort structure can be associated with each IRQ. Initially none
\r
253 are create/installed. */
\r
254 xComPort *xPortStatus[ serMAX_IRQs ] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
\r
256 /*-----------------------------------------------------------*/
\r
258 /* These prototypes are repeated here so we don't have to include the serial header. This allows
\r
259 the xComPortHandle structure details to be private to this file. */
\r
260 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength );
\r
261 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime );
\r
262 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime );
\r
263 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
\r
265 static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits );
\r
266 static short sComPortISR( const xComPort * const pxPort );
\r
268 /*-----------------------------------------------------------*/
\r
270 /* Define an interrupt handler for each slot in the xPortStatus array. */
\r
272 #define COM_IRQ_WRAPPER(N) \
\r
273 static void __interrupt COM_IRQ##N##_WRAPPER( void ) \
\r
275 portDISABLE_INTERRUPTS(); \
\r
276 if( sComPortISR( xPortStatus[##N##] ) ) \
\r
278 portSWITCH_CONTEXT(); \
\r
282 COM_IRQ_WRAPPER( 0 )
\r
283 COM_IRQ_WRAPPER( 1 )
\r
284 COM_IRQ_WRAPPER( 2 )
\r
285 COM_IRQ_WRAPPER( 3 )
\r
286 COM_IRQ_WRAPPER( 4 )
\r
287 COM_IRQ_WRAPPER( 5 )
\r
288 COM_IRQ_WRAPPER( 6 )
\r
289 COM_IRQ_WRAPPER( 7 )
\r
290 COM_IRQ_WRAPPER( 8 )
\r
291 COM_IRQ_WRAPPER( 9 )
\r
292 COM_IRQ_WRAPPER( 10 )
\r
293 COM_IRQ_WRAPPER( 11 )
\r
294 COM_IRQ_WRAPPER( 12 )
\r
295 COM_IRQ_WRAPPER( 13 )
\r
296 COM_IRQ_WRAPPER( 14 )
\r
297 COM_IRQ_WRAPPER( 15 )
\r
299 static pxISR xISRs[ serMAX_IRQs ] =
\r
311 COM_IRQ10_WRAPPER,
\r
312 COM_IRQ11_WRAPPER,
\r
313 COM_IRQ12_WRAPPER,
\r
314 COM_IRQ13_WRAPPER,
\r
319 static pxISR xOldISRs[ serMAX_IRQs ] = { NULL };
\r
321 /*-----------------------------------------------------------*/
\r
324 xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength )
\r
328 /* Create a structure to handle this port. */
\r
329 pxPort = ( xComPort * ) pvPortMalloc( sizeof( xComPort ) );
\r
331 if( pxPort != NULL )
\r
333 /* Create the queues used by the comtest task. */
\r
334 pxPort->xRxedChars = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
335 pxPort->xCharsForTx = xQueueCreate( uxBufferLength, ( unsigned portBASE_TYPE ) sizeof( char ) );
\r
337 /* Create the test semaphore. This does nothing useful except test a feature of the scheduler. */
\r
338 vSemaphoreCreateBinary( pxPort->xTestSem );
\r
340 prvSetupPortHardware( pxPort, ePort, eWantedBaud, eWantedParity, eWantedDataBits, eWantedStopBits );
\r
347 /*-----------------------------------------------------------*/
\r
349 static void prvSetupPortHardware( xComPort *pxPort, eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits )
\r
352 unsigned long ulDivisor;
\r
353 unsigned char ucDivisorLow;
\r
354 unsigned char ucDivisorHigh;
\r
355 unsigned char ucCommParam;
\r
357 /* IRQ numbers - standard */
\r
358 if( ( ePort == serCOM1 ) || ( ePort == serCOM3 ) || ( ePort == serCOM5 ) || ( ePort == serCOM7 ) )
\r
360 pxPort->ucIRQ = serCOM1_STANDARD_IRQ;
\r
361 pxPort->sPort = 0x3f8;
\r
365 pxPort->ucIRQ = serCOM2_STANDARD_IRQ;
\r
366 pxPort->sPort = 0x2f8;
\r
369 /* Set up variables in port making it easy to see which sIn/o address is which */
\r
370 pxPort->usTransmitHoldReg = pxPort->sPort + serTRANSMIT_HOLD_OFFSET;
\r
371 pxPort->usReceiveDataRegister = pxPort->sPort + serRECEIVE_DATA_OFFSET;
\r
372 pxPort->usBaudRateDivisorLow = pxPort->sPort + serBAUD_RATE_DIVISOR_LOW_OFFSET;
\r
373 pxPort->usBaudRateDivisorHigh = pxPort->sPort + serBAUD_RATE_DIVISOR_HIGH_OFFSET;
\r
374 pxPort->usInterruptEnableReg = pxPort->sPort + serINTERRUPT_ENABLE_OFFSET;
\r
375 pxPort->usInterruptIDReg = pxPort->sPort + serINTERRUPT_ID_OFFSET;
\r
376 pxPort->usFIFOCtrlReg = pxPort->sPort + serFIFO_CTRL_OFFSET;
\r
377 pxPort->usLineCtrlReg = pxPort->sPort + serLINE_CTRL_OFFSET;
\r
378 pxPort->usModemCtrlReg = pxPort->sPort + serMODEM_CTRL_OFFSET;
\r
379 pxPort->usLineStatusReg = pxPort->sPort + serLINE_STATUS_OFFSET;
\r
380 pxPort->usModemStatusReg = pxPort->sPort + serMODEM_STATUS_OFFSET;
\r
381 pxPort->usSCRReg = pxPort->sPort + serSCR_OFFSET;
\r
383 /* Set communication parameters. */
\r
384 ulDivisor = serMAX_BAUD / ulBaudFromEnum[ eWantedBaud ];
\r
385 ucDivisorLow = ( unsigned char ) ulDivisor & ( unsigned char ) 0xff;
\r
386 ucDivisorHigh = ( unsigned char ) ( ( ( unsigned short ) ulDivisor >> 8 ) & 0xff );
\r
388 switch( eWantedParity )
\r
390 case serNO_PARITY: ucCommParam = 0x00;
\r
392 case serODD_PARITY: ucCommParam = 0x08;
\r
394 case serEVEN_PARITY: ucCommParam = 0x18;
\r
396 case serMARK_PARITY: ucCommParam = 0x28;
\r
398 case serSPACE_PARITY: ucCommParam = 0x38;
\r
400 default: ucCommParam = 0x00;
\r
404 switch ( eWantedDataBits )
\r
406 case serBITS_5: ucCommParam |= 0x00;
\r
408 case serBITS_6: ucCommParam |= 0x01;
\r
410 case serBITS_7: ucCommParam |= 0x02;
\r
412 case serBITS_8: ucCommParam |= 0x03;
\r
414 default: ucCommParam |= 0x03;
\r
418 if( eWantedStopBits == serSTOP_2 )
\r
420 ucCommParam |= 0x04;
\r
423 /* Reset UART into known state - Thanks to Bradley Town */
\r
424 portOUTPUT_BYTE( pxPort->usLineCtrlReg, 0x00 ); /* Access usTransmitHoldReg/RBR/usInterruptEnableReg */
\r
425 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, 0x00 ); /* Disable interrupts from UART */
\r
426 portOUTPUT_BYTE( pxPort->usModemCtrlReg, 0x04 ); /* Enable some multi-port cards */
\r
428 /* Code based on stuff from SVAsync lib. Clear UART Status and data registers
\r
429 setting up FIFO if possible */
\r
430 sIn = portINPUT_BYTE( pxPort->usSCRReg );
\r
431 portOUTPUT_BYTE( pxPort->usSCRReg, 0x55 );
\r
433 if( portINPUT_BYTE( pxPort->usSCRReg ) == 0x55 )
\r
435 /* The chip is better than an 8250 */
\r
436 portOUTPUT_BYTE( pxPort->usSCRReg, sIn ); /* Set usSCRReg back to what it was before */
\r
437 portINPUT_BYTE( pxPort->usSCRReg); /* Give slow motherboards a chance */
\r
439 /* Try and start the FIFO. It appears that some chips need a two call
\r
440 protocol, but those that don't seem to work even if you do start it twice.
\r
441 The first call is simply to start it, the second starts it and sets an 8
\r
442 byte FIFO trigger level. */
\r
443 portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x01 );
\r
444 portINPUT_BYTE( pxPort->usFIFOCtrlReg ); /* Give slow motherboards a chance to catch up */
\r
445 portOUTPUT_BYTE( pxPort->usFIFOCtrlReg, 0x87 );
\r
447 /* Check that the FIFO initialised */
\r
448 if( ( portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0xc0 ) != 0xc0 )
\r
450 /* It didn't so we assume it isn't there but disable it to be on the
\r
452 portOUTPUT_BYTE( pxPort->usInterruptIDReg, 0xfe );
\r
456 /* End of (modified) SVAsync code.
\r
457 Set interrupt parameters calculating mask for 8259 controller's
\r
458 IMR and number of interrupt handler for given irq level */
\r
459 if (pxPort->ucIRQ <= 7)
\r
461 /* if 0<=irq<=7 first IMR address used */
\r
462 pxPort->ucInterruptEnableMast = ~(0x01 << pxPort->ucIRQ);
\r
463 pxPort->usIRQVector = pxPort->ucIRQ + 8;
\r
464 pxPort->us8259InterruptMaskReg = serIMR_8259_0;
\r
465 pxPort->us8259InterruptServiceReg = serISR_8259_0;
\r
469 pxPort->ucInterruptEnableMast = ~( 0x01 << ( pxPort->ucIRQ % 8 ) );
\r
470 pxPort->usIRQVector = 0x70 + ( pxPort->ucIRQ - 8) ;
\r
471 pxPort->us8259InterruptMaskReg = serIMR_8259_1;
\r
472 pxPort->us8259InterruptServiceReg = serISR_8259_1;
\r
475 /* Set Port Toggle to usBaudRateDivisorLow/usBaudRateDivisorHigh registers
\r
476 to set baud rate */
\r
477 portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam | 0x80 );
\r
478 portOUTPUT_BYTE( pxPort->usBaudRateDivisorLow, ucDivisorLow );
\r
479 portOUTPUT_BYTE( pxPort->usBaudRateDivisorHigh, ucDivisorHigh );
\r
481 /* reset usLineCtrlReg and Port Toggleout */
\r
482 portOUTPUT_BYTE( pxPort->usLineCtrlReg, ucCommParam & 0x7F );
\r
484 portENTER_CRITICAL();
\r
486 if( xPortStatus[ pxPort->ucIRQ ] == NULL )
\r
488 xPortStatus[ pxPort->ucIRQ ] = pxPort;
\r
491 xOldISRs[ pxPort->ucIRQ ] = _dos_getvect( pxPort->usIRQVector );
\r
492 _dos_setvect( pxPort->usIRQVector, xISRs[ pxPort->ucIRQ ] );
\r
494 /* enable interrupt pxPort->ucIRQ level */
\r
495 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
\r
497 /* And allow interrupts again now the hairy bit's done */
\r
498 portEXIT_CRITICAL();
\r
500 /* This version does not allow flow control. */
\r
501 portOUTPUT_BYTE( pxPort->usModemCtrlReg, serALL_MODEM_CTRL_INTERRUPTS );
\r
503 /* enable all communication's interrupts */
\r
504 portOUTPUT_BYTE( pxPort->usInterruptEnableReg, serALL_COMS_INTERRUPTS );
\r
506 /*-----------------------------------------------------------*/
\r
508 static short sComPortISR( const xComPort * const pxPort )
\r
510 short sInterruptID;
\r
512 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
513 extern void vComTestUnsuspendTask( void );
\r
515 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, ( portINPUT_BYTE( pxPort->us8259InterruptMaskReg) | ~pxPort->ucInterruptEnableMast ) );
\r
517 /* Decide which UART has issued the interrupt */
\r
518 sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg );
\r
520 /* service whatever requests the calling UART may have. The top 4 bits are
\r
521 either unused or indicate the presence of a functioning FIFO, which we don't
\r
522 need to know. So trim them off to simplify the switch statement below. */
\r
523 sInterruptID &= 0x0f;
\r
526 switch( sInterruptID )
\r
528 case 0x0c: /* Timeout
\r
529 Called when FIFO not up to trigger level but no activity for
\r
530 a while. Handled exactly as RDAINT, see below for
\r
534 cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
\r
535 xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
\r
537 /* Also release the semaphore - this does nothing interesting and is just a test.
\r
538 We first attempt to unsuspend the task to check the scheduler correctely detects
\r
539 this as an invalid call, then give the semaphore for real. */
\r
540 vComTestUnsuspendTask();
\r
541 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
543 } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
\r
546 case 0x06: /* LSINT */
\r
547 portINPUT_BYTE( pxPort->usLineStatusReg );
\r
550 case 0x04: /* RDAINT */
\r
551 /* The usInterruptIDReg flag tested above stops when the
\r
552 FIFO is below the trigger level rather than empty, whereas
\r
553 this flag allows one to empty it: (do loop because there
\r
554 must be at least one to read by virtue of having got here.) */
\r
557 cIn = ( char ) portINPUT_BYTE( pxPort->usReceiveDataRegister );
\r
558 xQueueSendFromISR( pxPort->xRxedChars, &cIn, &xHigherPriorityTaskWoken );
\r
560 /* Also release the semaphore - this does nothing interesting and is just a test.
\r
561 We first attempt to unsuspend the task to check the scheduler correctely detects
\r
562 this as an invalid call, then give the semaphore for real. */
\r
563 vComTestUnsuspendTask();
\r
564 xSemaphoreGiveFromISR( pxPort->xTestSem, &xHigherPriorityTaskWoken );
\r
566 } while( portINPUT_BYTE( pxPort->usLineStatusReg ) & 0x01 );
\r
569 case 0x02: /* serTRANSMIT_HOLD_EMPTY_INT */
\r
570 if( xQueueReceiveFromISR( pxPort->xCharsForTx, &cOut, &xHigherPriorityTaskWoken ) != pdTRUE )
\r
572 /* Queue empty, nothing to send */
\r
573 vInterruptOff( pxPort, serTRANSMIT_HOLD_EMPTY_INT);
\r
577 portOUTPUT_BYTE( pxPort->usTransmitHoldReg, ( short ) cOut );
\r
581 case 0x00: /* MSINT */
\r
582 portINPUT_BYTE( pxPort->usModemStatusReg );
\r
586 /* Get the next instruction, trimming as above */
\r
587 sInterruptID = portINPUT_BYTE( pxPort->usInterruptIDReg ) & 0x0f;
\r
589 } while( !( sInterruptID & 0x01 ) );
\r
591 if( pxPort->ucIRQ > 7 )
\r
593 portOUTPUT_BYTE( 0xA0, 0x60 + ( pxPort->ucIRQ & 0x07 ) );
\r
594 portOUTPUT_BYTE( 0x20, 0x62);
\r
598 portOUTPUT_BYTE( 0x20, 0x60 + pxPort->ucIRQ );
\r
601 portOUTPUT_BYTE( pxPort->us8259InterruptMaskReg, portINPUT_BYTE( pxPort->us8259InterruptMaskReg ) & pxPort->ucInterruptEnableMast );
\r
603 /* If posting any of the characters to a queue woke a task that was blocked on
\r
604 the queue we may want to return to the task just woken (depending on its
\r
605 priority relative to the task this ISR interrupted. */
\r
606 return xHigherPriorityTaskWoken;
\r
608 /*-----------------------------------------------------------*/
\r
610 portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, char *pcRxedChar, portTickType xBlockTime )
\r
612 /* Get the next character from the buffer, note that this routine is only
\r
613 called having checked that the is (at least) one to get */
\r
614 if( xQueueReceive( pxPort->xRxedChars, pcRxedChar, xBlockTime ) )
\r
623 /*-----------------------------------------------------------*/
\r
625 portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, char cOutChar, portTickType xBlockTime )
\r
627 if( xQueueSend( pxPort->xCharsForTx, &cOutChar, xBlockTime ) != pdPASS )
\r
632 vInterruptOn( pxPort, serTRANSMIT_HOLD_EMPTY_INT );
\r
636 /*-----------------------------------------------------------*/
\r
638 void vSerialPutString( xComPortHandle pxPort, const char * const pcString, unsigned short usStringLength )
\r
641 const portTickType xNoBlock = ( portTickType ) 0;
\r
643 /* Stop warnings. */
\r
644 ( void ) usStringLength;
\r
646 pcNextChar = ( char * ) pcString;
\r
647 while( *pcNextChar )
\r
649 xSerialPutChar( pxPort, *pcNextChar, xNoBlock );
\r
653 /*-----------------------------------------------------------*/
\r
655 portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort )
\r
657 const portTickType xBlockTime = ( portTickType ) 0xffff;
\r
659 /* This function does nothing interesting, but test the
\r
660 semaphore from ISR mechanism. */
\r
661 return xSemaphoreTake( xPort->xTestSem, xBlockTime );
\r
663 /*-----------------------------------------------------------*/
\r
665 void vSerialClose( xComPortHandle xPort )
\r
667 portENTER_CRITICAL();
\r
669 /* Turn off the interrupts. */
\r
670 portOUTPUT_BYTE( xPort->usModemCtrlReg, serNO_INTERRUPTS );
\r
671 portOUTPUT_BYTE( xPort->usInterruptEnableReg, serNO_INTERRUPTS );
\r
673 /* Put back the original ISR. */
\r
674 _dos_setvect( xPort->usIRQVector, xOldISRs[ xPort->ucIRQ ] );
\r
676 /* Remove the reference in the array of xComPort structures. */
\r
677 xPortStatus[ xPort->ucIRQ ] = NULL;
\r
679 /* Delete the queues. */
\r
680 vQueueDelete( xPort->xRxedChars );
\r
681 vQueueDelete( xPort->xCharsForTx );
\r
683 vPortFree( ( void * ) xPort );
\r
685 portEXIT_CRITICAL();
\r