📄 s3c2410xsio.c
字号:
/* s3c2410xSio.c - MagicARM2410 UART tty driver */#include "copyright_wrs.h"#include "vxWorks.h"#include "intLib.h"#include "errnoLib.h"#include "errno.h"#include "sioLib.h"#include "s3c2410xSio.h"#include "s3c2410x.h"/* local defines */#define s3c2410x_BAUD_MIN 18#define s3c2410x_BAUD_MAX 115200#define s3c2410x_SIO_DEFAULT_BAUD 115200#ifndef s3c2410x_UART_REG#define s3c2410x_UART_REG(pChan, reg) \ (*(volatile UINT32 *)((UINT32)(pChan)->regs + (reg)))#endif#ifndef s3c2410x_UART_REG_READ#define s3c2410x_UART_REG_READ(pChan, reg, result) \ (result) = (s3c2410x_UART_REG(pChan, reg))#endif#ifndef s3c2410x_UART_REG_WRITE#define s3c2410x_UART_REG_WRITE(pChan, reg, data) \ (s3c2410x_UART_REG(pChan, reg)) = (data)#endif#ifndef s3c2410x_UART_REG_BIT_SET#define s3c2410x_UART_REG_BIT_SET(pChan, reg, data) \ (s3c2410x_UART_REG(pChan, reg)) |= (data)#endif#ifndef s3c2410x_UART_REG_BIT_CLR#define s3c2410x_UART_REG_BIT_CLR(pChan, reg, data) \ (s3c2410x_UART_REG(pChan, reg)) &= ~(data)#endif/* hardware access methods */#ifndef s3c2410x_INT_REG_READ#define s3c2410x_INT_REG_READ(reg,result) \ ((result) = *(volatile UINT32 *)(reg))#endif#ifndef s3c2410x_INT_REG_WRITE#define s3c2410x_INT_REG_WRITE(reg,data) \ (*((volatile UINT32 *)(reg)) = (data))#endif/* locals *//* function prototypes */LOCAL STATUS s3c2410xIoctl (SIO_CHAN * pSioChan, int request, int arg);LOCAL int s3c2410xTxStartup (SIO_CHAN * pSioChan);LOCAL int s3c2410xCallbackInstall (SIO_CHAN * pSioChan, int callbackType, STATUS (*callback)(), void * callbackArg);LOCAL int s3c2410xPollInput (SIO_CHAN * pSioChan, char *);LOCAL int s3c2410xPollOutput (SIO_CHAN * pSioChan, char);LOCAL STATUS s3c2410xDummyCallback (void);/* driver functions */LOCAL SIO_DRV_FUNCS s3c2410xSioDrvFuncs = { (int (*)())s3c2410xIoctl, s3c2410xTxStartup, (int (*)())s3c2410xCallbackInstall, s3c2410xPollInput, s3c2410xPollOutput };/* * s3c2410xDummyCallback - dummy callback routine. * * RETURNS: ERROR, always. */LOCAL STATUS s3c2410xDummyCallback (void){ return ERROR;}/* * s3c2410xInitChannel - initialise UART * * This routine performs hardware initialisation of the UART channel. * * RETURNS: N/A */LOCAL void s3c2410xInitChannel ( s3c2410x_CHAN * pChan /* ptr to s3c2410x_CHAN describing this channel */ ){ UINT32 tempUINT32; /* Set UCLK, polling&interrupt mode. */ s3c2410x_UART_REG_WRITE(pChan, OFFSET_UCON, CLK_PCLK+TxMode_IntPoll+RxMode_IntPoll); /* enable subInterrupt for UART0. */ s3c2410x_INT_REG_READ(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); switch((int)(pChan->regs)) { case UART_1_BASE_ADR: tempUINT32 &= ~((1<<SUBINT_LVL_RXD1)|(1<<SUBINT_LVL_TXD1)); break; case UART_0_BASE_ADR: default: tempUINT32 &= ~((1<<SUBINT_LVL_RXD0)|(1<<SUBINT_LVL_TXD0)); } s3c2410x_INT_REG_WRITE(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); /* Set baud rate to 9600. */ s3c2410xIoctl((SIO_CHAN *)pChan, SIO_BAUD_SET,pChan->baudRate );/*s3c2410x_SIO_DEFAULT_BAUD*//*061013*/ /* Set NonInfra-red mode, 8, N, 1. */ s3c2410xIoctl((SIO_CHAN *)pChan, SIO_HW_OPTS_SET, CLOCAL+CS8); s3c2410xIoctl((SIO_CHAN *)pChan, SIO_MODE_SET, SIO_MODE_POLL); /* Set disable FIFO */ s3c2410x_UART_REG_WRITE(pChan, OFFSET_UFCON, FIFO_OFF); /* Enable pin for UART */ s3c2410x_IO_READ(rGPHCON, tempUINT32); switch((int)(pChan->regs)) { case UART_1_BASE_ADR: tempUINT32 |= (MASK_GPH4(2)+MASK_GPH5(2)+MASK_GPH6(3)+MASK_GPH7(3)); /* +MASK_GPH8(2)); */ break; case UART_0_BASE_ADR: default: tempUINT32|= (MASK_GPH0(2)+MASK_GPH1(2)+MASK_GPH2(2)+MASK_GPH3(2)); /* +MASK_GPH8(2)); */ } s3c2410x_IO_WRITE(rGPHCON,tempUINT32); /* Clear Rx */ s3c2410x_UART_REG_READ(pChan, OFFSET_URXH, tempUINT32);}/* * s3c2410xSioDevInit - initialise an s3c2410x 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 * s3c2410x_CHAN structure. * * RETURNS: N/A */void s3c2410xSioDevInit ( s3c2410x_CHAN * pChan /* ptr to s3c2410x_CHAN describing this channel */ ){ int oldlevel = intLock(); /* initialise the driver function pointers in the SIO_CHAN pChan->pDrvFuncs = &s3c2410xSioDrvFuncs;*/ pChan->sio.pDrvFuncs = &s3c2410xSioDrvFuncs; /* set the non BSP-specific constants */ pChan->getTxChar = s3c2410xDummyCallback; pChan->putRcvChar = s3c2410xDummyCallback; pChan->channelMode = SIO_MODE_POLL; /*undefined */ /* initialise the chip */ s3c2410xInitChannel(pChan); intUnlock(oldlevel);}/* * s3c2410xIoctl - special device control * * This routine handles the IOCTL messages from the user. * * RETURNS: OK on success, ENOSYS on unsupported request, EIO on failed * request. */LOCAL int s3c2410xIoctl ( SIO_CHAN* pSioChan, /* device to control */ int request, /* request code */ int arg ){ s3c2410x_CHAN *pChan = (s3c2410x_CHAN*) pSioChan; int oldlevel; /* current interrupt level mask */ UINT32 tempUINT32 = 0; int lvl; switch (request) { case SIO_BAUD_SET: if(arg < s3c2410x_BAUD_MIN || arg > s3c2410x_BAUD_MAX) return(EIO); /* disable interrupts during chip access */ oldlevel = intLock (); s3c2410x_UART_REG_WRITE(pChan,OFFSET_UDIV,(((s3c2410x_PCLK/16)/arg)-1)); intUnlock (oldlevel); s3c2410x_UART_REG_READ(pChan,OFFSET_UDIV,tempUINT32); pChan->baudRate=((s3c2410x_PCLK/16)/(tempUINT32+1)); break; case SIO_BAUD_GET: *(int *)arg = pChan->baudRate; break; case SIO_MODE_SET: switch(arg) { case SIO_MODE_INT: /* clear subpend-flag of RX_TX */ switch((int)(pChan->regs)) { case UART_1_BASE_ADR: s3c2410x_INT_REG_WRITE(s3c2410x_INT_CSR_SUBSRCPND,((1<<SUBINT_LVL_TXD1)|(1<<SUBINT_LVL_RXD1))); break; case UART_0_BASE_ADR: default: s3c2410x_INT_REG_WRITE(s3c2410x_INT_CSR_SUBSRCPND,((1<<SUBINT_LVL_TXD0)|(1<<SUBINT_LVL_RXD0))); } /* enable uart_int */ intEnable(pChan->intLevelRx); /* enable subInterrupt for UART0. */ s3c2410x_INT_REG_READ(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); switch((int)(pChan->regs)) { case UART_1_BASE_ADR: tempUINT32 &= ~((1<<SUBINT_LVL_RXD1)|(1<<SUBINT_LVL_TXD1)); break; case UART_0_BASE_ADR: default: tempUINT32 &= ~((1<<SUBINT_LVL_RXD0)|(1<<SUBINT_LVL_TXD0)); } s3c2410x_INT_REG_WRITE(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); break; case SIO_MODE_POLL: /* disable uart_int */ intDisable(pChan->intLevelRx); /* disable subInterrupt for UART0. */ s3c2410x_INT_REG_READ(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); switch((int)(pChan->regs)) { case UART_1_BASE_ADR: tempUINT32 |= ((1<<SUBINT_LVL_RXD1)|(1<<SUBINT_LVL_TXD1)); break; case UART_0_BASE_ADR: default: tempUINT32 |= ((1<<SUBINT_LVL_RXD0)|(1<<SUBINT_LVL_TXD0)); } s3c2410x_INT_REG_WRITE(s3c2410x_INT_CSR_INTSUBMSK,tempUINT32); break; default: return(EIO); } pChan->channelMode = arg; break; case SIO_MODE_GET: *(int *)arg = pChan->channelMode; break; case SIO_AVAIL_MODES_GET: /* Get the available modes and return OK. */ *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL; break; case SIO_HW_OPTS_SET: if(arg & 0xffffff00) return EIO; /* do nothing if options already set */ if(pChan->options == arg) break; switch (arg & CSIZE) { case CS5: tempUINT32 = DATABIT_5; break; case CS6: tempUINT32 = DATABIT_6; break; case CS7: tempUINT32 = DATABIT_7; break; default: case CS8: tempUINT32 = DATABIT_8; break; } if (arg & STOPB) { tempUINT32 |= TWO_STOPBIT; } else { /* tempUINT32 &= ~TWO_STOPBIT */; } switch (arg & (PARENB|PARODD)) { case PARENB|PARODD: tempUINT32 += ODD_PARITY; break; case PARENB: tempUINT32 += EVEN_PARITY; break; case 0: default: ;/* no parity */ } lvl = intLock(); s3c2410x_UART_REG_WRITE(pChan,OFFSET_ULCON,tempUINT32); intUnlock(lvl); if (arg & CLOCAL) { /* clocal disables hardware flow control */ lvl = intLock(); s3c2410x_UART_REG_WRITE(pChan,OFFSET_UMCON,AFC_OFF); intUnlock(lvl); } else { lvl = intLock(); s3c2410x_UART_REG_WRITE(pChan,OFFSET_UMCON,AFC_ON); intUnlock(lvl); } pChan->options = arg; break; case SIO_HW_OPTS_GET: *(int*)arg = pChan->options; return (OK); case SIO_HUP: /* check if hupcl option is enabled */ break; case SIO_OPEN: break; /* always open */ default: return (ENOSYS); } return (OK);}/* * s3c2410xSioIntTx - handle a transmitter interrupt * * This routine handles write interrupts from the UART. * * RETURNS: N/A */void s3c2410xSioIntTx ( s3c2410x_CHAN * pChan /* ptr to s3c2410x_CHAN describing this channel */ ){ char outChar; /* clear subpending of the TXn */ switch((int)(pChan->regs)) { case UART_1_BASE_ADR: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_SUBSRCPND, (1<<SUBINT_LVL_TXD1)); break; case UART_0_BASE_ADR: default: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_SUBSRCPND,(1<<SUBINT_LVL_TXD0) ); } if((*pChan->getTxChar) (pChan->getTxArg, &outChar) != ERROR)/**/ { /* write char. to Transmit Holding Reg.*/ s3c2410x_UART_REG_WRITE(pChan, OFFSET_UTXH, (((UINT32)outChar)&0x000000ff)); }}/* * s3c2410xSioIntRx - handle a receiver interrupt * * This routine handles read interrupts from the UART. * * RETURNS: N/A */void s3c2410xSioIntRx ( s3c2410x_CHAN * pChan /* ptr to s3c2410x_CHAN describing this channel */ ){ char inchar; /* clear subpending of the RXn */ switch((int)(pChan->regs)) { case UART_1_BASE_ADR: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_SUBSRCPND, (1<<SUBINT_LVL_RXD1)); break; case UART_0_BASE_ADR: default: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_SUBSRCPND, (1<<SUBINT_LVL_RXD0)); } /* read character from Receive Holding Reg. */ s3c2410x_UART_REG_READ(pChan, OFFSET_URXH, inchar); (*pChan->putRcvChar) (pChan->putRcvArg, inchar);}/* * s3c2410xSioInt - handle any UART interrupt * * This routine handles interrupts from the UART and determines whether * the source is a transmit interrupt or receive/receive-timeout interrupt. * * The Prime Cell UART generates a receive interrupt when the RX FIFO is * half-full, and a receive-timeout interrupt after 32 bit-clocks have * elapsed with no incoming data. * * RETURNS: N/A */void s3c2410xSioInt ( s3c2410x_CHAN * pChan /* ptr to s3c2410x_CHAN describing this channel */ ){ UINT32 intId; s3c2410x_INT_REG_READ(s3c2410x_INT_CSR_SUBSRCPND, intId); if(intId & ((1<<SUBINT_LVL_TXD0)|(1<<SUBINT_LVL_TXD1))) { s3c2410xSioIntTx(pChan); } if(intId & ((1<<SUBINT_LVL_RXD0)|(1<<SUBINT_LVL_RXD1))) { s3c2410xSioIntRx (pChan); } /*mask set has error in function s3c2410xIntLvlVecChk*/ switch((int)(pChan->regs)) { case UART_1_BASE_ADR: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_INTSUBMSK,(intId&0xffc7)); break; case UART_0_BASE_ADR: default: s3c2410x_IO_WRITE(s3c2410x_INT_CSR_INTSUBMSK,(intId&0xff80) ); }}/* * s3c2410xTxStartup - transmitter startup routine * * Enable interrupt so that interrupt-level char output routine will be called. * * RETURNS: OK on success, ENOSYS if the device is polled-only, or * EIO on hardware error. */LOCAL int s3c2410xTxStartup ( SIO_CHAN * pSioChan /* ptr to SIO_CHAN describing this channel */ ){/*int temp;*/ s3c2410x_CHAN * pChan = (s3c2410x_CHAN *)pSioChan; if(pChan->channelMode == SIO_MODE_INT) { intEnable(pChan->intLevelTx); s3c2410xSioIntTx(pChan); return OK; } else { return ENOSYS; }}/* * s3c2410xPollOutput - output a character in polled mode. * * RETURNS: OK if a character arrived, EIO on device error, EAGAIN * if the output buffer is full, ENOSYS if the device is interrupt-only. */LOCAL int s3c2410xPollOutput ( SIO_CHAN* pSioChan, /* ptr to SIO_CHAN describing this channel */ char outChar /* to output */ ){ s3c2410x_CHAN * pChan = (s3c2410x_CHAN *)pSioChan; FAST UINT32 pollStatus; s3c2410x_UART_REG_READ(pChan, OFFSET_UTRSTAT, pollStatus); /* is the transmitter ready to accept a character? */ if(!(pollStatus & UTRSTAT_TRNSR_EM)) { return EAGAIN; } /* write out the character */ s3c2410x_UART_REG_WRITE(pChan, OFFSET_UTXH, outChar); /* transmit character */ return OK;}/* * s3c2410xPollInput - poll the device for input. * * RETURNS: OK if a character arrived, EIO on device error, EAGAIN * if the input buffer is empty, ENOSYS if the device is interrupt-only. */LOCAL int s3c2410xPollInput ( SIO_CHAN * pSioChan, /* ptr to SIO_CHAN describing this channel */ char* thisChar /* pointer to where to return character */ ){ s3c2410x_CHAN * pChan = (s3c2410x_CHAN *)pSioChan; FAST UINT32 pollStatus; s3c2410x_UART_REG_READ(pChan, OFFSET_UTRSTAT, pollStatus); if(!(pollStatus & UTRSTAT_RB_RDY)) { return EAGAIN; } /* got a character */ s3c2410x_UART_REG_READ(pChan, OFFSET_URXH, *thisChar); return OK;}/* * s3c2410xCallbackInstall - install ISR callbacks to get/put chars. * * This routine installs interrupt callbacks for transmitting characters * and receiving characters. * * RETURNS: OK on success, or ENOSYS for an unsupported callback type. * */LOCAL int s3c2410xCallbackInstall ( SIO_CHAN* pSioChan, /* ptr to SIO_CHAN describing this channel */ int callbackType, /* type of callback */ STATUS (*callback)(), /* callback */ void* callbackArg /* parameter to callback */ ){ s3c2410x_CHAN * pChan = (s3c2410x_CHAN *)pSioChan; switch(callbackType) { case SIO_CALLBACK_GET_TX_CHAR: pChan->getTxChar = callback; pChan->getTxArg = callbackArg; return OK; case SIO_CALLBACK_PUT_RCV_CHAR: pChan->putRcvChar = callback; pChan->putRcvArg = callbackArg; return OK; default: return ENOSYS; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -