rp.c revision 196403
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: head/sys/dev/rp/rp.c 196403 2009-08-20 19:17:53Z jhb $");
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
555struct callout_handle rp_callout_handle;
556
557static int	rp_num_ports_open = 0;
558static int	rp_ndevs = 0;
559
560static int rp_num_ports[4];	/* Number of ports on each controller */
561
562#define POLL_INTERVAL 1
563
564#define RP_ISMULTIPORT(dev)	((dev)->id_flags & 0x1)
565#define RP_MPMASTER(dev)	(((dev)->id_flags >> 8) & 0xff)
566#define RP_NOTAST4(dev) 	((dev)->id_flags & 0x04)
567
568static	struct	rp_port *p_rp_addr[4];
569static	struct	rp_port *p_rp_table[MAX_RP_PORTS];
570#define rp_addr(unit)	(p_rp_addr[unit])
571#define rp_table(port)	(p_rp_table[port])
572
573/*
574 * The top-level routines begin here
575 */
576
577static	void	rpclose(struct tty *tp);
578static	void	rphardclose(struct tty *tp);
579static	int	rpmodem(struct tty *, int, int);
580static	int	rpparam(struct tty *, struct termios *);
581static	void	rpstart(struct tty *);
582static	int	rpioctl(struct tty *, u_long, caddr_t, struct thread *);
583static	int	rpopen(struct tty *);
584
585static void rp_do_receive(struct rp_port *rp, struct tty *tp,
586			CHANNEL_t *cp, unsigned int ChanStatus)
587{
588	unsigned	int	CharNStat;
589	int	ToRecv, ch, err = 0;
590
591	ToRecv = sGetRxCnt(cp);
592	if(ToRecv == 0)
593		return;
594
595/*	If status indicates there are errored characters in the
596	FIFO, then enter status mode (a word in FIFO holds
597	characters and status)
598*/
599
600	if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
601		if(!(ChanStatus & STATMODE)) {
602			ChanStatus |= STATMODE;
603			sEnRxStatusMode(cp);
604		}
605	}
606/*
607	if we previously entered status mode then read down the
608	FIFO one word at a time, pulling apart the character and
609	the status. Update error counters depending on status.
610*/
611	tty_lock(tp);
612	if(ChanStatus & STATMODE) {
613		while(ToRecv) {
614			CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp));
615			ch = CharNStat & 0xff;
616
617			if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
618				err |= TRE_FRAMING;
619			else if (CharNStat & STMPARITYH)
620				err |= TRE_PARITY;
621			else if (CharNStat & STMRCVROVRH) {
622				rp->rp_overflows++;
623				err |= TRE_OVERRUN;
624			}
625
626			ttydisc_rint(tp, ch, err);
627			ToRecv--;
628		}
629/*
630	After emtying FIFO in status mode, turn off status mode
631*/
632
633		if(sGetRxCnt(cp) == 0) {
634			sDisRxStatusMode(cp);
635		}
636	} else {
637		ToRecv = sGetRxCnt(cp);
638		while (ToRecv) {
639			ch = rp_readch1(cp,sGetTxRxDataIO(cp));
640			ttydisc_rint(tp, ch & 0xff, err);
641			ToRecv--;
642		}
643	}
644        ttydisc_rint_done(tp);
645        tty_unlock(tp);
646}
647
648static void rp_handle_port(struct rp_port *rp)
649{
650	CHANNEL_t	*cp;
651	struct	tty	*tp;
652	unsigned	int	IntMask, ChanStatus;
653
654	if(!rp)
655		return;
656
657	cp = &rp->rp_channel;
658	tp = rp->rp_tty;
659	IntMask = sGetChanIntID(cp);
660	IntMask = IntMask & rp->rp_intmask;
661	ChanStatus = sGetChanStatus(cp);
662	if(IntMask & RXF_TRIG)
663		rp_do_receive(rp, tp, cp, ChanStatus);
664	if(IntMask & DELTA_CD) {
665		if(ChanStatus & CD_ACT) {
666			(void)ttydisc_modem(tp, 1);
667		} else {
668			(void)ttydisc_modem(tp, 0);
669		}
670	}
671/*	oldcts = rp->rp_cts;
672	rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
673	if(oldcts != rp->rp_cts) {
674		printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
675	}
676*/
677}
678
679static void rp_do_poll(void *not_used)
680{
681	CONTROLLER_t	*ctl;
682	struct rp_port	*rp;
683	struct tty	*tp;
684	int	unit, aiop, ch, line, count;
685	unsigned char	CtlMask, AiopMask;
686
687	for(unit = 0; unit < rp_ndevs; unit++) {
688	rp = rp_addr(unit);
689	ctl = rp->rp_ctlp;
690	CtlMask = ctl->ctlmask(ctl);
691	for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
692		if(CtlMask & 1) {
693			AiopMask = sGetAiopIntStatus(ctl, aiop);
694			for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
695				if(AiopMask & 1) {
696					line = (unit << 5) | (aiop << 3) | ch;
697					rp = rp_table(line);
698					rp_handle_port(rp);
699				}
700			}
701		}
702	}
703
704	for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
705			line++, rp++) {
706		tp = rp->rp_tty;
707		tty_lock(tp);
708		count = sGetTxCnt(&rp->rp_channel);
709		if (count >= 0  &&
710		    (count <= rp->rp_restart)) {
711			rpstart(tp);
712		}
713		tty_unlock(tp);
714	}
715	}
716	if(rp_num_ports_open)
717		rp_callout_handle = timeout(rp_do_poll,
718					    (void *)NULL, POLL_INTERVAL);
719}
720
721static struct ttydevsw rp_tty_class = {
722	.tsw_flags	= TF_INITLOCK|TF_CALLOUT,
723	.tsw_open	= rpopen,
724	.tsw_close	= rpclose,
725	.tsw_outwakeup	= rpstart,
726	.tsw_ioctl	= rpioctl,
727	.tsw_param	= rpparam,
728	.tsw_modem	= rpmodem,
729	.tsw_free	= rpfree,
730};
731
732
733static void
734rpfree(void *softc)
735{
736	struct	rp_port *rp = softc;
737	CONTROLLER_t *ctlp = rp->rp_ctlp;
738
739	atomic_subtract_32(&ctlp->free, 1);
740}
741
742int
743rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports)
744{
745	int	unit;
746	int	num_chan;
747	int	aiop, chan, port;
748	int	ChanStatus, line, count;
749	int	retval;
750	struct	rp_port *rp;
751	struct tty *tp;
752
753	unit = device_get_unit(ctlp->dev);
754
755	printf("RocketPort%d (Version %s) %d ports.\n", unit,
756		RocketPortVersion, num_ports);
757	rp_num_ports[unit] = num_ports;
758	callout_handle_init(&rp_callout_handle);
759
760	ctlp->rp = rp = (struct rp_port *)
761		malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO);
762	if (rp == NULL) {
763		device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n");
764		retval = ENOMEM;
765		goto nogo;
766	}
767
768	count = unit * 32;      /* board times max ports per card SG */
769
770	bzero(rp, sizeof(struct rp_port) * num_ports);
771	rp_addr(unit) = rp;
772
773	port = 0;
774	for(aiop=0; aiop < num_aiops; aiop++) {
775		num_chan = sGetAiopNumChan(ctlp, aiop);
776		for(chan=0; chan < num_chan; chan++, port++, rp++) {
777			rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp);
778			rp->rp_port = port;
779			rp->rp_ctlp = ctlp;
780			rp->rp_unit = unit;
781			rp->rp_chan = chan;
782			rp->rp_aiop = aiop;
783
784			rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
785				DELTA_CD | DELTA_CTS | DELTA_DSR;
786#ifdef notdef
787			ChanStatus = sGetChanStatus(&rp->rp_channel);
788#endif /* notdef */
789			if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
790				device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n",
791					      unit, aiop, chan);
792				retval = ENXIO;
793				goto nogo;
794			}
795			ChanStatus = sGetChanStatus(&rp->rp_channel);
796			rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
797			line = (unit << 5) | (aiop << 3) | chan;
798			rp_table(line) = rp;
799			tty_makedev(tp, NULL, "R%r%r", unit, port);
800		}
801	}
802
803	rp_ndevs++;
804	mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF);
805	ctlp->hwmtx_init = 1;
806	return (0);
807
808nogo:
809	rp_releaseresource(ctlp);
810
811	return (retval);
812}
813
814void
815rp_releaseresource(CONTROLLER_t *ctlp)
816{
817	int i, unit;
818	struct	rp_port *rp;
819
820
821	unit = device_get_unit(ctlp->dev);
822	if (rp_addr(unit) != NULL) {
823		for (i = 0; i < rp_num_ports[unit]; i++) {
824			rp = rp_addr(unit) + i;
825			atomic_add_32(&ctlp->free, 1);
826			tty_lock(rp->rp_tty);
827			tty_rel_gone(rp->rp_tty);
828		}
829	}
830
831	while (ctlp->free != 0) {
832		pause("rpwt", hz / 10);
833	}
834
835	if (ctlp->rp != NULL) {
836		for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++)
837			if (p_rp_addr[i] == ctlp->rp)
838				p_rp_addr[i] = NULL;
839		for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++)
840			if (p_rp_table[i] == ctlp->rp)
841				p_rp_table[i] = NULL;
842                free(ctlp->rp, M_DEVBUF);
843                ctlp->rp = NULL;
844	}
845}
846
847void
848rp_untimeout(void)
849{
850	untimeout(rp_do_poll, (void *)NULL, rp_callout_handle);
851}
852
853static int
854rpopen(struct tty *tp)
855{
856	struct	rp_port *rp;
857	int	flags;
858	unsigned int	IntMask, ChanStatus;
859
860	rp = tty_softc(tp);
861
862	flags = 0;
863	flags |= SET_RTS;
864	flags |= SET_DTR;
865	rp->rp_channel.TxControl[3] =
866		((rp->rp_channel.TxControl[3]
867		& ~(SET_RTS | SET_DTR)) | flags);
868	rp_writech4(&rp->rp_channel,_INDX_ADDR,
869		le32dec(rp->rp_channel.TxControl));
870	sSetRxTrigger(&rp->rp_channel, TRIG_1);
871	sDisRxStatusMode(&rp->rp_channel);
872	sFlushRxFIFO(&rp->rp_channel);
873	sFlushTxFIFO(&rp->rp_channel);
874
875	sEnInterrupts(&rp->rp_channel,
876		(TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
877	sSetRxTrigger(&rp->rp_channel, TRIG_1);
878
879	sDisRxStatusMode(&rp->rp_channel);
880	sClrTxXOFF(&rp->rp_channel);
881
882/*	sDisRTSFlowCtl(&rp->rp_channel);
883	sDisCTSFlowCtl(&rp->rp_channel);
884*/
885	sDisTxSoftFlowCtl(&rp->rp_channel);
886
887	sStartRxProcessor(&rp->rp_channel);
888
889	sEnRxFIFO(&rp->rp_channel);
890	sEnTransmit(&rp->rp_channel);
891
892/*	sSetDTR(&rp->rp_channel);
893	sSetRTS(&rp->rp_channel);
894*/
895
896	rp_num_ports_open++;
897
898	IntMask = sGetChanIntID(&rp->rp_channel);
899	IntMask = IntMask & rp->rp_intmask;
900	ChanStatus = sGetChanStatus(&rp->rp_channel);
901
902	if(rp_num_ports_open == 1)
903		rp_callout_handle = timeout(rp_do_poll,
904					    (void *)NULL, POLL_INTERVAL);
905
906	device_busy(rp->rp_ctlp->dev);
907	return(0);
908}
909
910static void
911rpclose(struct tty *tp)
912{
913	struct	rp_port	*rp;
914
915	rp = tty_softc(tp);
916	rphardclose(tp);
917	device_unbusy(rp->rp_ctlp->dev);
918}
919
920static void
921rphardclose(struct tty *tp)
922{
923	struct	rp_port	*rp;
924	CHANNEL_t	*cp;
925
926	rp = tty_softc(tp);
927	cp = &rp->rp_channel;
928
929	sFlushRxFIFO(cp);
930	sFlushTxFIFO(cp);
931	sDisTransmit(cp);
932	sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
933	sDisRTSFlowCtl(cp);
934	sDisCTSFlowCtl(cp);
935	sDisTxSoftFlowCtl(cp);
936	sClrTxXOFF(cp);
937
938#ifdef DJA
939	if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) {
940		sClrDTR(cp);
941	}
942	if(ISCALLOUT(tp->t_dev)) {
943		sClrDTR(cp);
944	}
945	tp->t_actout = FALSE;
946	wakeup(&tp->t_actout);
947	wakeup(TSA_CARR_ON(tp));
948#endif /* DJA */
949}
950
951static int
952rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
953{
954	struct rp_port	*rp;
955
956	rp = tty_softc(tp);
957	switch (cmd) {
958	case TIOCSBRK:
959		sSendBreak(&rp->rp_channel);
960		return (0);
961	case TIOCCBRK:
962		sClrBreak(&rp->rp_channel);
963		return (0);
964	default:
965		return ENOIOCTL;
966	}
967}
968
969static int
970rpmodem(struct tty *tp, int sigon, int sigoff)
971{
972	struct rp_port	*rp;
973	int i, j, k;
974
975	rp = tty_softc(tp);
976	if (sigon != 0 || sigoff != 0) {
977		i = j = 0;
978		if (sigon & SER_DTR)
979			i = SET_DTR;
980		if (sigoff & SER_DTR)
981			j = SET_DTR;
982		if (sigon & SER_RTS)
983			i = SET_RTS;
984		if (sigoff & SER_RTS)
985			j = SET_RTS;
986		rp->rp_channel.TxControl[3] &= ~i;
987		rp->rp_channel.TxControl[3] |= j;
988		rp_writech4(&rp->rp_channel,_INDX_ADDR,
989			le32dec(rp->rp_channel.TxControl));
990	} else {
991		i = sGetChanStatusLo(&rp->rp_channel);
992		j = rp->rp_channel.TxControl[3];
993		k = 0;
994		if (j & SET_DTR)
995			k |= SER_DTR;
996		if (j & SET_RTS)
997			k |= SER_RTS;
998		if (i & CD_ACT)
999			k |= SER_DCD;
1000		if (i & DSR_ACT)
1001			k |= SER_DSR;
1002		if (i & CTS_ACT)
1003			k |= SER_CTS;
1004		return(k);
1005	}
1006	return (0);
1007}
1008
1009static struct
1010{
1011	int baud;
1012	int conversion;
1013} baud_table[] = {
1014	{B0,	0},		{B50,	BRD50},		{B75,	BRD75},
1015	{B110,	BRD110}, 	{B134,	BRD134}, 	{B150,	BRD150},
1016	{B200,	BRD200}, 	{B300,	BRD300}, 	{B600,	BRD600},
1017	{B1200,	BRD1200},	{B1800,	BRD1800},	{B2400,	BRD2400},
1018	{B4800,	BRD4800},	{B9600,	BRD9600},	{B19200, BRD19200},
1019	{B38400, BRD38400},	{B7200,	BRD7200},	{B14400, BRD14400},
1020				{B57600, BRD57600},	{B76800, BRD76800},
1021	{B115200, BRD115200},	{B230400, BRD230400},
1022	{-1,	-1}
1023};
1024
1025static int rp_convert_baud(int baud) {
1026	int i;
1027
1028	for (i = 0; baud_table[i].baud >= 0; i++) {
1029		if (baud_table[i].baud == baud)
1030			break;
1031	}
1032
1033	return baud_table[i].conversion;
1034}
1035
1036static int
1037rpparam(tp, t)
1038	struct tty *tp;
1039	struct termios *t;
1040{
1041	struct rp_port	*rp;
1042	CHANNEL_t	*cp;
1043	int	cflag, iflag, oflag, lflag;
1044	int	ospeed;
1045#ifdef RPCLOCAL
1046	int	devshift;
1047#endif
1048
1049	rp = tty_softc(tp);
1050	cp = &rp->rp_channel;
1051
1052	cflag = t->c_cflag;
1053#ifdef RPCLOCAL
1054	devshift = umynor / 32;
1055	devshift = 1 << devshift;
1056	if ( devshift & RPCLOCAL ) {
1057		cflag |= CLOCAL;
1058	}
1059#endif
1060	iflag = t->c_iflag;
1061	oflag = t->c_oflag;
1062	lflag = t->c_lflag;
1063
1064	ospeed = rp_convert_baud(t->c_ispeed);
1065	if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1066		return(EINVAL);
1067
1068	if(t->c_ospeed == 0) {
1069		sClrDTR(cp);
1070		return(0);
1071	}
1072	rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1073
1074	/* Set baud rate ----- we only pay attention to ispeed */
1075	sSetDTR(cp);
1076	sSetRTS(cp);
1077	sSetBaud(cp, ospeed);
1078
1079	if(cflag & CSTOPB) {
1080		sSetStop2(cp);
1081	} else {
1082		sSetStop1(cp);
1083	}
1084
1085	if(cflag & PARENB) {
1086		sEnParity(cp);
1087		if(cflag & PARODD) {
1088			sSetOddParity(cp);
1089		} else {
1090			sSetEvenParity(cp);
1091		}
1092	}
1093	else {
1094		sDisParity(cp);
1095	}
1096	if((cflag & CSIZE) == CS8) {
1097		sSetData8(cp);
1098		rp->rp_imask = 0xFF;
1099	} else {
1100		sSetData7(cp);
1101		rp->rp_imask = 0x7F;
1102	}
1103
1104	if(iflag & ISTRIP) {
1105		rp->rp_imask &= 0x7F;
1106	}
1107
1108	if(cflag & CLOCAL) {
1109		rp->rp_intmask &= ~DELTA_CD;
1110	} else {
1111		rp->rp_intmask |= DELTA_CD;
1112	}
1113
1114	/* Put flow control stuff here */
1115
1116	if(cflag & CCTS_OFLOW) {
1117		sEnCTSFlowCtl(cp);
1118	} else {
1119		sDisCTSFlowCtl(cp);
1120	}
1121
1122	if(cflag & CRTS_IFLOW) {
1123		rp->rp_rts_iflow = 1;
1124	} else {
1125		rp->rp_rts_iflow = 0;
1126	}
1127
1128	if(cflag & CRTS_IFLOW) {
1129		sEnRTSFlowCtl(cp);
1130	} else {
1131		sDisRTSFlowCtl(cp);
1132	}
1133
1134	return(0);
1135}
1136
1137static void
1138rpstart(struct tty *tp)
1139{
1140	struct rp_port	*rp;
1141	CHANNEL_t	*cp;
1142	char	flags;
1143	int	xmit_fifo_room;
1144	int	i, count, wcount;
1145
1146	rp = tty_softc(tp);
1147	cp = &rp->rp_channel;
1148	flags = rp->rp_channel.TxControl[3];
1149
1150	if(rp->rp_xmit_stopped) {
1151		sEnTransmit(cp);
1152		rp->rp_xmit_stopped = 0;
1153	}
1154
1155	xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1156	count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room);
1157	if(xmit_fifo_room > 0) {
1158		for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) {
1159			rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i]));
1160		}
1161		if ( count & 1 ) {
1162			rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]);
1163		}
1164	}
1165}
1166