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