2 * Copyright (c) Comtrol Corporation <support@comtrol.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted prodived that the follwoing conditions
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.
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
32 * $FreeBSD: src/sys/i386/isa/rp.c,v 1.33.2.2 2001/02/26 04:23:10 jlemon Exp $
33 * $DragonFly: src/sys/dev/serial/rp2/Attic/rp.c,v 1.14 2004/09/19 01:55:07 dillon Exp $
37 * rp.c - for RocketPort FreeBSD
40 #include "opt_compat.h"
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/fcntl.h>
45 #include <sys/malloc.h>
49 #include <sys/kernel.h>
51 #include <bus/isa/i386/isa_device.h>
53 #include <bus/pci/pcivar.h>
67 static Byte_t RData[RDATASIZE] =
69 0x00, 0x09, 0xf6, 0x82,
70 0x02, 0x09, 0x86, 0xfb,
71 0x04, 0x09, 0x00, 0x0a,
72 0x06, 0x09, 0x01, 0x0a,
73 0x08, 0x09, 0x8a, 0x13,
74 0x0a, 0x09, 0xc5, 0x11,
75 0x0c, 0x09, 0x86, 0x85,
76 0x0e, 0x09, 0x20, 0x0a,
77 0x10, 0x09, 0x21, 0x0a,
78 0x12, 0x09, 0x41, 0xff,
79 0x14, 0x09, 0x82, 0x00,
80 0x16, 0x09, 0x82, 0x7b,
81 0x18, 0x09, 0x8a, 0x7d,
82 0x1a, 0x09, 0x88, 0x81,
83 0x1c, 0x09, 0x86, 0x7a,
84 0x1e, 0x09, 0x84, 0x81,
85 0x20, 0x09, 0x82, 0x7c,
86 0x22, 0x09, 0x0a, 0x0a
89 static Byte_t RRegData[RREGDATASIZE]=
91 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
92 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
93 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
94 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
95 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
96 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
97 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
98 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
99 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
100 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
101 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
102 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
103 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
106 static CONTROLLER_T sController[CTL_SIZE] =
108 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
109 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
110 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}},
111 {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}
115 /* IRQ number to MUDBAC register 2 mapping */
118 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
122 static Byte_t sBitMapClrTbl[8] =
124 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
127 static Byte_t sBitMapSetTbl[8] =
129 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
132 static struct callout do_poll_ch;
134 /***************************************************************************
135 Function: sInitController
136 Purpose: Initialization of controller global registers and controller
138 Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
139 IRQNum,Frequency,PeriodicOnly)
140 CONTROLLER_T *CtlP; Ptr to controller structure
141 int CtlNum; Controller number
142 ByteIO_t MudbacIO; Mudbac base I/O address.
143 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
144 This list must be in the order the AIOPs will be found on the
145 controller. Once an AIOP in the list is not found, it is
146 assumed that there are no more AIOPs on the controller.
147 int AiopIOListSize; Number of addresses in AiopIOList
148 int IRQNum; Interrupt Request number. Can be any of the following:
149 0: Disable global interrupts
158 Byte_t Frequency: A flag identifying the frequency
159 of the periodic interrupt, can be any one of the following:
160 FREQ_DIS - periodic interrupt disabled
161 FREQ_137HZ - 137 Hertz
167 If IRQNum is set to 0 the Frequency parameter is
168 overidden, it is forced to a value of FREQ_DIS.
169 int PeriodicOnly: TRUE if all interrupts except the periodic
170 interrupt are to be blocked.
171 FALSE is both the periodic interrupt and
172 other channel interrupts are allowed.
173 If IRQNum is set to 0 the PeriodicOnly parameter is
174 overidden, it is forced to a value of FALSE.
175 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
176 initialization failed.
179 If periodic interrupts are to be disabled but AIOP interrupts
180 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
182 If interrupts are to be completely disabled set IRQNum to 0.
184 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
187 This function performs initialization of global interrupt modes,
188 but it does not actually enable global interrupts. To enable
189 and disable global interrupts use functions sEnGlobalInt() and
190 sDisGlobalInt(). Enabling of global interrupts is normally not
191 done until all other initializations are complete.
193 Even if interrupts are globally enabled, they must also be
194 individually enabled for each channel that is to generate
197 Warnings: No range checking on any of the parameters is done.
199 No context switches are allowed while executing this function.
201 After this function all AIOPs on the controller are disabled,
202 they can be enabled with sEnAiop().
204 int sInitController( CONTROLLER_T *CtlP,
207 ByteIO_t *AiopIOList,
216 CtlP->CtlNum = CtlNum;
217 CtlP->BusType = isISA;
218 CtlP->CtlID = CTLID_0001; /* controller release 1 */
220 CtlP->MBaseIO = MudbacIO;
221 CtlP->MReg1IO = MudbacIO + 1;
222 CtlP->MReg2IO = MudbacIO + 2;
223 CtlP->MReg3IO = MudbacIO + 3;
225 CtlP->MReg2 = 0; /* interrupt disable */
226 CtlP->MReg3 = 0; /* no periodic interrupts */
228 if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */
230 CtlP->MReg2 = 0; /* interrupt disable */
231 CtlP->MReg3 = 0; /* no periodic interrupts */
235 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
236 CtlP->MReg3 = Frequency; /* set frequency */
237 if(PeriodicOnly) /* periodic interrupt only */
239 CtlP->MReg3 |= PERIODIC_ONLY;
243 sOutB(CtlP->MReg2IO,CtlP->MReg2);
244 sOutB(CtlP->MReg3IO,CtlP->MReg3);
245 sControllerEOI(CtlP); /* clear EOI if warm init */
249 for(i=0; i < AiopIOListSize; i++)
252 CtlP->AiopIO[i] = (WordIO_t)io;
253 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
254 sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */
255 sOutB(MudbacIO,(Byte_t)(io >> 6)); /* set up AIOP I/O in MUDBAC */
256 sEnAiop(CtlP,i); /* enable the AIOP */
258 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
259 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
261 sDisAiop(CtlP,i); /* disable AIOP */
262 break; /* done looking for AIOPs */
265 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
266 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */
267 sOutB(io + _INDX_DATA,CLOCK_PRESC);
268 CtlP->NumAiop++; /* bump count of AIOPs */
269 sDisAiop(CtlP,i); /* disable AIOP */
272 if(CtlP->NumAiop == 0)
275 return(CtlP->NumAiop);
278 int sPCIInitController( CONTROLLER_T *CtlP,
280 ByteIO_t *AiopIOList,
289 CtlP->CtlNum = CtlNum;
290 CtlP->BusType = isPCI;
291 CtlP->CtlID = CTLID_0001; /* controller release 1 */
292 CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC);
294 sPCIControllerEOI(CtlP);
298 for(i=0; i < AiopIOListSize; i++)
301 CtlP->AiopIO[i] = (WordIO_t)io;
302 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
304 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
305 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
307 break; /* done looking for AIOPs */
310 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
311 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */
312 sOutB(io + _INDX_DATA,CLOCK_PRESC);
313 CtlP->NumAiop++; /* bump count of AIOPs */
316 if(CtlP->NumAiop == 0)
319 return(CtlP->NumAiop);
322 /***************************************************************************
323 Function: sReadAiopID
324 Purpose: Read the AIOP idenfication number directly from an AIOP.
325 Call: sReadAiopID(io)
326 ByteIO_t io: AIOP base I/O address
327 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
328 is replace by an identifying number.
329 Flag AIOPID_NULL if no valid AIOP is found
330 Warnings: No context switches are allowed while executing this function.
333 int sReadAiopID(ByteIO_t io)
335 Byte_t AiopID; /* ID byte from AIOP */
337 sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */
338 sOutB(io + _CMD_REG,0x0);
339 AiopID = sInB(io + _CHN_STAT0) & 0x07;
342 else /* AIOP does not exist */
346 /***************************************************************************
347 Function: sReadAiopNumChan
348 Purpose: Read the number of channels available in an AIOP directly from
350 Call: sReadAiopNumChan(io)
351 WordIO_t io: AIOP base I/O address
352 Return: int: The number of channels available
353 Comments: The number of channels is determined by write/reads from identical
354 offsets within the SRAM address spaces for channels 0 and 4.
355 If the channel 4 space is mirrored to channel 0 it is a 4 channel
356 AIOP, otherwise it is an 8 channel.
357 Warnings: No context switches are allowed while executing this function.
359 int sReadAiopNumChan(WordIO_t io)
363 sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
364 sOutW(io + _INDX_ADDR,0); /* read from SRAM, chan 0 */
365 x = sInW(io + _INDX_DATA);
366 sOutW(io + _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
367 if(x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
373 /***************************************************************************
375 Purpose: Initialization of a channel and channel structure
376 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
377 CONTROLLER_T *CtlP; Ptr to controller structure
378 CHANNEL_T *ChP; Ptr to channel structure
379 int AiopNum; AIOP number within controller
380 int ChanNum; Channel number within AIOP
381 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
382 number exceeds number of channels available in AIOP.
383 Comments: This function must be called before a channel can be used.
384 Warnings: No range checking on any of the parameters is done.
386 No context switches are allowed while executing this function.
388 int sInitChan( CONTROLLER_T *CtlP,
400 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
401 return(FALSE); /* exceeds num chans in AIOP */
403 /* Channel, AIOP, and controller identifiers */
405 ChP->ChanID = CtlP->AiopID[AiopNum];
406 ChP->AiopNum = AiopNum;
407 ChP->ChanNum = ChanNum;
409 /* Global direct addresses */
410 AiopIO = CtlP->AiopIO[AiopNum];
411 ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG;
412 ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN;
413 ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK;
414 ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR;
415 ChP->IndexData = AiopIO + _INDX_DATA;
417 /* Channel direct addresses */
418 ChIOOff = AiopIO + ChP->ChanNum * 2;
419 ChP->TxRxData = ChIOOff + _TD0;
420 ChP->ChanStat = ChIOOff + _CHN_STAT0;
421 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
422 ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0;
424 /* Initialize the channel from the RData array */
425 for(i=0; i < RDATASIZE; i+=4)
428 R[1] = RData[i+1] + 0x10 * ChanNum;
431 sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0]));
435 for(i=0; i < RREGDATASIZE; i+=4)
437 ChR[i] = RRegData[i];
438 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
439 ChR[i+2] = RRegData[i+2];
440 ChR[i+3] = RRegData[i+3];
443 /* Indexed registers */
444 ChOff = (Word_t)ChanNum * 0x1000;
446 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
447 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
448 ChP->BaudDiv[2] = (Byte_t)BRD9600;
449 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
450 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]);
452 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
453 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
454 ChP->TxControl[2] = 0;
455 ChP->TxControl[3] = 0;
456 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
458 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
459 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
460 ChP->RxControl[2] = 0;
461 ChP->RxControl[3] = 0;
462 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
464 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
465 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
466 ChP->TxEnables[2] = 0;
467 ChP->TxEnables[3] = 0;
468 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]);
470 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
471 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
472 ChP->TxCompare[2] = 0;
473 ChP->TxCompare[3] = 0;
474 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]);
476 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
477 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
478 ChP->TxReplace1[2] = 0;
479 ChP->TxReplace1[3] = 0;
480 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]);
482 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
483 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
484 ChP->TxReplace2[2] = 0;
485 ChP->TxReplace2[3] = 0;
486 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]);
488 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
489 ChP->TxFIFO = ChOff + _TX_FIFO;
491 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
492 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
493 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
494 sOutW(ChP->IndexData,0);
495 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
496 ChP->RxFIFO = ChOff + _RX_FIFO;
498 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
499 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
500 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
501 sOutW(ChP->IndexData,0);
502 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
503 sOutW(ChP->IndexData,0);
504 ChP->TxPrioCnt = ChOff + _TXP_CNT;
505 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt);
506 sOutB(ChP->IndexData,0);
507 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
508 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr);
509 sOutB(ChP->IndexData,0);
510 ChP->TxPrioBuf = ChOff + _TXP_BUF;
511 sEnRxProcessor(ChP); /* start the Rx processor */
516 /***************************************************************************
517 Function: sStopRxProcessor
518 Purpose: Stop the receive processor from processing a channel.
519 Call: sStopRxProcessor(ChP)
520 CHANNEL_T *ChP; Ptr to channel structure
522 Comments: The receive processor can be started again with sStartRxProcessor().
523 This function causes the receive processor to skip over the
524 stopped channel. It does not stop it from processing other channels.
526 Warnings: No context switches are allowed while executing this function.
528 Do not leave the receive processor stopped for more than one
531 After calling this function a delay of 4 uS is required to ensure
532 that the receive processor is no longer processing this channel.
534 void sStopRxProcessor(CHANNEL_T *ChP)
542 sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]);
545 /***************************************************************************
546 Function: sFlushRxFIFO
547 Purpose: Flush the Rx FIFO
548 Call: sFlushRxFIFO(ChP)
549 CHANNEL_T *ChP; Ptr to channel structure
551 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
552 while it is being flushed the receive processor is stopped
553 and the transmitter is disabled. After these operations a
554 4 uS delay is done before clearing the pointers to allow
555 the receive processor to stop. These items are handled inside
557 Warnings: No context switches are allowed while executing this function.
559 void sFlushRxFIFO(CHANNEL_T *ChP)
562 Byte_t Ch; /* channel number within AIOP */
563 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
565 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
566 return; /* don't need to flush */
568 RxFIFOEnabled = FALSE;
569 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
571 RxFIFOEnabled = TRUE;
572 sDisRxFIFO(ChP); /* disable it */
573 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
574 sInB(ChP->IntChan); /* depends on bus i/o timing */
576 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
577 Ch = (Byte_t)sGetChanNum(ChP);
578 sOutB(ChP->Cmd,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
579 sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */
580 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
581 sOutW(ChP->IndexData,0);
582 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
583 sOutW(ChP->IndexData,0);
585 sEnRxFIFO(ChP); /* enable Rx FIFO */
588 /***************************************************************************
589 Function: sFlushTxFIFO
590 Purpose: Flush the Tx FIFO
591 Call: sFlushTxFIFO(ChP)
592 CHANNEL_T *ChP; Ptr to channel structure
594 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
595 while it is being flushed the receive processor is stopped
596 and the transmitter is disabled. After these operations a
597 4 uS delay is done before clearing the pointers to allow
598 the receive processor to stop. These items are handled inside
600 Warnings: No context switches are allowed while executing this function.
602 void sFlushTxFIFO(CHANNEL_T *ChP)
605 Byte_t Ch; /* channel number within AIOP */
606 int TxEnabled; /* TRUE if transmitter enabled */
608 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
609 return; /* don't need to flush */
612 if(ChP->TxControl[3] & TX_ENABLE)
615 sDisTransmit(ChP); /* disable transmitter */
617 sStopRxProcessor(ChP); /* stop Rx processor */
618 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
619 sInB(ChP->IntChan); /* depends on bus i/o timing */
620 Ch = (Byte_t)sGetChanNum(ChP);
621 sOutB(ChP->Cmd,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
622 sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */
623 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
624 sOutW(ChP->IndexData,0);
626 sEnTransmit(ChP); /* enable transmitter */
627 sStartRxProcessor(ChP); /* restart Rx processor */
630 /***************************************************************************
631 Function: sWriteTxPrioByte
632 Purpose: Write a byte of priority transmit data to a channel
633 Call: sWriteTxPrioByte(ChP,Data)
634 CHANNEL_T *ChP; Ptr to channel structure
635 Byte_t Data; The transmit data byte
637 Return: int: 1 if the bytes is successfully written, otherwise 0.
639 Comments: The priority byte is transmitted before any data in the Tx FIFO.
641 Warnings: No context switches are allowed while executing this function.
643 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
645 Byte_t DWBuf[4]; /* buffer for double word writes */
646 Word_t *WordPtr; /* must be far because Win SS != DS */
649 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
651 IndexAddr = ChP->IndexAddr;
652 sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */
653 if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */
654 return(0); /* nothing sent */
656 WordPtr = (Word_t *)(&DWBuf[0]);
657 *WordPtr = ChP->TxPrioBuf; /* data byte address */
659 DWBuf[2] = Data; /* data byte value */
660 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
662 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
664 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
665 DWBuf[3] = 0; /* priority buffer pointer */
666 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
668 else /* write it to Tx FIFO */
670 sWriteTxByte(sGetTxRxDataIO(ChP),Data);
672 return(1); /* 1 byte sent */
675 /***************************************************************************
676 Function: sEnInterrupts
677 Purpose: Enable one or more interrupts for a channel
678 Call: sEnInterrupts(ChP,Flags)
679 CHANNEL_T *ChP; Ptr to channel structure
680 Word_t Flags: Interrupt enable flags, can be any combination
681 of the following flags:
682 TXINT_EN: Interrupt on Tx FIFO empty
683 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
685 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
686 MCINT_EN: Interrupt on modem input change
687 CHANINT_EN: Allow channel interrupt signal to the AIOP's
688 Interrupt Channel Register.
690 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
691 enabled. If an interrupt enable flag is not set in Flags, that
692 interrupt will not be changed. Interrupts can be disabled with
693 function sDisInterrupts().
695 This function sets the appropriate bit for the channel in the AIOP's
696 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
697 this channel's bit to be set in the AIOP's Interrupt Channel Register.
699 Interrupts must also be globally enabled before channel interrupts
700 will be passed on to the host. This is done with function
703 In some cases it may be desirable to disable interrupts globally but
704 enable channel interrupts. This would allow the global interrupt
705 status register to be used to determine which AIOPs need service.
707 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
709 Byte_t Mask; /* Interrupt Mask Register */
712 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
714 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
716 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
718 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
720 if(Flags & CHANINT_EN)
722 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
723 sOutB(ChP->IntMask,Mask);
727 /***************************************************************************
728 Function: sDisInterrupts
729 Purpose: Disable one or more interrupts for a channel
730 Call: sDisInterrupts(ChP,Flags)
731 CHANNEL_T *ChP; Ptr to channel structure
732 Word_t Flags: Interrupt flags, can be any combination
733 of the following flags:
734 TXINT_EN: Interrupt on Tx FIFO empty
735 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
737 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
738 MCINT_EN: Interrupt on modem input change
739 CHANINT_EN: Disable channel interrupt signal to the
740 AIOP's Interrupt Channel Register.
742 Comments: If an interrupt flag is set in Flags, that interrupt will be
743 disabled. If an interrupt flag is not set in Flags, that
744 interrupt will not be changed. Interrupts can be enabled with
745 function sEnInterrupts().
747 This function clears the appropriate bit for the channel in the AIOP's
748 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
749 this channel's bit from being set in the AIOP's Interrupt Channel
752 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
754 Byte_t Mask; /* Interrupt Mask Register */
757 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
758 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
759 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
760 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
762 if(Flags & CHANINT_EN)
764 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
765 sOutB(ChP->IntMask,Mask);
769 /*********************************************************************
770 Begin FreeBsd-specific driver code
771 **********************************************************************/
773 static int rpprobe (struct isa_device *);
774 static int rpattach (struct isa_device *);
776 static const char* rp_pciprobe(pcici_t tag, pcidi_t type);
777 static void rp_pciattach(pcici_t tag, int unit);
778 static u_long rp_pcicount;
780 static struct pci_device rp_pcidevice = {
788 COMPAT_PCI_DRIVER (rp_pci, rp_pcidevice);
790 static timeout_t rpdtrwakeup;
792 struct isa_driver rpdriver = {
793 rpprobe, rpattach, "rp"
796 static char driver_name[] = "rp";
798 static d_open_t rpopen;
799 static d_close_t rpclose;
800 static d_write_t rpwrite;
801 static d_ioctl_t rpioctl;
803 #define CDEV_MAJOR 81
804 static struct cdevsw rp_cdevsw = {
805 /* name */ driver_name,
806 /* maj */ CDEV_MAJOR,
807 /* flags */ D_TTY | D_KQFILTER,
818 /* strategy */ nostrategy,
821 /* kqfilter */ ttykqfilter
824 static int rp_controller_port = 0;
825 static int rp_num_ports_open = 0;
826 static int ndevs = 0;
827 static int minor_to_unit[128];
829 static struct tty rp_tty[128];
832 static int rp_num_ports[4]; /* Number of ports on each controller */
834 #define _INLINE_ __inline
835 #define POLL_INTERVAL 1
837 #define CALLOUT_MASK 0x80
838 #define CONTROL_MASK 0x60
839 #define CONTROL_INIT_STATE 0x20
840 #define CONTROL_LOCK_STATE 0x40
841 #define DEV_UNIT(dev) (MINOR_TO_UNIT(minor(dev))
842 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
843 #define MINOR_MAGIC(dev) ((minor(dev)) & ~MINOR_MAGIC_MASK)
844 #define IS_CALLOUT(dev) (minor(dev) & CALLOUT_MASK)
845 #define IS_CONTROL(dev) (minor(dev) & CONTROL_MASK)
847 #define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
848 #define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
849 #define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
851 static struct rp_port *p_rp_addr[4];
852 static struct rp_port *p_rp_table[MAX_RP_PORTS];
853 #define rp_addr(unit) (p_rp_addr[unit])
854 #define rp_table(port) (p_rp_table[port])
857 * The top-level routines begin here
860 static int rpparam (struct tty *, struct termios *);
861 static void rpstart (struct tty *);
862 static void rpstop (struct tty *, int);
863 static void rphardclose (struct rp_port *);
864 static void rp_disc_optim (struct tty *tp, struct termios *t,
867 static _INLINE_ void rp_do_receive(struct rp_port *rp, struct tty *tp,
868 CHANNEL_t *cp, unsigned int ChanStatus)
871 unsigned int CharNStat;
874 ToRecv = sGetRxCnt(cp);
878 /* If status indicates there are errored characters in the
879 FIFO, then enter status mode (a word in FIFO holds
880 characters and status)
883 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
884 if(!(ChanStatus & STATMODE)) {
885 ChanStatus |= STATMODE;
890 if we previously entered status mode then read down the
891 FIFO one word at a time, pulling apart the character and
892 the status. Update error counters depending on status.
894 if(ChanStatus & STATMODE) {
896 if(tp->t_state & TS_TBLOCK) {
899 CharNStat = sInW(sGetTxRxDataIO(cp));
900 ch = CharNStat & 0xff;
902 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
904 else if (CharNStat & STMPARITYH)
906 else if (CharNStat & STMRCVROVRH)
909 (*linesw[tp->t_line].l_rint)(ch, tp);
913 After emtying FIFO in status mode, turn off status mode
916 if(sGetRxCnt(cp) == 0)
917 sDisRxStatusMode(cp);
921 if(tp->t_state & TS_TBLOCK) {
924 ch = (u_char) sInB(sGetTxRxDataIO(cp));
926 (*linesw[tp->t_line].l_rint)(ch, tp);
933 static _INLINE_ void rp_handle_port(struct rp_port *rp)
937 unsigned int IntMask, ChanStatus;
943 cp = &rp->rp_channel;
945 IntMask = sGetChanIntID(cp);
946 IntMask = IntMask & rp->rp_intmask;
947 ChanStatus = sGetChanStatus(cp);
948 if(IntMask & RXF_TRIG)
949 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
950 rp_do_receive(rp, tp, cp, ChanStatus);
952 if(IntMask & DELTA_CD) {
953 if(ChanStatus & CD_ACT) {
954 if(!(tp->t_state & TS_CARR_ON) ) {
955 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
958 if((tp->t_state & TS_CARR_ON)) {
959 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
960 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
966 /* oldcts = rp->rp_cts;
967 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
968 if(oldcts != rp->rp_cts) {
969 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
974 static void rp_do_poll(void *not_used)
979 int unit, aiop, ch, line, count;
980 unsigned char CtlMask, AiopMask;
982 for(unit = 0; unit <= ndevs; unit++) {
985 if(ctl->BusType == isPCI)
986 CtlMask = sPCIGetControllerIntStatus(ctl);
988 CtlMask = sGetControllerIntStatus(ctl);
989 for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
991 AiopMask = sGetAiopIntStatus(ctl, aiop);
992 for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
994 line = (unit << 5) | (aiop << 3) | ch;
1002 for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
1005 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
1006 count = sGetTxCnt(&rp->rp_channel);
1008 tp->t_state &= ~(TS_BUSY);
1009 if(!(tp->t_state & TS_TTSTOP) &&
1010 (count <= rp->rp_restart)) {
1011 (*linesw[tp->t_line].l_start)(tp);
1016 if (rp_num_ports_open)
1017 callout_reset(&do_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1021 rp_pciprobe(pcici_t tag, pcidi_t type)
1025 vendor_id = type & 0xffff;
1035 struct isa_device *dev;
1037 int controller, unit;
1038 int aiop, num_aiops;
1039 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1042 unit = dev->id_unit;
1043 if (dev->id_unit >= 4) {
1044 printf("rpprobe: unit number %d invalid.\n", dev->id_unit);
1047 printf("probing for RocketPort(ISA) unit %d\n", unit);
1048 if (rp_controller_port)
1049 controller = rp_controller_port;
1051 controller = dev->id_iobase + 0x40;
1054 for (aiop=0; aiop<MAX_AIOPS_PER_BOARD; aiop++)
1055 aiopio[aiop]= dev->id_iobase + (aiop * 0x400);
1057 ctlp = sCtlNumToCtlPtr(dev->id_unit);
1058 num_aiops = sInitController(ctlp, dev->id_unit,
1059 controller + ((unit-rp_pcicount)*0x400),
1060 aiopio, MAX_AIOPS_PER_BOARD, 0,
1062 if (num_aiops <= 0) {
1063 printf("board%d init failed\n", unit);
1067 if (rp_controller_port) {
1071 rp_controller_port = controller;
1080 rp_pciattach(pcici_t tag, int unit)
1082 int success, oldspl;
1084 int num_ports, num_chan, num_aiops;
1085 int aiop, chan, port;
1086 int ChanStatus, line, i, count;
1087 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1092 success = pci_map_port(tag, 0x10, &iobase);
1094 printf("ioaddr mapping failed for RocketPort(PCI)\n");
1096 for(aiop=0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
1097 aiopio[aiop] = iobase + (aiop * 0x40);
1099 ctlp = sCtlNumToCtlPtr(unit);
1100 num_aiops = sPCIInitController(ctlp, unit,
1101 aiopio, MAX_AIOPS_PER_BOARD, 0,
1105 for(aiop=0; aiop < num_aiops; aiop++) {
1106 sResetAiopByNum(ctlp, aiop);
1107 num_ports += sGetAiopNumChan(ctlp, aiop);
1109 printf("RocketPort%d = %d ports\n", unit, num_ports);
1110 rp_num_ports[unit] = num_ports;
1112 rp = malloc(sizeof(struct rp_port) * num_ports,
1113 M_TTYS, M_WAITOK | M_ZERO);
1115 count = unit * 32; /* board times max ports per card SG */
1116 for(i=count;i < (count + rp_num_ports[unit]);i++)
1117 minor_to_unit[i] = unit;
1119 tty = malloc(sizeof(struct tty) * num_ports, M_TTYS, M_WAITOK | M_ZERO);
1125 cdevsw_add(&rp_cdevsw, 0, 0);
1128 for(aiop=0; aiop < num_aiops; aiop++) {
1129 num_chan = sGetAiopNumChan(ctlp, aiop);
1130 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
1139 /* tty->t_termios = deftermios;
1141 rp->dtr_wait = 3 * hz;
1142 callout_init(&rp->dtr_ch);
1143 rp->it_in.c_iflag = 0;
1144 rp->it_in.c_oflag = 0;
1145 rp->it_in.c_cflag = TTYDEF_CFLAG;
1146 rp->it_in.c_lflag = 0;
1147 termioschars(&rp->it_in);
1148 /* termioschars(&tty->t_termios);
1150 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
1151 rp->it_out = rp->it_in;
1153 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
1154 DELTA_CD | DELTA_CTS | DELTA_DSR;
1155 ChanStatus = sGetChanStatus(&rp->rp_channel);
1156 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
1157 printf("RocketPort sInitChan(%d, %d, %d) failed\n",
1161 ChanStatus = sGetChanStatus(&rp->rp_channel);
1162 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
1163 line = (unit << 5) | (aiop << 3) | chan;
1164 rp_table(line) = rp;
1172 struct isa_device *dev;
1174 int iobase, unit, /*rpmajor,*/ oldspl;
1175 int num_ports, num_chan, num_aiops;
1176 int aiop, chan, port;
1177 int ChanStatus, line, i, count;
1178 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1183 iobase = dev->id_iobase;
1184 unit = dev->id_unit;
1187 for(aiop=0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
1188 aiopio[aiop] = iobase + (aiop * 0x400);
1190 ctlp = sCtlNumToCtlPtr(unit);
1191 num_aiops = sInitController(ctlp, unit,
1192 rp_controller_port + ((unit-rp_pcicount) * 0x400),
1193 aiopio, MAX_AIOPS_PER_BOARD, 0,
1197 for(aiop=0; aiop < num_aiops; aiop++) {
1198 sResetAiopByNum(ctlp, aiop);
1199 sEnAiop(ctlp, aiop);
1200 num_ports += sGetAiopNumChan(ctlp, aiop);
1202 printf("RocketPort%d = %d ports\n", unit, num_ports);
1203 rp_num_ports[unit] = num_ports;
1205 rp = malloc(sizeof(struct rp_port) * num_ports,
1206 M_TTYS, M_WAITOK | M_ZERO);
1208 count = unit * 32; /* board # times max ports per card SG */
1209 for(i=count;i < (count + rp_num_ports[unit]);i++)
1210 minor_to_unit[i] = unit;
1212 tty = malloc(sizeof(struct tty) * num_ports, M_TTYS, M_WAITOK | M_ZERO);
1218 cdevsw_add(&rp_cdevsw, 0, 0);
1221 for(aiop=0; aiop < num_aiops; aiop++) {
1222 num_chan = sGetAiopNumChan(ctlp, aiop);
1223 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
1232 /* tty->t_termios = deftermios;
1234 rp->dtr_wait = 3 * hz;
1235 rp->it_in.c_iflag = 0;
1236 rp->it_in.c_oflag = 0;
1237 rp->it_in.c_cflag = TTYDEF_CFLAG;
1238 rp->it_in.c_lflag = 0;
1239 termioschars(&rp->it_in);
1240 /* termioschars(&tty->t_termios);
1242 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
1243 rp->it_out = rp->it_in;
1245 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
1246 DELTA_CD | DELTA_CTS | DELTA_DSR;
1247 ChanStatus = sGetChanStatus(&rp->rp_channel);
1248 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
1249 printf("RocketPort sInitChan(%d, %d, %d) failed\n",
1253 ChanStatus = sGetChanStatus(&rp->rp_channel);
1254 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
1255 line = (unit << 5) | (aiop << 3) | chan;
1256 rp_table(line) = rp;
1264 rpopen(dev, flag, mode, td)
1270 int unit, port, mynor, umynor, flags; /* SG */
1273 unsigned int IntMask, ChanStatus;
1276 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1277 port = (minor(dev) & 0x1f); /* SG */
1278 mynor = (port + umynor); /* SG */
1279 unit = minor_to_unit[mynor];
1280 if (rp_addr(unit) == NULL)
1284 rp = rp_addr(unit) + port;
1285 /* rp->rp_tty = &rp_tty[rp->rp_port];
1293 while(rp->state & ~SET_DTR) {
1294 error = tsleep(&rp->dtr_wait, PCATCH, "rpdtr", 0);
1299 if(tp->t_state & TS_ISOPEN) {
1300 if(IS_CALLOUT(dev)) {
1301 if(!rp->active_out) {
1306 if(rp->active_out) {
1307 if(flag & O_NONBLOCK) {
1311 error = tsleep(&rp->active_out,
1318 if(tp->t_state & TS_XCLUDE &&
1326 tp->t_param = rpparam;
1327 tp->t_oproc = rpstart;
1328 tp->t_stop = rpstop;
1330 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1334 rp->rp_channel.TxControl[3] =
1335 ((rp->rp_channel.TxControl[3]
1336 & ~(SET_RTS | SET_DTR)) | flags);
1337 sOutDW(rp->rp_channel.IndexAddr,
1338 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1339 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1340 sDisRxStatusMode(&rp->rp_channel);
1341 sFlushRxFIFO(&rp->rp_channel);
1342 sFlushTxFIFO(&rp->rp_channel);
1344 sEnInterrupts(&rp->rp_channel,
1345 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1346 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1348 sDisRxStatusMode(&rp->rp_channel);
1349 sClrTxXOFF(&rp->rp_channel);
1351 /* sDisRTSFlowCtl(&rp->rp_channel);
1352 sDisCTSFlowCtl(&rp->rp_channel);
1354 sDisTxSoftFlowCtl(&rp->rp_channel);
1356 sStartRxProcessor(&rp->rp_channel);
1358 sEnRxFIFO(&rp->rp_channel);
1359 sEnTransmit(&rp->rp_channel);
1361 /* sSetDTR(&rp->rp_channel);
1362 sSetRTS(&rp->rp_channel);
1366 error = rpparam(tp, &tp->t_termios);
1373 rp_num_ports_open++;
1375 IntMask = sGetChanIntID(&rp->rp_channel);
1376 IntMask = IntMask & rp->rp_intmask;
1377 ChanStatus = sGetChanStatus(&rp->rp_channel);
1378 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1379 if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1380 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1384 if (rp_num_ports_open == 1)
1385 if ((do_poll_ch.c_flags & CALLOUT_DID_INIT) == 0)
1386 callout_init(&do_poll_ch);
1387 callout_reset(&do_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1390 if(!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1391 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1393 error = tsleep(TSA_CARR_ON(tp), PCATCH, "rpdcd", 0);
1399 error = (*linesw[tp->t_line].l_open)(dev, tp);
1401 rp_disc_optim(tp, &tp->t_termios, rp);
1402 if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1403 rp->active_out = TRUE;
1407 if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1414 rpclose(dev, flag, mode, td)
1419 int oldspl, unit, mynor, umynor, port; /* SG */
1424 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1425 port = (minor(dev) & 0x1f); /* SG */
1426 mynor = (port + umynor); /* SG */
1427 unit = minor_to_unit[mynor]; /* SG */
1431 rp = rp_addr(unit) + port;
1432 cp = &rp->rp_channel;
1436 (*linesw[tp->t_line].l_close)(tp, flag);
1437 rp_disc_optim(tp, &tp->t_termios, rp);
1438 rpstop(tp, FREAD | FWRITE);
1441 tp->t_state &= ~TS_BUSY;
1450 rphardclose(struct rp_port *rp)
1456 cp = &rp->rp_channel;
1458 mynor = MINOR_MAGIC(tp->t_dev);
1463 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1466 sDisTxSoftFlowCtl(cp);
1469 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1472 if(IS_CALLOUT(tp->t_dev)) {
1475 if(rp->dtr_wait != 0) {
1476 callout_reset(&rp->dtr_ch, rp->dtr_wait, rpdtrwakeup, rp);
1477 rp->state |= ~SET_DTR;
1480 rp->active_out = FALSE;
1481 wakeup(&rp->active_out);
1482 wakeup(TSA_CARR_ON(tp));
1487 rpwrite(dev, uio, flag)
1494 int unit, mynor, port, umynor, error = 0; /* SG */
1496 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1497 port = (minor(dev) & 0x1f); /* SG */
1498 mynor = (port + umynor); /* SG */
1499 unit = minor_to_unit[mynor]; /* SG */
1503 rp = rp_addr(unit) + port;
1505 while(rp->rp_disable_writes) {
1507 error = ttysleep(tp, (caddr_t)rp, PCATCH, "rp_write", 0);
1512 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1517 rpdtrwakeup(void *chan)
1521 rp = (struct rp_port *)chan;
1522 rp->state &= SET_DTR;
1523 wakeup(&rp->dtr_wait);
1527 rpioctl(dev, cmd, data, flag, td)
1537 int unit, mynor, port, umynor; /* SG */
1540 int arg, flags, result, ChanStatus;
1542 struct termios term, *t;
1544 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1545 port = (minor(dev) & 0x1f); /* SG */
1546 mynor = (port + umynor); /* SG */
1547 unit = minor_to_unit[mynor];
1548 rp = rp_addr(unit) + port;
1550 if(IS_CONTROL(dev)) {
1553 switch (IS_CONTROL(dev)) {
1554 case CONTROL_INIT_STATE:
1555 ct = IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1557 case CONTROL_LOCK_STATE:
1558 ct = IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1561 return(ENODEV); /* /dev/nodev */
1568 *ct = *(struct termios *)data;
1571 *(struct termios *)data = *ct;
1574 *(int *)data = TTYDISC;
1577 bzero(data, sizeof(struct winsize));
1585 cp = &rp->rp_channel;
1587 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1588 term = tp->t_termios;
1590 error = ttsetcompat(tp, &cmd, data, &term);
1594 data = (caddr_t)&term;
1597 if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1599 struct termios *dt = (struct termios *)data;
1600 struct termios *lt = IS_CALLOUT(dev)
1601 ? &rp->lt_out : &rp->lt_in;
1603 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1604 | (dt->c_iflag & ~lt->c_iflag);
1605 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1606 | (dt->c_oflag & ~lt->c_oflag);
1607 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1608 | (dt->c_cflag & ~lt->c_cflag);
1609 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1610 | (dt->c_lflag & ~lt->c_lflag);
1611 for(cc = 0; cc < NCCS; ++cc)
1612 if(lt->c_cc[cc] != 0)
1613 dt->c_cc[cc] = tp->t_cc[cc];
1614 if(lt->c_ispeed != 0)
1615 dt->c_ispeed = tp->t_ispeed;
1616 if(lt->c_ospeed != 0)
1617 dt->c_ospeed = tp->t_ospeed;
1622 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
1623 if(error != ENOIOCTL) {
1628 flags = rp->rp_channel.TxControl[3];
1630 error = ttioctl(tp, cmd, data, flag);
1631 flags = rp->rp_channel.TxControl[3];
1632 rp_disc_optim(tp, &tp->t_termios, rp);
1633 if(error != ENOIOCTL) {
1639 sSendBreak(&rp->rp_channel);
1643 sClrBreak(&rp->rp_channel);
1647 sSetDTR(&rp->rp_channel);
1648 sSetRTS(&rp->rp_channel);
1652 sClrDTR(&rp->rp_channel);
1656 arg = *(int *) data;
1662 rp->rp_channel.TxControl[3] =
1663 ((rp->rp_channel.TxControl[3]
1664 & ~(SET_RTS | SET_DTR)) | flags);
1665 sOutDW(rp->rp_channel.IndexAddr,
1666 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1669 arg = *(int *) data;
1675 rp->rp_channel.TxControl[3] |= flags;
1676 sOutDW(rp->rp_channel.IndexAddr,
1677 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1680 arg = *(int *) data;
1686 rp->rp_channel.TxControl[3] &= ~flags;
1687 sOutDW(rp->rp_channel.IndexAddr,
1688 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1693 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1694 flags = rp->rp_channel.TxControl[3];
1695 result = TIOCM_LE; /* always on while open for some reason */
1696 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1697 | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1698 | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1699 | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1700 | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1702 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1704 result |= TIOCM_RTS;
1707 *(int *)data = result;
1715 rp->dtr_wait = *(int *)data * hz/100;
1718 *(int *)data = rp->dtr_wait * 100/hz;
1728 static struct speedtab baud_table[] = {
1729 {B0, 0}, {B50, BRD50}, {B75, BRD75},
1730 {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
1731 {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
1732 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
1733 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
1734 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
1735 {B57600, BRD57600}, {B76800, BRD76800},
1736 {B115200, BRD115200}, {B230400, BRD230400},
1747 int unit, mynor, port, umynor; /* SG */
1748 int oldspl, cflag, iflag, oflag, lflag;
1752 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1753 port = (minor(tp->t_dev) & 0x1f); /* SG */
1754 mynor = (port + umynor); /* SG */
1756 unit = minor_to_unit[mynor];
1757 rp = rp_addr(unit) + port;
1758 cp = &rp->rp_channel;
1766 ospeed = ttspeedtab(t->c_ispeed, baud_table);
1767 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1770 tp->t_ispeed = t->c_ispeed;
1771 tp->t_ospeed = t->c_ospeed;
1772 tp->t_cflag = cflag;
1773 tp->t_iflag = iflag;
1774 tp->t_oflag = oflag;
1775 tp->t_lflag = lflag;
1777 if(t->c_ospeed == 0) {
1781 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1783 /* Set baud rate ----- we only pay attention to ispeed */
1786 sSetBaud(cp, ospeed);
1788 if(cflag & CSTOPB) {
1794 if(cflag & PARENB) {
1796 if(cflag & PARODD) {
1805 if((cflag & CSIZE) == CS8) {
1807 rp->rp_imask = 0xFF;
1810 rp->rp_imask = 0x7F;
1813 if(iflag & ISTRIP) {
1814 rp->rp_imask &= 0x7F;
1817 if(cflag & CLOCAL) {
1818 rp->rp_intmask &= ~DELTA_CD;
1820 rp->rp_intmask |= DELTA_CD;
1823 /* Put flow control stuff here */
1825 if(cflag & CCTS_OFLOW) {
1831 if(cflag & CRTS_IFLOW) {
1832 rp->rp_rts_iflow = 1;
1834 rp->rp_rts_iflow = 0;
1837 if(cflag & CRTS_IFLOW) {
1842 rp_disc_optim(tp, t, rp);
1844 if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1845 tp->t_state |= TS_CARR_ON;
1846 wakeup(TSA_CARR_ON(tp));
1849 /* tp->t_state |= TS_CAN_BYPASS_L_RINT;
1850 flags = rp->rp_channel.TxControl[3];
1862 rp_disc_optim(tp, t, rp)
1867 if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1868 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1869 &&(!(t->c_iflag & PARMRK)
1870 ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1871 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1872 && linesw[tp->t_line].l_rint == ttyinput)
1873 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1875 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1885 int unit, mynor, port, umynor; /* SG */
1887 int spl, xmit_fifo_room;
1891 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1892 port = (minor(tp->t_dev) & 0x1f); /* SG */
1893 mynor = (port + umynor); /* SG */
1894 unit = minor_to_unit[mynor];
1895 rp = rp_addr(unit) + port;
1896 cp = &rp->rp_channel;
1897 flags = rp->rp_channel.TxControl[3];
1900 if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1905 if(rp->rp_xmit_stopped) {
1907 rp->rp_xmit_stopped = 0;
1909 count = sGetTxCnt(cp);
1911 if(tp->t_outq.c_cc == 0) {
1912 if((tp->t_state & TS_BUSY) && (count == 0)) {
1913 tp->t_state &= ~TS_BUSY;
1919 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1922 if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1923 tp->t_state |= TS_BUSY;
1925 while(xmit_fifo_room > 0 && qp->c_cc > 0) {
1927 sOutB(sGetTxRxDataIO(cp), ch);
1931 rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1945 int unit, mynor, port, umynor; /* SG */
1948 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1949 port = (minor(tp->t_dev) & 0x1f); /* SG */
1950 mynor = (port + umynor); /* SG */
1951 unit = minor_to_unit[mynor];
1952 rp = rp_addr(unit) + port;
1953 cp = &rp->rp_channel;
1957 if(tp->t_state & TS_BUSY) {
1958 if((tp->t_state&TS_TTSTOP) == 0) {
1961 if(rp->rp_xmit_stopped == 0) {
1963 rp->rp_xmit_stopped = 1;