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

VxWorks

开发平台:

C/C++

  1. /* m68302Sio.c - Motorola MC68302 bimodal tty driver */
  2. /* Copyright 1984-1996 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 01g,11jul97,dgp  doc: correct ttyDrv and tyLib in SEE ALSO
  8. 01f,20jun97,map  fixed RX event clear [SPR# 8803]
  9. 01e,12dec96,map  handle non-DPRAM buffers [SPR# 7479]
  10. 01d,06nov96,dgp  doc: final formatting
  11. 01c,30may96,dat  More ISR work, work on ModeSet().
  12. 01b,24may96,dat  fixed ISR and modeSet rtn, new baud rate setup
  13.  added polled mode operation.
  14. 01a,01mar96,dat  written (from m68302Serial.c).
  15. */
  16. /*
  17. DESCRIPTION
  18. This is the driver for the internal communications processor (CP)
  19. of the Motorola MC68302.
  20. USER-CALLABLE ROUTINES
  21. Most of the routines in this driver are accessible only through the I/O
  22. system.  Before the driver can be used, it must be initialized by calling the
  23. routines m68302SioInit() and m68302SioInit2().
  24. Normally, they are called by sysSerialHwInit() and sysSerialHwInit2()
  25. in sysSerial.c
  26. This driver uses 408 bytes of buffer space as follows:
  27.   128 bytes for portA tx buffer
  28.   128 bytes for portB tx buffer
  29.   128 bytes for portC tx buffer
  30.     8 bytes for portA rx buffers (8 buffers, 1 byte each)
  31.     8 bytes for portB rx buffers (8 buffers, 1 byte each)
  32.     8 bytes for portC rx buffers (8 buffers, 1 byte each)
  33. The buffer pointer in the `m68302cp' structure points to the buffer area,
  34. which is usually specified as IMP_BASE_ADDR.
  35. INTERNAL
  36. There is only one Tx buffer for each SCC device.  This is probably because
  37. SCC1 and SCC2 can have 8 buffers each, but SCC3 can only have 4.
  38. Hardware abstraction isn't used in this driver.  These SCCs are internal
  39. to the CPU.  It doesn't seem to make sense to abstract it under that
  40. condition - i.e. it can't be used with any other CPU.
  41. IOCTL FUNCTIONS
  42. This driver responds to the same ioctl() codes as a normal tty driver; for
  43. more information, see the manual entry for tyLib.  The available baud
  44. rates are 300, 600, 1200, 2400, 4800, 9600 and 19200.
  45. SEE ALSO
  46. ttyDrv, tyLib
  47. INCLUDE FILES: drv/sio/m68302Sio.h sioLib.h
  48. */
  49. #include "vxWorks.h"
  50. #include "sioLib.h"
  51. #include "intLib.h"
  52. #include "errno.h"
  53. #include "drv/sio/m68302Sio.h"
  54. #define MIN_BRG_DIV  3
  55. #define MAX_BRG_DIV  2047
  56. #define RX_BD_NUM  8 /* number of receiver BDs */
  57. #define DPRAM_START (char *)((*IMP_BAR & 0x0fff) << 12)
  58. #define DPRAM_END (DPRAM_START + 0x0fff)
  59. /* forward LOCAL declarations */
  60. LOCAL int m68302SioTxStartup (SIO_CHAN * pSioChan);
  61. LOCAL int m68302SioCallbackInstall (SIO_CHAN *pSioChan, int callbackType,
  62. STATUS (*callback)(), void *callbackArg);
  63. LOCAL int m68302SioPollOutput (SIO_CHAN *pSioChan, char outChar);
  64. LOCAL int m68302SioPollInput (SIO_CHAN *pSioChan, char *thisChar);
  65. LOCAL int m68302SioIoctl (SIO_CHAN *pSioChan, int request, void *arg);
  66. LOCAL void m68302SioChanInit (M68302_CHAN *pChan, M68302_CP *pCp);
  67. LOCAL STATUS dummyCallback (void);
  68. LOCAL int m68302ModeSet (M68302_CHAN *, uint_t);
  69. LOCAL int m68302BaudSet (M68302_CHAN *, int);
  70. /* local variables */
  71. #ifndef DEFAULT_BAUD
  72. #   define DEFAULT_BAUD 9600
  73. #endif
  74. LOCAL SIO_DRV_FUNCS m68302SioDrvFuncs =
  75.     {
  76.     m68302SioIoctl,
  77.     m68302SioTxStartup,
  78.     m68302SioCallbackInstall,
  79.     m68302SioPollInput,
  80.     m68302SioPollOutput
  81.     };
  82. /******************************************************************************
  83. *
  84. * m68302SioInit - initialize a M68302_CP
  85. *
  86. * This routine initializes the driver
  87. * function pointers and then resets the chip to a quiescent state.
  88. * The BSP must already have initialized all the device addresses and the
  89. * `baudFreq' fields in the M68302_CP structure before passing it to this
  90. * routine. The routine resets the device and initializes everything to support 
  91. * polled mode (if possible), but does not enable interrupts.
  92. *
  93. * RETURNS: N/A
  94. */
  95. void m68302SioInit
  96.     (
  97.     M68302_CP * pCp
  98.     )
  99.     {
  100.     int oldlevel = intLock (); /* LOCK INTERRUPTS */
  101.     /* reset the chip */
  102.     *pCp->pCr =  (char) (CR_RST | CR_FLG);
  103.     while (*pCp->pCr != 0)  /* Wait for reset to finish */
  104. /* do nothing */ ;
  105.     *pCp->pImr    = 0;
  106.     *pCp->pSiMask = 0xffff;
  107.     *pCp->pSiMode = 0x0000; /* NMSI for all channels */
  108.     pCp->intEnable= FALSE; /* disable int mode for now */
  109.     m68302SioChanInit (&pCp->portA, pCp);
  110.     m68302SioChanInit (&pCp->portB, pCp);
  111.     m68302SioChanInit (&pCp->portC, pCp);
  112.     intUnlock (oldlevel); /* UNLOCK INTERRUPTS */
  113.     }
  114. /******************************************************************************
  115. *
  116. * m68302SioInit2 - initialize a M68302_CP (part 2)
  117. *
  118. * Enables interrupt mode of operation.
  119. *
  120. * RETURNS: N/A
  121. */
  122. void m68302SioInit2
  123.     (
  124.     M68302_CP * pCp
  125.     )
  126.     {
  127.     pCp->intEnable = TRUE;
  128.     /* reset mode, since it may have changed */
  129.     m68302ModeSet (&pCp->portA, pCp->portA.mode);
  130.     m68302ModeSet (&pCp->portB, pCp->portB.mode);
  131.     m68302ModeSet (&pCp->portC, pCp->portC.mode);
  132.     *pCp->pImr |= pCp->imrMask;/* unmask int */
  133.     }
  134. /*********************************************************************
  135. *
  136. * m68302SioChanInit - initialize a single channel
  137. *
  138. * Initialize a single channel of the Communications Processor.  The
  139. * default initialization places the channel in UART protocol.
  140. *
  141. * If the pScc pointer is null, then this channel will not be initialized.
  142. * This is used to prevent initialization of a non-existant SCC channel
  143. * on some CPU variants.
  144. *
  145. * RETURNS: N/A
  146. */
  147. LOCAL void m68302SioChanInit
  148.     (
  149.     M68302_CHAN *pChan,
  150.     M68302_CP *pCp
  151.     )
  152.     {
  153.     int frame;
  154.     int baud;
  155.     int bdLocFlag=0;
  156.     if (pChan == NULL
  157.      || pChan->pScc == NULL)
  158. return;
  159.     if ((pCp->buffer < DPRAM_START) || (pCp->buffer > DPRAM_END))
  160.         bdLocFlag = UART_RX_BD_EXT;
  161.     pChan->sio.pDrvFuncs= &m68302SioDrvFuncs;
  162.     pChan->getTxChar    = dummyCallback;
  163.     pChan->putRcvChar = dummyCallback;
  164.     pChan->pCp = pCp;
  165.     pChan->pSccReg->scon= 0x0;
  166.     baud = (pChan->baud <= 0 ? DEFAULT_BAUD : pChan->baud);
  167.     m68302SioIoctl (&pChan->sio, SIO_BAUD_SET, (void *)baud);
  168.     pChan->mode = SIO_MODE_POLL;
  169.     /* 8 data bits, 1 stop bit, no parity, Rcvr enabled */
  170.     pChan->options = (CREAD | CS8);
  171.     pChan->pSccReg->scm = UART_SCM_ASYNC | UART_SCM_MANUAL |
  172.   UART_SCM_8BIT | UART_SCM_RTSM;
  173.     pChan->pSccReg->dsr = 0x7e7e; /* no fractional stop bits */
  174.     pChan->pParam->rfcr = 0x50; /* sup. data access */
  175.     pChan->pParam->tfcr = 0x50; /* sup. data access */
  176.     pChan->pParam->mrblr = 0x1; /* one character rx buffers */
  177.     /* next receive buffer */
  178.     pChan->rxBdNext = 0;
  179.     for (frame = 0; frame < 8; frame ++)
  180. {
  181. pChan->pScc->rxBd[frame].statusMode = bdLocFlag | UART_RX_BD_EMPTY
  182.     | UART_RX_BD_INT;
  183. pChan->pScc->rxBd[frame].dataLength = 1;
  184. pChan->pScc->rxBd[frame].dataPointer =
  185. (char *)((pChan->channel << 3) + frame + 0x180
  186. + (int)pCp->buffer);
  187. }
  188.     pChan->pScc->rxBd[RX_BD_NUM-1].statusMode |= UART_RX_BD_WRAP;
  189.     pChan->pScc->txBd[0].statusMode = bdLocFlag | UART_TX_BD_INT
  190.            | UART_TX_BD_WRAP;
  191.     pChan->pScc->txBd[0].dataLength = 0x80;
  192.     pChan->pScc->txBd[0].dataPointer = (char *)(pChan->channel * 0x80 +
  193.   (int)pCp->buffer);
  194.     pChan->pProt->maxIdl = 0x0;
  195.     pChan->pProt->idlc = 0x0;
  196.     pChan->pProt->brkcr = 0x0;
  197.     pChan->pProt->parec = 0x0;
  198.     pChan->pProt->frmec = 0x0;
  199.     pChan->pProt->nosec = 0x0;
  200.     pChan->pProt->brkec = 0x0;
  201.     pChan->pProt->uaddr1 = 0x0;
  202.     pChan->pProt->uaddr2 = 0x0;
  203.     pChan->pProt->cntChar1 = 0x8000;
  204.     pChan->pSccReg->scce = 0xff; /* clr all events */
  205.     pChan->pSccReg->sccm = 0;  /* mask all events for now */
  206.     pChan->pSccReg->scm |= UART_SCM_ENR | UART_SCM_ENT; /* enable RX,TX */
  207.     }
  208. /*******************************************************************************
  209. *
  210. * m68302SioInt - handle an SCC interrupt
  211. *
  212. * This routine gets called to handle SCC interrupts.
  213. *
  214. * RETURNS: N/A.
  215. *
  216. * NOMANUAL
  217. */
  218. void m68302SioInt
  219.     (
  220.     M68302_CHAN *pChan
  221.     )
  222.     {
  223.     char outChar;
  224.     FAST UINT16   dataLen = 0;
  225.     FAST UINT8    event = pChan->pSccReg->scce;
  226.     /* acknowledge interrupt */
  227.     pChan->pSccReg->scce= event; /* clear events */
  228.     /* restrict ourselves to interrupt events, not polled events */
  229.     event &= pChan->pSccReg->sccm;
  230.     *pChan->pCp->pIsr = pChan->intAck; /* ack. interrupt */
  231.     /* a negative channel # indicates an inactive channel */
  232.     if (pChan->channel < 0)
  233. return;
  234.     if (event & UART_SCCE_TX)
  235. {
  236. /* fill buffer with data */
  237. while (dataLen <= 0x80
  238.     && pChan->mode != SIO_MODE_POLL
  239.     && (pChan->getTxChar)(pChan->getTxArg, &outChar) == OK)
  240.     {
  241.     pChan->pScc->txBd[0].dataPointer[dataLen++] = outChar;
  242.     }
  243. /* handoff buffer to device */
  244. if (dataLen > 0)
  245.     {
  246.     pChan->pScc->txBd[0].dataLength  = dataLen;
  247.     pChan->pScc->txBd[0].statusMode |= UART_TX_BD_READY;
  248.     }
  249. }
  250.     /* Rx buffers are 1 chara in length, get all available */
  251.     if (event & UART_SCCE_RX)
  252. {
  253. int nextBd = pChan->rxBdNext;
  254. while (!(pChan->pScc->rxBd[nextBd].statusMode & UART_RX_BD_EMPTY)
  255.     && pChan->mode != SIO_MODE_POLL )
  256.     {
  257.     char data;
  258.     data = pChan->pScc->rxBd[nextBd].dataPointer[0];
  259.     pChan->pScc->rxBd[nextBd].statusMode |= UART_RX_BD_EMPTY;
  260.     nextBd = (nextBd + 1) % RX_BD_NUM;
  261.     pChan->rxBdNext = nextBd;
  262.     (*pChan->putRcvChar) (pChan->putRcvArg, data);
  263.     }
  264. }
  265.     /* all other events ignored */
  266.     }
  267. /******************************************************************************
  268. *
  269. * m68302SioTxStartup - start the interrupt transmitter
  270. *
  271. * This routine is called from ttyDrv to start the transmitter when data
  272. * is ready to go out.  TtyDrv keeps track of the transmitter status and only
  273. * calls this routine when needed to startup character output.
  274. *
  275. * RETURNS:
  276. * Returns OK on success, ENOSYS if the device is polled-only, or
  277. * EIO on hardware error.
  278. */
  279. LOCAL int m68302SioTxStartup
  280.     (
  281.     SIO_CHAN * pSioChan /* channel to start */
  282.     )
  283.     {
  284.     char outChar;
  285.     FAST int dataLen = 0;
  286.     M68302_CHAN *pChan = (M68302_CHAN *)pSioChan;
  287.     if (!(pChan->pScc->txBd[0].statusMode & UART_TX_BD_READY))
  288. {
  289. while ((dataLen <= 0x80)
  290.    && ((*pChan->getTxChar)(pChan->getTxArg, &outChar) == OK))
  291.     {
  292.     pChan->pScc->txBd[0].dataPointer[dataLen++] = outChar;
  293.     }
  294. if (dataLen > 0)
  295.     {
  296.     pChan->pScc->txBd[0].dataLength  = dataLen;
  297.     pChan->pScc->txBd[0].statusMode |= UART_TX_BD_READY;
  298.     }
  299. }
  300.     return (OK);
  301.     }
  302. /**************************************************************************
  303. *
  304. * m68302SioCallbackInstall - install ISR callbacks to get/put chars
  305. *
  306. * This driver allows interrupt callbacks for transmitting characters
  307. * and receiving characters. In general, drivers may support other
  308. * types of callbacks too.
  309. *
  310. * RETURNS:
  311. * Returns OK on success, or ENOSYS for an unsupported callback type.
  312. */
  313. LOCAL int m68302SioCallbackInstall
  314.     (
  315.     SIO_CHAN   *pSioChan, /* channel */
  316.     int callbackType, /* type of callback */
  317.     FUNCPTR callback, /* callback */
  318.     void *callbackArg /* parameter to callback */
  319.     )
  320.     {
  321.     M68302_CHAN *pChan = (M68302_CHAN *)pSioChan;
  322.     switch (callbackType)
  323. {
  324. case SIO_CALLBACK_GET_TX_CHAR:
  325.     pChan->getTxChar = callback;
  326.     pChan->getTxArg = callbackArg;
  327.     return (OK);
  328. case SIO_CALLBACK_PUT_RCV_CHAR:
  329.     pChan->putRcvChar = callback;
  330.     pChan->putRcvArg = callbackArg;
  331.     return (OK);
  332. default:
  333.     return (ENOSYS);
  334. }
  335.     }
  336. /*************************************************************************
  337. *
  338. * m68302SioPollOutput - output a character in polled mode
  339. *
  340. * Send out a single character in polled mode, if the transmitter is not
  341. * busy.  If it is busy, then EAGAIN is returned and the caller routine
  342. * must try again later.
  343. *
  344. * RETURNS:
  345. * Returns OK if a character arrived, EIO on device error, EAGAIN
  346. * if the output buffer if full. ENOSYS if the device is
  347. * interrupt-only.
  348. */
  349. LOCAL int m68302SioPollOutput
  350.     (
  351.     SIO_CHAN   *pSioChan,
  352.     char outChar
  353.     )
  354.     {
  355.     M68302_CHAN *pChan = (M68302_CHAN *)pSioChan;
  356.     if (pChan->pScc->txBd[0].statusMode & UART_TX_BD_READY)
  357.         return EAGAIN;
  358.  
  359.     /* reset the transmitter status bit */
  360.     pChan->pSccReg->scce = UART_SCCE_TX;
  361.  
  362.     /* fill buffer with data */
  363.     pChan->pScc->txBd[0].dataPointer[0] = outChar;
  364.     pChan->pScc->txBd[0].dataLength  = 1;
  365.     pChan->pScc->txBd[0].statusMode |= UART_TX_BD_READY;
  366.     return OK;
  367.     }
  368. /******************************************************************************
  369. *
  370. * m68302SioPollInput - poll the device for input
  371. *
  372. * RETURNS:
  373. * Returns OK if a character arrived, EIO on device error, EAGAIN
  374. * if the input buffer if empty, ENOSYS if the device is
  375. * interrupt-only.
  376. */
  377. LOCAL int m68302SioPollInput
  378.     (
  379.     SIO_CHAN   *pSioChan,
  380.     char * thisChar
  381.     )
  382.     {
  383.     M68302_CHAN *pChan = (M68302_CHAN *)pSioChan;
  384.     int nextBd;
  385.     nextBd = pChan->rxBdNext;
  386.     if (pChan->pScc->rxBd[nextBd].statusMode & UART_RX_BD_EMPTY)
  387. return EAGAIN;
  388.     *thisChar = pChan->pScc->rxBd[nextBd].dataPointer[0];
  389.     pChan->pScc->rxBd[nextBd].statusMode |= UART_RX_BD_EMPTY;
  390.     pChan->rxBdNext = (nextBd + 1) % RX_BD_NUM;
  391.     /* reset RX event if no more data */
  392.     if (pChan->pScc->rxBd[pChan->rxBdNext].statusMode & UART_RX_BD_EMPTY)
  393. pChan->pSccReg->scce = UART_SCCE_RX;
  394.     return OK;
  395.     }
  396. /******************************************************************************
  397. *
  398. * m68302ModeSet - toggle between interrupt and polled mode
  399. *
  400. * Changes the mode of the channel.  Note that only one channel can be
  401. * in polled mode at a time.  Most drivers do not enforce this though.
  402. *
  403. * RETURNS:
  404. * Returns OK on success, EIO on unsupported mode.
  405. */
  406. LOCAL int m68302ModeSet
  407.     (
  408.     M68302_CHAN *pChan, /* channel */
  409.     uint_t    newMode     /* new mode */
  410.     )
  411.     {
  412.     int level;
  413.     if (pChan == NULL
  414.      || pChan->pScc == NULL
  415.      || (newMode != SIO_MODE_POLL && newMode != SIO_MODE_INT))
  416. return (EIO);
  417.     if ((pChan->mode == SIO_MODE_POLL) && (newMode == SIO_MODE_INT))
  418. {
  419. while (pChan->pScc->txBd[0].statusMode & UART_TX_BD_READY)
  420.     ;
  421. }
  422.     level = intLock ();
  423.     if (newMode == SIO_MODE_INT
  424.      && pChan->pCp->intEnable == TRUE)
  425. {
  426. /* interrupt mode */
  427. *pChan->pCp->pIsr = pChan->intAck; /* reset ISR */
  428. *pChan->pCp->pImr |= pChan->intAck; /* enable int */
  429. pChan->pSccReg->scce = UART_SCCE_RX; /* reset rcv flag */
  430. pChan->pSccReg->sccm = UART_SCCE_RX | UART_SCCE_TX; /* enable events */
  431. }
  432.     else if (newMode == SIO_MODE_POLL)
  433. {
  434. /* Polled mode */
  435. pChan->pSccReg->sccm = 0; /* mask events */
  436. *pChan->pCp->pImr &= ~(pChan->intAck); /* mask interrupts */
  437. }
  438.     
  439.     pChan->mode = newMode;
  440.     intUnlock (level);
  441.     return (OK);
  442.     }
  443. /******************************************************************************
  444. *
  445. * m68302BaudSet - set baud rate for channel
  446. *
  447. * Change the baud rate for the specified channel.  The new baud rate
  448. * divisor is calculated and written to the scon register.
  449. *
  450. * For very slow baud rates the divide by 4 bit will be turned on.
  451. * Otherwise it will be off.
  452. *
  453. * NOTE: This driver can accept any baud rate as a valid value as long as
  454. * a valid divisor value can be computed.  The exact range of valid baud
  455. * rates will depend on the system clock rate, but rates from 200 to 300,000
  456. * will usually be okay.
  457. *
  458. * RETURNS:
  459. * Returns OK on success, EIO on unsupported mode.
  460. */
  461. LOCAL int m68302BaudSet
  462.     (
  463.     M68302_CHAN *pChan,
  464.     int baud
  465.     )
  466.     {
  467.     int tempDiv;
  468.     int baudClk;
  469.     int divBy4=0;
  470.     int scon;
  471.     int oldLevel;
  472.     /* Async clock is 1/16 the system clock, Sync clk = system clock */
  473.     baudClk = pChan->pCp->clockRate / 16;
  474.     tempDiv = baudClk / baud;
  475.     /* for slow baud rates, set divBy4 bit and recalc divisor */
  476.     if (tempDiv > (MAX_BRG_DIV + 1))
  477. {
  478. tempDiv = (baudClk / 4) / baud;
  479. divBy4 = 1;
  480. }
  481.     /* always subtract 1 */
  482.     tempDiv -= 1;
  483.     /* check for valid divisor, return error indication if not valid */
  484.     if (tempDiv < MIN_BRG_DIV
  485.      || tempDiv > MAX_BRG_DIV)
  486. return EIO;
  487.     /* change current rate */
  488.     oldLevel = intLock ();
  489.     scon  = pChan->pSccReg->scon & 0xf000;
  490.     scon |= (((tempDiv << 1) | divBy4) & 0x0fff);
  491.     pChan->pSccReg->scon = scon;
  492.     intUnlock (oldLevel);
  493.     pChan->baud = baud;
  494.     return OK;
  495.     }
  496. /*******************************************************************************
  497. *
  498. * m68302SioIoctl - special device control
  499. *
  500. * Perform device specific i/o control functions.  This routine is called
  501. * from ttyDrv first, and if this routine returns ENOSYS, then ttyDrv will
  502. * call tyLib with the same arguments.  The tyLib ioctl is not called if
  503. * this routine returns OK, or EIO.
  504. *
  505. * RETURNS:
  506. * Returns OK on success, ENOSYS on unsupported request, EIO on failed
  507. * request.
  508. */
  509. LOCAL int m68302SioIoctl
  510.     (
  511.     SIO_CHAN   *pSioChan, /* device to control */
  512.     int request, /* request code */
  513.     void * someArg /* some argument */
  514.     )
  515.     {
  516.     M68302_CHAN *pChan = (M68302_CHAN *)pSioChan;
  517.     int arg = (int)someArg;
  518.     switch (request)
  519. {
  520. case SIO_BAUD_SET:
  521.     /* set the baud rate */
  522.     return m68302BaudSet (pChan, arg);
  523. case SIO_BAUD_GET:
  524.     /* Get the baud rate and return OK */
  525.     *(int *)arg = pChan->baud;
  526.     return OK;
  527. case SIO_MODE_SET:
  528.     /*
  529.      * Set the mode (e.g., to interrupt or polled). Return OK
  530.      * or EIO for an unknown or unsupported mode.
  531.      */
  532.     return m68302ModeSet (pChan, arg);
  533. case SIO_MODE_GET:
  534.     /*
  535.      * Get the current mode and return OK.
  536.      */
  537.     *(int *)arg = pChan->mode;
  538.     return OK;
  539. case SIO_AVAIL_MODES_GET:
  540.     /*
  541.      * Get the available modes and return OK.
  542.      */
  543.     *(int *)arg = (SIO_MODE_INT | SIO_MODE_POLL);
  544.     return OK;
  545. case SIO_HW_OPTS_GET:
  546.     /*
  547.      * Optional command to get the hardware options (as defined
  548.      * in sioLib.h).
  549.      * Return OK or ENOSYS if this command is not implemented.
  550.      * Note: if this command is unimplemented, it will be
  551.      * assumed that the driver options are CREAD | CS8 (e.g.,
  552.      * eight data bits, one stop bit, no parity, ints enabled).
  553.      */
  554.     *(int *)arg = pChan->options;
  555.     return OK;
  556. case SIO_HW_OPTS_SET:
  557.     /*
  558.      * Optional command to set the hardware options (as defined
  559.      * in sioLib.h).
  560.      * Return OK, or ENOSYS if this command is not implemented.
  561.      * Note: several hardware options are specified at once.
  562.      * This routine should set as many as it can and then return
  563.      * OK. The SIO_HW_OPTS_GET is used to find out which options
  564.      * were actually set.
  565.      */
  566.     return ENOSYS;
  567. default:
  568.     return ENOSYS;
  569. }
  570.     }
  571. /*******************************************************************************
  572. *
  573. * dummyCallback - dummy callback routine
  574. *
  575. * RETURNS:
  576. * Always returs ERROR.
  577. *
  578. * NOMANUAL
  579. */
  580. LOCAL STATUS dummyCallback (void)
  581.     {
  582.     return ERROR;
  583.     }