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
61static const char RocketPortVersion[] = "3.02";
62
63static 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
85static 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 */
104Byte_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
110Byte_t rp_sBitMapClrTbl[8] =
111{
112   0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
113};
114
115Byte_t rp_sBitMapSetTbl[8] =
116{
117   0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
118};
119
120static void rpfree(void *);
121
122/***************************************************************************
123Function: sReadAiopID
124Purpose:  Read the AIOP idenfication number directly from an AIOP.
125Call:	  sReadAiopID(CtlP, aiop)
126	  CONTROLLER_T *CtlP; Ptr to controller structure
127	  int aiop: AIOP index
128Return:   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
131Warnings: No context switches are allowed while executing this function.
132
133*/
134int 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/***************************************************************************
148Function: sReadAiopNumChan
149Purpose:  Read the number of channels available in an AIOP directly from
150	  an AIOP.
151Call:	  sReadAiopNumChan(CtlP, aiop)
152	  CONTROLLER_T *CtlP; Ptr to controller structure
153	  int aiop: AIOP index
154Return:   int: The number of channels available
155Comments: 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.
159Warnings: No context switches are allowed while executing this function.
160*/
161int 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/***************************************************************************
177Function: sInitChan
178Purpose:  Initialization of a channel and channel structure
179Call:	  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
184Return:   int: TRUE if initialization succeeded, FALSE if it fails because channel
185	       number exceeds number of channels available in AIOP.
186Comments: This function must be called before a channel can be used.
187Warnings: No range checking on any of the parameters is done.
188
189	  No context switches are allowed while executing this function.
190*/
191int 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/***************************************************************************
302Function: sStopRxProcessor
303Purpose:  Stop the receive processor from processing a channel.
304Call:	  sStopRxProcessor(ChP)
305	  CHANNEL_T *ChP; Ptr to channel structure
306
307Comments: 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
311Warnings: 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*/
319void 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/***************************************************************************
331Function: sFlushRxFIFO
332Purpose:  Flush the Rx FIFO
333Call:	  sFlushRxFIFO(ChP)
334	  CHANNEL_T *ChP; Ptr to channel structure
335Return:   void
336Comments: 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.
342Warnings: No context switches are allowed while executing this function.
343*/
344void 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/***************************************************************************
374Function: sFlushTxFIFO
375Purpose:  Flush the Tx FIFO
376Call:	  sFlushTxFIFO(ChP)
377	  CHANNEL_T *ChP; Ptr to channel structure
378Return:   void
379Comments: 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.
385Warnings: No context switches are allowed while executing this function.
386*/
387void 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/***************************************************************************
416Function: sWriteTxPrioByte
417Purpose:  Write a byte of priority transmit data to a channel
418Call:	  sWriteTxPrioByte(ChP,Data)
419	  CHANNEL_T *ChP; Ptr to channel structure
420	  Byte_t Data; The transmit data byte
421
422Return:   int: 1 if the bytes is successfully written, otherwise 0.
423
424Comments: The priority byte is transmitted before any data in the Tx FIFO.
425
426Warnings: No context switches are allowed while executing this function.
427*/
428int 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/***************************************************************************
458Function: sEnInterrupts
459Purpose:  Enable one or more interrupts for a channel
460Call:	  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.
471Return:   void
472Comments: 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*/
489void 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/***************************************************************************
510Function: sDisInterrupts
511Purpose:  Disable one or more interrupts for a channel
512Call:	  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.
523Return:   void
524Comments: 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*/
534void 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
565static	void	rpclose(struct tty *tp);
566static	void	rphardclose(struct tty *tp);
567static	int	rpmodem(struct tty *, int, int);
568static	int	rpparam(struct tty *, struct termios *);
569static	void	rpstart(struct tty *);
570static	int	rpioctl(struct tty *, u_long, caddr_t, struct thread *);
571static	int	rpopen(struct tty *);
572
573static 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
636static 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
667static 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
694static 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
706static void
707rpfree(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
715int
716rp_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
773nogo:
774	rp_releaseresource(ctlp);
775
776	return (retval);
777}
778
779void
780rp_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
804static int
805rpopen(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
857static void
858rpclose(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
868static void
869rphardclose(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
899static int
900rpioctl(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
917static int
918rpmodem(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
957static 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
973static 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
984static int
985rpparam(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
1085static void
1086rpstart(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