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.15 2004/12/08 20:36:39 joerg Exp $
37 * rp.c - for RocketPort FreeBSD
40 #include "opt_compat.h"
41 #include "opt_depricated.h"
42 #ifndef I_WANT_DEPRICATED_STUFF
43 #error "Add options I_WANT_DEPRICATED_STUFF to your kernel config and send a mail to kernel@"
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/fcntl.h>
49 #include <sys/malloc.h>
53 #include <sys/kernel.h>
55 #include <bus/isa/i386/isa_device.h>
57 #include <bus/pci/pcivar.h>
71 static Byte_t RData[RDATASIZE] =
73 0x00, 0x09, 0xf6, 0x82,
74 0x02, 0x09, 0x86, 0xfb,
75 0x04, 0x09, 0x00, 0x0a,
76 0x06, 0x09, 0x01, 0x0a,
77 0x08, 0x09, 0x8a, 0x13,
78 0x0a, 0x09, 0xc5, 0x11,
79 0x0c, 0x09, 0x86, 0x85,
80 0x0e, 0x09, 0x20, 0x0a,
81 0x10, 0x09, 0x21, 0x0a,
82 0x12, 0x09, 0x41, 0xff,
83 0x14, 0x09, 0x82, 0x00,
84 0x16, 0x09, 0x82, 0x7b,
85 0x18, 0x09, 0x8a, 0x7d,
86 0x1a, 0x09, 0x88, 0x81,
87 0x1c, 0x09, 0x86, 0x7a,
88 0x1e, 0x09, 0x84, 0x81,
89 0x20, 0x09, 0x82, 0x7c,
90 0x22, 0x09, 0x0a, 0x0a
93 static Byte_t RRegData[RREGDATASIZE]=
95 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */
96 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */
97 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */
98 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */
99 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */
100 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */
101 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */
102 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */
103 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */
104 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */
105 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */
106 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */
107 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */
110 static CONTROLLER_T sController[CTL_SIZE] =
112 {-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}},
113 {-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}},
114 {-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 {-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}}
119 /* IRQ number to MUDBAC register 2 mapping */
122 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80
126 static Byte_t sBitMapClrTbl[8] =
128 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f
131 static Byte_t sBitMapSetTbl[8] =
133 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80
136 static struct callout do_poll_ch;
138 /***************************************************************************
139 Function: sInitController
140 Purpose: Initialization of controller global registers and controller
142 Call: sInitController(CtlP,CtlNum,MudbacIO,AiopIOList,AiopIOListSize,
143 IRQNum,Frequency,PeriodicOnly)
144 CONTROLLER_T *CtlP; Ptr to controller structure
145 int CtlNum; Controller number
146 ByteIO_t MudbacIO; Mudbac base I/O address.
147 ByteIO_t *AiopIOList; List of I/O addresses for each AIOP.
148 This list must be in the order the AIOPs will be found on the
149 controller. Once an AIOP in the list is not found, it is
150 assumed that there are no more AIOPs on the controller.
151 int AiopIOListSize; Number of addresses in AiopIOList
152 int IRQNum; Interrupt Request number. Can be any of the following:
153 0: Disable global interrupts
162 Byte_t Frequency: A flag identifying the frequency
163 of the periodic interrupt, can be any one of the following:
164 FREQ_DIS - periodic interrupt disabled
165 FREQ_137HZ - 137 Hertz
171 If IRQNum is set to 0 the Frequency parameter is
172 overidden, it is forced to a value of FREQ_DIS.
173 int PeriodicOnly: TRUE if all interrupts except the periodic
174 interrupt are to be blocked.
175 FALSE is both the periodic interrupt and
176 other channel interrupts are allowed.
177 If IRQNum is set to 0 the PeriodicOnly parameter is
178 overidden, it is forced to a value of FALSE.
179 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
180 initialization failed.
183 If periodic interrupts are to be disabled but AIOP interrupts
184 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
186 If interrupts are to be completely disabled set IRQNum to 0.
188 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
191 This function performs initialization of global interrupt modes,
192 but it does not actually enable global interrupts. To enable
193 and disable global interrupts use functions sEnGlobalInt() and
194 sDisGlobalInt(). Enabling of global interrupts is normally not
195 done until all other initializations are complete.
197 Even if interrupts are globally enabled, they must also be
198 individually enabled for each channel that is to generate
201 Warnings: No range checking on any of the parameters is done.
203 No context switches are allowed while executing this function.
205 After this function all AIOPs on the controller are disabled,
206 they can be enabled with sEnAiop().
208 int sInitController( CONTROLLER_T *CtlP,
211 ByteIO_t *AiopIOList,
220 CtlP->CtlNum = CtlNum;
221 CtlP->BusType = isISA;
222 CtlP->CtlID = CTLID_0001; /* controller release 1 */
224 CtlP->MBaseIO = MudbacIO;
225 CtlP->MReg1IO = MudbacIO + 1;
226 CtlP->MReg2IO = MudbacIO + 2;
227 CtlP->MReg3IO = MudbacIO + 3;
229 CtlP->MReg2 = 0; /* interrupt disable */
230 CtlP->MReg3 = 0; /* no periodic interrupts */
232 if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */
234 CtlP->MReg2 = 0; /* interrupt disable */
235 CtlP->MReg3 = 0; /* no periodic interrupts */
239 CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
240 CtlP->MReg3 = Frequency; /* set frequency */
241 if(PeriodicOnly) /* periodic interrupt only */
243 CtlP->MReg3 |= PERIODIC_ONLY;
247 sOutB(CtlP->MReg2IO,CtlP->MReg2);
248 sOutB(CtlP->MReg3IO,CtlP->MReg3);
249 sControllerEOI(CtlP); /* clear EOI if warm init */
253 for(i=0; i < AiopIOListSize; i++)
256 CtlP->AiopIO[i] = (WordIO_t)io;
257 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
258 sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */
259 sOutB(MudbacIO,(Byte_t)(io >> 6)); /* set up AIOP I/O in MUDBAC */
260 sEnAiop(CtlP,i); /* enable the AIOP */
262 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
263 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
265 sDisAiop(CtlP,i); /* disable AIOP */
266 break; /* done looking for AIOPs */
269 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
270 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */
271 sOutB(io + _INDX_DATA,CLOCK_PRESC);
272 CtlP->NumAiop++; /* bump count of AIOPs */
273 sDisAiop(CtlP,i); /* disable AIOP */
276 if(CtlP->NumAiop == 0)
279 return(CtlP->NumAiop);
282 int sPCIInitController( CONTROLLER_T *CtlP,
284 ByteIO_t *AiopIOList,
293 CtlP->CtlNum = CtlNum;
294 CtlP->BusType = isPCI;
295 CtlP->CtlID = CTLID_0001; /* controller release 1 */
296 CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC);
298 sPCIControllerEOI(CtlP);
302 for(i=0; i < AiopIOListSize; i++)
305 CtlP->AiopIO[i] = (WordIO_t)io;
306 CtlP->AiopIntChanIO[i] = io + _INT_CHAN;
308 CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */
309 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
311 break; /* done looking for AIOPs */
314 CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */
315 sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */
316 sOutB(io + _INDX_DATA,CLOCK_PRESC);
317 CtlP->NumAiop++; /* bump count of AIOPs */
320 if(CtlP->NumAiop == 0)
323 return(CtlP->NumAiop);
326 /***************************************************************************
327 Function: sReadAiopID
328 Purpose: Read the AIOP idenfication number directly from an AIOP.
329 Call: sReadAiopID(io)
330 ByteIO_t io: AIOP base I/O address
331 Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X
332 is replace by an identifying number.
333 Flag AIOPID_NULL if no valid AIOP is found
334 Warnings: No context switches are allowed while executing this function.
337 int sReadAiopID(ByteIO_t io)
339 Byte_t AiopID; /* ID byte from AIOP */
341 sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */
342 sOutB(io + _CMD_REG,0x0);
343 AiopID = sInB(io + _CHN_STAT0) & 0x07;
346 else /* AIOP does not exist */
350 /***************************************************************************
351 Function: sReadAiopNumChan
352 Purpose: Read the number of channels available in an AIOP directly from
354 Call: sReadAiopNumChan(io)
355 WordIO_t io: AIOP base I/O address
356 Return: int: The number of channels available
357 Comments: The number of channels is determined by write/reads from identical
358 offsets within the SRAM address spaces for channels 0 and 4.
359 If the channel 4 space is mirrored to channel 0 it is a 4 channel
360 AIOP, otherwise it is an 8 channel.
361 Warnings: No context switches are allowed while executing this function.
363 int sReadAiopNumChan(WordIO_t io)
367 sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */
368 sOutW(io + _INDX_ADDR,0); /* read from SRAM, chan 0 */
369 x = sInW(io + _INDX_DATA);
370 sOutW(io + _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */
371 if(x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */
377 /***************************************************************************
379 Purpose: Initialization of a channel and channel structure
380 Call: sInitChan(CtlP,ChP,AiopNum,ChanNum)
381 CONTROLLER_T *CtlP; Ptr to controller structure
382 CHANNEL_T *ChP; Ptr to channel structure
383 int AiopNum; AIOP number within controller
384 int ChanNum; Channel number within AIOP
385 Return: int: TRUE if initialization succeeded, FALSE if it fails because channel
386 number exceeds number of channels available in AIOP.
387 Comments: This function must be called before a channel can be used.
388 Warnings: No range checking on any of the parameters is done.
390 No context switches are allowed while executing this function.
392 int sInitChan( CONTROLLER_T *CtlP,
404 if(ChanNum >= CtlP->AiopNumChan[AiopNum])
405 return(FALSE); /* exceeds num chans in AIOP */
407 /* Channel, AIOP, and controller identifiers */
409 ChP->ChanID = CtlP->AiopID[AiopNum];
410 ChP->AiopNum = AiopNum;
411 ChP->ChanNum = ChanNum;
413 /* Global direct addresses */
414 AiopIO = CtlP->AiopIO[AiopNum];
415 ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG;
416 ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN;
417 ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK;
418 ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR;
419 ChP->IndexData = AiopIO + _INDX_DATA;
421 /* Channel direct addresses */
422 ChIOOff = AiopIO + ChP->ChanNum * 2;
423 ChP->TxRxData = ChIOOff + _TD0;
424 ChP->ChanStat = ChIOOff + _CHN_STAT0;
425 ChP->TxRxCount = ChIOOff + _FIFO_CNT0;
426 ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0;
428 /* Initialize the channel from the RData array */
429 for(i=0; i < RDATASIZE; i+=4)
432 R[1] = RData[i+1] + 0x10 * ChanNum;
435 sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0]));
439 for(i=0; i < RREGDATASIZE; i+=4)
441 ChR[i] = RRegData[i];
442 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum;
443 ChR[i+2] = RRegData[i+2];
444 ChR[i+3] = RRegData[i+3];
447 /* Indexed registers */
448 ChOff = (Word_t)ChanNum * 0x1000;
450 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD);
451 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8);
452 ChP->BaudDiv[2] = (Byte_t)BRD9600;
453 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8);
454 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]);
456 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL);
457 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8);
458 ChP->TxControl[2] = 0;
459 ChP->TxControl[3] = 0;
460 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
462 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL);
463 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8);
464 ChP->RxControl[2] = 0;
465 ChP->RxControl[3] = 0;
466 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
468 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS);
469 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8);
470 ChP->TxEnables[2] = 0;
471 ChP->TxEnables[3] = 0;
472 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]);
474 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1);
475 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8);
476 ChP->TxCompare[2] = 0;
477 ChP->TxCompare[3] = 0;
478 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]);
480 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1);
481 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8);
482 ChP->TxReplace1[2] = 0;
483 ChP->TxReplace1[3] = 0;
484 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]);
486 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2);
487 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8);
488 ChP->TxReplace2[2] = 0;
489 ChP->TxReplace2[3] = 0;
490 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]);
492 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP;
493 ChP->TxFIFO = ChOff + _TX_FIFO;
495 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */
496 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Tx FIFO count */
497 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
498 sOutW(ChP->IndexData,0);
499 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP;
500 ChP->RxFIFO = ChOff + _RX_FIFO;
502 sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */
503 sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Rx FIFO count */
504 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
505 sOutW(ChP->IndexData,0);
506 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
507 sOutW(ChP->IndexData,0);
508 ChP->TxPrioCnt = ChOff + _TXP_CNT;
509 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt);
510 sOutB(ChP->IndexData,0);
511 ChP->TxPrioPtr = ChOff + _TXP_PNTR;
512 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr);
513 sOutB(ChP->IndexData,0);
514 ChP->TxPrioBuf = ChOff + _TXP_BUF;
515 sEnRxProcessor(ChP); /* start the Rx processor */
520 /***************************************************************************
521 Function: sStopRxProcessor
522 Purpose: Stop the receive processor from processing a channel.
523 Call: sStopRxProcessor(ChP)
524 CHANNEL_T *ChP; Ptr to channel structure
526 Comments: The receive processor can be started again with sStartRxProcessor().
527 This function causes the receive processor to skip over the
528 stopped channel. It does not stop it from processing other channels.
530 Warnings: No context switches are allowed while executing this function.
532 Do not leave the receive processor stopped for more than one
535 After calling this function a delay of 4 uS is required to ensure
536 that the receive processor is no longer processing this channel.
538 void sStopRxProcessor(CHANNEL_T *ChP)
546 sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]);
549 /***************************************************************************
550 Function: sFlushRxFIFO
551 Purpose: Flush the Rx FIFO
552 Call: sFlushRxFIFO(ChP)
553 CHANNEL_T *ChP; Ptr to channel structure
555 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
556 while it is being flushed the receive processor is stopped
557 and the transmitter is disabled. After these operations a
558 4 uS delay is done before clearing the pointers to allow
559 the receive processor to stop. These items are handled inside
561 Warnings: No context switches are allowed while executing this function.
563 void sFlushRxFIFO(CHANNEL_T *ChP)
566 Byte_t Ch; /* channel number within AIOP */
567 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */
569 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */
570 return; /* don't need to flush */
572 RxFIFOEnabled = FALSE;
573 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */
575 RxFIFOEnabled = TRUE;
576 sDisRxFIFO(ChP); /* disable it */
577 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/
578 sInB(ChP->IntChan); /* depends on bus i/o timing */
580 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */
581 Ch = (Byte_t)sGetChanNum(ChP);
582 sOutB(ChP->Cmd,Ch | RESRXFCNT); /* apply reset Rx FIFO count */
583 sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */
584 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */
585 sOutW(ChP->IndexData,0);
586 sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */
587 sOutW(ChP->IndexData,0);
589 sEnRxFIFO(ChP); /* enable Rx FIFO */
592 /***************************************************************************
593 Function: sFlushTxFIFO
594 Purpose: Flush the Tx FIFO
595 Call: sFlushTxFIFO(ChP)
596 CHANNEL_T *ChP; Ptr to channel structure
598 Comments: To prevent data from being enqueued or dequeued in the Tx FIFO
599 while it is being flushed the receive processor is stopped
600 and the transmitter is disabled. After these operations a
601 4 uS delay is done before clearing the pointers to allow
602 the receive processor to stop. These items are handled inside
604 Warnings: No context switches are allowed while executing this function.
606 void sFlushTxFIFO(CHANNEL_T *ChP)
609 Byte_t Ch; /* channel number within AIOP */
610 int TxEnabled; /* TRUE if transmitter enabled */
612 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */
613 return; /* don't need to flush */
616 if(ChP->TxControl[3] & TX_ENABLE)
619 sDisTransmit(ChP); /* disable transmitter */
621 sStopRxProcessor(ChP); /* stop Rx processor */
622 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */
623 sInB(ChP->IntChan); /* depends on bus i/o timing */
624 Ch = (Byte_t)sGetChanNum(ChP);
625 sOutB(ChP->Cmd,Ch | RESTXFCNT); /* apply reset Tx FIFO count */
626 sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */
627 sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */
628 sOutW(ChP->IndexData,0);
630 sEnTransmit(ChP); /* enable transmitter */
631 sStartRxProcessor(ChP); /* restart Rx processor */
634 /***************************************************************************
635 Function: sWriteTxPrioByte
636 Purpose: Write a byte of priority transmit data to a channel
637 Call: sWriteTxPrioByte(ChP,Data)
638 CHANNEL_T *ChP; Ptr to channel structure
639 Byte_t Data; The transmit data byte
641 Return: int: 1 if the bytes is successfully written, otherwise 0.
643 Comments: The priority byte is transmitted before any data in the Tx FIFO.
645 Warnings: No context switches are allowed while executing this function.
647 int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data)
649 Byte_t DWBuf[4]; /* buffer for double word writes */
650 Word_t *WordPtr; /* must be far because Win SS != DS */
653 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */
655 IndexAddr = ChP->IndexAddr;
656 sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */
657 if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */
658 return(0); /* nothing sent */
660 WordPtr = (Word_t *)(&DWBuf[0]);
661 *WordPtr = ChP->TxPrioBuf; /* data byte address */
663 DWBuf[2] = Data; /* data byte value */
664 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
666 *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */
668 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */
669 DWBuf[3] = 0; /* priority buffer pointer */
670 sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */
672 else /* write it to Tx FIFO */
674 sWriteTxByte(sGetTxRxDataIO(ChP),Data);
676 return(1); /* 1 byte sent */
679 /***************************************************************************
680 Function: sEnInterrupts
681 Purpose: Enable one or more interrupts for a channel
682 Call: sEnInterrupts(ChP,Flags)
683 CHANNEL_T *ChP; Ptr to channel structure
684 Word_t Flags: Interrupt enable flags, can be any combination
685 of the following flags:
686 TXINT_EN: Interrupt on Tx FIFO empty
687 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
689 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
690 MCINT_EN: Interrupt on modem input change
691 CHANINT_EN: Allow channel interrupt signal to the AIOP's
692 Interrupt Channel Register.
694 Comments: If an interrupt enable flag is set in Flags, that interrupt will be
695 enabled. If an interrupt enable flag is not set in Flags, that
696 interrupt will not be changed. Interrupts can be disabled with
697 function sDisInterrupts().
699 This function sets the appropriate bit for the channel in the AIOP's
700 Interrupt Mask Register if the CHANINT_EN flag is set. This allows
701 this channel's bit to be set in the AIOP's Interrupt Channel Register.
703 Interrupts must also be globally enabled before channel interrupts
704 will be passed on to the host. This is done with function
707 In some cases it may be desirable to disable interrupts globally but
708 enable channel interrupts. This would allow the global interrupt
709 status register to be used to determine which AIOPs need service.
711 void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags)
713 Byte_t Mask; /* Interrupt Mask Register */
716 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
718 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
720 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN);
722 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
724 if(Flags & CHANINT_EN)
726 Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum];
727 sOutB(ChP->IntMask,Mask);
731 /***************************************************************************
732 Function: sDisInterrupts
733 Purpose: Disable one or more interrupts for a channel
734 Call: sDisInterrupts(ChP,Flags)
735 CHANNEL_T *ChP; Ptr to channel structure
736 Word_t Flags: Interrupt flags, can be any combination
737 of the following flags:
738 TXINT_EN: Interrupt on Tx FIFO empty
739 RXINT_EN: Interrupt on Rx FIFO at trigger level (see
741 SRCINT_EN: Interrupt on SRC (Special Rx Condition)
742 MCINT_EN: Interrupt on modem input change
743 CHANINT_EN: Disable channel interrupt signal to the
744 AIOP's Interrupt Channel Register.
746 Comments: If an interrupt flag is set in Flags, that interrupt will be
747 disabled. If an interrupt flag is not set in Flags, that
748 interrupt will not be changed. Interrupts can be enabled with
749 function sEnInterrupts().
751 This function clears the appropriate bit for the channel in the AIOP's
752 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks
753 this channel's bit from being set in the AIOP's Interrupt Channel
756 void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags)
758 Byte_t Mask; /* Interrupt Mask Register */
761 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN));
762 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]);
763 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN);
764 sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]);
766 if(Flags & CHANINT_EN)
768 Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum];
769 sOutB(ChP->IntMask,Mask);
773 /*********************************************************************
774 Begin FreeBsd-specific driver code
775 **********************************************************************/
777 static int rpprobe (struct isa_device *);
778 static int rpattach (struct isa_device *);
780 static const char* rp_pciprobe(pcici_t tag, pcidi_t type);
781 static void rp_pciattach(pcici_t tag, int unit);
782 static u_long rp_pcicount;
784 static struct pci_device rp_pcidevice = {
792 COMPAT_PCI_DRIVER (rp_pci, rp_pcidevice);
794 static timeout_t rpdtrwakeup;
796 struct isa_driver rpdriver = {
797 rpprobe, rpattach, "rp"
800 static char driver_name[] = "rp";
802 static d_open_t rpopen;
803 static d_close_t rpclose;
804 static d_write_t rpwrite;
805 static d_ioctl_t rpioctl;
807 #define CDEV_MAJOR 81
808 static struct cdevsw rp_cdevsw = {
809 /* name */ driver_name,
810 /* maj */ CDEV_MAJOR,
811 /* flags */ D_TTY | D_KQFILTER,
822 /* strategy */ nostrategy,
825 /* kqfilter */ ttykqfilter
828 static int rp_controller_port = 0;
829 static int rp_num_ports_open = 0;
830 static int ndevs = 0;
831 static int minor_to_unit[128];
833 static struct tty rp_tty[128];
836 static int rp_num_ports[4]; /* Number of ports on each controller */
838 #define _INLINE_ __inline
839 #define POLL_INTERVAL 1
841 #define CALLOUT_MASK 0x80
842 #define CONTROL_MASK 0x60
843 #define CONTROL_INIT_STATE 0x20
844 #define CONTROL_LOCK_STATE 0x40
845 #define DEV_UNIT(dev) (MINOR_TO_UNIT(minor(dev))
846 #define MINOR_MAGIC_MASK (CALLOUT_MASK | CONTROL_MASK)
847 #define MINOR_MAGIC(dev) ((minor(dev)) & ~MINOR_MAGIC_MASK)
848 #define IS_CALLOUT(dev) (minor(dev) & CALLOUT_MASK)
849 #define IS_CONTROL(dev) (minor(dev) & CONTROL_MASK)
851 #define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1)
852 #define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff)
853 #define RP_NOTAST4(dev) ((dev)->id_flags & 0x04)
855 static struct rp_port *p_rp_addr[4];
856 static struct rp_port *p_rp_table[MAX_RP_PORTS];
857 #define rp_addr(unit) (p_rp_addr[unit])
858 #define rp_table(port) (p_rp_table[port])
861 * The top-level routines begin here
864 static int rpparam (struct tty *, struct termios *);
865 static void rpstart (struct tty *);
866 static void rpstop (struct tty *, int);
867 static void rphardclose (struct rp_port *);
868 static void rp_disc_optim (struct tty *tp, struct termios *t,
871 static _INLINE_ void rp_do_receive(struct rp_port *rp, struct tty *tp,
872 CHANNEL_t *cp, unsigned int ChanStatus)
875 unsigned int CharNStat;
878 ToRecv = sGetRxCnt(cp);
882 /* If status indicates there are errored characters in the
883 FIFO, then enter status mode (a word in FIFO holds
884 characters and status)
887 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) {
888 if(!(ChanStatus & STATMODE)) {
889 ChanStatus |= STATMODE;
894 if we previously entered status mode then read down the
895 FIFO one word at a time, pulling apart the character and
896 the status. Update error counters depending on status.
898 if(ChanStatus & STATMODE) {
900 if(tp->t_state & TS_TBLOCK) {
903 CharNStat = sInW(sGetTxRxDataIO(cp));
904 ch = CharNStat & 0xff;
906 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH))
908 else if (CharNStat & STMPARITYH)
910 else if (CharNStat & STMRCVROVRH)
913 (*linesw[tp->t_line].l_rint)(ch, tp);
917 After emtying FIFO in status mode, turn off status mode
920 if(sGetRxCnt(cp) == 0)
921 sDisRxStatusMode(cp);
925 if(tp->t_state & TS_TBLOCK) {
928 ch = (u_char) sInB(sGetTxRxDataIO(cp));
930 (*linesw[tp->t_line].l_rint)(ch, tp);
937 static _INLINE_ void rp_handle_port(struct rp_port *rp)
941 unsigned int IntMask, ChanStatus;
947 cp = &rp->rp_channel;
949 IntMask = sGetChanIntID(cp);
950 IntMask = IntMask & rp->rp_intmask;
951 ChanStatus = sGetChanStatus(cp);
952 if(IntMask & RXF_TRIG)
953 if(!(tp->t_state & TS_TBLOCK) && (tp->t_state & TS_CARR_ON) && (tp->t_state & TS_ISOPEN)) {
954 rp_do_receive(rp, tp, cp, ChanStatus);
956 if(IntMask & DELTA_CD) {
957 if(ChanStatus & CD_ACT) {
958 if(!(tp->t_state & TS_CARR_ON) ) {
959 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
962 if((tp->t_state & TS_CARR_ON)) {
963 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
964 if((*linesw[tp->t_line].l_modem)(tp, 0) == 0) {
970 /* oldcts = rp->rp_cts;
971 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0);
972 if(oldcts != rp->rp_cts) {
973 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port);
978 static void rp_do_poll(void *not_used)
983 int unit, aiop, ch, line, count;
984 unsigned char CtlMask, AiopMask;
986 for(unit = 0; unit <= ndevs; unit++) {
989 if(ctl->BusType == isPCI)
990 CtlMask = sPCIGetControllerIntStatus(ctl);
992 CtlMask = sGetControllerIntStatus(ctl);
993 for(aiop=0; CtlMask; CtlMask >>=1, aiop++) {
995 AiopMask = sGetAiopIntStatus(ctl, aiop);
996 for(ch = 0; AiopMask; AiopMask >>=1, ch++) {
998 line = (unit << 5) | (aiop << 3) | ch;
1006 for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit];
1009 if((tp->t_state & TS_BUSY) && (tp->t_state & TS_ISOPEN)) {
1010 count = sGetTxCnt(&rp->rp_channel);
1012 tp->t_state &= ~(TS_BUSY);
1013 if(!(tp->t_state & TS_TTSTOP) &&
1014 (count <= rp->rp_restart)) {
1015 (*linesw[tp->t_line].l_start)(tp);
1020 if (rp_num_ports_open)
1021 callout_reset(&do_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1025 rp_pciprobe(pcici_t tag, pcidi_t type)
1029 vendor_id = type & 0xffff;
1039 struct isa_device *dev;
1041 int controller, unit;
1042 int aiop, num_aiops;
1043 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1046 unit = dev->id_unit;
1047 if (dev->id_unit >= 4) {
1048 printf("rpprobe: unit number %d invalid.\n", dev->id_unit);
1051 printf("probing for RocketPort(ISA) unit %d\n", unit);
1052 if (rp_controller_port)
1053 controller = rp_controller_port;
1055 controller = dev->id_iobase + 0x40;
1058 for (aiop=0; aiop<MAX_AIOPS_PER_BOARD; aiop++)
1059 aiopio[aiop]= dev->id_iobase + (aiop * 0x400);
1061 ctlp = sCtlNumToCtlPtr(dev->id_unit);
1062 num_aiops = sInitController(ctlp, dev->id_unit,
1063 controller + ((unit-rp_pcicount)*0x400),
1064 aiopio, MAX_AIOPS_PER_BOARD, 0,
1066 if (num_aiops <= 0) {
1067 printf("board%d init failed\n", unit);
1071 if (rp_controller_port) {
1075 rp_controller_port = controller;
1084 rp_pciattach(pcici_t tag, int unit)
1086 int success, oldspl;
1088 int num_ports, num_chan, num_aiops;
1089 int aiop, chan, port;
1090 int ChanStatus, line, i, count;
1091 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1096 success = pci_map_port(tag, 0x10, &iobase);
1098 printf("ioaddr mapping failed for RocketPort(PCI)\n");
1100 for(aiop=0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
1101 aiopio[aiop] = iobase + (aiop * 0x40);
1103 ctlp = sCtlNumToCtlPtr(unit);
1104 num_aiops = sPCIInitController(ctlp, unit,
1105 aiopio, MAX_AIOPS_PER_BOARD, 0,
1109 for(aiop=0; aiop < num_aiops; aiop++) {
1110 sResetAiopByNum(ctlp, aiop);
1111 num_ports += sGetAiopNumChan(ctlp, aiop);
1113 printf("RocketPort%d = %d ports\n", unit, num_ports);
1114 rp_num_ports[unit] = num_ports;
1116 rp = malloc(sizeof(struct rp_port) * num_ports,
1117 M_TTYS, M_WAITOK | M_ZERO);
1119 count = unit * 32; /* board times max ports per card SG */
1120 for(i=count;i < (count + rp_num_ports[unit]);i++)
1121 minor_to_unit[i] = unit;
1123 tty = malloc(sizeof(struct tty) * num_ports, M_TTYS, M_WAITOK | M_ZERO);
1129 cdevsw_add(&rp_cdevsw, 0, 0);
1132 for(aiop=0; aiop < num_aiops; aiop++) {
1133 num_chan = sGetAiopNumChan(ctlp, aiop);
1134 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
1143 /* tty->t_termios = deftermios;
1145 rp->dtr_wait = 3 * hz;
1146 callout_init(&rp->dtr_ch);
1147 rp->it_in.c_iflag = 0;
1148 rp->it_in.c_oflag = 0;
1149 rp->it_in.c_cflag = TTYDEF_CFLAG;
1150 rp->it_in.c_lflag = 0;
1151 termioschars(&rp->it_in);
1152 /* termioschars(&tty->t_termios);
1154 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
1155 rp->it_out = rp->it_in;
1157 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
1158 DELTA_CD | DELTA_CTS | DELTA_DSR;
1159 ChanStatus = sGetChanStatus(&rp->rp_channel);
1160 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
1161 printf("RocketPort sInitChan(%d, %d, %d) failed\n",
1165 ChanStatus = sGetChanStatus(&rp->rp_channel);
1166 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
1167 line = (unit << 5) | (aiop << 3) | chan;
1168 rp_table(line) = rp;
1176 struct isa_device *dev;
1178 int iobase, unit, /*rpmajor,*/ oldspl;
1179 int num_ports, num_chan, num_aiops;
1180 int aiop, chan, port;
1181 int ChanStatus, line, i, count;
1182 unsigned int aiopio[MAX_AIOPS_PER_BOARD];
1187 iobase = dev->id_iobase;
1188 unit = dev->id_unit;
1191 for(aiop=0; aiop < MAX_AIOPS_PER_BOARD; aiop++)
1192 aiopio[aiop] = iobase + (aiop * 0x400);
1194 ctlp = sCtlNumToCtlPtr(unit);
1195 num_aiops = sInitController(ctlp, unit,
1196 rp_controller_port + ((unit-rp_pcicount) * 0x400),
1197 aiopio, MAX_AIOPS_PER_BOARD, 0,
1201 for(aiop=0; aiop < num_aiops; aiop++) {
1202 sResetAiopByNum(ctlp, aiop);
1203 sEnAiop(ctlp, aiop);
1204 num_ports += sGetAiopNumChan(ctlp, aiop);
1206 printf("RocketPort%d = %d ports\n", unit, num_ports);
1207 rp_num_ports[unit] = num_ports;
1209 rp = malloc(sizeof(struct rp_port) * num_ports,
1210 M_TTYS, M_WAITOK | M_ZERO);
1212 count = unit * 32; /* board # times max ports per card SG */
1213 for(i=count;i < (count + rp_num_ports[unit]);i++)
1214 minor_to_unit[i] = unit;
1216 tty = malloc(sizeof(struct tty) * num_ports, M_TTYS, M_WAITOK | M_ZERO);
1222 cdevsw_add(&rp_cdevsw, 0, 0);
1225 for(aiop=0; aiop < num_aiops; aiop++) {
1226 num_chan = sGetAiopNumChan(ctlp, aiop);
1227 for(chan=0; chan < num_chan; chan++, port++, rp++, tty++) {
1236 /* tty->t_termios = deftermios;
1238 rp->dtr_wait = 3 * hz;
1239 rp->it_in.c_iflag = 0;
1240 rp->it_in.c_oflag = 0;
1241 rp->it_in.c_cflag = TTYDEF_CFLAG;
1242 rp->it_in.c_lflag = 0;
1243 termioschars(&rp->it_in);
1244 /* termioschars(&tty->t_termios);
1246 rp->it_in.c_ispeed = rp->it_in.c_ospeed = TTYDEF_SPEED;
1247 rp->it_out = rp->it_in;
1249 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT |
1250 DELTA_CD | DELTA_CTS | DELTA_DSR;
1251 ChanStatus = sGetChanStatus(&rp->rp_channel);
1252 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) {
1253 printf("RocketPort sInitChan(%d, %d, %d) failed\n",
1257 ChanStatus = sGetChanStatus(&rp->rp_channel);
1258 rp->rp_cts = (ChanStatus & CTS_ACT) != 0;
1259 line = (unit << 5) | (aiop << 3) | chan;
1260 rp_table(line) = rp;
1268 rpopen(dev, flag, mode, td)
1274 int unit, port, mynor, umynor, flags; /* SG */
1277 unsigned int IntMask, ChanStatus;
1280 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1281 port = (minor(dev) & 0x1f); /* SG */
1282 mynor = (port + umynor); /* SG */
1283 unit = minor_to_unit[mynor];
1284 if (rp_addr(unit) == NULL)
1288 rp = rp_addr(unit) + port;
1289 /* rp->rp_tty = &rp_tty[rp->rp_port];
1297 while(rp->state & ~SET_DTR) {
1298 error = tsleep(&rp->dtr_wait, PCATCH, "rpdtr", 0);
1303 if(tp->t_state & TS_ISOPEN) {
1304 if(IS_CALLOUT(dev)) {
1305 if(!rp->active_out) {
1310 if(rp->active_out) {
1311 if(flag & O_NONBLOCK) {
1315 error = tsleep(&rp->active_out,
1322 if(tp->t_state & TS_XCLUDE &&
1330 tp->t_param = rpparam;
1331 tp->t_oproc = rpstart;
1332 tp->t_stop = rpstop;
1334 tp->t_termios = IS_CALLOUT(dev) ? rp->it_out : rp->it_in;
1338 rp->rp_channel.TxControl[3] =
1339 ((rp->rp_channel.TxControl[3]
1340 & ~(SET_RTS | SET_DTR)) | flags);
1341 sOutDW(rp->rp_channel.IndexAddr,
1342 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1343 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1344 sDisRxStatusMode(&rp->rp_channel);
1345 sFlushRxFIFO(&rp->rp_channel);
1346 sFlushTxFIFO(&rp->rp_channel);
1348 sEnInterrupts(&rp->rp_channel,
1349 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN));
1350 sSetRxTrigger(&rp->rp_channel, TRIG_1);
1352 sDisRxStatusMode(&rp->rp_channel);
1353 sClrTxXOFF(&rp->rp_channel);
1355 /* sDisRTSFlowCtl(&rp->rp_channel);
1356 sDisCTSFlowCtl(&rp->rp_channel);
1358 sDisTxSoftFlowCtl(&rp->rp_channel);
1360 sStartRxProcessor(&rp->rp_channel);
1362 sEnRxFIFO(&rp->rp_channel);
1363 sEnTransmit(&rp->rp_channel);
1365 /* sSetDTR(&rp->rp_channel);
1366 sSetRTS(&rp->rp_channel);
1370 error = rpparam(tp, &tp->t_termios);
1377 rp_num_ports_open++;
1379 IntMask = sGetChanIntID(&rp->rp_channel);
1380 IntMask = IntMask & rp->rp_intmask;
1381 ChanStatus = sGetChanStatus(&rp->rp_channel);
1382 if((IntMask & DELTA_CD) || IS_CALLOUT(dev)) {
1383 if((ChanStatus & CD_ACT) || IS_CALLOUT(dev)) {
1384 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
1388 if (rp_num_ports_open == 1)
1389 if ((do_poll_ch.c_flags & CALLOUT_DID_INIT) == 0)
1390 callout_init(&do_poll_ch);
1391 callout_reset(&do_poll_ch, POLL_INTERVAL, rp_do_poll, NULL);
1394 if(!(flag&O_NONBLOCK) && !(tp->t_cflag&CLOCAL) &&
1395 !(tp->t_state & TS_CARR_ON) && !(IS_CALLOUT(dev))) {
1397 error = tsleep(TSA_CARR_ON(tp), PCATCH, "rpdcd", 0);
1403 error = (*linesw[tp->t_line].l_open)(dev, tp);
1405 rp_disc_optim(tp, &tp->t_termios, rp);
1406 if(tp->t_state & TS_ISOPEN && IS_CALLOUT(dev))
1407 rp->active_out = TRUE;
1411 if(!(tp->t_state & TS_ISOPEN) && rp->wopeners == 0) {
1418 rpclose(dev, flag, mode, td)
1423 int oldspl, unit, mynor, umynor, port; /* SG */
1428 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1429 port = (minor(dev) & 0x1f); /* SG */
1430 mynor = (port + umynor); /* SG */
1431 unit = minor_to_unit[mynor]; /* SG */
1435 rp = rp_addr(unit) + port;
1436 cp = &rp->rp_channel;
1440 (*linesw[tp->t_line].l_close)(tp, flag);
1441 rp_disc_optim(tp, &tp->t_termios, rp);
1442 rpstop(tp, FREAD | FWRITE);
1445 tp->t_state &= ~TS_BUSY;
1454 rphardclose(struct rp_port *rp)
1460 cp = &rp->rp_channel;
1462 mynor = MINOR_MAGIC(tp->t_dev);
1467 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN);
1470 sDisTxSoftFlowCtl(cp);
1473 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !rp->active_out) {
1476 if(IS_CALLOUT(tp->t_dev)) {
1479 if(rp->dtr_wait != 0) {
1480 callout_reset(&rp->dtr_ch, rp->dtr_wait, rpdtrwakeup, rp);
1481 rp->state |= ~SET_DTR;
1484 rp->active_out = FALSE;
1485 wakeup(&rp->active_out);
1486 wakeup(TSA_CARR_ON(tp));
1491 rpwrite(dev, uio, flag)
1498 int unit, mynor, port, umynor, error = 0; /* SG */
1500 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1501 port = (minor(dev) & 0x1f); /* SG */
1502 mynor = (port + umynor); /* SG */
1503 unit = minor_to_unit[mynor]; /* SG */
1507 rp = rp_addr(unit) + port;
1509 while(rp->rp_disable_writes) {
1511 error = ttysleep(tp, (caddr_t)rp, PCATCH, "rp_write", 0);
1516 error = (*linesw[tp->t_line].l_write)(tp, uio, flag);
1521 rpdtrwakeup(void *chan)
1525 rp = (struct rp_port *)chan;
1526 rp->state &= SET_DTR;
1527 wakeup(&rp->dtr_wait);
1531 rpioctl(dev, cmd, data, flag, td)
1541 int unit, mynor, port, umynor; /* SG */
1544 int arg, flags, result, ChanStatus;
1546 struct termios term, *t;
1548 umynor = (((minor(dev) >> 16) -1) * 32); /* SG */
1549 port = (minor(dev) & 0x1f); /* SG */
1550 mynor = (port + umynor); /* SG */
1551 unit = minor_to_unit[mynor];
1552 rp = rp_addr(unit) + port;
1554 if(IS_CONTROL(dev)) {
1557 switch (IS_CONTROL(dev)) {
1558 case CONTROL_INIT_STATE:
1559 ct = IS_CALLOUT(dev) ? &rp->it_out : &rp->it_in;
1561 case CONTROL_LOCK_STATE:
1562 ct = IS_CALLOUT(dev) ? &rp->lt_out : &rp->lt_in;
1565 return(ENODEV); /* /dev/nodev */
1572 *ct = *(struct termios *)data;
1575 *(struct termios *)data = *ct;
1578 *(int *)data = TTYDISC;
1581 bzero(data, sizeof(struct winsize));
1589 cp = &rp->rp_channel;
1591 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1592 term = tp->t_termios;
1594 error = ttsetcompat(tp, &cmd, data, &term);
1598 data = (caddr_t)&term;
1601 if((cmd == TIOCSETA) || (cmd == TIOCSETAW) || (cmd == TIOCSETAF)) {
1603 struct termios *dt = (struct termios *)data;
1604 struct termios *lt = IS_CALLOUT(dev)
1605 ? &rp->lt_out : &rp->lt_in;
1607 dt->c_iflag = (tp->t_iflag & lt->c_iflag)
1608 | (dt->c_iflag & ~lt->c_iflag);
1609 dt->c_oflag = (tp->t_oflag & lt->c_oflag)
1610 | (dt->c_oflag & ~lt->c_oflag);
1611 dt->c_cflag = (tp->t_cflag & lt->c_cflag)
1612 | (dt->c_cflag & ~lt->c_cflag);
1613 dt->c_lflag = (tp->t_lflag & lt->c_lflag)
1614 | (dt->c_lflag & ~lt->c_lflag);
1615 for(cc = 0; cc < NCCS; ++cc)
1616 if(lt->c_cc[cc] != 0)
1617 dt->c_cc[cc] = tp->t_cc[cc];
1618 if(lt->c_ispeed != 0)
1619 dt->c_ispeed = tp->t_ispeed;
1620 if(lt->c_ospeed != 0)
1621 dt->c_ospeed = tp->t_ospeed;
1626 error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
1627 if(error != ENOIOCTL) {
1632 flags = rp->rp_channel.TxControl[3];
1634 error = ttioctl(tp, cmd, data, flag);
1635 flags = rp->rp_channel.TxControl[3];
1636 rp_disc_optim(tp, &tp->t_termios, rp);
1637 if(error != ENOIOCTL) {
1643 sSendBreak(&rp->rp_channel);
1647 sClrBreak(&rp->rp_channel);
1651 sSetDTR(&rp->rp_channel);
1652 sSetRTS(&rp->rp_channel);
1656 sClrDTR(&rp->rp_channel);
1660 arg = *(int *) data;
1666 rp->rp_channel.TxControl[3] =
1667 ((rp->rp_channel.TxControl[3]
1668 & ~(SET_RTS | SET_DTR)) | flags);
1669 sOutDW(rp->rp_channel.IndexAddr,
1670 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1673 arg = *(int *) data;
1679 rp->rp_channel.TxControl[3] |= flags;
1680 sOutDW(rp->rp_channel.IndexAddr,
1681 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1684 arg = *(int *) data;
1690 rp->rp_channel.TxControl[3] &= ~flags;
1691 sOutDW(rp->rp_channel.IndexAddr,
1692 *(DWord_t *) &(rp->rp_channel.TxControl[0]));
1697 ChanStatus = sGetChanStatusLo(&rp->rp_channel);
1698 flags = rp->rp_channel.TxControl[3];
1699 result = TIOCM_LE; /* always on while open for some reason */
1700 result |= (((flags & SET_DTR) ? TIOCM_DTR : 0)
1701 | ((flags & SET_RTS) ? TIOCM_RTS : 0)
1702 | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0)
1703 | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0)
1704 | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0));
1706 if(rp->rp_channel.RxControl[2] & RTSFC_EN)
1708 result |= TIOCM_RTS;
1711 *(int *)data = result;
1719 rp->dtr_wait = *(int *)data * hz/100;
1722 *(int *)data = rp->dtr_wait * 100/hz;
1732 static struct speedtab baud_table[] = {
1733 {B0, 0}, {B50, BRD50}, {B75, BRD75},
1734 {B110, BRD110}, {B134, BRD134}, {B150, BRD150},
1735 {B200, BRD200}, {B300, BRD300}, {B600, BRD600},
1736 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400},
1737 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200},
1738 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400},
1739 {B57600, BRD57600}, {B76800, BRD76800},
1740 {B115200, BRD115200}, {B230400, BRD230400},
1751 int unit, mynor, port, umynor; /* SG */
1752 int oldspl, cflag, iflag, oflag, lflag;
1756 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1757 port = (minor(tp->t_dev) & 0x1f); /* SG */
1758 mynor = (port + umynor); /* SG */
1760 unit = minor_to_unit[mynor];
1761 rp = rp_addr(unit) + port;
1762 cp = &rp->rp_channel;
1770 ospeed = ttspeedtab(t->c_ispeed, baud_table);
1771 if(ospeed < 0 || t->c_ispeed != t->c_ospeed)
1774 tp->t_ispeed = t->c_ispeed;
1775 tp->t_ospeed = t->c_ospeed;
1776 tp->t_cflag = cflag;
1777 tp->t_iflag = iflag;
1778 tp->t_oflag = oflag;
1779 tp->t_lflag = lflag;
1781 if(t->c_ospeed == 0) {
1785 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1;
1787 /* Set baud rate ----- we only pay attention to ispeed */
1790 sSetBaud(cp, ospeed);
1792 if(cflag & CSTOPB) {
1798 if(cflag & PARENB) {
1800 if(cflag & PARODD) {
1809 if((cflag & CSIZE) == CS8) {
1811 rp->rp_imask = 0xFF;
1814 rp->rp_imask = 0x7F;
1817 if(iflag & ISTRIP) {
1818 rp->rp_imask &= 0x7F;
1821 if(cflag & CLOCAL) {
1822 rp->rp_intmask &= ~DELTA_CD;
1824 rp->rp_intmask |= DELTA_CD;
1827 /* Put flow control stuff here */
1829 if(cflag & CCTS_OFLOW) {
1835 if(cflag & CRTS_IFLOW) {
1836 rp->rp_rts_iflow = 1;
1838 rp->rp_rts_iflow = 0;
1841 if(cflag & CRTS_IFLOW) {
1846 rp_disc_optim(tp, t, rp);
1848 if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) {
1849 tp->t_state |= TS_CARR_ON;
1850 wakeup(TSA_CARR_ON(tp));
1853 /* tp->t_state |= TS_CAN_BYPASS_L_RINT;
1854 flags = rp->rp_channel.TxControl[3];
1866 rp_disc_optim(tp, t, rp)
1871 if(!(t->c_iflag & (ICRNL | IGNCR | IMAXBEL | INLCR | ISTRIP | IXON))
1872 &&(!(t->c_iflag & BRKINT) || (t->c_iflag & IGNBRK))
1873 &&(!(t->c_iflag & PARMRK)
1874 ||(t->c_iflag & (IGNPAR | IGNBRK)) == (IGNPAR | IGNBRK))
1875 && !(t->c_lflag & (ECHO | ICANON | IEXTEN | ISIG | PENDIN))
1876 && linesw[tp->t_line].l_rint == ttyinput)
1877 tp->t_state |= TS_CAN_BYPASS_L_RINT;
1879 tp->t_state &= ~TS_CAN_BYPASS_L_RINT;
1889 int unit, mynor, port, umynor; /* SG */
1891 int spl, xmit_fifo_room;
1895 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1896 port = (minor(tp->t_dev) & 0x1f); /* SG */
1897 mynor = (port + umynor); /* SG */
1898 unit = minor_to_unit[mynor];
1899 rp = rp_addr(unit) + port;
1900 cp = &rp->rp_channel;
1901 flags = rp->rp_channel.TxControl[3];
1904 if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) {
1909 if(rp->rp_xmit_stopped) {
1911 rp->rp_xmit_stopped = 0;
1913 count = sGetTxCnt(cp);
1915 if(tp->t_outq.c_cc == 0) {
1916 if((tp->t_state & TS_BUSY) && (count == 0)) {
1917 tp->t_state &= ~TS_BUSY;
1923 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp);
1926 if(xmit_fifo_room > 0 && qp->c_cc > 0) {
1927 tp->t_state |= TS_BUSY;
1929 while(xmit_fifo_room > 0 && qp->c_cc > 0) {
1931 sOutB(sGetTxRxDataIO(cp), ch);
1935 rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0;
1949 int unit, mynor, port, umynor; /* SG */
1952 umynor = (((minor(tp->t_dev) >> 16) -1) * 32); /* SG */
1953 port = (minor(tp->t_dev) & 0x1f); /* SG */
1954 mynor = (port + umynor); /* SG */
1955 unit = minor_to_unit[mynor];
1956 rp = rp_addr(unit) + port;
1957 cp = &rp->rp_channel;
1961 if(tp->t_state & TS_BUSY) {
1962 if((tp->t_state&TS_TTSTOP) == 0) {
1965 if(rp->rp_xmit_stopped == 0) {
1967 rp->rp_xmit_stopped = 1;