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$"); 36 37/* 38 * rp.c - for RocketPort FreeBSD 39 */ 40 41#include "opt_compat.h" 42 43#include <sys/param.h> 44#include <sys/systm.h> 45#include <sys/endian.h> 46#include <sys/fcntl.h> 47#include <sys/malloc.h> 48#include <sys/serial.h> 49#include <sys/tty.h> 50#include <sys/conf.h> 51#include <sys/kernel.h> 52#include <machine/resource.h> 53#include <machine/bus.h> 54#include <sys/bus.h> 55#include <sys/rman.h> 56 57#define ROCKET_C 58#include <dev/rp/rpreg.h> 59#include <dev/rp/rpvar.h> 60 61static const char RocketPortVersion[] = "3.02"; 62 63static Byte_t RData[RDATASIZE] = 64{ 65 0x00, 0x09, 0xf6, 0x82, 66 0x02, 0x09, 0x86, 0xfb, 67 0x04, 0x09, 0x00, 0x0a, 68 0x06, 0x09, 0x01, 0x0a, 69 0x08, 0x09, 0x8a, 0x13, 70 0x0a, 0x09, 0xc5, 0x11, 71 0x0c, 0x09, 0x86, 0x85, 72 0x0e, 0x09, 0x20, 0x0a, 73 0x10, 0x09, 0x21, 0x0a, 74 0x12, 0x09, 0x41, 0xff, 75 0x14, 0x09, 0x82, 0x00, 76 0x16, 0x09, 0x82, 0x7b, 77 0x18, 0x09, 0x8a, 0x7d, 78 0x1a, 0x09, 0x88, 0x81, 79 0x1c, 0x09, 0x86, 0x7a, 80 0x1e, 0x09, 0x84, 0x81, 81 0x20, 0x09, 0x82, 0x7c, 82 0x22, 0x09, 0x0a, 0x0a 83}; 84 85static Byte_t RRegData[RREGDATASIZE]= 86{ 87 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ 88 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ 89 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ 90 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ 91 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ 92 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ 93 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ 94 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ 95 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ 96 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ 97 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ 98 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ 99 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ 100}; 101 102#if 0 103/* IRQ number to MUDBAC register 2 mapping */ 104Byte_t sIRQMap[16] = 105{ 106 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80 107}; 108#endif 109 110Byte_t rp_sBitMapClrTbl[8] = 111{ 112 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f 113}; 114 115Byte_t rp_sBitMapSetTbl[8] = 116{ 117 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 118}; 119 120static void rpfree(void *); 121 122/*************************************************************************** 123Function: sReadAiopID 124Purpose: Read the AIOP idenfication number directly from an AIOP. 125Call: sReadAiopID(CtlP, aiop) 126 CONTROLLER_T *CtlP; Ptr to controller structure 127 int aiop: AIOP index 128Return: int: Flag AIOPID_XXXX if a valid AIOP is found, where X 129 is replace by an identifying number. 130 Flag AIOPID_NULL if no valid AIOP is found 131Warnings: No context switches are allowed while executing this function. 132 133*/ 134int sReadAiopID(CONTROLLER_T *CtlP, int aiop) 135{ 136 Byte_t AiopID; /* ID byte from AIOP */ 137 138 rp_writeaiop1(CtlP, aiop, _CMD_REG, RESET_ALL); /* reset AIOP */ 139 rp_writeaiop1(CtlP, aiop, _CMD_REG, 0x0); 140 AiopID = rp_readaiop1(CtlP, aiop, _CHN_STAT0) & 0x07; 141 if(AiopID == 0x06) 142 return(1); 143 else /* AIOP does not exist */ 144 return(-1); 145} 146 147/*************************************************************************** 148Function: sReadAiopNumChan 149Purpose: Read the number of channels available in an AIOP directly from 150 an AIOP. 151Call: sReadAiopNumChan(CtlP, aiop) 152 CONTROLLER_T *CtlP; Ptr to controller structure 153 int aiop: AIOP index 154Return: int: The number of channels available 155Comments: The number of channels is determined by write/reads from identical 156 offsets within the SRAM address spaces for channels 0 and 4. 157 If the channel 4 space is mirrored to channel 0 it is a 4 channel 158 AIOP, otherwise it is an 8 channel. 159Warnings: No context switches are allowed while executing this function. 160*/ 161int sReadAiopNumChan(CONTROLLER_T *CtlP, int aiop) 162{ 163 Word_t x, y; 164 165 rp_writeaiop4(CtlP, aiop, _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */ 166 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0); /* read from SRAM, chan 0 */ 167 x = rp_readaiop2(CtlP, aiop, _INDX_DATA); 168 rp_writeaiop2(CtlP, aiop, _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */ 169 y = rp_readaiop2(CtlP, aiop, _INDX_DATA); 170 if(x != y) /* if different must be 8 chan */ 171 return(8); 172 else 173 return(4); 174} 175 176/*************************************************************************** 177Function: sInitChan 178Purpose: Initialization of a channel and channel structure 179Call: sInitChan(CtlP,ChP,AiopNum,ChanNum) 180 CONTROLLER_T *CtlP; Ptr to controller structure 181 CHANNEL_T *ChP; Ptr to channel structure 182 int AiopNum; AIOP number within controller 183 int ChanNum; Channel number within AIOP 184Return: int: TRUE if initialization succeeded, FALSE if it fails because channel 185 number exceeds number of channels available in AIOP. 186Comments: This function must be called before a channel can be used. 187Warnings: No range checking on any of the parameters is done. 188 189 No context switches are allowed while executing this function. 190*/ 191int sInitChan( CONTROLLER_T *CtlP, 192 CHANNEL_T *ChP, 193 int AiopNum, 194 int ChanNum) 195{ 196 int i, ChOff; 197 Byte_t *ChR; 198 static Byte_t R[4]; 199 200 if(ChanNum >= CtlP->AiopNumChan[AiopNum]) 201 return(FALSE); /* exceeds num chans in AIOP */ 202 203 /* Channel, AIOP, and controller identifiers */ 204 ChP->CtlP = CtlP; 205 ChP->ChanID = CtlP->AiopID[AiopNum]; 206 ChP->AiopNum = AiopNum; 207 ChP->ChanNum = ChanNum; 208 209 /* Initialize the channel from the RData array */ 210 for(i=0; i < RDATASIZE; i+=4) 211 { 212 R[0] = RData[i]; 213 R[1] = RData[i+1] + 0x10 * ChanNum; 214 R[2] = RData[i+2]; 215 R[3] = RData[i+3]; 216 rp_writech4(ChP,_INDX_ADDR,le32dec(R)); 217 } 218 219 ChR = ChP->R; 220 for(i=0; i < RREGDATASIZE; i+=4) 221 { 222 ChR[i] = RRegData[i]; 223 ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum; 224 ChR[i+2] = RRegData[i+2]; 225 ChR[i+3] = RRegData[i+3]; 226 } 227 228 /* Indexed registers */ 229 ChOff = (Word_t)ChanNum * 0x1000; 230 231 ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD); 232 ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8); 233 ChP->BaudDiv[2] = (Byte_t)BRD9600; 234 ChP->BaudDiv[3] = (Byte_t)(BRD9600 >> 8); 235 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->BaudDiv)); 236 237 ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL); 238 ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8); 239 ChP->TxControl[2] = 0; 240 ChP->TxControl[3] = 0; 241 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); 242 243 ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL); 244 ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8); 245 ChP->RxControl[2] = 0; 246 ChP->RxControl[3] = 0; 247 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); 248 249 ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS); 250 ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8); 251 ChP->TxEnables[2] = 0; 252 ChP->TxEnables[3] = 0; 253 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxEnables)); 254 255 ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1); 256 ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8); 257 ChP->TxCompare[2] = 0; 258 ChP->TxCompare[3] = 0; 259 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxCompare)); 260 261 ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1); 262 ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8); 263 ChP->TxReplace1[2] = 0; 264 ChP->TxReplace1[3] = 0; 265 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace1)); 266 267 ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2); 268 ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8); 269 ChP->TxReplace2[2] = 0; 270 ChP->TxReplace2[3] = 0; 271 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxReplace2)); 272 273 ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; 274 ChP->TxFIFO = ChOff + _TX_FIFO; 275 276 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ 277 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Tx FIFO count */ 278 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 279 rp_writech2(ChP,_INDX_DATA,0); 280 ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; 281 ChP->RxFIFO = ChOff + _RX_FIFO; 282 283 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ 284 rp_writech1(ChP,_CMD_REG,(Byte_t)ChanNum); /* remove reset Rx FIFO count */ 285 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */ 286 rp_writech2(ChP,_INDX_DATA,0); 287 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 288 rp_writech2(ChP,_INDX_DATA,0); 289 ChP->TxPrioCnt = ChOff + _TXP_CNT; 290 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); 291 rp_writech1(ChP,_INDX_DATA,0); 292 ChP->TxPrioPtr = ChOff + _TXP_PNTR; 293 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioPtr); 294 rp_writech1(ChP,_INDX_DATA,0); 295 ChP->TxPrioBuf = ChOff + _TXP_BUF; 296 sEnRxProcessor(ChP); /* start the Rx processor */ 297 298 return(TRUE); 299} 300 301/*************************************************************************** 302Function: sStopRxProcessor 303Purpose: Stop the receive processor from processing a channel. 304Call: sStopRxProcessor(ChP) 305 CHANNEL_T *ChP; Ptr to channel structure 306 307Comments: The receive processor can be started again with sStartRxProcessor(). 308 This function causes the receive processor to skip over the 309 stopped channel. It does not stop it from processing other channels. 310 311Warnings: No context switches are allowed while executing this function. 312 313 Do not leave the receive processor stopped for more than one 314 character time. 315 316 After calling this function a delay of 4 uS is required to ensure 317 that the receive processor is no longer processing this channel. 318*/ 319void sStopRxProcessor(CHANNEL_T *ChP) 320{ 321 Byte_t R[4]; 322 323 R[0] = ChP->R[0]; 324 R[1] = ChP->R[1]; 325 R[2] = 0x0a; 326 R[3] = ChP->R[3]; 327 rp_writech4(ChP,_INDX_ADDR,le32dec(R)); 328} 329 330/*************************************************************************** 331Function: sFlushRxFIFO 332Purpose: Flush the Rx FIFO 333Call: sFlushRxFIFO(ChP) 334 CHANNEL_T *ChP; Ptr to channel structure 335Return: void 336Comments: To prevent data from being enqueued or dequeued in the Tx FIFO 337 while it is being flushed the receive processor is stopped 338 and the transmitter is disabled. After these operations a 339 4 uS delay is done before clearing the pointers to allow 340 the receive processor to stop. These items are handled inside 341 this function. 342Warnings: No context switches are allowed while executing this function. 343*/ 344void sFlushRxFIFO(CHANNEL_T *ChP) 345{ 346 int i; 347 Byte_t Ch; /* channel number within AIOP */ 348 int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ 349 350 if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ 351 return; /* don't need to flush */ 352 353 RxFIFOEnabled = FALSE; 354 if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */ 355 { 356 RxFIFOEnabled = TRUE; 357 sDisRxFIFO(ChP); /* disable it */ 358 for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/ 359 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */ 360 } 361 sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ 362 Ch = (Byte_t)sGetChanNum(ChP); 363 rp_writech1(ChP,_CMD_REG,Ch | RESRXFCNT); /* apply reset Rx FIFO count */ 364 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Rx FIFO count */ 365 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs); /* clear Rx out ptr */ 366 rp_writech2(ChP,_INDX_DATA,0); 367 rp_writech2(ChP,_INDX_ADDR,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ 368 rp_writech2(ChP,_INDX_DATA,0); 369 if(RxFIFOEnabled) 370 sEnRxFIFO(ChP); /* enable Rx FIFO */ 371} 372 373/*************************************************************************** 374Function: sFlushTxFIFO 375Purpose: Flush the Tx FIFO 376Call: sFlushTxFIFO(ChP) 377 CHANNEL_T *ChP; Ptr to channel structure 378Return: void 379Comments: To prevent data from being enqueued or dequeued in the Tx FIFO 380 while it is being flushed the receive processor is stopped 381 and the transmitter is disabled. After these operations a 382 4 uS delay is done before clearing the pointers to allow 383 the receive processor to stop. These items are handled inside 384 this function. 385Warnings: No context switches are allowed while executing this function. 386*/ 387void sFlushTxFIFO(CHANNEL_T *ChP) 388{ 389 int i; 390 Byte_t Ch; /* channel number within AIOP */ 391 int TxEnabled; /* TRUE if transmitter enabled */ 392 393 if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ 394 return; /* don't need to flush */ 395 396 TxEnabled = FALSE; 397 if(ChP->TxControl[3] & TX_ENABLE) 398 { 399 TxEnabled = TRUE; 400 sDisTransmit(ChP); /* disable transmitter */ 401 } 402 sStopRxProcessor(ChP); /* stop Rx processor */ 403 for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */ 404 rp_readch1(ChP,_INT_CHAN); /* depends on bus i/o timing */ 405 Ch = (Byte_t)sGetChanNum(ChP); 406 rp_writech1(ChP,_CMD_REG,Ch | RESTXFCNT); /* apply reset Tx FIFO count */ 407 rp_writech1(ChP,_CMD_REG,Ch); /* remove reset Tx FIFO count */ 408 rp_writech2(ChP,_INDX_ADDR,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ 409 rp_writech2(ChP,_INDX_DATA,0); 410 if(TxEnabled) 411 sEnTransmit(ChP); /* enable transmitter */ 412 sStartRxProcessor(ChP); /* restart Rx processor */ 413} 414 415/*************************************************************************** 416Function: sWriteTxPrioByte 417Purpose: Write a byte of priority transmit data to a channel 418Call: sWriteTxPrioByte(ChP,Data) 419 CHANNEL_T *ChP; Ptr to channel structure 420 Byte_t Data; The transmit data byte 421 422Return: int: 1 if the bytes is successfully written, otherwise 0. 423 424Comments: The priority byte is transmitted before any data in the Tx FIFO. 425 426Warnings: No context switches are allowed while executing this function. 427*/ 428int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data) 429{ 430 Byte_t DWBuf[4]; /* buffer for double word writes */ 431 432 if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */ 433 { 434 rp_writech2(ChP,_INDX_ADDR,ChP->TxPrioCnt); /* get priority buffer status */ 435 if(rp_readch1(ChP,_INDX_DATA) & PRI_PEND) /* priority buffer busy */ 436 return(0); /* nothing sent */ 437 438 le16enc(DWBuf,ChP->TxPrioBuf); /* data byte address */ 439 440 DWBuf[2] = Data; /* data byte value */ 441 DWBuf[3] = 0; /* priority buffer pointer */ 442 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */ 443 444 le16enc(DWBuf,ChP->TxPrioCnt); /* Tx priority count address */ 445 446 DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ 447 DWBuf[3] = 0; /* priority buffer pointer */ 448 rp_writech4(ChP,_INDX_ADDR,le32dec(DWBuf)); /* write it out */ 449 } 450 else /* write it to Tx FIFO */ 451 { 452 sWriteTxByte(ChP,sGetTxRxDataIO(ChP),Data); 453 } 454 return(1); /* 1 byte sent */ 455} 456 457/*************************************************************************** 458Function: sEnInterrupts 459Purpose: Enable one or more interrupts for a channel 460Call: sEnInterrupts(ChP,Flags) 461 CHANNEL_T *ChP; Ptr to channel structure 462 Word_t Flags: Interrupt enable flags, can be any combination 463 of the following flags: 464 TXINT_EN: Interrupt on Tx FIFO empty 465 RXINT_EN: Interrupt on Rx FIFO at trigger level (see 466 sSetRxTrigger()) 467 SRCINT_EN: Interrupt on SRC (Special Rx Condition) 468 MCINT_EN: Interrupt on modem input change 469 CHANINT_EN: Allow channel interrupt signal to the AIOP's 470 Interrupt Channel Register. 471Return: void 472Comments: If an interrupt enable flag is set in Flags, that interrupt will be 473 enabled. If an interrupt enable flag is not set in Flags, that 474 interrupt will not be changed. Interrupts can be disabled with 475 function sDisInterrupts(). 476 477 This function sets the appropriate bit for the channel in the AIOP's 478 Interrupt Mask Register if the CHANINT_EN flag is set. This allows 479 this channel's bit to be set in the AIOP's Interrupt Channel Register. 480 481 Interrupts must also be globally enabled before channel interrupts 482 will be passed on to the host. This is done with function 483 sEnGlobalInt(). 484 485 In some cases it may be desirable to disable interrupts globally but 486 enable channel interrupts. This would allow the global interrupt 487 status register to be used to determine which AIOPs need service. 488*/ 489void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags) 490{ 491 Byte_t Mask; /* Interrupt Mask Register */ 492 493 ChP->RxControl[2] |= 494 ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 495 496 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); 497 498 ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN); 499 500 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); 501 502 if(Flags & CHANINT_EN) 503 { 504 Mask = rp_readch1(ChP,_INT_MASK) | rp_sBitMapSetTbl[ChP->ChanNum]; 505 rp_writech1(ChP,_INT_MASK,Mask); 506 } 507} 508 509/*************************************************************************** 510Function: sDisInterrupts 511Purpose: Disable one or more interrupts for a channel 512Call: sDisInterrupts(ChP,Flags) 513 CHANNEL_T *ChP; Ptr to channel structure 514 Word_t Flags: Interrupt flags, can be any combination 515 of the following flags: 516 TXINT_EN: Interrupt on Tx FIFO empty 517 RXINT_EN: Interrupt on Rx FIFO at trigger level (see 518 sSetRxTrigger()) 519 SRCINT_EN: Interrupt on SRC (Special Rx Condition) 520 MCINT_EN: Interrupt on modem input change 521 CHANINT_EN: Disable channel interrupt signal to the 522 AIOP's Interrupt Channel Register. 523Return: void 524Comments: If an interrupt flag is set in Flags, that interrupt will be 525 disabled. If an interrupt flag is not set in Flags, that 526 interrupt will not be changed. Interrupts can be enabled with 527 function sEnInterrupts(). 528 529 This function clears the appropriate bit for the channel in the AIOP's 530 Interrupt Mask Register if the CHANINT_EN flag is set. This blocks 531 this channel's bit from being set in the AIOP's Interrupt Channel 532 Register. 533*/ 534void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags) 535{ 536 Byte_t Mask; /* Interrupt Mask Register */ 537 538 ChP->RxControl[2] &= 539 ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); 540 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->RxControl)); 541 ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN); 542 rp_writech4(ChP,_INDX_ADDR,le32dec(ChP->TxControl)); 543 544 if(Flags & CHANINT_EN) 545 { 546 Mask = rp_readch1(ChP,_INT_MASK) & rp_sBitMapClrTbl[ChP->ChanNum]; 547 rp_writech1(ChP,_INT_MASK,Mask); 548 } 549} 550 551/********************************************************************* 552 Begin FreeBsd-specific driver code 553**********************************************************************/ 554 555#define POLL_INTERVAL (hz / 100) 556 557#define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1) 558#define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff) 559#define RP_NOTAST4(dev) ((dev)->id_flags & 0x04) 560 561/* 562 * The top-level routines begin here 563 */ 564 565static void rpclose(struct tty *tp); 566static void rphardclose(struct tty *tp); 567static int rpmodem(struct tty *, int, int); 568static int rpparam(struct tty *, struct termios *); 569static void rpstart(struct tty *); 570static int rpioctl(struct tty *, u_long, caddr_t, struct thread *); 571static int rpopen(struct tty *); 572 573static void rp_do_receive(struct rp_port *rp, struct tty *tp, 574 CHANNEL_t *cp, unsigned int ChanStatus) 575{ 576 unsigned int CharNStat; 577 int ToRecv, ch, err = 0; 578 579 ToRecv = sGetRxCnt(cp); 580 if(ToRecv == 0) 581 return; 582 583/* If status indicates there are errored characters in the 584 FIFO, then enter status mode (a word in FIFO holds 585 characters and status) 586*/ 587 588 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { 589 if(!(ChanStatus & STATMODE)) { 590 ChanStatus |= STATMODE; 591 sEnRxStatusMode(cp); 592 } 593 } 594/* 595 if we previously entered status mode then read down the 596 FIFO one word at a time, pulling apart the character and 597 the status. Update error counters depending on status. 598*/ 599 tty_lock(tp); 600 if(ChanStatus & STATMODE) { 601 while(ToRecv) { 602 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp)); 603 ch = CharNStat & 0xff; 604 605 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH)) 606 err |= TRE_FRAMING; 607 else if (CharNStat & STMPARITYH) 608 err |= TRE_PARITY; 609 else if (CharNStat & STMRCVROVRH) { 610 rp->rp_overflows++; 611 err |= TRE_OVERRUN; 612 } 613 614 ttydisc_rint(tp, ch, err); 615 ToRecv--; 616 } 617/* 618 After emtying FIFO in status mode, turn off status mode 619*/ 620 621 if(sGetRxCnt(cp) == 0) { 622 sDisRxStatusMode(cp); 623 } 624 } else { 625 ToRecv = sGetRxCnt(cp); 626 while (ToRecv) { 627 ch = rp_readch1(cp,sGetTxRxDataIO(cp)); 628 ttydisc_rint(tp, ch & 0xff, err); 629 ToRecv--; 630 } 631 } 632 ttydisc_rint_done(tp); 633 tty_unlock(tp); 634} 635 636static void rp_handle_port(struct rp_port *rp) 637{ 638 CHANNEL_t *cp; 639 struct tty *tp; 640 unsigned int IntMask, ChanStatus; 641 642 if(!rp) 643 return; 644 645 cp = &rp->rp_channel; 646 tp = rp->rp_tty; 647 IntMask = sGetChanIntID(cp); 648 IntMask = IntMask & rp->rp_intmask; 649 ChanStatus = sGetChanStatus(cp); 650 if(IntMask & RXF_TRIG) 651 rp_do_receive(rp, tp, cp, ChanStatus); 652 if(IntMask & DELTA_CD) { 653 if(ChanStatus & CD_ACT) { 654 (void)ttydisc_modem(tp, 1); 655 } else { 656 (void)ttydisc_modem(tp, 0); 657 } 658 } 659/* oldcts = rp->rp_cts; 660 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0); 661 if(oldcts != rp->rp_cts) { 662 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port); 663 } 664*/ 665} 666 667static void rp_do_poll(void *arg) 668{ 669 CONTROLLER_t *ctl; 670 struct rp_port *rp; 671 struct tty *tp; 672 int count; 673 unsigned char CtlMask, AiopMask; 674 675 rp = arg; 676 tp = rp->rp_tty; 677 tty_lock_assert(tp, MA_OWNED); 678 ctl = rp->rp_ctlp; 679 CtlMask = ctl->ctlmask(ctl); 680 if (CtlMask & (1 << rp->rp_aiop)) { 681 AiopMask = sGetAiopIntStatus(ctl, rp->rp_aiop); 682 if (AiopMask & (1 << rp->rp_chan)) { 683 rp_handle_port(rp); 684 } 685 } 686 687 count = sGetTxCnt(&rp->rp_channel); 688 if (count >= 0 && (count <= rp->rp_restart)) { 689 rpstart(tp); 690 } 691 callout_schedule(&rp->rp_timer, POLL_INTERVAL); 692} 693 694static struct ttydevsw rp_tty_class = { 695 .tsw_flags = TF_INITLOCK|TF_CALLOUT, 696 .tsw_open = rpopen, 697 .tsw_close = rpclose, 698 .tsw_outwakeup = rpstart, 699 .tsw_ioctl = rpioctl, 700 .tsw_param = rpparam, 701 .tsw_modem = rpmodem, 702 .tsw_free = rpfree, 703}; 704 705 706static void 707rpfree(void *softc) 708{ 709 struct rp_port *rp = softc; 710 CONTROLLER_t *ctlp = rp->rp_ctlp; 711 712 atomic_subtract_32(&ctlp->free, 1); 713} 714 715int 716rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports) 717{ 718 int unit; 719 int num_chan; 720 int aiop, chan, port; 721 int ChanStatus; 722 int retval; 723 struct rp_port *rp; 724 struct tty *tp; 725 726 unit = device_get_unit(ctlp->dev); 727 728 printf("RocketPort%d (Version %s) %d ports.\n", unit, 729 RocketPortVersion, num_ports); 730 731 ctlp->num_ports = num_ports; 732 ctlp->rp = rp = (struct rp_port *) 733 malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO); 734 if (rp == NULL) { 735 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n"); 736 retval = ENOMEM; 737 goto nogo; 738 } 739 740 port = 0; 741 for(aiop=0; aiop < num_aiops; aiop++) { 742 num_chan = sGetAiopNumChan(ctlp, aiop); 743 for(chan=0; chan < num_chan; chan++, port++, rp++) { 744 rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp); 745 callout_init_mtx(&rp->rp_timer, tty_getlock(tp), 0); 746 rp->rp_port = port; 747 rp->rp_ctlp = ctlp; 748 rp->rp_unit = unit; 749 rp->rp_chan = chan; 750 rp->rp_aiop = aiop; 751 752 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | 753 DELTA_CD | DELTA_CTS | DELTA_DSR; 754#ifdef notdef 755 ChanStatus = sGetChanStatus(&rp->rp_channel); 756#endif /* notdef */ 757 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) { 758 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n", 759 unit, aiop, chan); 760 retval = ENXIO; 761 goto nogo; 762 } 763 ChanStatus = sGetChanStatus(&rp->rp_channel); 764 rp->rp_cts = (ChanStatus & CTS_ACT) != 0; 765 tty_makedev(tp, NULL, "R%r%r", unit, port); 766 } 767 } 768 769 mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF); 770 ctlp->hwmtx_init = 1; 771 return (0); 772 773nogo: 774 rp_releaseresource(ctlp); 775 776 return (retval); 777} 778 779void 780rp_releaseresource(CONTROLLER_t *ctlp) 781{ 782 struct rp_port *rp; 783 int i; 784 785 if (ctlp->rp != NULL) { 786 for (i = 0; i < ctlp->num_ports; i++) { 787 rp = ctlp->rp + i; 788 atomic_add_32(&ctlp->free, 1); 789 tty_lock(rp->rp_tty); 790 tty_rel_gone(rp->rp_tty); 791 } 792 free(ctlp->rp, M_DEVBUF); 793 ctlp->rp = NULL; 794 } 795 796 while (ctlp->free != 0) { 797 pause("rpwt", hz / 10); 798 } 799 800 if (ctlp->hwmtx_init) 801 mtx_destroy(&ctlp->hwmtx); 802} 803 804static int 805rpopen(struct tty *tp) 806{ 807 struct rp_port *rp; 808 int flags; 809 unsigned int IntMask, ChanStatus; 810 811 rp = tty_softc(tp); 812 813 flags = 0; 814 flags |= SET_RTS; 815 flags |= SET_DTR; 816 rp->rp_channel.TxControl[3] = 817 ((rp->rp_channel.TxControl[3] 818 & ~(SET_RTS | SET_DTR)) | flags); 819 rp_writech4(&rp->rp_channel,_INDX_ADDR, 820 le32dec(rp->rp_channel.TxControl)); 821 sSetRxTrigger(&rp->rp_channel, TRIG_1); 822 sDisRxStatusMode(&rp->rp_channel); 823 sFlushRxFIFO(&rp->rp_channel); 824 sFlushTxFIFO(&rp->rp_channel); 825 826 sEnInterrupts(&rp->rp_channel, 827 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 828 sSetRxTrigger(&rp->rp_channel, TRIG_1); 829 830 sDisRxStatusMode(&rp->rp_channel); 831 sClrTxXOFF(&rp->rp_channel); 832 833/* sDisRTSFlowCtl(&rp->rp_channel); 834 sDisCTSFlowCtl(&rp->rp_channel); 835*/ 836 sDisTxSoftFlowCtl(&rp->rp_channel); 837 838 sStartRxProcessor(&rp->rp_channel); 839 840 sEnRxFIFO(&rp->rp_channel); 841 sEnTransmit(&rp->rp_channel); 842 843/* sSetDTR(&rp->rp_channel); 844 sSetRTS(&rp->rp_channel); 845*/ 846 847 IntMask = sGetChanIntID(&rp->rp_channel); 848 IntMask = IntMask & rp->rp_intmask; 849 ChanStatus = sGetChanStatus(&rp->rp_channel); 850 851 callout_reset(&rp->rp_timer, POLL_INTERVAL, rp_do_poll, rp); 852 853 device_busy(rp->rp_ctlp->dev); 854 return(0); 855} 856 857static void 858rpclose(struct tty *tp) 859{ 860 struct rp_port *rp; 861 862 rp = tty_softc(tp); 863 callout_stop(&rp->rp_timer); 864 rphardclose(tp); 865 device_unbusy(rp->rp_ctlp->dev); 866} 867 868static void 869rphardclose(struct tty *tp) 870{ 871 struct rp_port *rp; 872 CHANNEL_t *cp; 873 874 rp = tty_softc(tp); 875 cp = &rp->rp_channel; 876 877 sFlushRxFIFO(cp); 878 sFlushTxFIFO(cp); 879 sDisTransmit(cp); 880 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN); 881 sDisRTSFlowCtl(cp); 882 sDisCTSFlowCtl(cp); 883 sDisTxSoftFlowCtl(cp); 884 sClrTxXOFF(cp); 885 886#ifdef DJA 887 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) { 888 sClrDTR(cp); 889 } 890 if(ISCALLOUT(tp->t_dev)) { 891 sClrDTR(cp); 892 } 893 tp->t_actout = FALSE; 894 wakeup(&tp->t_actout); 895 wakeup(TSA_CARR_ON(tp)); 896#endif /* DJA */ 897} 898 899static int 900rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 901{ 902 struct rp_port *rp; 903 904 rp = tty_softc(tp); 905 switch (cmd) { 906 case TIOCSBRK: 907 sSendBreak(&rp->rp_channel); 908 return (0); 909 case TIOCCBRK: 910 sClrBreak(&rp->rp_channel); 911 return (0); 912 default: 913 return ENOIOCTL; 914 } 915} 916 917static int 918rpmodem(struct tty *tp, int sigon, int sigoff) 919{ 920 struct rp_port *rp; 921 int i, j, k; 922 923 rp = tty_softc(tp); 924 if (sigon != 0 || sigoff != 0) { 925 i = j = 0; 926 if (sigon & SER_DTR) 927 i = SET_DTR; 928 if (sigoff & SER_DTR) 929 j = SET_DTR; 930 if (sigon & SER_RTS) 931 i = SET_RTS; 932 if (sigoff & SER_RTS) 933 j = SET_RTS; 934 rp->rp_channel.TxControl[3] &= ~i; 935 rp->rp_channel.TxControl[3] |= j; 936 rp_writech4(&rp->rp_channel,_INDX_ADDR, 937 le32dec(rp->rp_channel.TxControl)); 938 } else { 939 i = sGetChanStatusLo(&rp->rp_channel); 940 j = rp->rp_channel.TxControl[3]; 941 k = 0; 942 if (j & SET_DTR) 943 k |= SER_DTR; 944 if (j & SET_RTS) 945 k |= SER_RTS; 946 if (i & CD_ACT) 947 k |= SER_DCD; 948 if (i & DSR_ACT) 949 k |= SER_DSR; 950 if (i & CTS_ACT) 951 k |= SER_CTS; 952 return(k); 953 } 954 return (0); 955} 956 957static struct 958{ 959 int baud; 960 int conversion; 961} baud_table[] = { 962 {B0, 0}, {B50, BRD50}, {B75, BRD75}, 963 {B110, BRD110}, {B134, BRD134}, {B150, BRD150}, 964 {B200, BRD200}, {B300, BRD300}, {B600, BRD600}, 965 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400}, 966 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200}, 967 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400}, 968 {B57600, BRD57600}, {B76800, BRD76800}, 969 {B115200, BRD115200}, {B230400, BRD230400}, 970 {-1, -1} 971}; 972 973static int rp_convert_baud(int baud) { 974 int i; 975 976 for (i = 0; baud_table[i].baud >= 0; i++) { 977 if (baud_table[i].baud == baud) 978 break; 979 } 980 981 return baud_table[i].conversion; 982} 983 984static int 985rpparam(tp, t) 986 struct tty *tp; 987 struct termios *t; 988{ 989 struct rp_port *rp; 990 CHANNEL_t *cp; 991 int cflag, iflag, oflag, lflag; 992 int ospeed; 993#ifdef RPCLOCAL 994 int devshift; 995#endif 996 997 rp = tty_softc(tp); 998 cp = &rp->rp_channel; 999 1000 cflag = t->c_cflag; 1001#ifdef RPCLOCAL 1002 devshift = umynor / 32; 1003 devshift = 1 << devshift; 1004 if ( devshift & RPCLOCAL ) { 1005 cflag |= CLOCAL; 1006 } 1007#endif 1008 iflag = t->c_iflag; 1009 oflag = t->c_oflag; 1010 lflag = t->c_lflag; 1011 1012 ospeed = rp_convert_baud(t->c_ispeed); 1013 if(ospeed < 0 || t->c_ispeed != t->c_ospeed) 1014 return(EINVAL); 1015 1016 if(t->c_ospeed == 0) { 1017 sClrDTR(cp); 1018 return(0); 1019 } 1020 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1; 1021 1022 /* Set baud rate ----- we only pay attention to ispeed */ 1023 sSetDTR(cp); 1024 sSetRTS(cp); 1025 sSetBaud(cp, ospeed); 1026 1027 if(cflag & CSTOPB) { 1028 sSetStop2(cp); 1029 } else { 1030 sSetStop1(cp); 1031 } 1032 1033 if(cflag & PARENB) { 1034 sEnParity(cp); 1035 if(cflag & PARODD) { 1036 sSetOddParity(cp); 1037 } else { 1038 sSetEvenParity(cp); 1039 } 1040 } 1041 else { 1042 sDisParity(cp); 1043 } 1044 if((cflag & CSIZE) == CS8) { 1045 sSetData8(cp); 1046 rp->rp_imask = 0xFF; 1047 } else { 1048 sSetData7(cp); 1049 rp->rp_imask = 0x7F; 1050 } 1051 1052 if(iflag & ISTRIP) { 1053 rp->rp_imask &= 0x7F; 1054 } 1055 1056 if(cflag & CLOCAL) { 1057 rp->rp_intmask &= ~DELTA_CD; 1058 } else { 1059 rp->rp_intmask |= DELTA_CD; 1060 } 1061 1062 /* Put flow control stuff here */ 1063 1064 if(cflag & CCTS_OFLOW) { 1065 sEnCTSFlowCtl(cp); 1066 } else { 1067 sDisCTSFlowCtl(cp); 1068 } 1069 1070 if(cflag & CRTS_IFLOW) { 1071 rp->rp_rts_iflow = 1; 1072 } else { 1073 rp->rp_rts_iflow = 0; 1074 } 1075 1076 if(cflag & CRTS_IFLOW) { 1077 sEnRTSFlowCtl(cp); 1078 } else { 1079 sDisRTSFlowCtl(cp); 1080 } 1081 1082 return(0); 1083} 1084 1085static void 1086rpstart(struct tty *tp) 1087{ 1088 struct rp_port *rp; 1089 CHANNEL_t *cp; 1090 char flags; 1091 int xmit_fifo_room; 1092 int i, count, wcount; 1093 1094 rp = tty_softc(tp); 1095 cp = &rp->rp_channel; 1096 flags = rp->rp_channel.TxControl[3]; 1097 1098 if(rp->rp_xmit_stopped) { 1099 sEnTransmit(cp); 1100 rp->rp_xmit_stopped = 0; 1101 } 1102 1103 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 1104 count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room); 1105 if(xmit_fifo_room > 0) { 1106 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) { 1107 rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i])); 1108 } 1109 if ( count & 1 ) { 1110 rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]); 1111 } 1112 } 1113} 1114