xref: /freebsd-11-stable/sys/dev/rp/rp.c (revision 4ab2e064d7950be84256d671a7ae93f87cc6aa36)
1 /*-
2  * Copyright (c) Comtrol Corporation <support@comtrol.com>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted prodived that the follwoing conditions
7  * are met.
8  * 1. Redistributions of source code must retain the above copyright
9  *    notive, this list of conditions and the following disclainer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials prodided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *       This product includes software developed by Comtrol Corporation.
16  * 4. The name of Comtrol Corporation may not be used to endorse or
17  *    promote products derived from this software without specific
18  *    prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
21  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
24  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  */
33 
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36 
37 /*
38  * rp.c - for RocketPort FreeBSD
39  */
40 
41 #include "opt_compat.h"
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/endian.h>
46 #include <sys/fcntl.h>
47 #include <sys/malloc.h>
48 #include <sys/serial.h>
49 #include <sys/tty.h>
50 #include <sys/conf.h>
51 #include <sys/kernel.h>
52 #include <machine/resource.h>
53 #include <machine/bus.h>
54 #include <sys/bus.h>
55 #include <sys/rman.h>
56 
57 #define ROCKET_C
58 #include <dev/rp/rpreg.h>
59 #include <dev/rp/rpvar.h>
60 
61 static const char RocketPortVersion[] = "3.02";
62 
63 static Byte_t RData[RDATASIZE] =
64 {
65    0x00, 0x09, 0xf6, 0x82,
66    0x02, 0x09, 0x86, 0xfb,
67    0x04, 0x09, 0x00, 0x0a,
68    0x06, 0x09, 0x01, 0x0a,
69    0x08, 0x09, 0x8a, 0x13,
70    0x0a, 0x09, 0xc5, 0x11,
71    0x0c, 0x09, 0x86, 0x85,
72    0x0e, 0x09, 0x20, 0x0a,
73    0x10, 0x09, 0x21, 0x0a,
74    0x12, 0x09, 0x41, 0xff,
75    0x14, 0x09, 0x82, 0x00,
76    0x16, 0x09, 0x82, 0x7b,
77    0x18, 0x09, 0x8a, 0x7d,
78    0x1a, 0x09, 0x88, 0x81,
79    0x1c, 0x09, 0x86, 0x7a,
80    0x1e, 0x09, 0x84, 0x81,
81    0x20, 0x09, 0x82, 0x7c,
82    0x22, 0x09, 0x0a, 0x0a
83 };
84 
85 static Byte_t RRegData[RREGDATASIZE]=
86 {
87    0x00, 0x09, 0xf6, 0x82,	       /* 00: Stop Rx processor */
88    0x08, 0x09, 0x8a, 0x13,	       /* 04: Tx software flow control */
89    0x0a, 0x09, 0xc5, 0x11,	       /* 08: XON char */
90    0x0c, 0x09, 0x86, 0x85,	       /* 0c: XANY */
91    0x12, 0x09, 0x41, 0xff,	       /* 10: Rx mask char */
92    0x14, 0x09, 0x82, 0x00,	       /* 14: Compare/Ignore #0 */
93    0x16, 0x09, 0x82, 0x7b,	       /* 18: Compare #1 */
94    0x18, 0x09, 0x8a, 0x7d,	       /* 1c: Compare #2 */
95    0x1a, 0x09, 0x88, 0x81,	       /* 20: Interrupt #1 */
96    0x1c, 0x09, 0x86, 0x7a,	       /* 24: Ignore/Replace #1 */
97    0x1e, 0x09, 0x84, 0x81,	       /* 28: Interrupt #2 */
98    0x20, 0x09, 0x82, 0x7c,	       /* 2c: Ignore/Replace #2 */
99    0x22, 0x09, 0x0a, 0x0a	       /* 30: Rx FIFO Enable */
100 };
101 
102 #if 0
103 /* IRQ number to MUDBAC register 2 mapping */
104 Byte_t sIRQMap[16] =
105 {
106    0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
107 };
108 #endif
109 
110 Byte_t rp_sBitMapClrTbl[8] =
111 {
112    0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
113 };
114 
115 Byte_t rp_sBitMapSetTbl[8] =
116 {
117    0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
118 };
119 
120 static void rpfree(void *);
121 
122 /***************************************************************************
123 Function: sReadAiopID
124 Purpose:  Read the AIOP idenfication number directly from an AIOP.
125 Call:	  sReadAiopID(CtlP, aiop)
126 	  CONTROLLER_T *CtlP; Ptr to controller structure
127 	  int aiop: AIOP index
128 Return:   int: Flag AIOPID_XXXX if a valid AIOP is found, where X
129 		 is replace by an identifying number.
130 	  Flag AIOPID_NULL if no valid AIOP is found
131 Warnings: No context switches are allowed while executing this function.
132 
133 */
sReadAiopID(CONTROLLER_T * CtlP,int aiop)134 int sReadAiopID(CONTROLLER_T *CtlP, int aiop)
135 {
136    Byte_t AiopID;		/* ID byte from AIOP */
137 
138    rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL);     /* reset AIOP */
139    rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0);
140    AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07;
141    if(AiopID == 0x06)
142       return(1);
143    else 			       /* AIOP does not exist */
144       return(-1);
145 }
146 
147 /***************************************************************************
148 Function: sReadAiopNumChan
149 Purpose:  Read the number of channels available in an AIOP directly from
150 	  an AIOP.
151 Call:	  sReadAiopNumChan(CtlP, aiop)
152 	  CONTROLLER_T *CtlP; Ptr to controller structure
153 	  int aiop: AIOP index
154 Return:   int: The number of channels available
155 Comments: The number of channels is determined by write/reads from identical
156 	  offsets within the SRAM address spaces for channels 0 and 4.
157 	  If the channel 4 space is mirrored to channel 0 it is a 4 channel
158 	  AIOP, otherwise it is an 8 channel.
159 Warnings: No context switches are allowed while executing this function.
160 */
sReadAiopNumChan(CONTROLLER_T * CtlP,int aiop)161 int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop)
162 {
163    Word_t x, y;
164 
165    rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
166    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0);	   /* read from SRAM, chan 0 */
167    x = rp_readaiop2(CtlP, aiop, _INDX_DATA);
168    rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000);  /* read from SRAM, chan 4 */
169    y = rp_readaiop2(CtlP, aiop, _INDX_DATA);
170    if(x != y)  /* if different must be 8 chan */
171       return(8);
172    else
173       return(4);
174 }
175 
176 /***************************************************************************
177 Function: sInitChan
178 Purpose:  Initialization of a channel and channel structure
179 Call:	  sInitChan(CtlP,ChP,AiopNum,ChanNum)
180 	  CONTROLLER_T *CtlP; Ptr to controller structure
181 	  CHANNEL_T *ChP; Ptr to channel structure
182 	  int AiopNum; AIOP number within controller
183 	  int ChanNum; Channel number within AIOP
184 Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
185 	       number exceeds number of channels available in AIOP.
186 Comments: This function must be called before a channel can be used.
187 Warnings: No range checking on any of the parameters is done.
188 
189 	  No context switches are allowed while executing this function.
190 */
sInitChan(CONTROLLER_T * CtlP,CHANNEL_T * ChP,int AiopNum,int ChanNum)191 int sInitChan(	CONTROLLER_T *CtlP,
192 		CHANNEL_T *ChP,
193 		int AiopNum,
194 		int ChanNum)
195 {
196    int i, ChOff;
197    Byte_t *ChR;
198    static Byte_t R[4];
199 
200    if(ChanNum >= CtlP->AiopNumChan[AiopNum])
201       return(FALSE);		       /* exceeds num chans in AIOP */
202 
203    /* Channel, AIOP, and controller identifiers */
204    ChP->CtlP = CtlP;
205    ChP->ChanID = CtlP->AiopID[AiopNum];
206    ChP->AiopNum = AiopNum;
207    ChP->ChanNum = ChanNum;
208 
209    /* Initialize the channel from the RData array */
210    for(i=0; i < RDATASIZE; i+=4)
211    {
212       R[0] = RData[i];
213       R[1] = RData[i+1] + 0x10 * ChanNum;
214       R[2] = RData[i+2];
215       R[3] = RData[i+3];
216       rp_writech4(ChP,_INDX_ADDR,le32dec(R));
217    }
218 
219    ChR = ChP->R;
220    for(i=0; i < RREGDATASIZE; i+=4)
221    {
222       ChR[i] = RRegData[i];
223       ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
224       ChR[i+2] = RRegData[i+2];
225       ChR[i+3] = RRegData[i+3];
226    }
227 
228    /* Indexed registers */
229    ChOff = (Word_t)ChanNum * 0x1000;
230 
231    ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
232    ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
233    ChP->BaudDiv[2] = (Byte_t)BRD9600;
234    ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
235    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv));
236 
237    ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
238    ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
239    ChP->TxControl[2] = 0;
240    ChP->TxControl[3] = 0;
241    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
242 
243    ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
244    ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
245    ChP->RxControl[2] = 0;
246    ChP->RxControl[3] = 0;
247    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
248 
249    ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
250    ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
251    ChP->TxEnables[2] = 0;
252    ChP->TxEnables[3] = 0;
253    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables));
254 
255    ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
256    ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
257    ChP->TxCompare[2] = 0;
258    ChP->TxCompare[3] = 0;
259    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare));
260 
261    ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
262    ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
263    ChP->TxReplace1[2] = 0;
264    ChP->TxReplace1[3] = 0;
265    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1));
266 
267    ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
268    ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
269    ChP->TxReplace2[2] = 0;
270    ChP->TxReplace2[3] = 0;
271    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2));
272 
273    ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
274    ChP->TxFIFO = ChOff + _TX_FIFO;
275 
276    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
277    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Tx FIFO count */
278    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
279    rp_writech2(ChP,_INDX_DATA,0);
280    ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
281    ChP->RxFIFO = ChOff + _RX_FIFO;
282 
283    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
284    rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum);  /* remove reset Rx FIFO count */
285    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
286    rp_writech2(ChP,_INDX_DATA,0);
287    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
288    rp_writech2(ChP,_INDX_DATA,0);
289    ChP->TxPrioCnt = ChOff + _TXP_CNT;
290    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt);
291    rp_writech1(ChP,_INDX_DATA,0);
292    ChP->TxPrioPtr = ChOff + _TXP_PNTR;
293    rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr);
294    rp_writech1(ChP,_INDX_DATA,0);
295    ChP->TxPrioBuf = ChOff + _TXP_BUF;
296    sEnRxProcessor(ChP); 	       /* start the Rx processor */
297 
298    return(TRUE);
299 }
300 
301 /***************************************************************************
302 Function: sStopRxProcessor
303 Purpose:  Stop the receive processor from processing a channel.
304 Call:	  sStopRxProcessor(ChP)
305 	  CHANNEL_T *ChP; Ptr to channel structure
306 
307 Comments: The receive processor can be started again with sStartRxProcessor().
308 	  This function causes the receive processor to skip over the
309 	  stopped channel.  It does not stop it from processing other channels.
310 
311 Warnings: No context switches are allowed while executing this function.
312 
313 	  Do not leave the receive processor stopped for more than one
314 	  character time.
315 
316 	  After calling this function a delay of 4 uS is required to ensure
317 	  that the receive processor is no longer processing this channel.
318 */
sStopRxProcessor(CHANNEL_T * ChP)319 void sStopRxProcessor(CHANNEL_T *ChP)
320 {
321    Byte_t R[4];
322 
323    R[0] = ChP->R[0];
324    R[1] = ChP->R[1];
325    R[2] = 0x0a;
326    R[3] = ChP->R[3];
327    rp_writech4(ChP,_INDX_ADDR,le32dec(R));
328 }
329 
330 /***************************************************************************
331 Function: sFlushRxFIFO
332 Purpose:  Flush the Rx FIFO
333 Call:	  sFlushRxFIFO(ChP)
334 	  CHANNEL_T *ChP; Ptr to channel structure
335 Return:   void
336 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
337 	  while it is being flushed the receive processor is stopped
338 	  and the transmitter is disabled.  After these operations a
339 	  4 uS delay is done before clearing the pointers to allow
340 	  the receive processor to stop.  These items are handled inside
341 	  this function.
342 Warnings: No context switches are allowed while executing this function.
343 */
sFlushRxFIFO(CHANNEL_T * ChP)344 void sFlushRxFIFO(CHANNEL_T *ChP)
345 {
346    int i;
347    Byte_t Ch;			/* channel number within AIOP */
348    int RxFIFOEnabled;		       /* TRUE if Rx FIFO enabled */
349 
350    if(sGetRxCnt(ChP) == 0)	       /* Rx FIFO empty */
351       return;			       /* don't need to flush */
352 
353    RxFIFOEnabled = FALSE;
354    if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
355    {
356       RxFIFOEnabled = TRUE;
357       sDisRxFIFO(ChP);		       /* disable it */
358       for(i=0; i < 2000/200; i++)	/* delay 2 uS to allow proc to disable FIFO*/
359 	 rp_readch1(ChP,_INT_CHAN);		/* depends on bus i/o timing */
360    }
361    sGetChanStatus(ChP); 	 /* clear any pending Rx errors in chan stat */
362    Ch = (Byte_t)sGetChanNum(ChP);
363    rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT);     /* apply reset Rx FIFO count */
364    rp_writech1(ChP,_CMD_REG,Ch);		       /* remove reset Rx FIFO count */
365    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */
366    rp_writech2(ChP,_INDX_DATA,0);
367    rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
368    rp_writech2(ChP,_INDX_DATA,0);
369    if(RxFIFOEnabled)
370       sEnRxFIFO(ChP);		       /* enable Rx FIFO */
371 }
372 
373 /***************************************************************************
374 Function: sFlushTxFIFO
375 Purpose:  Flush the Tx FIFO
376 Call:	  sFlushTxFIFO(ChP)
377 	  CHANNEL_T *ChP; Ptr to channel structure
378 Return:   void
379 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
380 	  while it is being flushed the receive processor is stopped
381 	  and the transmitter is disabled.  After these operations a
382 	  4 uS delay is done before clearing the pointers to allow
383 	  the receive processor to stop.  These items are handled inside
384 	  this function.
385 Warnings: No context switches are allowed while executing this function.
386 */
sFlushTxFIFO(CHANNEL_T * ChP)387 void sFlushTxFIFO(CHANNEL_T *ChP)
388 {
389    int i;
390    Byte_t Ch;			/* channel number within AIOP */
391    int TxEnabled;		       /* TRUE if transmitter enabled */
392 
393    if(sGetTxCnt(ChP) == 0)	       /* Tx FIFO empty */
394       return;			       /* don't need to flush */
395 
396    TxEnabled = FALSE;
397    if(ChP->TxControl[3] & TX_ENABLE)
398    {
399       TxEnabled = TRUE;
400       sDisTransmit(ChP);	       /* disable transmitter */
401    }
402    sStopRxProcessor(ChP);	       /* stop Rx processor */
403    for(i = 0; i < 4000/200; i++)	 /* delay 4 uS to allow proc to stop */
404       rp_readch1(ChP,_INT_CHAN);	/* depends on bus i/o timing */
405    Ch = (Byte_t)sGetChanNum(ChP);
406    rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT);     /* apply reset Tx FIFO count */
407    rp_writech1(ChP,_CMD_REG,Ch);		       /* remove reset Tx FIFO count */
408    rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
409    rp_writech2(ChP,_INDX_DATA,0);
410    if(TxEnabled)
411       sEnTransmit(ChP); 	       /* enable transmitter */
412    sStartRxProcessor(ChP);	       /* restart Rx processor */
413 }
414 
415 /***************************************************************************
416 Function: sWriteTxPrioByte
417 Purpose:  Write a byte of priority transmit data to a channel
418 Call:	  sWriteTxPrioByte(ChP,Data)
419 	  CHANNEL_T *ChP; Ptr to channel structure
420 	  Byte_t Data; The transmit data byte
421 
422 Return:   int: 1 if the bytes is successfully written, otherwise 0.
423 
424 Comments: The priority byte is transmitted before any data in the Tx FIFO.
425 
426 Warnings: No context switches are allowed while executing this function.
427 */
sWriteTxPrioByte(CHANNEL_T * ChP,Byte_t Data)428 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
429 {
430    Byte_t DWBuf[4];		/* buffer for double word writes */
431 
432    if(sGetTxCnt(ChP) > 1)	       /* write it to Tx priority buffer */
433    {
434       rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */
435       if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */
436 	 return(0);		       /* nothing sent */
437 
438       le16enc(DWBuf,ChP->TxPrioBuf);   /* data byte address */
439 
440       DWBuf[2] = Data;		       /* data byte value */
441       DWBuf[3] = 0;		       /* priority buffer pointer */
442       rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
443 
444       le16enc(DWBuf,ChP->TxPrioCnt);   /* Tx priority count address */
445 
446       DWBuf[2] = PRI_PEND + 1;	       /* indicate 1 byte pending */
447       DWBuf[3] = 0;		       /* priority buffer pointer */
448       rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */
449    }
450    else 			       /* write it to Tx FIFO */
451    {
452       sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data);
453    }
454    return(1);			       /* 1 byte sent */
455 }
456 
457 /***************************************************************************
458 Function: sEnInterrupts
459 Purpose:  Enable one or more interrupts for a channel
460 Call:	  sEnInterrupts(ChP,Flags)
461 	  CHANNEL_T *ChP; Ptr to channel structure
462 	  Word_t Flags: Interrupt enable flags, can be any combination
463 	     of the following flags:
464 		TXINT_EN:   Interrupt on Tx FIFO empty
465 		RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
466 			    sSetRxTrigger())
467 		SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
468 		MCINT_EN:   Interrupt on modem input change
469 		CHANINT_EN: Allow channel interrupt signal to the AIOP's
470 			    Interrupt Channel Register.
471 Return:   void
472 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
473 	  enabled.  If an interrupt enable flag is not set in Flags, that
474 	  interrupt will not be changed.  Interrupts can be disabled with
475 	  function sDisInterrupts().
476 
477 	  This function sets the appropriate bit for the channel in the AIOP's
478 	  Interrupt Mask Register if the CHANINT_EN flag is set.  This allows
479 	  this channel's bit to be set in the AIOP's Interrupt Channel Register.
480 
481 	  Interrupts must also be globally enabled before channel interrupts
482 	  will be passed on to the host.  This is done with function
483 	  sEnGlobalInt().
484 
485 	  In some cases it may be desirable to disable interrupts globally but
486 	  enable channel interrupts.  This would allow the global interrupt
487 	  status register to be used to determine which AIOPs need service.
488 */
sEnInterrupts(CHANNEL_T * ChP,Word_t Flags)489 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
490 {
491    Byte_t Mask; 		/* Interrupt Mask Register */
492 
493    ChP->RxControl[2] |=
494       ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
495 
496    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
497 
498    ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
499 
500    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
501 
502    if(Flags & CHANINT_EN)
503    {
504       Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum];
505       rp_writech1(ChP,_INT_MASK,Mask);
506    }
507 }
508 
509 /***************************************************************************
510 Function: sDisInterrupts
511 Purpose:  Disable one or more interrupts for a channel
512 Call:	  sDisInterrupts(ChP,Flags)
513 	  CHANNEL_T *ChP; Ptr to channel structure
514 	  Word_t Flags: Interrupt flags, can be any combination
515 	     of the following flags:
516 		TXINT_EN:   Interrupt on Tx FIFO empty
517 		RXINT_EN:   Interrupt on Rx FIFO at trigger level (see
518 			    sSetRxTrigger())
519 		SRCINT_EN:  Interrupt on SRC (Special Rx Condition)
520 		MCINT_EN:   Interrupt on modem input change
521 		CHANINT_EN: Disable channel interrupt signal to the
522 			    AIOP's Interrupt Channel Register.
523 Return:   void
524 Comments: If an interrupt flag is set in Flags, that interrupt will be
525 	  disabled.  If an interrupt flag is not set in Flags, that
526 	  interrupt will not be changed.  Interrupts can be enabled with
527 	  function sEnInterrupts().
528 
529 	  This function clears the appropriate bit for the channel in the AIOP's
530 	  Interrupt Mask Register if the CHANINT_EN flag is set.  This blocks
531 	  this channel's bit from being set in the AIOP's Interrupt Channel
532 	  Register.
533 */
sDisInterrupts(CHANNEL_T * ChP,Word_t Flags)534 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
535 {
536    Byte_t Mask; 		/* Interrupt Mask Register */
537 
538    ChP->RxControl[2] &=
539 	 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
540    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl));
541    ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
542    rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl));
543 
544    if(Flags & CHANINT_EN)
545    {
546       Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum];
547       rp_writech1(ChP,_INT_MASK,Mask);
548    }
549 }
550 
551 /*********************************************************************
552   Begin FreeBsd-specific driver code
553 **********************************************************************/
554 
555 #define POLL_INTERVAL		(hz / 100)
556 
557 #define RP_ISMULTIPORT(dev)	((dev)->id_flags & 0x1)
558 #define RP_MPMASTER(dev)	(((dev)->id_flags >> 8) & 0xff)
559 #define RP_NOTAST4(dev) 	((dev)->id_flags & 0x04)
560 
561 /*
562  * The top-level routines begin here
563  */
564 
565 static	void	rpclose(struct tty *tp);
566 static	void	rphardclose(struct tty *tp);
567 static	int	rpmodem(struct tty *, int, int);
568 static	int	rpparam(struct tty *, struct termios *);
569 static	void	rpstart(struct tty *);
570 static	int	rpioctl(struct tty *, u_long, caddr_t, struct thread *);
571 static	int	rpopen(struct tty *);
572 
rp_do_receive(struct rp_port * rp,struct tty * tp,CHANNEL_t * cp,unsigned int ChanStatus)573 static void rp_do_receive(struct rp_port *rp, struct tty *tp,
574 			CHANNEL_t *cp, unsigned int ChanStatus)
575 {
576 	unsigned	int	CharNStat;
577 	int	ToRecv, ch, err = 0;
578 
579 	ToRecv = sGetRxCnt(cp);
580 	if(ToRecv == 0)
581 		return;
582 
583 /*	If status indicates there are errored characters in the
584 	FIFO, then enter status mode (a word in FIFO holds
585 	characters and status)
586 */
587 
588 	if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
589 		if(!(ChanStatus & STATMODE)) {
590 			ChanStatus |= STATMODE;
591 			sEnRxStatusMode(cp);
592 		}
593 	}
594 /*
595 	if we previously entered status mode then read down the
596 	FIFO one word at a time, pulling apart the character and
597 	the status. Update error counters depending on status.
598 */
599 	tty_lock(tp);
600 	if(ChanStatus & STATMODE) {
601 		while(ToRecv) {
602 			CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
603 			ch = CharNStat & 0xff;
604 
605 			if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
606 				err |= TRE_FRAMING;
607 			else if (CharNStat & STMPARITYH)
608 				err |= TRE_PARITY;
609 			else if (CharNStat & STMRCVROVRH) {
610 				rp->rp_overflows++;
611 				err |= TRE_OVERRUN;
612 			}
613 
614 			ttydisc_rint(tp, ch, err);
615 			ToRecv--;
616 		}
617 /*
618 	After emtying FIFO in status mode, turn off status mode
619 */
620 
621 		if(sGetRxCnt(cp) == 0) {
622 			sDisRxStatusMode(cp);
623 		}
624 	} else {
625 		ToRecv = sGetRxCnt(cp);
626 		while (ToRecv) {
627 			ch = rp_readch1(cp,sGetTxRxDataIO(cp));
628 			ttydisc_rint(tp, ch & 0xff, err);
629 			ToRecv--;
630 		}
631 	}
632         ttydisc_rint_done(tp);
633         tty_unlock(tp);
634 }
635 
rp_handle_port(struct rp_port * rp)636 static void rp_handle_port(struct rp_port *rp)
637 {
638 	CHANNEL_t	*cp;
639 	struct	tty	*tp;
640 	unsigned	int	IntMask, ChanStatus;
641 
642 	if(!rp)
643 		return;
644 
645 	cp = &rp->rp_channel;
646 	tp = rp->rp_tty;
647 	IntMask = sGetChanIntID(cp);
648 	IntMask = IntMask & rp->rp_intmask;
649 	ChanStatus = sGetChanStatus(cp);
650 	if(IntMask & RXF_TRIG)
651 		rp_do_receive(rp, tp, cp, ChanStatus);
652 	if(IntMask & DELTA_CD) {
653 		if(ChanStatus & CD_ACT) {
654 			(void)ttydisc_modem(tp, 1);
655 		} else {
656 			(void)ttydisc_modem(tp, 0);
657 		}
658 	}
659 /*	oldcts = rp->rp_cts;
660 	rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
661 	if(oldcts != rp->rp_cts) {
662 		printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
663 	}
664 */
665 }
666 
rp_do_poll(void * arg)667 static void rp_do_poll(void *arg)
668 {
669 	CONTROLLER_t	*ctl;
670 	struct rp_port	*rp;
671 	struct tty	*tp;
672 	int	count;
673 	unsigned char	CtlMask, AiopMask;
674 
675 	rp = arg;
676 	tp = rp->rp_tty;
677 	tty_lock_assert(tp, MA_OWNED);
678 	ctl = rp->rp_ctlp;
679 	CtlMask = ctl->ctlmask(ctl);
680 	if (CtlMask & (1 << rp->rp_aiop)) {
681 		AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop);
682 		if (AiopMask & (1 << rp->rp_chan)) {
683 			rp_handle_port(rp);
684 		}
685 	}
686 
687 	count = sGetTxCnt(&rp->rp_channel);
688 	if (count >= 0  && (count <= rp->rp_restart)) {
689 		rpstart(tp);
690 	}
691 	callout_schedule(&rp->rp_timer, POLL_INTERVAL);
692 }
693 
694 static struct ttydevsw rp_tty_class = {
695 	.tsw_flags	= TF_INITLOCK|TF_CALLOUT,
696 	.tsw_open	= rpopen,
697 	.tsw_close	= rpclose,
698 	.tsw_outwakeup	= rpstart,
699 	.tsw_ioctl	= rpioctl,
700 	.tsw_param	= rpparam,
701 	.tsw_modem	= rpmodem,
702 	.tsw_free	= rpfree,
703 };
704 
705 
706 static void
rpfree(void * softc)707 rpfree(void *softc)
708 {
709 	struct	rp_port *rp = softc;
710 	CONTROLLER_t *ctlp = rp->rp_ctlp;
711 
712 	atomic_subtract_32(&ctlp->free, 1);
713 }
714 
715 int
rp_attachcommon(CONTROLLER_T * ctlp,int num_aiops,int num_ports)716 rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
717 {
718 	int	unit;
719 	int	num_chan;
720 	int	aiop, chan, port;
721 	int	ChanStatus;
722 	int	retval;
723 	struct	rp_port *rp;
724 	struct tty *tp;
725 
726 	unit = device_get_unit(ctlp->dev);
727 
728 	printf("RocketPort%d (Version %s) %d ports.\n", unit,
729 		RocketPortVersion, num_ports);
730 
731 	ctlp->num_ports = num_ports;
732 	ctlp->rp = rp = (struct rp_port *)
733 		malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
734 	if (rp == NULL) {
735 		device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
736 		retval = ENOMEM;
737 		goto nogo;
738 	}
739 
740 	port = 0;
741 	for(aiop=0; aiop < num_aiops; aiop++) {
742 		num_chan = sGetAiopNumChan(ctlp, aiop);
743 		for(chan=0; chan < num_chan; chan++, port++, rp++) {
744 			rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
745 			callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0);
746 			rp->rp_port = port;
747 			rp->rp_ctlp = ctlp;
748 			rp->rp_unit = unit;
749 			rp->rp_chan = chan;
750 			rp->rp_aiop = aiop;
751 
752 			rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
753 				DELTA_CD | DELTA_CTS | DELTA_DSR;
754 #ifdef notdef
755 			ChanStatus = sGetChanStatus(&rp->rp_channel);
756 #endif /* notdef */
757 			if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
758 				device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
759 					      unit, aiop, chan);
760 				retval = ENXIO;
761 				goto nogo;
762 			}
763 			ChanStatus = sGetChanStatus(&rp->rp_channel);
764 			rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
765 			tty_makedev(tp, NULL, "R%r%r", unit, port);
766 		}
767 	}
768 
769 	mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
770 	ctlp->hwmtx_init = 1;
771 	return (0);
772 
773 nogo:
774 	rp_releaseresource(ctlp);
775 
776 	return (retval);
777 }
778 
779 void
rp_releaseresource(CONTROLLER_t * ctlp)780 rp_releaseresource(CONTROLLER_t *ctlp)
781 {
782 	struct	rp_port *rp;
783 	int i;
784 
785 	if (ctlp->rp != NULL) {
786 		for (i = 0; i < ctlp->num_ports; i++) {
787 			rp = ctlp->rp + i;
788 			atomic_add_32(&ctlp->free, 1);
789 			tty_lock(rp->rp_tty);
790 			tty_rel_gone(rp->rp_tty);
791 		}
792                 free(ctlp->rp, M_DEVBUF);
793                 ctlp->rp = NULL;
794 	}
795 
796 	while (ctlp->free != 0) {
797 		pause("rpwt", hz / 10);
798 	}
799 
800 	if (ctlp->hwmtx_init)
801 		mtx_destroy(&ctlp->hwmtx);
802 }
803 
804 static int
rpopen(struct tty * tp)805 rpopen(struct tty *tp)
806 {
807 	struct	rp_port *rp;
808 	int	flags;
809 	unsigned int	IntMask, ChanStatus;
810 
811 	rp = tty_softc(tp);
812 
813 	flags = 0;
814 	flags |= SET_RTS;
815 	flags |= SET_DTR;
816 	rp->rp_channel.TxControl[3] =
817 		((rp->rp_channel.TxControl[3]
818 		& ~(SET_RTS | SET_DTR)) | flags);
819 	rp_writech4(&rp->rp_channel,_INDX_ADDR,
820 		le32dec(rp->rp_channel.TxControl));
821 	sSetRxTrigger(&rp->rp_channel, TRIG_1);
822 	sDisRxStatusMode(&rp->rp_channel);
823 	sFlushRxFIFO(&rp->rp_channel);
824 	sFlushTxFIFO(&rp->rp_channel);
825 
826 	sEnInterrupts(&rp->rp_channel,
827 		(TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
828 	sSetRxTrigger(&rp->rp_channel, TRIG_1);
829 
830 	sDisRxStatusMode(&rp->rp_channel);
831 	sClrTxXOFF(&rp->rp_channel);
832 
833 /*	sDisRTSFlowCtl(&rp->rp_channel);
834 	sDisCTSFlowCtl(&rp->rp_channel);
835 */
836 	sDisTxSoftFlowCtl(&rp->rp_channel);
837 
838 	sStartRxProcessor(&rp->rp_channel);
839 
840 	sEnRxFIFO(&rp->rp_channel);
841 	sEnTransmit(&rp->rp_channel);
842 
843 /*	sSetDTR(&rp->rp_channel);
844 	sSetRTS(&rp->rp_channel);
845 */
846 
847 	IntMask = sGetChanIntID(&rp->rp_channel);
848 	IntMask = IntMask & rp->rp_intmask;
849 	ChanStatus = sGetChanStatus(&rp->rp_channel);
850 
851 	callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp);
852 
853 	device_busy(rp->rp_ctlp->dev);
854 	return(0);
855 }
856 
857 static void
rpclose(struct tty * tp)858 rpclose(struct tty *tp)
859 {
860 	struct	rp_port	*rp;
861 
862 	rp = tty_softc(tp);
863 	callout_stop(&rp->rp_timer);
864 	rphardclose(tp);
865 	device_unbusy(rp->rp_ctlp->dev);
866 }
867 
868 static void
rphardclose(struct tty * tp)869 rphardclose(struct tty *tp)
870 {
871 	struct	rp_port	*rp;
872 	CHANNEL_t	*cp;
873 
874 	rp = tty_softc(tp);
875 	cp = &rp->rp_channel;
876 
877 	sFlushRxFIFO(cp);
878 	sFlushTxFIFO(cp);
879 	sDisTransmit(cp);
880 	sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
881 	sDisRTSFlowCtl(cp);
882 	sDisCTSFlowCtl(cp);
883 	sDisTxSoftFlowCtl(cp);
884 	sClrTxXOFF(cp);
885 
886 #ifdef DJA
887 	if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
888 		sClrDTR(cp);
889 	}
890 	if(ISCALLOUT(tp->t_dev)) {
891 		sClrDTR(cp);
892 	}
893 	tp->t_actout = FALSE;
894 	wakeup(&tp->t_actout);
895 	wakeup(TSA_CARR_ON(tp));
896 #endif /* DJA */
897 }
898 
899 static int
rpioctl(struct tty * tp,u_long cmd,caddr_t data,struct thread * td)900 rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
901 {
902 	struct rp_port	*rp;
903 
904 	rp = tty_softc(tp);
905 	switch (cmd) {
906 	case TIOCSBRK:
907 		sSendBreak(&rp->rp_channel);
908 		return (0);
909 	case TIOCCBRK:
910 		sClrBreak(&rp->rp_channel);
911 		return (0);
912 	default:
913 		return ENOIOCTL;
914 	}
915 }
916 
917 static int
rpmodem(struct tty * tp,int sigon,int sigoff)918 rpmodem(struct tty *tp, int sigon, int sigoff)
919 {
920 	struct rp_port	*rp;
921 	int i, j, k;
922 
923 	rp = tty_softc(tp);
924 	if (sigon != 0 || sigoff != 0) {
925 		i = j = 0;
926 		if (sigon & SER_DTR)
927 			i = SET_DTR;
928 		if (sigoff & SER_DTR)
929 			j = SET_DTR;
930 		if (sigon & SER_RTS)
931 			i = SET_RTS;
932 		if (sigoff & SER_RTS)
933 			j = SET_RTS;
934 		rp->rp_channel.TxControl[3] &= ~i;
935 		rp->rp_channel.TxControl[3] |= j;
936 		rp_writech4(&rp->rp_channel,_INDX_ADDR,
937 			le32dec(rp->rp_channel.TxControl));
938 	} else {
939 		i = sGetChanStatusLo(&rp->rp_channel);
940 		j = rp->rp_channel.TxControl[3];
941 		k = 0;
942 		if (j & SET_DTR)
943 			k |= SER_DTR;
944 		if (j & SET_RTS)
945 			k |= SER_RTS;
946 		if (i & CD_ACT)
947 			k |= SER_DCD;
948 		if (i & DSR_ACT)
949 			k |= SER_DSR;
950 		if (i & CTS_ACT)
951 			k |= SER_CTS;
952 		return(k);
953 	}
954 	return (0);
955 }
956 
957 static struct
958 {
959 	int baud;
960 	int conversion;
961 } baud_table[] = {
962 	{B0,	0},		{B50,	BRD50},		{B75,	BRD75},
963 	{B110,	BRD110}, 	{B134,	BRD134}, 	{B150,	BRD150},
964 	{B200,	BRD200}, 	{B300,	BRD300}, 	{B600,	BRD600},
965 	{B1200,	BRD1200},	{B1800,	BRD1800},	{B2400,	BRD2400},
966 	{B4800,	BRD4800},	{B9600,	BRD9600},	{B19200, BRD19200},
967 	{B38400, BRD38400},	{B7200,	BRD7200},	{B14400, BRD14400},
968 				{B57600, BRD57600},	{B76800, BRD76800},
969 	{B115200, BRD115200},	{B230400, BRD230400},
970 	{-1,	-1}
971 };
972 
rp_convert_baud(int baud)973 static int rp_convert_baud(int baud) {
974 	int i;
975 
976 	for (i = 0; baud_table[i].baud >= 0; i++) {
977 		if (baud_table[i].baud == baud)
978 			break;
979 	}
980 
981 	return baud_table[i].conversion;
982 }
983 
984 static int
rpparam(tp,t)985 rpparam(tp, t)
986 	struct tty *tp;
987 	struct termios *t;
988 {
989 	struct rp_port	*rp;
990 	CHANNEL_t	*cp;
991 	int	cflag, iflag, oflag, lflag;
992 	int	ospeed;
993 #ifdef RPCLOCAL
994 	int	devshift;
995 #endif
996 
997 	rp = tty_softc(tp);
998 	cp = &rp->rp_channel;
999 
1000 	cflag = t->c_cflag;
1001 #ifdef RPCLOCAL
1002 	devshift = umynor / 32;
1003 	devshift = 1 << devshift;
1004 	if ( devshift & RPCLOCAL ) {
1005 		cflag |= CLOCAL;
1006 	}
1007 #endif
1008 	iflag = t->c_iflag;
1009 	oflag = t->c_oflag;
1010 	lflag = t->c_lflag;
1011 
1012 	ospeed = rp_convert_baud(t->c_ispeed);
1013 	if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1014 		return(EINVAL);
1015 
1016 	if(t->c_ospeed == 0) {
1017 		sClrDTR(cp);
1018 		return(0);
1019 	}
1020 	rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1021 
1022 	/* Set baud rate ----- we only pay attention to ispeed */
1023 	sSetDTR(cp);
1024 	sSetRTS(cp);
1025 	sSetBaud(cp, ospeed);
1026 
1027 	if(cflag & CSTOPB) {
1028 		sSetStop2(cp);
1029 	} else {
1030 		sSetStop1(cp);
1031 	}
1032 
1033 	if(cflag & PARENB) {
1034 		sEnParity(cp);
1035 		if(cflag & PARODD) {
1036 			sSetOddParity(cp);
1037 		} else {
1038 			sSetEvenParity(cp);
1039 		}
1040 	}
1041 	else {
1042 		sDisParity(cp);
1043 	}
1044 	if((cflag & CSIZE) == CS8) {
1045 		sSetData8(cp);
1046 		rp->rp_imask = 0xFF;
1047 	} else {
1048 		sSetData7(cp);
1049 		rp->rp_imask = 0x7F;
1050 	}
1051 
1052 	if(iflag & ISTRIP) {
1053 		rp->rp_imask &= 0x7F;
1054 	}
1055 
1056 	if(cflag & CLOCAL) {
1057 		rp->rp_intmask &= ~DELTA_CD;
1058 	} else {
1059 		rp->rp_intmask |= DELTA_CD;
1060 	}
1061 
1062 	/* Put flow control stuff here */
1063 
1064 	if(cflag & CCTS_OFLOW) {
1065 		sEnCTSFlowCtl(cp);
1066 	} else {
1067 		sDisCTSFlowCtl(cp);
1068 	}
1069 
1070 	if(cflag & CRTS_IFLOW) {
1071 		rp->rp_rts_iflow = 1;
1072 	} else {
1073 		rp->rp_rts_iflow = 0;
1074 	}
1075 
1076 	if(cflag & CRTS_IFLOW) {
1077 		sEnRTSFlowCtl(cp);
1078 	} else {
1079 		sDisRTSFlowCtl(cp);
1080 	}
1081 
1082 	return(0);
1083 }
1084 
1085 static void
rpstart(struct tty * tp)1086 rpstart(struct tty *tp)
1087 {
1088 	struct rp_port	*rp;
1089 	CHANNEL_t	*cp;
1090 	char	flags;
1091 	int	xmit_fifo_room;
1092 	int	i, count, wcount;
1093 
1094 	rp = tty_softc(tp);
1095 	cp = &rp->rp_channel;
1096 	flags = rp->rp_channel.TxControl[3];
1097 
1098 	if(rp->rp_xmit_stopped) {
1099 		sEnTransmit(cp);
1100 		rp->rp_xmit_stopped = 0;
1101 	}
1102 
1103 	xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1104 	count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1105 	if(xmit_fifo_room > 0) {
1106 		for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1107 			rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1108 		}
1109 		if ( count & 1 ) {
1110 			rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);
1111 		}
1112 	}
1113 }
1114