m8260Sio.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:30k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* m8260Sio.c - Motorola MPC8260 SCC UART serial driver */
  2. /* Copyright 1984-2002 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01o,24apr02,pmr  SPR 75161: returning int as required from m8260SioStartup().
  8. 01n,30nov01,rcs  allow pSccChan->pRBASE and pSccChan->pTBASE to be passed in
  9.                  SPR# 34524
  10. 01m,22may01,rcs  changed m8260SioIoctl SIO_BAUD_SET to use M8260_BRGC_DIVISOR
  11. 01l,15may01,rcs  changes m8260SioIoctl SIO_BAUD_SET to correctly calculate 
  12.                  baudrate, added include "drv/sio/m8260Brg.h SPR#66989
  13. 01k,03oct99,ms_  roll back to circa 01g to fix hang
  14. 01j,16sep99,ms_  some include files come from drv/sio
  15. 01i,16sep99,ms_  rename m8260Int.h to m8260IntrCtl.h
  16. 01h,15jul99,ms_  make compliant with our coding standards
  17.  use macros to access hardware registers
  18. 01g,21may99,ms_  set a number of "not used" fields as indicated by user's
  19.                  manual
  20. 01f,19apr99,ms_  add documentation to functions with none
  21. 01e,17apr99,ms_  final EAR cleanup
  22. 01d,14apr99,ms_  interrupt numbers are defined, not vectors
  23. 01c,08apr99,ms_  upgrade to multiple channels
  24. 01b,06apr99,ms_  try using claudios buffer scheme
  25. 01a,08mar99,ms_  adapted from src/drv/m8260Sio.c version 01b
  26. */
  27. /*
  28. DESCRIPTION
  29. This is the driver for the SCCs in the internal Communications Processor (CP)
  30. of the Motorola MPC8260. This driver only supports the SCCs in 
  31. asynchronous UART mode.
  32. USAGE
  33. An M8260_SIO_CHAN structure is used to describe the chip.
  34. The BSP's sysHwInit() routine typically calls sysSerialHwInit(),
  35. which initializes all the values in the M8260_SCC_CHAN structure (except
  36. the SIO_DRV_FUNCS) before calling m8260SioDevInit(). 
  37. This driver requires that the BSP create and initialize the global variable
  38. baudRateGenClk. This global variable must contain the value of the 
  39. Baud Rate Generator Input Clock. 
  40. The value should be calculated as:
  41.  
  42.                     VCO_OUT/SCCR[DFBRG].  
  43. Typically this will be: 
  44. (CPM clock * 2) / 16
  45. This driver requires the BSP Parameter M8260_BRGC_DIVISOR. This Parameter
  46. must be initialized according to the system oscillator present on the board.
  47. For the ads8260 BSP this is automatic. The Parameter will be initialzed to
  48. M8260_BRGC_DIV1 for a 40 MHz system oscillator and M8260_BRGC_DIV16 for 33 MHz
  49. and 66 MHz.
  50. The BSP's sysHwInit2() routine typically calls sysSerialHwInit2() which
  51. connects the chip's interrupts via intConnect().
  52. INCLUDE FILES: drv/sio/m8260Sio.h drv/sio/m8260Cp.h drv/intrCtl/m8260IntrCtl.h
  53. */
  54. /* includes */
  55. #include "vxWorks.h"
  56. #include "intLib.h"
  57. #include "errno.h"
  58. #include "sioLib.h"
  59. #include "drv/sio/m8260Sio.h"
  60. #include "drv/sio/m8260Cp.h"
  61. #include "drv/sio/m8260Brg.h"
  62. #include "drv/intrCtl/m8260IntrCtl.h"
  63. /* defines */
  64. #define DEFAULT_BAUD 9600
  65. /* local forward declarations */
  66. static STATUS m8260SioIoctl (M8260_SCC_CHAN *pSccChan,int request,int arg);
  67. static int    m8260SioPollOutput (SIO_CHAN *pSioChan,char);
  68. static int    m8260SioPollInput (SIO_CHAN *pSioChan,char *);
  69. static int    m8260SioStartup (M8260_SCC_CHAN *pSccChan);
  70. static int    m8260SioCallbackInstall (SIO_CHAN *pSioChan, int, STATUS (*)(), void *);
  71. /* global forward declarations */
  72. void   m8260SioResetChannel (M8260_SCC_CHAN *pSccChan);
  73. /* local driver function table */
  74. static SIO_DRV_FUNCS m8260SioDrvFuncs =
  75.     {
  76.     (int (*)()) m8260SioIoctl,
  77.     (int (*)()) m8260SioStartup,
  78.     (int (*)()) m8260SioCallbackInstall,
  79.     (int (*)()) m8260SioPollInput,
  80.     (int (*)(SIO_CHAN *,char)) m8260SioPollOutput
  81.     };
  82. /*******************************************************************************
  83. *
  84. * m8260SioDevInit - initialize the SCC
  85. *
  86. * This routine is called to initialize the chip to a quiescent state.
  87. * Note that the `sccNum' field of M8260_SCC_CHAN must be less than 
  88. * or equal to the
  89. * maximum number of SCC channels to configure as SIOs, as defined in 
  90. * ads8260.h
  91. */
  92. void m8260SioDevInit
  93.     (
  94.     M8260_SCC_CHAN *pSccChan
  95.     )
  96.     {
  97.     UINT32  immrVal = pSccChan->immrVal;    /* holder for the immr value */
  98.     UINT8   sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  99.     UINT8   scc = sccNum - 1;             /* a convenience */
  100.     VINT16 *pSCCM = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCM_OFFSET +
  101.                        (scc * M8260_SCC_OFFSET_NEXT_SCC));
  102.     if (sccNum > N_SIO_CHANNELS)
  103. return;
  104.     /*
  105.      * Disable receive and transmit interrupts.
  106.      * Always flush cache pipe before first read
  107.      */
  108.     CACHE_PIPE_FLUSH ();
  109.     *pSCCM &= ~(M8260_SCC_UART_SCCX_RX | M8260_SCC_UART_SCCX_TX);
  110.     pSccChan->baudRate  = DEFAULT_BAUD;
  111.     pSccChan->pDrvFuncs = &m8260SioDrvFuncs;
  112.     }
  113. /*******************************************************************************
  114. *
  115. * m8260SioResetChannel - initialize an SCC channel
  116. *
  117. * This routines initializes an SCC channel. Initialized are:
  118. * .CS
  119. *        CPCR
  120. *        BRGC
  121. *        Baud rate
  122. *        Buffer Descriptors
  123. *        RBASE field in SCC Parameter RAM
  124. *        TBASE field in SCC Parameter RAM
  125. *        RFCR field in SCC Parameter RAM
  126. *        TFCR field in SCC Parameter RAM
  127. *        MRBLR field in SCC Parameter RAM
  128. *        
  129. *        SCC mode registers: GSMR_L, GSMR_H, AND PSMR
  130. *        transmit and receive interrupts are enabled in SCCM 
  131. *
  132. * RETURNS: NA
  133. *
  134. * .CE
  135. */
  136. void m8260SioResetChannel 
  137.     (
  138.     M8260_SCC_CHAN *pSccChan
  139.     )
  140.     {
  141.     UINT32  immrVal = pSccChan->immrVal;    /* holder for the immr value */
  142.     UINT8   sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  143.     UINT8   scc = sccNum - 1;             /* a convenience */
  144.     VINT32  cpcrVal = 0;          /* a convenience */
  145.     VINT32 *pBRGC = (VINT32 *) (immrVal + M8260_BRGC_BASE + 
  146.         (scc * M8260_BRGC_OFFSET_NEXT_BRGC));
  147.     VINT32 *pGSMR_L = (VINT32 *) (immrVal + M8260_SCC_BASE + 
  148.                                   M8260_GSMR_L_OFFSET +
  149.   (scc * M8260_SCC_OFFSET_NEXT_SCC));
  150.     VINT32 *pGSMR_H = (VINT32 *) (immrVal + M8260_SCC_BASE + 
  151.                                   M8260_GSMR_H_OFFSET +
  152.   (scc * M8260_SCC_OFFSET_NEXT_SCC));
  153.     VINT16 *pPSMR = (VINT16 *) (immrVal + M8260_SCC_BASE + 
  154.                (scc * M8260_SCC_OFFSET_NEXT_SCC) +
  155.         M8260_PSMR_OFFSET);
  156.     VINT16 *pSCCM = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCM_OFFSET +
  157.                (scc * M8260_SCC_OFFSET_NEXT_SCC));
  158.     VINT8 * pRFCR = (VINT8 *) (immrVal + M8260_SCC_PRAM_BASE +
  159.                                M8260_SCC_PRAM_RFCR +
  160.                                (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  161.     VINT8 * pTFCR = (VINT8 *) (immrVal + M8260_SCC_PRAM_BASE +
  162.                                M8260_SCC_PRAM_TFCR +
  163.                                (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  164.     VINT16 *pMRBLR = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  165.                                  M8260_SCC_PRAM_MRBLR +
  166.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  167.     VINT16 *pMAX_IDL = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  168.                                  0x38 +
  169.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  170.     VINT16 *pBRKCR = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  171.                                  0x3C +
  172.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  173.     VINT16 *pPAREC = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  174.                                  M8260_SCC_UART_PRAM_PAREC +
  175.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  176.     VINT16 *pFRMEC = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  177.                                  M8260_SCC_UART_PRAM_FRMEC +
  178.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  179.     VINT16 *pNOSEC = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  180.                                  M8260_SCC_UART_PRAM_NOSEC +
  181.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  182.     VINT16 *pBRKEC = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  183.                                  M8260_SCC_UART_PRAM_BRKEC +
  184.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  185.     VINT16 *pUADDR1 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  186.                                  0x48 +
  187.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  188.     VINT16 *pUADDR2 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  189.                                  0x4A +
  190.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  191.     VINT16 *pTOSEQ = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  192.                                  0x4E +
  193.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  194.     VINT16 *pCHARACTER1 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  195.                                  0x50 +
  196.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  197.     VINT16 *pCHARACTER2 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  198.                                  0x52 +
  199.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  200.     VINT16 *pCHARACTER3 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  201.                                  0x54 +
  202.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  203.     VINT16 *pCHARACTER4 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  204.                                  0x56 +
  205.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  206.     VINT16 *pCHARACTER5 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  207.                                  0x58 +
  208.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  209.     VINT16 *pCHARACTER6 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  210.                                  0x5A +
  211.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  212.     VINT16 *pCHARACTER7 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  213.                                  0x5C +
  214.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  215.     VINT16 *pCHARACTER8 = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  216.                                  0x5E +
  217.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  218.     VINT16 *pRCCM = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  219.                                  0x60 +
  220.                                  (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  221.     int ix = 0;
  222.     
  223.     int oldlevel = intLock (); /* lock interrupts */ 
  224.     if (pSccChan->pRBASE == NULL)
  225.         {
  226.         pSccChan->pRBASE = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  227.                                        M8260_SCC_PRAM_RBASE +
  228.                                        (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  229.         } 
  230.     if (pSccChan->pTBASE == NULL)
  231.         {
  232.         pSccChan->pTBASE = (VINT16 *) (immrVal + M8260_SCC_PRAM_BASE +
  233.                                        M8260_SCC_PRAM_TBASE +
  234.                                        (scc * M8260_SCC_PRAM_OFFSET_NEXT_PRAM));
  235.         }
  236.     CACHE_PIPE_FLUSH ();
  237.     /* wait until the CP is clear */
  238.     do
  239.         {
  240. M8260_SCC_32_RD((M8260_CPCR (immrVal)), cpcrVal);
  241.         if (ix++ == M8260_CPCR_LATENCY)
  242.             break;
  243.         } while (cpcrVal & M8260_CPCR_FLG) 
  244.     ;
  245.     if (ix >= M8260_CPCR_LATENCY)
  246.         {
  247.         /* what to do, other than log an error? */
  248.         }
  249.     /* Stop transmitting on SCC, if doing so */
  250.     cpcrVal = (M8260_CPCR_OP (M8260_CPCR_TX_STOP)
  251.                | M8260_CPCR_SBC (M8260_CPCR_SBC_SCC1 | (scc * 0x1))
  252.                | M8260_CPCR_PAGE (M8260_CPCR_PAGE_SCC1 | (scc * 0x1))
  253.                | M8260_CPCR_FLG);
  254.     M8260_SCC_32_WR (M8260_CPCR (immrVal), cpcrVal);
  255.     /* flush cache pipe when switching from write to read */
  256.     CACHE_PIPE_FLUSH ();
  257.    /* wait until the CP is clear */
  258.     ix = 0;
  259.     do
  260.         {
  261.         M8260_SCC_32_RD((M8260_CPCR (immrVal)), cpcrVal);
  262.         if (ix++ == M8260_CPCR_LATENCY)
  263.             break;
  264.         } while (cpcrVal & M8260_CPCR_FLG) ;
  265.     if (ix >= M8260_CPCR_LATENCY)
  266.         {
  267.         /* what to do, other than log an error? */
  268.         }
  269.     /* set up SCC as NMSI, select Baud Rate Generator */
  270.     /* reset baud rate generator, wait for reset to clear... */
  271.  
  272.     * pBRGC |= M8260_BRGC_RST;
  273.     /* flush cache pipe when switching from write to read */
  274.     CACHE_PIPE_FLUSH ();
  275.     while ((*pBRGC) & M8260_BRGC_RST);
  276.     m8260SioIoctl (pSccChan, SIO_BAUD_SET, pSccChan->baudRate);
  277.     /* set up the RECEIVE buffer descriptors */
  278.     /* buffer status/control */
  279.     M8260_SCC_16_WR((pSccChan->pBdBase + 
  280.                      M8260_SCC_RCV_BD_OFF + 
  281.                      M8260_SCC_BD_STAT_OFF), 0xB000);
  282.     CACHE_PIPE_FLUSH ();
  283.     /* buffer length */
  284.     M8260_SCC_16_WR((pSccChan->pBdBase + 
  285.                      M8260_SCC_RCV_BD_OFF + 
  286.                      M8260_SCC_BD_LEN_OFF), 0x0001);
  287.     CACHE_PIPE_FLUSH ();
  288.     /* buffer address */
  289.     M8260_SCC_32_WR((pSccChan->pBdBase + 
  290.                      M8260_SCC_RCV_BD_OFF + 
  291.                      M8260_SCC_BD_ADDR_OFF), pSccChan->rcvBufferAddr);
  292.     /* set the SCC parameter ram field RBASE */
  293.     * pSccChan->pRBASE = 0x00 + (0x100 * scc);
  294.     /* set up the TRANSMIT buffer descriptors */
  295.     /* 
  296.      * buffer status/control;
  297.      * not ready, Wrap, Bit Clear-to-send_report, Interrupt 
  298.      */
  299.     M8260_SCC_16_WR((pSccChan->pBdBase + 
  300.                      M8260_SCC_TX_BD_OFF + 
  301.                      M8260_SCC_BD_STAT_OFF), 0x3800);
  302.     /* buffer length */
  303.     M8260_SCC_16_WR((pSccChan->pBdBase + 
  304.                      M8260_SCC_TX_BD_OFF + 
  305.                      M8260_SCC_BD_LEN_OFF), 0x0001);
  306.     /* buffer address */
  307.     M8260_SCC_32_WR((pSccChan->pBdBase + 
  308.                      M8260_SCC_TX_BD_OFF + 
  309.                      M8260_SCC_BD_ADDR_OFF), pSccChan->txBufferAddr);
  310.     /* set the SCC parameter ram field TBASE */
  311.     * pSccChan->pTBASE = 0x08 + (0x100 * scc);
  312.     /* disable transmit and receive interrupts */
  313.     * pSCCM &= ~(M8260_SCC_UART_SCCX_RX | M8260_SCC_UART_SCCX_TX);
  314.     /* program the three SCC mode registers: gsmrl, gsmrh, and psmr */
  315.     /* 
  316.      * Protocol Specific Mode Register for SCC
  317.      * Normal CTS, 1 stop bit, 8 data bits 
  318.      */
  319.     * pPSMR   = M8260_SCC_UART_PSMR_FLC  | M8260_SCC_UART_PSMR_CL_8BIT;
  320.     /* 
  321.      * General Serial Mode Register for SCC, high word
  322.      * xmit fifo is 1 byte, receive fifo 8 bits 
  323.      */
  324.     * pGSMR_H = M8260_SCC_GSMRH_RFW      | M8260_SCC_GSMRH_TFL;
  325.     /* 
  326.      * General Serial Mode Register for SCC, low word
  327.      * set SCC attributes to standard UART mode, disable xmit and rcv
  328.      */
  329.     * pGSMR_L = (M8260_SCC_GSMRL_RDCR_X16 | 
  330.  M8260_SCC_GSMRL_TDCR_X16 | 
  331.  M8260_SCC_GSMRL_UART) 
  332.  & ~
  333.  (M8260_SCC_GSMRL_ENT | M8260_SCC_GSMRL_ENR);
  334.     /* initialize parameter RAM area for this SCC */
  335.     * pRFCR = 0x18; /* supervisor data access */
  336.     * pTFCR = 0x18; /* supervisor data access */
  337.     * pMRBLR = 1;
  338.     /* initialize some unused parameters in SCC parameter RAM */
  339.     * pMAX_IDL = 0x0;
  340.     * pBRKCR = 0x0001;
  341.     * pPAREC = 0x0;
  342.     * pFRMEC = 0x0;
  343.     * pNOSEC = 0x0;
  344.     * pBRKEC = 0x0;
  345.     * pUADDR1 = 0x0;
  346.     * pUADDR2 = 0x0;
  347.     * pTOSEQ = 0x0;
  348.     * pCHARACTER1 = 0x8000;
  349.     * pCHARACTER2 = 0x8000;
  350.     * pCHARACTER3 = 0x8000;
  351.     * pCHARACTER4 = 0x8000;
  352.     * pCHARACTER5 = 0x8000;
  353.     * pCHARACTER6 = 0x8000;
  354.     * pCHARACTER7 = 0x8000;
  355.     * pCHARACTER8 = 0x8000;
  356.     * pRCCM = 0x0C0FF;
  357.     CACHE_PIPE_FLUSH ();
  358.    /* wait until the CP is clear */
  359.     ix = 0;
  360.     do
  361.         {
  362.         M8260_SCC_32_RD((M8260_CPCR (immrVal)), cpcrVal);
  363.         if (ix++ == M8260_CPCR_LATENCY)
  364.             break;
  365.         } while (cpcrVal & M8260_CPCR_FLG) ;
  366.     if (ix >= M8260_CPCR_LATENCY)
  367.         {
  368.         /* what to do, other than log an error? */
  369.         }
  370.     /* Tell CP to initialize tx and rx parameters for SCC */
  371.     cpcrVal = (M8260_CPCR_OP (M8260_CPCR_RT_INIT)
  372.                | M8260_CPCR_SBC (M8260_CPCR_SBC_SCC1 | (scc * 0x1))
  373.                | M8260_CPCR_PAGE (M8260_CPCR_PAGE_SCC1 | (scc * 0x1))
  374.                | M8260_CPCR_MCN (M8260_CPCR_MCN_ETH)
  375.                | M8260_CPCR_FLG);
  376.     M8260_SCC_32_WR (M8260_CPCR (immrVal), cpcrVal);
  377.     CACHE_PIPE_FLUSH ();
  378.     /* wait until the CP is clear */
  379.     ix = 0;
  380.     do
  381.         {
  382.         M8260_SCC_32_RD((M8260_CPCR (immrVal)), cpcrVal);
  383.         if (ix++ == M8260_CPCR_LATENCY)
  384.             break;
  385.         } while (cpcrVal & M8260_CPCR_FLG) ;
  386.     if (ix >= M8260_CPCR_LATENCY)
  387.         {
  388.         /* what to do, other than log an error? */
  389.         }
  390.     CACHE_PIPE_FLUSH ();
  391.     /* lastly, enable the transmitter and receiver  */
  392.     * pGSMR_L |= (M8260_SCC_GSMRL_ENT | M8260_SCC_GSMRL_ENR);
  393.     CACHE_PIPE_FLUSH ();
  394.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  395.     }
  396. /*******************************************************************************
  397. *
  398. * m8260SioIoctl - special device control
  399. *
  400. * Allows the caller to get and set the buad rate; to get and set the mode;
  401. * and to get the allowable modes.
  402. *
  403. * RETURNS: OK on success, EIO on device error, ENOSYS on unsupported
  404. *          request.
  405. *
  406. */
  407. LOCAL STATUS m8260SioIoctl
  408.     (
  409.     M8260_SCC_CHAN * pSccChan, /* device to control */
  410.     int request, /* request code */
  411.     int arg /* some argument */
  412.     )
  413.     {
  414.     int  oldlevel;
  415.     STATUS  status = OK;
  416.     UINT8       sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  417.     UINT8       scc = sccNum - 1;             /* a convenience */
  418.     UINT32      immrVal = pSccChan->immrVal;    /* holder for the immr value */
  419.     int         baudRate;
  420.     int         baud;
  421.     VINT32 *pBRGC = (VINT32 *) (immrVal + M8260_BRGC_BASE + 
  422.         (scc * M8260_BRGC_OFFSET_NEXT_BRGC));
  423.     VINT16 *pSCCM = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCM_OFFSET +
  424.                (scc * M8260_SCC_OFFSET_NEXT_SCC));
  425.     switch (request)
  426. {
  427. case SIO_BAUD_SET:
  428.     if (arg >=  300 && arg <= 38400)     /* could go higher... */
  429.                 {
  430.                 baudRate = (baudRateGenClk + (8 * arg)) / (16 * arg);
  431.                 if (--baudRate > 0xfff)
  432.                     baud = (M8260_BRGC_CD_MASK &
  433.                    (((baudRate + 8) / 16) << M8260_BRGC_CD_SHIFT)) |
  434.                     M8260_BRGC_EN | M8260_BRGC_DIVISOR ;
  435.                 else
  436.                     baud = ( M8260_BRGC_CD_MASK &
  437.                         (baudRate << 1)) | M8260_BRGC_EN;
  438.                 *pBRGC = baud;
  439.                 pSccChan->baudRate = arg;
  440.                 }
  441.             else
  442.         status = EIO;
  443.     break;
  444.     
  445. case SIO_BAUD_GET:
  446.     * (int *) arg = pSccChan->baudRate;
  447.     break;
  448. case SIO_MODE_SET:
  449.             if (!((int) arg == SIO_MODE_POLL || (int) arg == SIO_MODE_INT))
  450.                 {
  451.                 status = EIO;
  452.                 break;
  453.                 }
  454.             /* lock interrupt  */
  455.             oldlevel = intLock();
  456.             /* initialize channel on first MODE_SET */
  457.             if (!pSccChan->channelMode)
  458.                 m8260SioResetChannel(pSccChan);
  459.             if (arg == SIO_MODE_INT)
  460. {
  461. /* enable SCC interrupts at the SIU Interrupt Controller */
  462. if (scc == 0) 
  463.     {
  464.                     m8260IntEnable(INUM_SCC1);
  465.     }
  466. else if (scc == 1) 
  467.     {
  468.                     m8260IntEnable(INUM_SCC2);
  469.     }
  470. /* enable receive and transmit interrupts at the scc */
  471. * pSCCM |= (M8260_SCC_UART_SCCX_RX | M8260_SCC_UART_SCCX_TX);
  472. CACHE_PIPE_FLUSH ();
  473. }
  474.             else
  475. {
  476. /* disable transmit and receive interrupts */
  477. * pSCCM &= ~(M8260_SCC_UART_SCCX_RX | M8260_SCC_UART_SCCX_TX);
  478. CACHE_PIPE_FLUSH ();
  479. /* mask off this SCC's interrupt */ 
  480. if (scc == 0) 
  481.                     m8260IntDisable(INUM_SCC1);
  482. else if (scc == 1) 
  483.                     m8260IntDisable(INUM_SCC2);
  484. CACHE_PIPE_FLUSH ();
  485.                 }
  486.             pSccChan->channelMode = arg;
  487.             intUnlock(oldlevel);
  488.             break;
  489.         case SIO_MODE_GET:
  490.             * (int *) arg = pSccChan->channelMode;
  491.     break;
  492.         case SIO_AVAIL_MODES_GET:
  493.             *(int *)arg = SIO_MODE_INT | SIO_MODE_POLL;
  494.     break;
  495. default:
  496.     status = ENOSYS;
  497. }
  498.     return (status);
  499.     }
  500. /*******************************************************************************
  501. *
  502. * m8260SioInt - handle an SCC interrupt
  503. *
  504. * This routine is called to handle SCC interrupts.
  505. *
  506. * RETURNS: NA
  507. */
  508. void m8260SioInt
  509.     (
  510.     M8260_SCC_CHAN *pSccChan
  511.     )
  512.     {
  513.     char outChar;
  514.     VINT16              bdStatus;      /* holder for the BD status */
  515.     UINT8       sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  516.     UINT8       scc = sccNum - 1;             /* a convenience */
  517.     UINT32      immrVal = pSccChan->immrVal;    /* holder for the immr value */
  518.     VINT16 *pSCCE = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCE_OFFSET +
  519.                (scc * M8260_SCC_OFFSET_NEXT_SCC));
  520.     CACHE_PIPE_FLUSH ();
  521.     /* check for a receive event */
  522.     if (* pSCCE & M8260_SCC_UART_SCCX_RX )
  523. {
  524. /*
  525.  * clear receive event bit by setting the bit in the event register.
  526.  * This also clears the bit in SIPNR
  527.  */
  528.         * pSCCE = M8260_SCC_UART_SCCX_RX; 
  529. CACHE_PIPE_FLUSH ();
  530. /* 
  531.  * as long as there is a character: 
  532.  * Inspect bit 0 of the status word which is the empty flag:
  533.  * 0 if buffer is full or if there was an error
  534.  * 1 if buffer is not full
  535.  */
  536. M8260_SCC_16_RD((pSccChan->pBdBase +
  537.  M8260_SCC_RCV_BD_OFF +
  538.  M8260_SCC_BD_STAT_OFF), bdStatus);
  539.         /* if bit is set there is nothing */
  540. while (!(bdStatus & M8260_SCC_UART_RX_BD_EMPTY)) 
  541.     {
  542.     M8260_SCC_8_RD(pSccChan->rcvBufferAddr, outChar);
  543.             /*
  544.              * indicate that we've processed this buffer; set empty
  545.              * flag to 1 indicating that the buffer is empty
  546.              */
  547.     M8260_SCC_16_WR((pSccChan->pBdBase +
  548.                      M8260_SCC_RCV_BD_OFF +
  549.                      M8260_SCC_BD_STAT_OFF), 
  550.                      bdStatus |= M8260_SCC_UART_RX_BD_EMPTY);
  551.             /* necessary when switching from write to read */
  552.     CACHE_PIPE_FLUSH ();
  553.             /* pass the received character up to the tty driver */
  554.     (*pSccChan->putRcvChar) (pSccChan->putRcvArg,outChar);
  555.             /* if driver is in polled mode, we're done */
  556.     if (pSccChan->channelMode == SIO_MODE_POLL)
  557. break;
  558.     /*
  559.              * If interrupt mode, read the status again;
  560.              * it's possible a new char has arrived
  561.              */
  562.     M8260_SCC_16_RD((pSccChan->pBdBase +
  563.      M8260_SCC_RCV_BD_OFF +
  564.      M8260_SCC_BD_STAT_OFF), bdStatus);
  565.     }
  566. }
  567.     /* check for a transmit event and if a character needs to be output */
  568.     /* transmit event */
  569.     CACHE_PIPE_FLUSH ();
  570.     if ((* pSCCE & M8260_SCC_UART_SCCX_TX ) && 
  571.         (pSccChan->channelMode != SIO_MODE_POLL)) /* ...and we're not polling */
  572. {
  573. /*
  574.          * clear transmit event bit by setting the bit in the event register.
  575.          * This also clears the bit in SIPNR
  576.          */
  577.         * pSCCE = M8260_SCC_UART_SCCX_TX; 
  578. CACHE_PIPE_FLUSH ();
  579.     
  580.         if ((*pSccChan->getTxChar) (pSccChan->getTxArg, &outChar) == OK)
  581.             {
  582.     CACHE_PIPE_FLUSH ();
  583.     /* wait for the ready bit to be 0 meaning the buffer is free */
  584.     do
  585. {
  586. M8260_SCC_16_RD((pSccChan->pBdBase +
  587.  M8260_SCC_TX_BD_OFF +
  588.  M8260_SCC_BD_STAT_OFF), bdStatus);
  589. } while (bdStatus & M8260_SCC_UART_TX_BD_READY);
  590.     M8260_SCC_8_WR(pSccChan->txBufferAddr, outChar); /* write char */
  591.     /* set buffer length */
  592.     M8260_SCC_16_WR((pSccChan->pBdBase +
  593.      M8260_SCC_TX_BD_OFF +
  594.      M8260_SCC_BD_LEN_OFF), 0x0001);
  595.                 /* set ready bit so CPM will process buffer */
  596.     M8260_SCC_16_WR((pSccChan->pBdBase +
  597.      M8260_SCC_TX_BD_OFF +
  598.      M8260_SCC_BD_STAT_OFF), 
  599.                              bdStatus |= M8260_SCC_UART_TX_BD_READY);
  600.     CACHE_PIPE_FLUSH ();
  601.     }
  602.         }
  603.     /*
  604.      * acknowledge all other interrupts - ignore events. This also clears
  605.      * the bit in SIPNR
  606.      */
  607.     * pSCCE &= ~(M8260_SCC_UART_SCCX_TX | M8260_SCC_UART_SCCX_RX);
  608.     CACHE_PIPE_FLUSH ();
  609.    }
  610. /*******************************************************************************
  611. *
  612. * m8260SioStartup - transmitter startup routine
  613. * Starts transmission on the indicated channel
  614. *
  615. * RETURNS: OK, or ENOSYS if in polled mode.
  616. */
  617. LOCAL int m8260SioStartup
  618.     (
  619.     M8260_SCC_CHAN *pSccChan /* ty device to start up */
  620.     )
  621.     {
  622.     char outChar;
  623.     UINT16              bdStatus;      /* holder for the BD status */
  624.     if (pSccChan->channelMode == SIO_MODE_POLL)
  625. return (ENOSYS);
  626.     /* 
  627.      * check if a transmit buffer is ready and if a character needs to be 
  628.      * output 
  629.      */
  630.     CACHE_PIPE_FLUSH ();                /* before first read */
  631.     M8260_SCC_16_RD((pSccChan->pBdBase +
  632.      M8260_SCC_TX_BD_OFF +
  633.      M8260_SCC_BD_STAT_OFF), bdStatus);
  634.     if (!(bdStatus & M8260_SCC_UART_TX_BD_READY))
  635. if ((*pSccChan->getTxChar) (pSccChan->getTxArg, &outChar) == OK)
  636.     {
  637.             /* write char; set length; flag buffer as not empty */
  638.     M8260_SCC_8_WR(pSccChan->txBufferAddr, outChar); /* write char */
  639.     /* set buffer length */
  640.     M8260_SCC_16_WR((pSccChan->pBdBase +
  641.      M8260_SCC_TX_BD_OFF +
  642.      M8260_SCC_BD_LEN_OFF), 0x0001);
  643.     /* flag buffer as not empty */
  644.     M8260_SCC_16_WR((pSccChan->pBdBase +
  645.      M8260_SCC_TX_BD_OFF +
  646.      M8260_SCC_BD_STAT_OFF), bdStatus |= 0x8000);
  647.     }
  648.     CACHE_PIPE_FLUSH ();
  649.     return (OK);
  650.     }
  651. /******************************************************************************
  652. *
  653. * m8260SioPollInput - poll the device for input.
  654. *
  655. * Poll the indicated device for input characters
  656. *
  657. * RETURNS: OK if a character arrived, ERROR on device error, EAGAIN
  658. *          if the input buffer is empty.
  659. */
  660. LOCAL int m8260SioPollInput
  661.     (
  662.     SIO_CHAN * pSioChan,
  663.     char * thisChar
  664.     )
  665.     {
  666.     M8260_SCC_CHAN * pSccChan = (M8260_SCC_CHAN *) pSioChan;
  667.     UINT16              bdStatus;      /* holder for the BD status */
  668.     UINT8       sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  669.     UINT8       scc = sccNum - 1;             /* a convenience */
  670.     UINT32      immrVal = pSccChan->immrVal;    /* holder for the immr value */
  671.     VINT16 *pSCCE = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCE_OFFSET +
  672.                (scc * M8260_SCC_OFFSET_NEXT_SCC));
  673.     CACHE_PIPE_FLUSH ();
  674.     /* is there a receive event? */
  675.     if (!(* pSCCE & M8260_SCC_UART_SCCX_RX ))
  676.         return (EAGAIN); 
  677.     /* is the buffer empty? */
  678.     M8260_SCC_16_RD((pSccChan->pBdBase +
  679.      M8260_SCC_RCV_BD_OFF +
  680.      M8260_SCC_BD_STAT_OFF), bdStatus);
  681.     /* if bit is high there is nothing */
  682.     if (bdStatus & M8260_SCC_UART_RX_BD_EMPTY) 
  683. return (EAGAIN);
  684.     /* get a character */
  685.     M8260_SCC_8_RD(pSccChan->rcvBufferAddr, * thisChar);
  686.     /* set the empty bit */
  687.     M8260_SCC_16_WR((pSccChan->pBdBase +
  688.      M8260_SCC_RCV_BD_OFF +
  689.      M8260_SCC_BD_STAT_OFF), bdStatus |= M8260_SCC_UART_RX_BD_EMPTY);
  690.     CACHE_PIPE_FLUSH ();
  691.     /* only clear RX event if no more characters are ready */
  692.     M8260_SCC_16_RD((pSccChan->pBdBase +
  693.      M8260_SCC_RCV_BD_OFF +
  694.      M8260_SCC_BD_STAT_OFF), bdStatus);
  695.     CACHE_PIPE_FLUSH ();
  696.     /* if bit is high there is nothing */
  697.     if (bdStatus & M8260_SCC_UART_RX_BD_EMPTY) 
  698. *pSCCE = M8260_SCC_UART_SCCX_RX; /* clear rx event bit */
  699.     CACHE_PIPE_FLUSH ();
  700.     return (OK);
  701.     }
  702. /******************************************************************************
  703. *
  704. * m8260SioPollOutput - output a character in polled mode.
  705. *
  706. * Transmit a character in polled mode
  707. *
  708. * RETURNS: OK if a character is sent, ERROR on device error, EAGAIN
  709. *          if the output buffer if full.
  710. */
  711. static int m8260SioPollOutput
  712.     (
  713.     SIO_CHAN * pSioChan,
  714.     char outChar
  715.     )
  716.     {
  717.     M8260_SCC_CHAN * pSccChan = (M8260_SCC_CHAN *) pSioChan;
  718.     int i;
  719.     UINT16              bdStatus;      /* holder for the BD status */
  720.     UINT8       sccNum = pSccChan->sccNum;      /* holder for the fcc number */
  721.     UINT8       scc = sccNum - 1;             /* a convenience */
  722.     UINT32      immrVal = pSccChan->immrVal;    /* holder for the immr value */
  723.     VINT16 *pSCCE = (VINT16 *) (immrVal + M8260_SCC_BASE + M8260_SCCE_OFFSET +
  724.                (scc * M8260_SCC_OFFSET_NEXT_SCC));
  725.     CACHE_PIPE_FLUSH ();
  726.     /*
  727.      * wait a bit for the last character to get out
  728.      * because the PPC603 is a very fast processor
  729.      */
  730.     for (i=0; i<M8260_SCC_POLL_OUT_DELAY; i++)
  731.         ;
  732.     /*
  733.      * is the transmitter ready yet to accept a character?
  734.      * if still not, we have a problem
  735.      */
  736.     M8260_SCC_16_RD((pSccChan->pBdBase +
  737.      M8260_SCC_TX_BD_OFF +
  738.      M8260_SCC_BD_STAT_OFF), bdStatus);
  739.     if (!(bdStatus & 0x8000))
  740. return(EAGAIN);
  741.     /* reset the transmitter status bit */
  742.     /*
  743.      * clear transmit event bit by setting the bit in the event register.
  744.      * This also clears the bit in SIPNR
  745.      */
  746.     * pSCCE = M8260_SCC_UART_SCCX_TX; 
  747.     /* write char; set length; flag buffer as not empty */
  748.     M8260_SCC_8_WR(pSccChan->txBufferAddr, outChar); /* write char */
  749.     /* set buffer length */
  750.     M8260_SCC_16_WR((pSccChan->pBdBase +
  751.      M8260_SCC_TX_BD_OFF +
  752.      M8260_SCC_BD_LEN_OFF), 0x0001);
  753.     /* flag buffer as not empty */
  754.     M8260_SCC_16_WR((pSccChan->pBdBase +
  755.      M8260_SCC_TX_BD_OFF +
  756.      M8260_SCC_BD_STAT_OFF), 
  757.                      bdStatus |= M8260_SCC_UART_TX_BD_READY);
  758.     CACHE_PIPE_FLUSH ();
  759.     return (OK);
  760.     }
  761. /******************************************************************************
  762. *
  763. * m8260SioCallbackInstall - install ISR callbacks to get and put chars.
  764. *
  765. * Install the indicated ISR callback functions that are used to get and
  766. * put characters
  767. *
  768. * RETURNS: NA
  769. *
  770. */
  771. static int m8260SioCallbackInstall
  772.     (
  773.     SIO_CHAN * pSioChan,
  774.     int callbackType,
  775.     STATUS (* callback)(),
  776.     void * callbackArg
  777.     )
  778.     {
  779.     M8260_SCC_CHAN * pSccChan = (M8260_SCC_CHAN *) pSioChan;
  780.     CACHE_PIPE_FLUSH ();
  781.     switch (callbackType)
  782.         {
  783.         case SIO_CALLBACK_GET_TX_CHAR:
  784.             pSccChan->getTxChar    = callback;
  785.             pSccChan->getTxArg     = callbackArg;
  786.             return (OK);
  787.     break;
  788.         case SIO_CALLBACK_PUT_RCV_CHAR:
  789.             pSccChan->putRcvChar   = callback;
  790.             pSccChan->putRcvArg    = callbackArg;
  791.             return (OK);
  792.     break;
  793.         default:
  794.             return (ENOSYS);
  795.         }
  796.     }