rp.c revision 136111
1/* 2 * Copyright (c) Comtrol Corporation <support@comtrol.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted prodived that the follwoing conditions 7 * are met. 8 * 1. Redistributions of source code must retain the above copyright 9 * notive, this list of conditions and the following disclainer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials prodided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Comtrol Corporation. 16 * 4. The name of Comtrol Corporation may not be used to endorse or 17 * promote products derived from this software without specific 18 * prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY 21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/dev/rp/rp.c 136111 2004-10-04 09:38:53Z phk $"); 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 60static const char RocketPortVersion[] = "3.02"; 61 62static 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 84static 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 */ 103Byte_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 109Byte_t rp_sBitMapClrTbl[8] = 110{ 111 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f 112}; 113 114Byte_t rp_sBitMapSetTbl[8] = 115{ 116 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 117}; 118 119/*************************************************************************** 120Function: sReadAiopID 121Purpose: Read the AIOP idenfication number directly from an AIOP. 122Call: sReadAiopID(CtlP, aiop) 123 CONTROLLER_T *CtlP; Ptr to controller structure 124 int aiop: AIOP index 125Return: 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 128Warnings: No context switches are allowed while executing this function. 129 130*/ 131int 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/*************************************************************************** 145Function: sReadAiopNumChan 146Purpose: Read the number of channels available in an AIOP directly from 147 an AIOP. 148Call: sReadAiopNumChan(CtlP, aiop) 149 CONTROLLER_T *CtlP; Ptr to controller structure 150 int aiop: AIOP index 151Return: int: The number of channels available 152Comments: 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. 156Warnings: No context switches are allowed while executing this function. 157*/ 158int 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/*************************************************************************** 174Function: sInitChan 175Purpose: Initialization of a channel and channel structure 176Call: 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 181Return: int: TRUE if initialization succeeded, FALSE if it fails because channel 182 number exceeds number of channels available in AIOP. 183Comments: This function must be called before a channel can be used. 184Warnings: No range checking on any of the parameters is done. 185 186 No context switches are allowed while executing this function. 187*/ 188int 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/*************************************************************************** 299Function: sStopRxProcessor 300Purpose: Stop the receive processor from processing a channel. 301Call: sStopRxProcessor(ChP) 302 CHANNEL_T *ChP; Ptr to channel structure 303 304Comments: 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 308Warnings: 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*/ 316void 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/*************************************************************************** 328Function: sFlushRxFIFO 329Purpose: Flush the Rx FIFO 330Call: sFlushRxFIFO(ChP) 331 CHANNEL_T *ChP; Ptr to channel structure 332Return: void 333Comments: 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. 339Warnings: No context switches are allowed while executing this function. 340*/ 341void 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/*************************************************************************** 371Function: sFlushTxFIFO 372Purpose: Flush the Tx FIFO 373Call: sFlushTxFIFO(ChP) 374 CHANNEL_T *ChP; Ptr to channel structure 375Return: void 376Comments: 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. 382Warnings: No context switches are allowed while executing this function. 383*/ 384void 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/*************************************************************************** 413Function: sWriteTxPrioByte 414Purpose: Write a byte of priority transmit data to a channel 415Call: sWriteTxPrioByte(ChP,Data) 416 CHANNEL_T *ChP; Ptr to channel structure 417 Byte_t Data; The transmit data byte 418 419Return: int: 1 if the bytes is successfully written, otherwise 0. 420 421Comments: The priority byte is transmitted before any data in the Tx FIFO. 422 423Warnings: No context switches are allowed while executing this function. 424*/ 425int 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/*************************************************************************** 456Function: sEnInterrupts 457Purpose: Enable one or more interrupts for a channel 458Call: 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. 469Return: void 470Comments: 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*/ 487void 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/*************************************************************************** 508Function: sDisInterrupts 509Purpose: Disable one or more interrupts for a channel 510Call: 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. 521Return: void 522Comments: 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*/ 532void 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 553struct callout_handle rp_callout_handle; 554 555static int rp_num_ports_open = 0; 556static int rp_ndevs = 0; 557 558static 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 566static struct rp_port *p_rp_addr[4]; 567static 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 575static void rpbreak(struct tty *, int); 576static void rpclose(struct tty *tp); 577static int rpmodem(struct tty *, int, int); 578static int rpparam(struct tty *, struct termios *); 579static void rpstart(struct tty *); 580static void rpstop(struct tty *, int); 581static t_open_t rpopen; 582 583static 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 675static 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 715static 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 759int 760rp_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", port); 830 } 831 } 832 833 rp_ndevs++; 834 return (0); 835 836nogo: 837 rp_releaseresource(ctlp); 838 839 return (retval); 840} 841 842void 843rp_releaseresource(CONTROLLER_t *ctlp) 844{ 845 int i, s, unit; 846 struct rp_port *rp; 847 848 849 unit = device_get_unit(ctlp->dev); 850 if (rp_addr(unit) != NULL) { 851 for (i = 0; i < rp_num_ports[unit]; i++) { 852 rp = rp_addr(unit) + i; 853 ttyfree(rp->rp_tty); 854 } 855 } 856 857 if (ctlp->rp != NULL) { 858 s = spltty(); 859 for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++) 860 if (p_rp_addr[i] == ctlp->rp) 861 p_rp_addr[i] = NULL; 862 for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++) 863 if (p_rp_table[i] == ctlp->rp) 864 p_rp_table[i] = NULL; 865 splx(s); 866 free(ctlp->rp, M_DEVBUF); 867 ctlp->rp = NULL; 868 } 869} 870 871void 872rp_untimeout(void) 873{ 874 untimeout(rp_do_poll, (void *)NULL, rp_callout_handle); 875} 876 877static int 878rpopen(struct tty *tp, struct cdev *dev) 879{ 880 struct rp_port *rp; 881 int oldspl, flags; 882 unsigned int IntMask, ChanStatus; 883 884 rp = dev->si_drv1; 885 886 oldspl = spltty(); 887 888 flags = 0; 889 flags |= SET_RTS; 890 flags |= SET_DTR; 891 rp->rp_channel.TxControl[3] = 892 ((rp->rp_channel.TxControl[3] 893 & ~(SET_RTS | SET_DTR)) | flags); 894 rp_writech4(&rp->rp_channel,_INDX_ADDR, 895 *(DWord_t *) &(rp->rp_channel.TxControl[0])); 896 sSetRxTrigger(&rp->rp_channel, TRIG_1); 897 sDisRxStatusMode(&rp->rp_channel); 898 sFlushRxFIFO(&rp->rp_channel); 899 sFlushTxFIFO(&rp->rp_channel); 900 901 sEnInterrupts(&rp->rp_channel, 902 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 903 sSetRxTrigger(&rp->rp_channel, TRIG_1); 904 905 sDisRxStatusMode(&rp->rp_channel); 906 sClrTxXOFF(&rp->rp_channel); 907 908/* sDisRTSFlowCtl(&rp->rp_channel); 909 sDisCTSFlowCtl(&rp->rp_channel); 910*/ 911 sDisTxSoftFlowCtl(&rp->rp_channel); 912 913 sStartRxProcessor(&rp->rp_channel); 914 915 sEnRxFIFO(&rp->rp_channel); 916 sEnTransmit(&rp->rp_channel); 917 918/* sSetDTR(&rp->rp_channel); 919 sSetRTS(&rp->rp_channel); 920*/ 921 922 rp_num_ports_open++; 923 924 IntMask = sGetChanIntID(&rp->rp_channel); 925 IntMask = IntMask & rp->rp_intmask; 926 ChanStatus = sGetChanStatus(&rp->rp_channel); 927 928 if(rp_num_ports_open == 1) 929 rp_callout_handle = timeout(rp_do_poll, 930 (void *)NULL, POLL_INTERVAL); 931 932 device_busy(rp->rp_ctlp->dev); 933 return(0); 934} 935 936static void 937rpclose(struct tty *tp) 938{ 939 struct rp_port *rp; 940 CHANNEL_t *cp; 941 942 rp = tp->t_sc; 943 cp = &rp->rp_channel; 944 945 sFlushRxFIFO(cp); 946 sFlushTxFIFO(cp); 947 sDisTransmit(cp); 948 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN); 949 sDisRTSFlowCtl(cp); 950 sDisCTSFlowCtl(cp); 951 sDisTxSoftFlowCtl(cp); 952 sClrTxXOFF(cp); 953 954 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) { 955 sClrDTR(cp); 956 } 957 if(ISCALLOUT(tp->t_dev)) { 958 sClrDTR(cp); 959 } 960 tp->t_actout = FALSE; 961 wakeup(&tp->t_actout); 962 wakeup(TSA_CARR_ON(tp)); 963 device_unbusy(rp->rp_ctlp->dev); 964} 965 966static void 967rpbreak(struct tty *tp, int sig) 968{ 969 struct rp_port *rp; 970 971 rp = tp->t_sc; 972 if (sig) { 973 sSendBreak(&rp->rp_channel); 974 } else { 975 sClrBreak(&rp->rp_channel); 976 } 977} 978 979static int 980rpmodem(struct tty *tp, int sigon, int sigoff) 981{ 982 struct rp_port *rp; 983 int i, j, k; 984 985 rp = tp->t_sc; 986 if (sigon != 0 || sigoff != 0) { 987 i = j = 0; 988 if (sigon & SER_DTR) 989 i = SET_DTR; 990 if (sigoff & SER_DTR) 991 j = SET_DTR; 992 if (sigon & SER_RTS) 993 i = SET_RTS; 994 if (sigoff & SER_RTS) 995 j = SET_RTS; 996 rp->rp_channel.TxControl[3] &= ~i; 997 rp->rp_channel.TxControl[3] |= j; 998 rp_writech4(&rp->rp_channel,_INDX_ADDR, 999 *(DWord_t *) &(rp->rp_channel.TxControl[0])); 1000 } else { 1001 i = sGetChanStatusLo(&rp->rp_channel); 1002 j = rp->rp_channel.TxControl[3]; 1003 k = 0; 1004 if (j & SET_DTR) 1005 k |= SER_DTR; 1006 if (j & SET_RTS) 1007 k |= SER_RTS; 1008 if (i & CD_ACT) 1009 k |= SER_DCD; 1010 if (i & DSR_ACT) 1011 k |= SER_DSR; 1012 if (i & CTS_ACT) 1013 k |= SER_CTS; 1014 return(k); 1015 } 1016 return (0); 1017} 1018 1019static struct speedtab baud_table[] = { 1020 {B0, 0}, {B50, BRD50}, {B75, BRD75}, 1021 {B110, BRD110}, {B134, BRD134}, {B150, BRD150}, 1022 {B200, BRD200}, {B300, BRD300}, {B600, BRD600}, 1023 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400}, 1024 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200}, 1025 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400}, 1026 {B57600, BRD57600}, {B76800, BRD76800}, 1027 {B115200, BRD115200}, {B230400, BRD230400}, 1028 {-1, -1} 1029}; 1030 1031static int 1032rpparam(tp, t) 1033 struct tty *tp; 1034 struct termios *t; 1035{ 1036 struct rp_port *rp; 1037 CHANNEL_t *cp; 1038 int oldspl, cflag, iflag, oflag, lflag; 1039 int ospeed; 1040#ifdef RPCLOCAL 1041 int devshift; 1042#endif 1043 1044 1045 rp = tp->t_sc; 1046 cp = &rp->rp_channel; 1047 oldspl = spltty(); 1048 1049 cflag = t->c_cflag; 1050#ifdef RPCLOCAL 1051 devshift = umynor / 32; 1052 devshift = 1 << devshift; 1053 if ( devshift & RPCLOCAL ) { 1054 cflag |= CLOCAL; 1055 } 1056#endif 1057 iflag = t->c_iflag; 1058 oflag = t->c_oflag; 1059 lflag = t->c_lflag; 1060 1061 ospeed = ttspeedtab(t->c_ispeed, baud_table); 1062 if(ospeed < 0 || t->c_ispeed != t->c_ospeed) 1063 return(EINVAL); 1064 1065 tp->t_ispeed = t->c_ispeed; 1066 tp->t_ospeed = t->c_ospeed; 1067 tp->t_cflag = cflag; 1068 tp->t_iflag = iflag; 1069 tp->t_oflag = oflag; 1070 tp->t_lflag = lflag; 1071 1072 if(t->c_ospeed == 0) { 1073 sClrDTR(cp); 1074 return(0); 1075 } 1076 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1; 1077 1078 /* Set baud rate ----- we only pay attention to ispeed */ 1079 sSetDTR(cp); 1080 sSetRTS(cp); 1081 sSetBaud(cp, ospeed); 1082 1083 if(cflag & CSTOPB) { 1084 sSetStop2(cp); 1085 } else { 1086 sSetStop1(cp); 1087 } 1088 1089 if(cflag & PARENB) { 1090 sEnParity(cp); 1091 if(cflag & PARODD) { 1092 sSetOddParity(cp); 1093 } else { 1094 sSetEvenParity(cp); 1095 } 1096 } 1097 else { 1098 sDisParity(cp); 1099 } 1100 if((cflag & CSIZE) == CS8) { 1101 sSetData8(cp); 1102 rp->rp_imask = 0xFF; 1103 } else { 1104 sSetData7(cp); 1105 rp->rp_imask = 0x7F; 1106 } 1107 1108 if(iflag & ISTRIP) { 1109 rp->rp_imask &= 0x7F; 1110 } 1111 1112 if(cflag & CLOCAL) { 1113 rp->rp_intmask &= ~DELTA_CD; 1114 } else { 1115 rp->rp_intmask |= DELTA_CD; 1116 } 1117 1118 /* Put flow control stuff here */ 1119 1120 if(cflag & CCTS_OFLOW) { 1121 sEnCTSFlowCtl(cp); 1122 } else { 1123 sDisCTSFlowCtl(cp); 1124 } 1125 1126 if(cflag & CRTS_IFLOW) { 1127 rp->rp_rts_iflow = 1; 1128 } else { 1129 rp->rp_rts_iflow = 0; 1130 } 1131 1132 if(cflag & CRTS_IFLOW) { 1133 sEnRTSFlowCtl(cp); 1134 } else { 1135 sDisRTSFlowCtl(cp); 1136 } 1137 ttyldoptim(tp); 1138 1139 if((cflag & CLOCAL) || (sGetChanStatusLo(cp) & CD_ACT)) { 1140 tp->t_state |= TS_CARR_ON; 1141 wakeup(TSA_CARR_ON(tp)); 1142 } 1143 1144/* tp->t_state |= TS_CAN_BYPASS_L_RINT; 1145 flags = rp->rp_channel.TxControl[3]; 1146 if(flags & SET_DTR) 1147 else 1148 if(flags & SET_RTS) 1149 else 1150*/ 1151 splx(oldspl); 1152 1153 return(0); 1154} 1155 1156static void 1157rpstart(tp) 1158 struct tty *tp; 1159{ 1160 struct rp_port *rp; 1161 CHANNEL_t *cp; 1162 struct clist *qp; 1163 char flags; 1164 int spl, xmit_fifo_room; 1165 int count, wcount; 1166 1167 1168 rp = tp->t_sc; 1169 cp = &rp->rp_channel; 1170 flags = rp->rp_channel.TxControl[3]; 1171 spl = spltty(); 1172 1173 if(tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { 1174 ttwwakeup(tp); 1175 splx(spl); 1176 return; 1177 } 1178 if(rp->rp_xmit_stopped) { 1179 sEnTransmit(cp); 1180 rp->rp_xmit_stopped = 0; 1181 } 1182 count = sGetTxCnt(cp); 1183 1184 if(tp->t_outq.c_cc == 0) { 1185 if((tp->t_state & TS_BUSY) && (count == 0)) { 1186 tp->t_state &= ~TS_BUSY; 1187 } 1188 ttwwakeup(tp); 1189 splx(spl); 1190 return; 1191 } 1192 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 1193 qp = &tp->t_outq; 1194 if(xmit_fifo_room > 0 && qp->c_cc > 0) { 1195 tp->t_state |= TS_BUSY; 1196 count = q_to_b( qp, (char *)rp->TxBuf, xmit_fifo_room ); 1197 wcount = count >> 1; 1198 if ( wcount ) { 1199 rp_writemultich2(cp, sGetTxRxDataIO(cp), (u_int16_t *)rp->TxBuf, wcount); 1200 } 1201 if ( count & 1 ) { 1202 rp_writech1(cp, sGetTxRxDataIO(cp), 1203 ((unsigned char *)(rp->TxBuf))[(count-1)]); 1204 } 1205 } 1206 rp->rp_restart = (qp->c_cc > 0) ? rp->rp_fifo_lw : 0; 1207 1208 ttwwakeup(tp); 1209 splx(spl); 1210} 1211 1212static 1213void 1214rpstop(tp, flag) 1215 register struct tty *tp; 1216 int flag; 1217{ 1218 struct rp_port *rp; 1219 CHANNEL_t *cp; 1220 int spl; 1221 1222 rp = tp->t_sc; 1223 cp = &rp->rp_channel; 1224 1225 spl = spltty(); 1226 1227 if(tp->t_state & TS_BUSY) { 1228 if((tp->t_state&TS_TTSTOP) == 0) { 1229 sFlushTxFIFO(cp); 1230 } else { 1231 if(rp->rp_xmit_stopped == 0) { 1232 sDisTransmit(cp); 1233 rp->rp_xmit_stopped = 1; 1234 } 1235 } 1236 } 1237 splx(spl); 1238 rpstart(tp); 1239} 1240