• /* at91UART.c - AT91RM9200 serial driver */  
  •   
  • /* Copyright 2003-2004 Coordinate Co., Ltd. */  
  • /* Copyright 1984-2002 Wind River Systems, Inc. */  
  •   
  • /* 
  • modification history 
  • -------------------- 
  • 01a,28jul04,cor  created from original at91Sio.c. 
  • */  
  •   
  • /* 
  • .SH TODO 
  •  
  •  - Replace the documentation for this template driver with documentation 
  • for the driver being written.   
  •  
  •  - Begin with an overview of the complete device.  Indicate if the new driver 
  • only implements a sub-section of the whole device or not. 
  •  
  •  - Describe all of the operating modes of the device, and indicate which 
  • ones this driver implements. 
  •  
  •  - Document the device initialization steps to be used in the BSP to create 
  • and initialize the device.  Document all the macros that 
  • can be used to customize the driver to a particular hardware environment. 
  •  
  •  - Document anything that will help the user to understand how this device 
  • works and interacts with this driver. 
  •  
  • .SH TEMPLATE OVERVIEW 
  • This is a template serial driver. It can be used as a starting point 
  • when writing new drivers for VxWorks version 5.4 or later. 
  •  
  • These drivers support new functionality not found in the older style 
  • serial drivers. First, they provide an interface for setting hardware 
  • options; e.g., the number of stop bits, data bits, parity, etc. 
  • Second, they provide an interface for polled communication which 
  • can be used to provided external mode debugging (i.e., ROM monitor 
  • style debugging) over a serial line. Currently only asynchronous mode 
  • drivers are supported. 
  •  
  • Throughout this file the word "template" is used in place of a real 
  • device name, which by convention uses the first letter of the 
  • manufacturers name followed by the part number. For example, the 
  • Zilog 8530 serial device would have a data structure called a 
  • Z8530_CHAN, rather than TEMPLATE_CHAN. 
  •  
  • .SH CALLBACKS 
  • Servicing a "transmitter ready" interrupt involves making a callback to a 
  • higher level library in order to get a character to transmit. 
  • By default, this driver installs dummy callback routines which do 
  • nothing. A higher layer library that wants to use this driver (e.g., ttyDrv) 
  • will install its own callback routines using the SIO_INSTALL_CALLBACK 
  • ioctl command. (See below). 
  •  
  • The prototype for the transmit data callback SIO_CALLBACK_GET_TX_CHAR is: 
  • .CS 
  •     int sioTxCharGet 
  •     ( 
  •     void * arg,      /@ callback argument @/ 
  •     char * pChar         /@ ptr to data location @/ 
  •     ) 
  • .CE 
  • This callback routine should fetch the next character to send and store it 
  • in the location pointed to by pChar.  It returns OK to indicate that a 
  • character is ready and should be sent.  It returns ERROR to indicate that 
  • no character was available and the transmitter can be placed in an idle state. 
  •  
  • Likewise, a receiver interrupt handler makes a callback to pass the 
  • character to the higher layer library.  It will be called by the driver 
  • for each character received.  This routine should capture the data and pass 
  • it along to other layers and eventually to the user. 
  •  
  • The prototype for the receive data callback SIO_CALLBACK_PUT_RCV_CHAR is: 
  • .CS 
  •     void sioRxCharPut 
  •     ( 
  •     void * arg,      /@ callback argument @/ 
  •     char data        /@ data byte @/ 
  •     ) 
  • .CE 
  • A new error handling callback has been added SIO_CALLBACK_ERROR. This driver 
  • should use this callback to inform the higher layer about error conditions. 
  • The prototype for this callback is: 
  • .CS 
  •     void sioErrorRtn 
  •     ( 
  •     void * arg,      /@ callback argument @/ 
  •     int code,        /@ error code @/ 
  •     void * pData,        /@ opt dev specific data @/ 
  •     int dataSize         /@ opt size of data in bytes @/ 
  •     ) 
  • .CE 
  • The available error codes for this callback are: 
  • .CS 
  •     SIO_ERROR_FRAMING    /@ (1) Framing error @/ 
  •     SIO_ERROR_PARITY     /@ (2) Parity error @/ 
  •     SIO_ERROR_OFLOW  /@ (3) data overflow @/ 
  •     SIO_ERROR_UFLOW  /@ (4) data underflow @/ 
  •     SIO_ERROR_CONNECT    /@ (5) connection made @/ 
  •     SIO_ERROR_DISCONNECT /@ (6) connection lost @/ 
  •     SIO_ERROR_NO_CLK     /@ (7) clock lost @/ 
  •     SIO_ERROR_UNKNWN     /@ (8) other errors @/ 
  • .CE 
  • For engineering purposes, the driver may return device specific data in 
  • the form of a data buffer. The argument pData is the location of the buffer 
  • and dataSize is its size, in bytes.  The data is not guaranteed to be static 
  • so it should be copied to a static buffer for safekeeping. 
  •  
  • .SH MODES 
  • Ideally the driver should support both polled and interrupt modes, and be 
  • capable of switching modes dynamically. However this is not required. 
  • VxWorks will be able to support a tty device on this driver even if 
  • the driver only supports interrupt mode. 
  • Polled mode is provided solely for WDB system mode usage.  Users can use 
  • the polled mode interface directly, but there is no clear reason for doing so. 
  • Normal access to SIO devices through ttyDrv only uses interrupt mode. 
  •  
  • For dynamically switchable drivers, be aware that the driver may be 
  • asked to switch modes in the middle of its input ISR. A driver's input ISR 
  • will look something like this: 
  •  
  •    inChar = *pDev->dr;          /@ read a char from data register @/ 
  •    *pDev->cr = GOT_IT;          /@ acknowledge the interrupt @/ 
  •    pDev->putRcvChar (...);      /@ give the character to the higher layer @/ 
  •  
  • If this channel is used as a communication path to an external mode 
  • debug agent, and if the character received is a special "end of packet" 
  • character, then the agent's callback will lock interrupts, switch 
  • the device to polled mode, and use the device in polled mode for awhile. 
  • Later on the agent will unlock interrupts, switch the device back to 
  • interrupt mode, and return to the ISR. 
  • In particular, the callback can cause two mode switches, first to polled mode 
  • and then back to interrupt mode, before it returns. 
  • This may require careful ordering of the callback within the interrupt 
  • handler. For example, you may need to acknowledge the interrupt before 
  • invoking the callback. 
  •  
  • .SH USAGE 
  • The driver is typically called only by the BSP. The directly callable 
  • routines in this module are templateSioCreate(), templateSioDestroy(). 
  •  
  • .SH BSP 
  • By convention all the BSP-specific serial initialization is performed in 
  • a file called sysSerial.c, which is #include'ed by sysLib.c. 
  •  
  • This driver can be customized by redefining the macros SYS_SIO_READ8 and 
  • SYS_SIO_WRITE8.  These two macros are used for all accesses to the 
  • actual chip.  If not defined, the source code will assume a simple memory 
  • mapped device using byte read/write access to all registers. 
  •  
  • The macros SYS_SIO_INT_CONNECT, SYS_SIO_INT_DISCONNECT, SYS_SIO_INT_ENABLE, 
  • and SYS_SIO_PROBE can be redefined by the BSP to perform basic low level 
  • routines with the same calling sequence as intConnect(), intConnect(), 
  • intEnable(), and vxMemProbe(). 
  •  
  • .SH TESTING 
  • The interrupt driven interface can be tested in the usual way; VxWorks 
  • prints to the serial console when it comes up, so seeing the usual VxWorks 
  • output on power-up shows that the driver is basically working. 
  • The VxWorks portkit test can be used to perform a more strenuous test. 
  •  
  • The polled interface should be easy enough to verify - you should be able 
  • to call the channels SIO_MODE_SET ioctl to put it in polled mode.  Note 
  • that the usual print tools won't work with a serial channel in polled mode. 
  • Some agent has to perform a polling loop to handle input/output on a 
  • character by character basis.  It is not automatic.  The WDB agent 
  • performs its own polling loop when it switches the WDB serial line into 
  • polled mode.  
  •  
  • The dynamic mode switching can be verified using the tornado tools. 
  • Reconfigure the agent to use the WDB_COMM_UDLP_SLIP communication path (see 
  • the Configuration section in the VxWorks run-time Guide for details). 
  • Start VxWorks, and connect the tgtsvr to the agent using the wdbserial 
  • backend (see the Tornado Users Guide for details). 
  • Start the wtxtcl shell as follows: 
  •     % wtxtcl 
  • From the tcl prompt, attach to the target server: 
  •     wtxtcl.ex> wtxToolAttach <tgtsvr name> 
  • Tell the agent to switch to external mode, and verify the reply is OK (0). 
  •     wtxtcl.ex>wtxAgentModeSet 2 
  •     0 
  • Ask the agent to suspend the system (the request will reach the agent in 
  • interrupt mode, but the reply will be sent in polled mode): 
  •     wtxtcl.ex>wtxContextSuspend 0 0 
  •     0 
  • At this point the target will be suspended. The console should apprear 
  • frozen (if the board has a console device), and you will not be able to 
  • "ping" the target's network interface. 
  • Resume the target: 
  •     wtxtcl.ex>wtxContextResume 0 0 
  •     0 
  • The target should now be running again, so you should be able to type into 
  • the console (if the board has a console device) and ping the targets network 
  • interface from the host. 
  •  
  • .SH INCLUDE FILES: 
  • at91Sio.h sioLib.h 
  • */  
  •   
  • #include "vxWorks.h"  
  • #include "intLib.h"  
  • #include "errnoLib.h"  
  • #include "iosLib.h"     /* For S_iosLib_DEVICE_NOT_FOUND */  
  • #include "cacheLib.h"  
  • #include "stdlib.h" /* malloc/free */  
  • #include "stdio.h"  /* for printf */  
  • #include "vxLib.h"  /* for vxMemProbe */  
  • #include "at91.h"  
  • #include "at91rm9200.h"  
  • #include "at91If.h"  
  • #include "at91Sio.h"  
  • #include "arch\arm\ivarm.h"  
  •   
  • #define DEFAULT_BAUD    9600  
  •   
  •   
  • /* channel control register (write) definitions */  
  •   
  • #if 0  
  •   
  • /* TODO - These are just made up bit defines for a mythical device! */  
  •   
  • #define TEMPLATE_RESET_CHIP 0x07    /* reset all */  
  • #define TEMPLATE_RESET_TX   0x01    /* reset the transmitter */  
  • #define TEMPLATE_RESET_ERR  0x02    /* reset error condition */  
  • #define TEMPLATE_RESET_INT  0x04    /* acknoledge the interrupt */  
  • #define TEMPLATE_INT_ENABLE 0x08    /* enable interrupts */  
  • #define TEMPLATE_TX_ENABLE  0x10    /* enable interrupts */  
  • #define TEMPLATE_RX_ENABLE  0x20    /* enable interrupts */  
  •   
  • /* channel status register (read) definitions */  
  •   
  • #define TEMPLATE_CR_OKAY    0x00    /* no error conditions */  
  • #define TEMPLATE_CR_TX_READY    0x01    /* txmitter ready for another char */  
  • #define TEMPLATE_CR_TX_ERROR    0x04    /* txmitter int enable */  
  • #define TEMPLATE_CR_RX_AVAIL    0x10    /* character has arrived */  
  • #define TEMPLATE_CR_RX_ERROR    0x40    /* receiver error */  
  •   
  • /* channel modem status register definitions */  
  •   
  • #define TEMPLATE_MSR_RTS    0x1 /* RTS signal asserted */  
  • #define TEMPLATE_MSR_DTR    0x2 /* DTR signal asserted */  
  • #define TEMPLATE_MSR_DSR    0x4 /* DSR signal asserted */  
  • #define TEMPLATE_MSR_CTS    0x8 /* CTS signal asserted */  
  • #define TEMPLATE_MSR_CD     0x10    /* CD signal asserted */  
  •   
  • /* input and output signals */  
  •   
  • #define TEMPLATE_ISIG_MASK  (SIO_MODEM_CTS|SIO_MODEM_DSR|SIO_MODEM_CD)  
  • #define TEMPLATE_OSIG_MASK  (SIO_MODEM_RTS|SIO_MODEM_DTR)  
  •   
  • /* channel modem control register definitions */  
  •   
  • #define TEMPLATE_MC_RTS     0x1 /* enable RTS */  
  • #define TEMPLATE_MC_DTR     0x2 /* enable DTR */  
  •   
  • #endif  
  •   
  • #define AT91_BAUD_MIN   110  
  • #define AT91_BAUD_MAX   921600  
  •   
  •   
  • /* Hardware abstraction macros */  
  •   
  • #if 0  
  • /* Macros from BSP */  
  •   
  • #define SYS_SIO_READ8(addr, pData) \  
  •     (*pData = *(UINT8 *)(addr))  
  • #define SYS_SIO_WRITE8(addr, data) \  
  •     (*(UINT8 *)addr = data)  
  • #define SYS_SIO_INT_CONNECT(vec, rtn, arg) \  
  •     intConnect ((VOIDFUNCPTR *)vec, (VOIDFUNCPTR)rtn, (int)arg)  
  • #define SYS_SIO_INT_DISCONNECT(vec, rtn, arg) \  
  •     intConnect ((VOIDFUNCPTR *)vec, NULL, 0)  
  • #define SYS_SIO_INT_ENABLE(level) \  
  •     intEnable (level)  
  • #define SYS_SIO_PROBE(addr, mode, size, pData) \  
  •     vxMemProbe (addr, mode, size, pData)  
  • /* #define CACHE_PIPE_FLUSH() */  
  •   
  •   
  • /* Local driver abstractions, following bus/adaptor model */  
  •   
  • #define TEMPLATE_SIO_READ8(pChan, reg, result) \  
  •     SYS_SIO_READ8(((pChan->ioBase) + reg),result)  
  •   
  • #define TEMPLATE_SIO_WRITE8(pChan, reg, data) \  
  •     SYS_SIO_WRITE8(((pChan->ioBase) + reg),data)  
  •   
  • #define TEMPLATE_SIO_INT_CONNECT(pChan, vec, rtn, arg) \  
  •     do { \  
  •     SYS_SIO_INT_CONNECT((pChan->vecBase) + vec, rtn, arg); \  
  •     SYS_SIO_INT_ENABLE(pChan->intLevel); \  
  •     } while (0)  
  •   
  • #define TEMPLATE_INT_DISCONNECT(pChan, vec, rtn, arg) \  
  •     SYS_SIO_INT_DISCONNECT(((pChan)->vecBase + vec), rtn, arg)  
  •     /* Do NOT disable interrupt level for disconnect */  
  •   
  • #define TEMPLATE_PROBE(pChan, offset, dir, size, ptr) \  
  •     SYS_SIO_PROBE((char *)((pChan)->ioBase + offset), dir, size, ptr)  
  •   
  • #define TEMPLATE_PIPE_FLUSH(pChan) \  
  •     CACHE_PIPE_FLUSH()  
  •   
  • #endif   
  •   
  • /* forward static declarations */  
  •   
  •   
  • LOCAL int   at91TxStartup (SIO_CHAN * pSioChan);  
  • LOCAL int   at91CallbackInstall (SIO_CHAN *pSioChan, int callbackType,  
  •             STATUS (*callback)(void *,...), void *callbackArg);  
  • LOCAL int   at91PollOutput (SIO_CHAN *pSioChan, char    outChar);  
  • LOCAL int   at91PollInput (SIO_CHAN *pSioChan, char *thisChar);  
  • LOCAL int   at91Ioctl (SIO_CHAN *pSioChan, int request, void *arg);  
  • LOCAL STATUS    at91DummyTxCallback (void *, char *);  
  • LOCAL void  at91DummyRxCallback (void *, char);  
  • LOCAL void  at91DummyErrCallback (void *, int, void *, int);  
  • LOCAL void  at91UARTIntRx (AT91_UART_CHAN * pChan);  
  • LOCAL void  at91UARTIntTx (AT91_UART_CHAN * pChan);  
  • LOCAL STATUS    at91Probe (AT91_UART_CHAN * pChan);  
  • /*  
  • LOCAL STATUS    at91Verify (AT91_UART_CHAN *pChan); 
  • LOCAL int   at91MstatGet (AT91_UART_CHAN *pChan); 
  • LOCAL int   at91MstatSetClr (AT91_UART_CHAN *pChan, UINT bits, BOOL setFlag); 
  • */  
  • /* local variables */  
  •   
  • LOCAL   SIO_DRV_FUNCS at91UARTDrvFuncs =  
  •     {  
  •     at91Ioctl,  
  •     at91TxStartup,  
  •     at91CallbackInstall,  
  •     at91PollInput,  
  •     at91PollOutput  
  •     };  
  •   
  • /****************************************************************************** 
  • * at91UARTDevInit - initialise an AT91_SIO channel 
  • * This routine initialises some SIO_CHAN function pointers and then resets 
  • * the chip to a quiescent state.  Before this routine is called, the BSP 
  • * must already have initialised all the device addresses, etc. in the 
  • * AT91_UART_CHAN structure. 
  • * RETURNS: N/A 
  • */  
  •   
  • void at91UARTDevInit  
  •     (  
  •     AT91_UART_CHAN * pChan  /* ptr to AT91_UART_CHAN describing this channel */  
  •     )  
  •     {  
  •     AT91PS_USART pUsart;    /* point to UART register index by ioBase of pChan */  
  •     AT91PS_PIO pPIOA, pPIOB;    /* point to  PIO Controller A, B */  
  •     AT91_UART_PARAS *pParas;  
  •   
  •     int oldIntLvl;  
  •   
  •     if (pChan != NULL)  
  •     {  
  •     pChan->sio.pDrvFuncs = &at91UARTDrvFuncs;  
  •   
  •     /* install dummy driver callbacks */  
  •   
  •     pChan->getTxChar    = at91DummyTxCallback;  
  •     pChan->putRcvChar   = at91DummyRxCallback;  
  •     pChan->errorRtn      = at91DummyErrCallback;  
  •   
  •     pChan->intConnect    = FALSE;    /* int's not connected yet */  
  •   
  •     /* setting polled mode is one way to make the device quiet */  
  •     pChan->mode = SIO_MODE_POLL; /* setting mode to poll mode */  
  •       
  •     if (at91Probe (pChan) == OK)  
  •         {  
  •         oldIntLvl = intLock();  
  •           
  •         pParas = pChan->pUart;  
  •         pChan->ioBase = pParas->ioBase;   /* set parameter of pParas to pChan for easy usage */  
  •         pUsart = (AT91PS_USART)(pParas->ioBase);  
  •         pPIOA = (AT91PS_PIO)(AT91RM9200_PIOA_BASE_ADDR);  
  •         pPIOB = (AT91PS_PIO)(AT91RM9200_PIOB_BASE_ADDR);  
  •   
  •         *(volatile unsigned int *)AT91RM9200_PMC_PCER = 1 << pParas->uartId;   /* enable clock */  
  •         pPIOA->PIO_ASR = pParas->PIOA_ASR;  
  •         pPIOA->PIO_BSR = pParas->PIOA_BSR;  
  •         pPIOA->PIO_PDR = pParas->PIOA_ASR | pParas->PIOA_BSR;  
  •         pPIOB->PIO_ASR = pParas->PIOA_ASR;  
  •         pPIOB->PIO_BSR = pParas->PIOA_BSR;   
  •         pPIOB->PIO_PDR = pParas->PIOB_ASR | pParas->PIOB_BSR;  
  •   
  •         pUsart->US_IDR = -1; /* disable all USART interrupts */  
  •         /* reset & disble transmit and receive */  
  •         pUsart->US_CR = AT91RM9200_US_CR_RSTRX | AT91RM9200_US_CR_RSTTX | \  
  •                         AT91RM9200_US_CR_RXDIS | AT91RM9200_US_CR_TXDIS;      
  •         pUsart->US_BRGR = AT91_MASTER_CLOCK / (pParas->baudRate) / 16;    /* 115200 baud with 18.432 Mhz Crystal */  
  •   
  •         pUsart->US_RTOR = AT91_USART_RX_TIMEOUT; /* Receiver Time-out Register */  
  •         pUsart->US_TTGR = 0; /* Transmitter timeguart is disabled */      
  •         pUsart->US_FIDI = 0; /* in ISO7816 mode, BRG generates no signal */  
  •   
  •         /* Disable PDC Channels for DBGU and Initial the State of it */  
  •         pUsart->US_PTCR = AT91RM9200_PDC_PTCR_TXTDIS | AT91RM9200_PDC_PTCR_RXTDIS;  
  •   
  •         pUsart->US_TNPR = 0;  
  •         pUsart->US_TNCR = 0; /* clear out next transmit counts */  
  •           
  •         pUsart->US_RNPR = 0;  
  •         pUsart->US_RNCR = 0; /* clear out next receive counts */  
  •           
  •         pUsart->US_TPR = 0;  
  •         pUsart->US_TCR = 0;  /* clear out transmit counts */  
  •   
  •         pUsart->US_RPR = 0;  
  •         pUsart->US_RCR = 0;  /* clear out receive counts */  
  •   
  •         pUsart->US_MR = pParas->uartOption;   /* default mode */  
  •               
  •         intUnlock(oldIntLvl);  
  •   
  •         pChan->mode = SIO_MODE_INT;  
  •   
  •         /* Enable transmit and received of UART Device */  
  •         pUsart->US_CR = AT91RM9200_US_CR_RXEN | AT91RM9200_US_CR_TXEN;  
  •           
  •         }  
  •     else  
  •         {  
  •         /* Whoops, device is not there! */  
  •   
  •         free ((char *)pChan);  
  •         errnoSet (S_iosLib_DEVICE_NOT_FOUND);  
  •           
  •         return;  
  •         }  
  •     }  
  •   
  •     return;  
  •     }  
  •   
  • /******************************************************************************* 
  • * at91UARTInt - handle an AT91RM9200 UART interrupt 
  • * This routine is called to handle AT91RM9200 UART interrupts. 
  • */  
  •   
  • void at91UARTInt  
  •     (  
  •     AT91_UART_CHAN *pChan  
  •     )  
  •     {  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */      
  •     UINT32  status;  
  •     int errorCode = SIO_ERROR_NONE;  
  •   
  •     status = pUsart->US_CSR;  
  •   
  •     if (status)  
  •     {  
  •         /* we can make below process several times when TXRDY or RXRDY is there */  
  •           
  •         if (status & (AT91RM9200_US_SR_RXRDY))  
  •             at91UARTIntRx (pChan);  
  •   
  •         /* Check for error conditions */  
  •   
  •         if (status & (AT91RM9200_US_SR_PARE | AT91RM9200_US_SR_FRAME | AT91RM9200_US_SR_OVRE))  
  •         {  
  •         /* 
  •          * Determine precise error condition and perform 
  •          * recovery actions. 
  •          */  
  •             pUsart->US_CR = AT91RM9200_US_CR_RSTSTA;  
  •               
  •   
  •             /* 
  •              * If needed, you should acknowledge or reset the interrupt source 
  •              * as soon as possible, usually before passing any error conditions 
  •              * upstream. 
  •              */  
  •             if (status & (AT91RM9200_US_SR_PARE))  
  •                 {  
  •                     errorCode = SIO_ERROR_PARITY;  
  •                 }  
  •             else if (status & (AT91RM9200_US_SR_FRAME))  
  •                 {  
  •                     errorCode = SIO_ERROR_FRAMING;  
  •                 }  
  •               
  •             if (errorCode != SIO_ERROR_NONE)  
  •             (*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);  
  •   
  •             if (status & (AT91RM9200_US_SR_OVRE))  
  •                 {  
  •                     errorCode = SIO_ERROR_OFLOW;  
  •                 (*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);  
  •                 }  
  •         }  
  •   
  •         if (status & (AT91RM9200_US_SR_TXRDY))  
  •             at91UARTIntTx (pChan);  
  •     }  
  •   
  •     }  
  •   
  • /****************************************************************************** 
  • * at91UARTIntRx - handle a channel's receive-character interrupt 
  • * RETURNS: N/A 
  • */   
  •   
  • LOCAL void at91UARTIntRx  
  •     (  
  •     AT91_UART_CHAN *    pChan       /* channel generating the interrupt */  
  •     )  
  •     {  
  •     char   inChar;  /* receive data */  
  •     UINT32 rxStatus = 0; /* receive status */  
  • /*     
  •     STATUS status = OK; 
  •     int errorCode = SIO_ERROR_NONE; 
  • */  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */      
  •   
  •     /* 
  •      * 
  •      * Get status and data from the device. Determine if valid data is ready 
  •      * or not. 
  •      * 
  •      * For PCI devices, do an immediate return if device is not asserting 
  •      * an interrupt. 
  •      */  
  •   
  •     rxStatus = pUsart->US_CSR;  
  •       
  •     while (rxStatus & AT91RM9200_US_SR_RXRDY)  
  •         {  
  •         inChar = pUsart->US_RHR;  
  •         /* RXRDY bit in US_CSR will be clear when RHR is read */  
  •           
  •         /* send data character upstream */  
  •         (*pChan->putRcvChar) (pChan->putRcvArg, inChar);  
  •   
  •         if (pChan->mode != SIO_MODE_INT) break;  
  •   
  •         rxStatus = pUsart->US_CSR;  
  •         }  
  • #if 0   /* will be processed in at91UARTIntErr */  
  •     if (status == ERROR)  
  •     {  
  •     /* send error notification upstream */  
  •   
  •     (*pChan->errorRtn) (pChan->errorArg, SIO_ERROR_UNKNWN, NULL, 0);  
  •     }  
  • #endif   
  • #if 0 /* Keyboard emulation code */  
  •   
  •     /* 
  •      * TODO - For a keyboard type device we would map the raw scan code 
  •      * to ASCII, or other mapping.  Do that here. 
  •      */  
  •   
  •     if (pChan->scanMode == SIO_KYBD_MODE_ASCII)  
  •         inChar = templateAsciiTbl[(UINT8)inChar];  
  • #endif  
  •   
  •     }  
  •   
  • /****************************************************************************** 
  • * at91UARTIntTx - handle a channels transmitter-ready interrupt 
  • * RETURNS: N/A 
  • */   
  •   
  • LOCAL void at91UARTIntTx  
  •     (  
  •     AT91_UART_CHAN *pChan       /* channel generating the interrupt */  
  •     )  
  •     {  
  •     char    outChar;  
  •     UINT32 txStatus;    /* status of transmit */  
  •     /* BOOL txReady = TRUE; */  
  •     int     errorCode = SIO_ERROR_NONE;  
  •   
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);;    /* point to UART register index by ioBase of pChan */          
  •   
  •     /* 
  •      * Check the Tx status 
  •      * 
  •      * For PCI devices, do an immediate return if device is not asserting 
  •      * an interrupt. 
  •      */  
  •   
  • #if 0  
  •   
  •     /* Check for error conditions */  
  •       
  •     if (crData & TEMPLATE_CR_TX_ERROR)  
  •     {  
  •     /* 
  •      * TODO - Typically you should determine the precise error condition 
  •      * and perform all recovery operations here. 
  •      */  
  •   
  •     TEMPLATE_SIO_WRITE8 (pChan, TEMPLATE_CSR_ID, TEMPLATE_RESET_TX);  
  •   
  •     errorCode = SIO_ERROR_UNKNWN;  
  •   
  •     txReady = TRUE; /* set to false if xmitter is not ready now */  
  •     }  
  •       
  • #endif  
  •     /* 
  •      * If transmitter is okay and ready to send, lets see if there is a 
  •      * data character ready to be sent. 
  •      * 
  •      * If there's a character to transmit then write it out, else reset (idle) 
  •      * the transmitter. For chips with output FIFO's it is more efficient 
  •      * to fill the entire FIFO here. 
  •      */  
  •     txStatus = pUsart->US_CSR;  
  •   
  •     if (txStatus & AT91RM9200_US_SR_TXRDY)  
  •     {  
  •     if ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)  
  •         {  
  •         /* Output data to device.  */  
  •   
  •         pUsart->US_THR = outChar;  
  •         /* need to insert a wait time for transmit finished ? */  
  •             txStatus = pUsart->US_CSR;  
  •   
  •         /* 
  •          * If a device error occurs at this point, then 
  •          * isolate the precise error type and try to recover. 
  •          */  
  •         }  
  •     else  
  •         {  
  •         /* 
  •          * There is no more data to send. 
  •          * 
  •          * Put XMTR in an idle state. Higher layer 
  •          * will call TxStartup entry to resume xmit operations. 
  •          */  
  •   
  •         pUsart->US_IDR = AT91RM9200_US_INT_TXRDY;      
  •            /* 
  •            pUsart->US_CR = AT91RM9200_US_CR_TXDIS | AT91RM9200_US_CR_RSTTX; */ /* disable transmit */  
  •              
  •            /* break; */  
  •         }  
  •     }  
  •   
  •     /* 
  •      * If needed, you should acknowledge or reset the interrupt source 
  •      * as soon as possible, usually before passing any error conditions 
  •      * upstream. 
  •      */  
  •   
  •     /* US_TXRDY will be cleared when char is sent */  
  •   
  •     /* Pass any errorCodes upstream.  */  
  •   
  •     if (errorCode != SIO_ERROR_NONE)  
  •     {  
  •     (*pChan->errorRtn) (pChan->errorArg, errorCode, NULL, 0);  
  •     }  
  •     }  
  •   
  • #if 0  
  •   
  • /****************************************************************************** 
  • * at91UARTIntErr - handle a channels error interrupt 
  • * RETURNS: N/A 
  • */   
  •   
  • LOCAL void at91UARTIntErr  
  •     (  
  •     AT91_UART_CHAN *    pChan       /* channel generating the interrupt */  
  •     )  
  •     {  
  •   
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase);;    /* point to UART register index by ioBase of pChan */          
  •       
  •     UINT32 errStatus;  
  •   
  •     errStatus = pUsart->US_CSR;  
  •       
  •     /* 
  •      * Determine the precise error condition and perform recovery 
  •      * operations. 
  •      * 
  •      * For PCI devices, do an immediate return if device is not asserting 
  •      * an interrupt. 
  •      */  
  •   
  •     if (errStatus & (AT91C_US_PARE | AT91C_US_FRAME | AT91C_US_OVRE)  
  •     {  
  •   
  •   
  •     }  
  • }  
  • #endif   
  •   
  • /****************************************************************************** 
  • * templateTxStartup - start the interrupt transmitter 
  • * This routine exits to inform the device to start transmitting data again. 
  • * The actual data will be obtained by calling the TxCharGet callback routine. 
  • * This routine is usually just the same as the tx interrupt routine.  This 
  • * routine runs at task level context and does not have to be interrupt safe. 
  • * RETURNS: OK on success, ENOSYS if the device is polled-only, or 
  • * EIO on hardware error. 
  • */  
  •   
  • LOCAL int at91TxStartup  
  •     (  
  •     SIO_CHAN * pSioChan                 /* channel to start */  
  •     )  
  •     {  
  •     AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •       
  •     /* char outChar; */  
  •   
  •     /* This routine should only be called while in interrupt mode */  
  •     /* NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE 
  •        NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE 
  •        NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE 
  •        NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE 
  •      */  
  •     /* pChan->mode = SIO_MODE_POLL; */  
  •   
  •     if (pChan->mode == SIO_MODE_INT)  
  •         {  
  • #if 0  
  •         if (pChan->options & CLOCAL)  
  •             {  
  •             /* No modem control - start immediately */  
  •             }  
  •         else  
  •             {  
  •         /* 
  •          * Modem controls are active.  
  •          * 
  •          * If CTS is high, we can start immediately so just enable 
  •          * the TX interrupt. 
  •          * 
  •          * If CTS is low, then we cannot send now.  The driver 
  •          * should be set up to generate a TX interrupt when the CTS 
  •          * line returns to the active state. 
  •          */  
  •             }  
  •   
  •         /* 
  •      * Enable the correct interrupts. A TX interrupt should either 
  •      * occur immediately, or later when CTS becomes active.  That will start 
  •      * the flow of data. 
  •      * 
  •      * There are two usual methods here.  The first is to just enable 
  •      * TX interrupts, which should cause an immediate TX interrupt, which 
  •      * will begin fetching and sending characters. 
  •      * 
  •      * The second method is to call the getTxChara callback here, put 
  •      * the data to the transmitter directly, and then to enable TX 
  •      * interrupts to fetch and send additional characters. 
  •      */  
  • #endif   
  • #if 0  
  •     if ((pUsart->US_CSR & AT91C_US_TXRDY) && \  
  •         ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR))  
  •         {  
  •         /* Output data to device.  */  
  •   
  •         pUsart->US_THR = outChar;  
  •   
  •         /* 
  •          * If a device error occurs at this point, then 
  •          * isolate the precise error type and try to recover. 
  •          */  
  •         }  
  • #endif  
  •   
  •      /* intEnable(pChan->intLevel); */  
  •      /* pUsart->US_CR = AT91C_US_TXEN; */  
  •      pUsart->US_IER = AT91RM9200_US_INT_TXRDY;   /* we need set it again here ? */  
  •      return OK;  
  •         }  
  •     else  
  • /*      
  •     while ((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR) 
  •     { 
  •         while (EAGAIN == at91PollOutput ((SIO_CHAN *)pChan, outChar)); 
  •     } 
  • */      
  •     return ENOSYS;      /* Not valid for polled mode operation */  
  •   
  •     return (OK);  
  •     }  
  •   
  •   
  •   
  • /****************************************************************************** 
  • * at91CallbackInstall - install ISR callbacks to get/put chars 
  • * This driver allows interrupt callbacks for transmitting characters 
  • * and receiving characters. In general, drivers may support other 
  • * types of callbacks too. 
  • * RETURNS: OK on success, or ENOSYS for an unsupported callback type. 
  • */   
  •   
  • LOCAL int at91CallbackInstall  
  •     (  
  •     SIO_CHAN *  pSioChan,               /* channel */  
  •     int     callbackType,           /* type of callback */  
  •     STATUS  (*callback)(void *,...),  /* callback */  
  •     void *      callbackArg             /* parameter to callback */  
  •     )  
  •     {  
  •     AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;  
  •   
  •     switch (callbackType)  
  •     {  
  •     case SIO_CALLBACK_GET_TX_CHAR:  
  •         pChan->getTxChar = (STATUS (*)(void *, char *))callback;  
  •         pChan->getTxArg  = callbackArg;  
  •         return (OK);  
  •   
  •     case SIO_CALLBACK_PUT_RCV_CHAR:  
  •         pChan->putRcvChar    = (void (*)(void *, char))callback;  
  •         pChan->putRcvArg = callbackArg;  
  •         return (OK);  
  •   
  •     case SIO_CALLBACK_ERROR:  
  •         pChan->errorRtn  = (void (*)(void *, int, void *, int))callback;  
  •         pChan->errorArg  = callbackArg;  
  •         return (OK);  
  •   
  •     default:  
  •         return (ENOSYS);  
  •     }  
  •     }  
  •   
  • /******************************************************************************* 
  • * templatePollOutput - output a character in polled mode 
  • * Polled mode operation takes place without any kernel or other OS 
  • * services available.  Use extreme care to insure that this code does not 
  • * call any kernel services.  Polled mode is only for WDB system mode use. 
  • * Kernel services, semaphores, tasks, etc, are not available during WDB 
  • * system mode. 
  • * RETURNS: OK if a character arrived, EIO on device error, EAGAIN 
  • * if the output buffer if full. ENOSYS if the device is 
  • * interrupt-only. 
  • */  
  •   
  • LOCAL int at91PollOutput  
  •     (  
  •     SIO_CHAN *  pSioChan,  
  •     char    outChar  
  •     )  
  •     {  
  •     AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •       
  •     UINT32  status;  
  •   
  •     /* is the transmitter ready to accept a character? */  
  •   
  •     /* Read TX device status */  
  •   
  •     status = pUsart->US_CSR;  
  •   
  •     /* determine if transmitter is ready */  
  •   
  •     if (0x00 == (status & (AT91RM9200_US_SR_TXRDY)))  
  •     /* device is busy, try again later */  
  •         return (EAGAIN);  
  •       
  •     /*  transmit the character */  
  •     pUsart->US_THR = (AT91_REG)outChar;  
  •   
  •     return (OK);  
  •     }  
  •   
  • /****************************************************************************** 
  • * at91PollInput - poll the device for input 
  • * Polled mode operation takes place without any kernel or other OS 
  • * services available.  Use extreme care to insure that this code does not 
  • * call any kernel services.  Polled mode is only for WDB system mode use. 
  • * Kernel services, semaphores, tasks, etc, are not available during WDB 
  • * system mode. 
  • * RETURNS: OK if a character arrived, EIO on device error, EAGAIN 
  • * if the input buffer if empty, ENOSYS if the device is 
  • * interrupt-only. 
  • */  
  •   
  • LOCAL int at91PollInput  
  •     (  
  •     SIO_CHAN *  pSioChan,  
  •     char *  thisChar  
  •     )  
  •     {  
  •     AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •       
  •     UINT32  status;  
  •   
  •     /* Read RX device status */  
  •   
  •     status = pUsart->US_CSR;  
  •   
  •     /* Check if receive data is available */  
  •   
  •     if (0x00 == (status & (AT91RM9200_US_SR_RXRDY)))  
  •     {  
  •     return EAGAIN;  /* no input available at this time */  
  •     }  
  •   
  •     /* Check for receive error conditions */  
  •   
  •     if (0x00 != (status & (AT91RM9200_US_SR_PARE | AT91RM9200_US_SR_FRAME | AT91RM9200_US_SR_OVRE)))  
  •     {  
  •     /* Decode and handle the specific error condition */  
  •   
  •     pUsart->US_CR = AT91RM9200_US_CR_RSTSTA; /* reset receive of USART to clear error */  
  •   
  •     /* Do NOT call the error callback routine, just return EIO */  
  •   
  •     return EIO;  
  •     }  
  •   
  •         /* read character, store it, and return OK  */  
  •   
  •     *thisChar = (char)(pUsart->US_RHR);  
  •   
  •        return (OK);  
  •     }  
  •   
  • /****************************************************************************** 
  • * at91ModeSet - toggle between interrupt and polled mode 
  • * RETURNS: OK on success, EIO on unsupported mode. 
  • */  
  •   
  • LOCAL int at91ModeSet  
  •     (  
  •     AT91_UART_CHAN * pChan,     /* channel */  
  •     uint_t      newMode             /* new mode */  
  •     )  
  •     {  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •     AT91_UART_PARAS *pParas =  (AT91_UART_PARAS *)(pChan->pUart);  
  •      
  •     int oldIntLvl;  
  •       
  •     if ((newMode != SIO_MODE_POLL) && (newMode != SIO_MODE_INT))  
  •     return (EIO);  
  •   
  •     oldIntLvl = intLock();  
  •       
  •     /*   
  •      * use this function will made all the action done in  
  •      * at91IosDevInit be cancelled, so we can't do it now 
  •     pUsart->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX; 
  •     */  
  •     if (pChan->mode == SIO_MODE_INT)  
  •     {  
  •     /* switch device to interrupt mode */  
  •   
  •     if (pChan->intConnect == FALSE)  
  •         {  
  •         /* interconnect ISR to intvector */;  
  •         intConnect (INUM_TO_IVEC(pParas->vector), at91UARTInt, (int)pChan);  
  •         pChan->intConnect = TRUE;  
  •         }  
  •     /* enable interrupt of device */  
  •     pUsart->US_IER = AT91RM9200_US_INT_RXRDY | AT91RM9200_US_INT_PARE |AT91RM9200_US_INT_FRAME | AT91RM9200_US_INT_OVRE;  
  •     pUsart->US_IDR = AT91RM9200_US_INT_TXRDY;      
  •     /* we only enable receive and error interrupt 
  •     pUsart->US_IER = AT91RM9200_US_INT_RXRDY | AT91RM9200_US_INT_RXRDY |AT91RM9200_US_INT_PARE | AT91RM9200_US_INT_FRAME |AT91RM9200_US_INT_OVRE; 
  •     */  
  •     intEnable (pParas->intLevel);  
  •     }  
  •     else  
  •     {  
  •     /* switch device to polled mode */  
  •   
  •     /* disable interrupt of device */  
  •     pUsart->US_IDR = -1;     /* disable all interrupt */  
  •     intDisable (pParas->intLevel);  
  •     }  
  •   
  •     /* activate  the new mode */  
  •   
  •     pChan->mode = newMode;  
  •   
  •     intUnlock(oldIntLvl);  
  •   
  •     return (OK);  
  •     }  
  •   
  • #if 0  
  • /******************************************************************************* 
  • * templateHup - hang up the modem control lines  
  • * Resets the RTS and DTR signals. 
  • * RETURNS: OK always. 
  • */  
  •   
  • LOCAL STATUS at91Hup  
  •     (  
  •     AT91_UART_CHAN * pChan  /* pointer to channel */  
  •     )  
  •     {  
  •     /* 
  •      * TODO - Use global intLock if lockout time will be very short. If not, 
  •      * use a device specific lockout that will not damage overall system 
  •      * latency. 
  •      */  
  •   
  •     at91MstatSetClr (pChan,(SIO_MODEM_RTS|SIO_MODEM_DTR), FALSE);  
  •   
  •     return (OK);  
  •     }      
  •   
  •   
  • /******************************************************************************* 
  • * at91Open - Set the modem control lines  
  • * Set the modem control lines(RTS, DTR) TRUE if not already set.   
  • * RETURNS: OK 
  • */  
  •   
  • LOCAL STATUS at91Open  
  •     (  
  •     AT91_UART_CHAN * pChan  /* pointer to channel */  
  •     )  
  •     {  
  •     /* 
  •      * TODO - Use global intLock if lockout time will be very short. If not, 
  •      * use a device specific lockout that will not damage overall system 
  •      * latency. 
  •      */  
  •   
  •     at91MstatSetClr (pChan, (SIO_MODEM_RTS|SIO_MODEM_DTR), TRUE);  
  •   
  •     return (OK);  
  •     }  
  • #endif  
  •   
  •   
  • /****************************************************************************** 
  • * at91OptSet - set hardware options 
  • * This routine sets up the hardware according to the specified option 
  • * argument.  If the hardware cannot support a particular option value, then 
  • * it should ignore that portion of the request. 
  • * RETURNS: OK upon success, or EIO for invalid arguments. 
  • */  
  •   
  • LOCAL int at91OptSet  
  •     (  
  •     AT91_UART_CHAN * pChan,     /* channel */  
  •     uint_t      newOpts             /* new options */  
  •     )  
  •     {  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •     AT91_UART_PARAS *pParas =  (AT91_UART_PARAS *)(pChan->pUart);  
  •   
  •     int uartHwOptions = pParas->uartOption;  
  • /* 
  •     BOOL hdweFlowCtrl=TRUE; 
  •     BOOL rcvrEnable = TRUE; 
  • */  
  •     int  oldIntLvl;  
  •   
  •     if (pChan == NULL || newOpts & 0xffffff00)  
  •     return EIO;  
  •   
  •     /* do nothing if options already set */  
  •   
  •     if (pParas->uartOption== newOpts)  
  •     return OK;  
  •   
  •     /* ignore requests for unsupported options */  
  •   
  •     /* decode individual request elements */  
  •       
  •     uartHwOptions &= ~(AT91RM9200_US_MR_CHRL);   
  •   
  •     switch (newOpts & CSIZE)  
  •     {  
  •     case CS5:  
  •         uartHwOptions |= AT91RM9200_US_MR_CHRL_5_BITS;  
  •         break;  
  •     case CS6:  
  •         uartHwOptions |= AT91RM9200_US_MR_CHRL_6_BITS;  
  •         break;  
  •     case CS7:  
  •         uartHwOptions |= AT91RM9200_US_MR_CHRL_7_BITS;  
  •         break;  
  •     default:  
  •     case CS8:  
  •         uartHwOptions |= AT91RM9200_US_MR_CHRL_8_BITS;  
  •         break;  
  •     }  
  •   
  •     uartHwOptions &= ~(AT91RM9200_US_MR_NBSTOP);  
  •   
  •     if (newOpts & STOPB)  
  •             /* 2 bits stop bit */  
  •         uartHwOptions |= AT91RM9200_US_MR_NBSTOP_2_BIT;  
  •     else  
  •             /* 1 bit stop bit */  
  •         uartHwOptions |= AT91RM9200_US_MR_NBSTOP_1_BIT;  
  •   
  •     uartHwOptions &= ~(AT91RM9200_US_MR_PAR);  
  •   
  •     switch (newOpts & (PARENB|PARODD))  
  •     {  
  •     case PARENB|PARODD:  
  •         /* enable odd parity */  
  •         uartHwOptions |= AT91RM9200_US_MR_PAR_ODD;  
  •         break;  
  •   
  •     case PARENB:  
  •         /* enable even parity */  
  •         uartHwOptions |= AT91RM9200_US_MR_PAR_EVEN;  
  •         break;  
  •   
  •     case PARODD:  
  •         /* invalid mode, not normally used. */  
  •         uartHwOptions |= AT91RM9200_US_MR_PAR_MULTI_DROP;  
  •         break;  
  •   
  •     default:  
  •     case 0:  
  •         /* no parity */;   
  •         uartHwOptions |= AT91RM9200_US_MR_PAR_NONE;  
  •         break;  
  •     }  
  •   
  •     if (newOpts & CLOCAL)  
  •     {  
  •   
  •     /* clocal disables hardware flow control */  
  •     uartHwOptions &= ~(AT91RM9200_US_MR_USMODE);  
  •     uartHwOptions |= AT91RM9200_US_MR_USMODE_NORMAL;  
  •     }  
  •     else  
  •         {  
  •         /* enable hardware flow control */  
  •     uartHwOptions &= ~(AT91RM9200_US_MR_USMODE);  
  •         uartHwOptions |= AT91RM9200_US_MR_USMODE_HWHSH;  
  •         uartHwOptions |= AT91RM9200_US_MR_USMODE_MODEM;  
  •         }  
  •   
  •   
  •     if ((newOpts & CREAD) == 0)  
  •     pUsart->US_CR = AT91RM9200_US_CR_RXDIS;  
  •     else  
  •         pUsart->US_CR = AT91RM9200_US_CR_RXEN;  
  •   
  •     oldIntLvl = intLock ();  
  •   
  •     /* 
  •      * Reset the device according to uartHwOptions 
  •      */  
  •   
  •     pUsart->US_MR = uartHwOptions;  
  •       
  •     intUnlock (oldIntLvl);  
  •   
  •     /* 
  •      * Be sure that pChan->options reflects the actual 
  •      * hardware settings.  If 5 data bits were requested, but unsupported, 
  •      * then be sure pChan->options reflects the actual number of data bits 
  •      * currently selected. 
  •      */  
  •   
  •     /*  
  •      * we store register setting in pParas->uartOption 
  •      * and software setting in pChan->options 
  •      */  
  •     pParas->uartOption = uartHwOptions;  
  •     pChan->options = newOpts;  
  •   
  •     return (OK);  
  •     }  
  •   
  • /******************************************************************************* 
  • * at91Ioctl - special device control 
  • * This routine handles the IOCTL messages from the user. It supports commands  
  • * to get/set baud rate, mode(INT,POLL), hardware options(parity, number of  
  • * data bits) and modem control(RTS/CTS and DTR/DSR handshakes). 
  • * The ioctl commands SIO_HUP and SIO_OPEN are used to implement the HUPCL(hang 
  • * up on last close) function. 
  • * As on a UNIX system, requesting a baud rate of zero is translated into 
  • * a hangup request.  The DTR and RTS lines are dropped.  This should cause 
  • * a connected modem to drop the connection.  The SIO_HUP command will only 
  • * hangup if the HUPCL option is active.  The SIO_OPEN function will raise 
  • * DTR and RTS lines whenever it is called. Use the BAUD_RATE=0 function 
  • * to hangup when HUPCL is not active. 
  • * The CLOCAL option will disable hardware flow control.  When selected, 
  • * hardware flow control is not used.  When not selected hardware flow control 
  • * is based on the RTS/CTS signals.  CTS is the clear to send input 
  • * from the other end.  It must be true for this end to begin sending new 
  • * characters.  In most drivers, the RTS signal will be assumed to be connected 
  • * to the opposite end's CTS signal and can be used to control output from 
  • * the other end.  Raising RTS asserts CTS at the other end and the other end 
  • * can send data.  Lowering RTS de-asserts CTS and the other end will stop 
  • * sending data. (This is non-EIA defined use of RTS). 
  • * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed 
  • * request. 
  • */  
  •   
  • LOCAL int at91Ioctl  
  •     (  
  •     SIO_CHAN *  pSioChan,       /* device to control */  
  •     int     request,        /* request code */  
  •     void *  someArg         /* some argument */  
  •     )  
  •     {  
  •     AT91_UART_CHAN *pChan = (AT91_UART_CHAN *) pSioChan;  
  •     AT91PS_USART pUsart = (AT91PS_USART)(pChan->ioBase); /* point to UART register index by ioBase of pChan */  
  •     AT91_UART_PARAS *pParas =  (AT91_UART_PARAS *)(pChan->pUart);  
  •   
  •     int     oldLevel;       /* current interrupt level mask */  
  •     int     baudConstant;  
  •     int     arg = (int)someArg;  
  •   
  •     /* TEMPLATE_PIPE_FLUSH(pChan); */  
  •     switch (request)  
  •     {  
  •     case SIO_BAUD_SET:  
  •   
  •         /* 
  •          * like unix, a baud request for 0 is really a request to hangup. 
  •          */  
  •   
  •         if (arg == 0)  
  •         return (EIO);  
  •           
  •         /* return (at91Hup (pChan)); */  
  •   
  •         /* 
  •          * Set the baud rate. Return EIO for an invalid baud rate, or 
  •          * OK on success. 
  •          */  
  •   
  •         if (arg < AT91_BAUD_MIN || arg > AT91_BAUD_MAX)  
  •             {  
  •         return (EIO);  
  •             }  
  •   
  •         /* Calculate the baud rate constant for the new baud rate */  
  •   
  •         baudConstant = AT91_MASTER_CLOCK / arg / 16;   
  •           
  •   
  •         /* disable interrupts during chip access */  
  •   
  •         oldLevel = intLock ();  
  •         pUsart->US_BRGR = baudConstant;  
  •         intUnlock (oldLevel);  
  •   
  •         pParas->baudRate = arg;  
  •   
  •         return (OK);  
  •   
  •     case SIO_BAUD_GET:  
  •   
  •         *(int *)someArg = pParas->baudRate;  
  •         return (OK);  
  •   
  •     case SIO_MODE_SET:  
  •   
  •         /* 
  •          * Set the mode (e.g., to interrupt or polled). Return OK 
  •          * or EIO for an unknown or unsupported mode. 
  •          */  
  •   
  •         return (at91ModeSet (pChan, arg));  
  •   
  •     case SIO_MODE_GET:  
  •   
  •         /* Get the current mode and return OK.  */  
  •   
  •         *(int *)someArg = pChan->mode;  
  •         return (OK);  
  •   
  •     case SIO_AVAIL_MODES_GET:  
  •   
  •         /* TODO - set the available modes and return OK.  */  
  •   
  •         *(int *)someArg = SIO_MODE_INT | SIO_MODE_POLL;  
  •         return (OK);  
  •   
  •     case SIO_HW_OPTS_SET:  
  •   
  •         /* 
  •          * Optional command to set the hardware options (as defined 
  •          * in sioLib.h). 
  •          * Return OK, or ENOSYS if this command is not implemented. 
  •          * Note: several hardware options are specified at once. 
  •          * This routine should set as many as it can and then return 
  •          * OK. The SIO_HW_OPTS_GET is used to find out which options 
  •          * were actually set. 
  •          */  
  •   
  •         return (at91OptSet (pChan, arg));  
  •   
  •     case SIO_HW_OPTS_GET:  
  •   
  •         /* 
  •          * Optional command to get the hardware options (as defined 
  •          * in sioLib.h). Return OK or ENOSYS if this command is not 
  •          * implemented.  Note: if this command is unimplemented, it 
  •          * will be assumed that the driver options are CREAD | CS8 
  •          * (e.g., eight data bits, one stop bit, no parity, ints enabled). 
  •          */  
  •   
  •         *(int *)someArg = pChan->options;  
  •         return (OK);  
  •           
  • #if 0  
  •         case SIO_HUP:  
  •   
  •             /* check if hupcl option is enabled */  
  •   
  •             if (pChan->options & HUPCL)   
  •                 return (at91Hup (pChan));  
  •             return (OK);  
  •   
  •         case SIO_OPEN:  
  •         return (at91Open (pChan)); /* always open */  
  • #endif  
  •   
  • #if 0 /* TODO - optional modem control line support */  
  •   
  •     /* 
  •      * These new ioctl commands are for monitoring and setting the 
  •      * state of the modem control lines under user control. The 
  •      * return values from these calls inform the user about which 
  •      * control lines are inputs and which are outputs. Basically 
  •      * this lets the user know if the device is wired for DTE or 
  •      * DCE configuration.  It also informs the user if any signals 
  •      * are missing altogether. 
  •      */  
  •   
  •     case SIO_MSTAT_GET:  
  •         return templateMstatGet(pChan);  
  •   
  •     case SIO_MCTRL_BITS_SET:  
  •         return templateMstatSetClr (pChan, arg, TRUE);  
  •   
  •     case SIO_MCTRL_BITS_CLR:  
  •         return templateMstatSetClr (pChan, arg, FALSE);  
  •   
  •     /* 
  •      * The ISIG and OSIG masks tell the user which signals are actually 
  •      * outputs and which aren't. In our case here, we assume the device 
  •      * is DTE mapped with DTR and RTS as outputs. DSR and CTS as inputs. 
  •      * This template driver doesn't support RI. 
  •      */  
  •     case SIO_MCTRL_OSIG_MASK:  
  •         *(int *)someArg = TEMPLATE_OSIG_MASK;  
  •         break;  
  •   
  •     case SIO_MCTRL_ISIG_MASK:  
  •         *(int *)someArg = TEMPLATE_ISIG_MASK;  
  •         break;  
  •   
  • #endif /* optional Modem control line support */  
  •   
  • #if 0 /* TODO - optional keyboard scan code support */  
  •   
  •     /* 
  •      * The following new ioctl commands are meant only for keyboard 
  •      * input devices to use.  These allow the user to specify and 
  •      * examine the type of keyboard character mapping to use.  The 
  •      * possible types are NONE (raw scan codes), ASCII (default ascii 
  •      * mappings, and UNICODE for standard 16 bit unicode mappings. 
  •      * 
  •      * Our template driver supports only raw and ascii modes. 
  •      */  
  •   
  •     case SIO_KYBD_MODE_SET:  
  •         switch (arg)  
  •         {  
  •         case SIO_KYBD_MODE_RAW:  
  •         case SIO_KYBD_MODE_ASCII:  
  •             break;  
  •   
  •         case SIO_KYBD_MODE_UNICODE:  
  •             return ENOSYS; /* template doesn't support unicode */  
  •         }  
  •         pChan->scanMode = arg;  
  •         return OK;  
  •   
  •     case SIO_KYBD_MODE_GET:  
  •         *(int *)someArg = pChan->scanMode;  
  •         return OK;  
  •   
  • #endif /* optional keyboard scan code support */  
  •   
  •     default:  
  •         return ENOSYS;  
  •     }  
  •     return OK;  
  •     }  
  •   
  • /******************************************************************************* 
  • * dummyTxCallback - dummy Tx callback routine 
  • * RETURNS: ERROR. 
  • */  
  •   
  • LOCAL STATUS at91DummyTxCallback  
  •     (  
  •     void * callbackArg, /* argument registered with callback */  
  •     char * pChara   /* ptr to data location */  
  •     )  
  •     {  
  •     static BOOL doit = TRUE;  
  •   
  •     /* 
  •      * TODO - Until an upstream module connects to this device, there 
  •      * is no data available to send.  We should only be concerned 
  •      * if this callback is being called repeatedly and often. That 
  •      * could indicate an interrupt servicing problem of some kind. 
  •      */  
  •   
  •     if (doit)  
  •     {  
  •     printf ("Dummy txCallback: 0x%x 0x%x\n",  
  •         (int)callbackArg, (int)pChara);  
  •     doit = FALSE;  
  •     }  
  •   
  •     return (ERROR);  
  •     }  
  •   
  • /******************************************************************************* 
  • * dummyRxCallback - dummy Rx callback routine 
  • * RETURNS: N/A. 
  • * ARGSUSED 
  • */  
  •   
  • LOCAL void at91DummyRxCallback  
  •     (  
  •     void * callbackArg, /* argument registered with callback */  
  •     char data       /* receive data */  
  •     )  
  •     {  
  •     static BOOL doit = TRUE;  
  •   
  •     /* 
  •      * TODO - Device is transferring data, but there is no 
  •      * upstream module connected to receive it.  Lets log 
  •      * a message about incoming data being lost.  Buts lets 
  •      * do this only once we don't want a 'flood' of logged 
  •      * messages. 
  •      */  
  •   
  •     if (doit)  
  •     {  
  •     printf ("Dummy rxCallback: 0x%x 0x%x\n",  
  •         (int)callbackArg, (int)data);  
  •     doit = FALSE;  
  •     }  
  •   
  •     return;  
  •     }  
  •   
  • /******************************************************************************* 
  • * dummyErrCallback - dummy Error callback routine 
  • * There should be an sioLib module to provide dummyCallbacks for all SIO 
  • * drivers to use. 
  • * RETURNS: N/A. 
  • * ARGSUSED 
  • */  
  •   
  • LOCAL void at91DummyErrCallback  
  •     (  
  •     void * callbackArg, /* argument registered with callback */  
  •     int errorCode,  /* error code */  
  •     void * pData,   /* ptr to device specific data */  
  •     int size        /* size of device specific data */  
  •     )  
  •     {  
  •     static BOOL doit = TRUE;  
  •   
  •     /* TODO -  We could log the reported error (once). */  
  •   
  •     if (doit)  
  •     {  
  •     printf ("Dummy errorCallback: 0x%x 0x%x 0x%x %d\n",  
  •         (int)callbackArg, errorCode, (int)pData, size);  
  •     doit = FALSE;  
  •     }  
  •   
  •     return;  
  •     }  
  •   
  • /******************************************************************************* 
  • * at91Probe - probe for device  
  • * Try to determine if device is present.  Do not reconfigure device if it 
  • * is there.  This should be a passive probe that does not interfere with 
  • * the device. 
  • * RETURNS: 
  • * Returns OK if device adaptor is there, ERROR if not there. 
  • */  
  •   
  • LOCAL STATUS at91Probe  
  •     (  
  •     AT91_UART_CHAN * pChan /* channel to probe */  
  •     )  
  •     {  
  •     /*  
  •      * the UART and DBGU is internal controller of AT91RM9200 CPU,  
  •      * so we needn't to probe it 
  •      */   
  •     return OK;  
  •     }  
  •   
  • #if 0  
  • /******************************************************************************* 
  • * at91Verify - verify at91_uart chan structure 
  • * Given a pointer to what should be a AT91_UART_CHAN, verify that it really 
  • * is a AT91_UART_CHAN structure. 
  • * This routine should not be called at every level with every routine.  It is 
  • * primarily provided for use with the xxxDestroy routine.  Performance will be 
  • * a problem if every pointer is checked for validity with every use. 
  • * RETURNS: 
  • * Returns OK if pointer is valid, ERROR if not. 
  • */  
  •   
  • LOCAL STATUS at91Verify  
  •     (  
  •     AT91_UART_CHAN * pChan /* pointer to be verified */  
  •     )  
  •     {  
  •     /* 
  •      * Examine the structure. Look for magic cookies or flag bits. 
  •      * Anything that would confirm this pointer as being a valid 
  •      * AT91_UART_CHAN pointer. 
  •      */  
  •   
  •     if (pChan == NULL)  
  •     return ERROR;  
  •   
  •     return OK;  
  •     }  
  •   
  • #endif  
  •   
  • #if 0 /* Optional modem control line support */  
  •   
  • /******************************************************************************* 
  • * at91MstatGet - read device modem control line status 
  • * Read the device modem control lines and map them to the standard 
  • * modem signal bits. 
  • * RETURNS: 
  • * Returns the modem control line status bits. 
  • */  
  •   
  • LOCAL int at91MstatGet  
  •     (  
  •     AT91_UART_CHAN *pChan  
  •     )  
  •     {  
  •     AT91_UART_CHAN * pChan = (AT91_UART_CHAN *)pSioChan;  
  •     UINT32  status;  
  •     int result = 0;  
  •   
  •     AT91PS_USART pUsart;    /* point to UART register index by ioBase of pChan */  
  •   
  •     pUsart = (AT91PS_USART)(pChan->ioBase);  
  •   
  •     /* Read RX device status */  
  •   
  •     status = pUsart->US_CSR;  
  •     /* Now map device status bits, to standard status bits */  
  •   
  •     if (rawStatus & TEMPLATE_MSR_CD)  
  •     result |= SIO_MODEM_CD;  
  •   
  •     if (rawStatus & TEMPLATE_MSR_DTR)  
  •     result |= SIO_MODEM_DTR;  
  •   
  •     if (rawStatus & TEMPLATE_MSR_DSR)  
  •     result |= SIO_MODEM_DSR;  
  •   
  •     if (rawStatus & TEMPLATE_MSR_RTS)  
  •     result |= SIO_MODEM_RTS;  
  •   
  •     if (rawStatus & TEMPLATE_MSR_CTS)  
  •     result |= SIO_MODEM_CTS;  
  •   
  •     return result;  
  •     }  
  •   
  • /******************************************************************************* 
  • * templateMstatSetClear - set/clear modem control lines 
  • * This routine allows the user to set or clear individual modem control 
  • * lines.  Of course, only the output lines can actually be changed. 
  • * RETURNS: 
  • * OK, or EIO upon detecting a hardware fault. 
  • */  
  •   
  • LOCAL int templateMstatSetClr  
  •     (  
  •     TEMPLATE_CHAN *pChan,  
  •     UINT bits,      /* bits to change */  
  •     BOOL setFlag    /* TRUE = set, FALSE = clear */  
  •     )  
  •     {  
  •     UINT8 rawStatus;  
  •     UINT8 rawMask = 0;  
  •   
  •     /* Read current modem status */  
  •     TEMPLATE_SIO_READ8 (pChan, TEMPLATE_MSR_ID, &rawStatus);  
  •   
  •     /* ignore input only bits */  
  •     bits &= TEMPLATE_OSIG_MASK;  
  •   
  •     /* Now map standard bits to device specific bits */  
  •   
  •     if (bits & SIO_MODEM_DTR)  
  •     rawMask |= TEMPLATE_MSR_DTR;  
  •   
  •     if (bits & SIO_MODEM_RTS)  
  •     rawMask |= TEMPLATE_MSR_RTS;  
  •   
  •     /* Update device with new output signals */  
  •   
  •     if (setFlag)  
  •     rawStatus |= rawMask; /* set new bits */  
  •     else  
  •     rawStatus &= ~rawMask; /* clear bits */  
  •   
  •     TEMPLATE_SIO_WRITE8 (pChan, TEMPLATE_MSR_ID, rawStatus);  
  •   
  •     return OK;  
  •     }  
  • #endif /* optional modem control line support */  
  • 相关文章: