rp.c revision 196403
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 196403 2009-08-20 19:17:53Z 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/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 555struct callout_handle rp_callout_handle; 556 557static int rp_num_ports_open = 0; 558static int rp_ndevs = 0; 559 560static int rp_num_ports[4]; /* Number of ports on each controller */ 561 562#define POLL_INTERVAL 1 563 564#define RP_ISMULTIPORT(dev) ((dev)->id_flags & 0x1) 565#define RP_MPMASTER(dev) (((dev)->id_flags >> 8) & 0xff) 566#define RP_NOTAST4(dev) ((dev)->id_flags & 0x04) 567 568static struct rp_port *p_rp_addr[4]; 569static struct rp_port *p_rp_table[MAX_RP_PORTS]; 570#define rp_addr(unit) (p_rp_addr[unit]) 571#define rp_table(port) (p_rp_table[port]) 572 573/* 574 * The top-level routines begin here 575 */ 576 577static void rpclose(struct tty *tp); 578static void rphardclose(struct tty *tp); 579static int rpmodem(struct tty *, int, int); 580static int rpparam(struct tty *, struct termios *); 581static void rpstart(struct tty *); 582static int rpioctl(struct tty *, u_long, caddr_t, struct thread *); 583static int rpopen(struct tty *); 584 585static void rp_do_receive(struct rp_port *rp, struct tty *tp, 586 CHANNEL_t *cp, unsigned int ChanStatus) 587{ 588 unsigned int CharNStat; 589 int ToRecv, ch, err = 0; 590 591 ToRecv = sGetRxCnt(cp); 592 if(ToRecv == 0) 593 return; 594 595/* If status indicates there are errored characters in the 596 FIFO, then enter status mode (a word in FIFO holds 597 characters and status) 598*/ 599 600 if(ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { 601 if(!(ChanStatus & STATMODE)) { 602 ChanStatus |= STATMODE; 603 sEnRxStatusMode(cp); 604 } 605 } 606/* 607 if we previously entered status mode then read down the 608 FIFO one word at a time, pulling apart the character and 609 the status. Update error counters depending on status. 610*/ 611 tty_lock(tp); 612 if(ChanStatus & STATMODE) { 613 while(ToRecv) { 614 CharNStat = rp_readch2(cp,sGetTxRxDataIO(cp)); 615 ch = CharNStat & 0xff; 616 617 if((CharNStat & STMBREAK) || (CharNStat & STMFRAMEH)) 618 err |= TRE_FRAMING; 619 else if (CharNStat & STMPARITYH) 620 err |= TRE_PARITY; 621 else if (CharNStat & STMRCVROVRH) { 622 rp->rp_overflows++; 623 err |= TRE_OVERRUN; 624 } 625 626 ttydisc_rint(tp, ch, err); 627 ToRecv--; 628 } 629/* 630 After emtying FIFO in status mode, turn off status mode 631*/ 632 633 if(sGetRxCnt(cp) == 0) { 634 sDisRxStatusMode(cp); 635 } 636 } else { 637 ToRecv = sGetRxCnt(cp); 638 while (ToRecv) { 639 ch = rp_readch1(cp,sGetTxRxDataIO(cp)); 640 ttydisc_rint(tp, ch & 0xff, err); 641 ToRecv--; 642 } 643 } 644 ttydisc_rint_done(tp); 645 tty_unlock(tp); 646} 647 648static void rp_handle_port(struct rp_port *rp) 649{ 650 CHANNEL_t *cp; 651 struct tty *tp; 652 unsigned int IntMask, ChanStatus; 653 654 if(!rp) 655 return; 656 657 cp = &rp->rp_channel; 658 tp = rp->rp_tty; 659 IntMask = sGetChanIntID(cp); 660 IntMask = IntMask & rp->rp_intmask; 661 ChanStatus = sGetChanStatus(cp); 662 if(IntMask & RXF_TRIG) 663 rp_do_receive(rp, tp, cp, ChanStatus); 664 if(IntMask & DELTA_CD) { 665 if(ChanStatus & CD_ACT) { 666 (void)ttydisc_modem(tp, 1); 667 } else { 668 (void)ttydisc_modem(tp, 0); 669 } 670 } 671/* oldcts = rp->rp_cts; 672 rp->rp_cts = ((ChanStatus & CTS_ACT) != 0); 673 if(oldcts != rp->rp_cts) { 674 printf("CTS change (now %s)... on port %d\n", rp->rp_cts ? "on" : "off", rp->rp_port); 675 } 676*/ 677} 678 679static void rp_do_poll(void *not_used) 680{ 681 CONTROLLER_t *ctl; 682 struct rp_port *rp; 683 struct tty *tp; 684 int unit, aiop, ch, line, count; 685 unsigned char CtlMask, AiopMask; 686 687 for(unit = 0; unit < rp_ndevs; unit++) { 688 rp = rp_addr(unit); 689 ctl = rp->rp_ctlp; 690 CtlMask = ctl->ctlmask(ctl); 691 for(aiop=0; CtlMask; CtlMask >>=1, aiop++) { 692 if(CtlMask & 1) { 693 AiopMask = sGetAiopIntStatus(ctl, aiop); 694 for(ch = 0; AiopMask; AiopMask >>=1, ch++) { 695 if(AiopMask & 1) { 696 line = (unit << 5) | (aiop << 3) | ch; 697 rp = rp_table(line); 698 rp_handle_port(rp); 699 } 700 } 701 } 702 } 703 704 for(line = 0, rp = rp_addr(unit); line < rp_num_ports[unit]; 705 line++, rp++) { 706 tp = rp->rp_tty; 707 tty_lock(tp); 708 count = sGetTxCnt(&rp->rp_channel); 709 if (count >= 0 && 710 (count <= rp->rp_restart)) { 711 rpstart(tp); 712 } 713 tty_unlock(tp); 714 } 715 } 716 if(rp_num_ports_open) 717 rp_callout_handle = timeout(rp_do_poll, 718 (void *)NULL, POLL_INTERVAL); 719} 720 721static struct ttydevsw rp_tty_class = { 722 .tsw_flags = TF_INITLOCK|TF_CALLOUT, 723 .tsw_open = rpopen, 724 .tsw_close = rpclose, 725 .tsw_outwakeup = rpstart, 726 .tsw_ioctl = rpioctl, 727 .tsw_param = rpparam, 728 .tsw_modem = rpmodem, 729 .tsw_free = rpfree, 730}; 731 732 733static void 734rpfree(void *softc) 735{ 736 struct rp_port *rp = softc; 737 CONTROLLER_t *ctlp = rp->rp_ctlp; 738 739 atomic_subtract_32(&ctlp->free, 1); 740} 741 742int 743rp_attachcommon(CONTROLLER_T *ctlp, int num_aiops, int num_ports) 744{ 745 int unit; 746 int num_chan; 747 int aiop, chan, port; 748 int ChanStatus, line, count; 749 int retval; 750 struct rp_port *rp; 751 struct tty *tp; 752 753 unit = device_get_unit(ctlp->dev); 754 755 printf("RocketPort%d (Version %s) %d ports.\n", unit, 756 RocketPortVersion, num_ports); 757 rp_num_ports[unit] = num_ports; 758 callout_handle_init(&rp_callout_handle); 759 760 ctlp->rp = rp = (struct rp_port *) 761 malloc(sizeof(struct rp_port) * num_ports, M_DEVBUF, M_NOWAIT | M_ZERO); 762 if (rp == NULL) { 763 device_printf(ctlp->dev, "rp_attachcommon: Could not malloc rp_ports structures.\n"); 764 retval = ENOMEM; 765 goto nogo; 766 } 767 768 count = unit * 32; /* board times max ports per card SG */ 769 770 bzero(rp, sizeof(struct rp_port) * num_ports); 771 rp_addr(unit) = rp; 772 773 port = 0; 774 for(aiop=0; aiop < num_aiops; aiop++) { 775 num_chan = sGetAiopNumChan(ctlp, aiop); 776 for(chan=0; chan < num_chan; chan++, port++, rp++) { 777 rp->rp_tty = tp = tty_alloc(&rp_tty_class, rp); 778 rp->rp_port = port; 779 rp->rp_ctlp = ctlp; 780 rp->rp_unit = unit; 781 rp->rp_chan = chan; 782 rp->rp_aiop = aiop; 783 784 rp->rp_intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | 785 DELTA_CD | DELTA_CTS | DELTA_DSR; 786#ifdef notdef 787 ChanStatus = sGetChanStatus(&rp->rp_channel); 788#endif /* notdef */ 789 if(sInitChan(ctlp, &rp->rp_channel, aiop, chan) == 0) { 790 device_printf(ctlp->dev, "RocketPort sInitChan(%d, %d, %d) failed.\n", 791 unit, aiop, chan); 792 retval = ENXIO; 793 goto nogo; 794 } 795 ChanStatus = sGetChanStatus(&rp->rp_channel); 796 rp->rp_cts = (ChanStatus & CTS_ACT) != 0; 797 line = (unit << 5) | (aiop << 3) | chan; 798 rp_table(line) = rp; 799 tty_makedev(tp, NULL, "R%r%r", unit, port); 800 } 801 } 802 803 rp_ndevs++; 804 mtx_init(&ctlp->hwmtx, "rp_hwmtx", NULL, MTX_DEF); 805 ctlp->hwmtx_init = 1; 806 return (0); 807 808nogo: 809 rp_releaseresource(ctlp); 810 811 return (retval); 812} 813 814void 815rp_releaseresource(CONTROLLER_t *ctlp) 816{ 817 int i, unit; 818 struct rp_port *rp; 819 820 821 unit = device_get_unit(ctlp->dev); 822 if (rp_addr(unit) != NULL) { 823 for (i = 0; i < rp_num_ports[unit]; i++) { 824 rp = rp_addr(unit) + i; 825 atomic_add_32(&ctlp->free, 1); 826 tty_lock(rp->rp_tty); 827 tty_rel_gone(rp->rp_tty); 828 } 829 } 830 831 while (ctlp->free != 0) { 832 pause("rpwt", hz / 10); 833 } 834 835 if (ctlp->rp != NULL) { 836 for (i = 0 ; i < sizeof(p_rp_addr) / sizeof(*p_rp_addr) ; i++) 837 if (p_rp_addr[i] == ctlp->rp) 838 p_rp_addr[i] = NULL; 839 for (i = 0 ; i < sizeof(p_rp_table) / sizeof(*p_rp_table) ; i++) 840 if (p_rp_table[i] == ctlp->rp) 841 p_rp_table[i] = NULL; 842 free(ctlp->rp, M_DEVBUF); 843 ctlp->rp = NULL; 844 } 845} 846 847void 848rp_untimeout(void) 849{ 850 untimeout(rp_do_poll, (void *)NULL, rp_callout_handle); 851} 852 853static int 854rpopen(struct tty *tp) 855{ 856 struct rp_port *rp; 857 int flags; 858 unsigned int IntMask, ChanStatus; 859 860 rp = tty_softc(tp); 861 862 flags = 0; 863 flags |= SET_RTS; 864 flags |= SET_DTR; 865 rp->rp_channel.TxControl[3] = 866 ((rp->rp_channel.TxControl[3] 867 & ~(SET_RTS | SET_DTR)) | flags); 868 rp_writech4(&rp->rp_channel,_INDX_ADDR, 869 le32dec(rp->rp_channel.TxControl)); 870 sSetRxTrigger(&rp->rp_channel, TRIG_1); 871 sDisRxStatusMode(&rp->rp_channel); 872 sFlushRxFIFO(&rp->rp_channel); 873 sFlushTxFIFO(&rp->rp_channel); 874 875 sEnInterrupts(&rp->rp_channel, 876 (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); 877 sSetRxTrigger(&rp->rp_channel, TRIG_1); 878 879 sDisRxStatusMode(&rp->rp_channel); 880 sClrTxXOFF(&rp->rp_channel); 881 882/* sDisRTSFlowCtl(&rp->rp_channel); 883 sDisCTSFlowCtl(&rp->rp_channel); 884*/ 885 sDisTxSoftFlowCtl(&rp->rp_channel); 886 887 sStartRxProcessor(&rp->rp_channel); 888 889 sEnRxFIFO(&rp->rp_channel); 890 sEnTransmit(&rp->rp_channel); 891 892/* sSetDTR(&rp->rp_channel); 893 sSetRTS(&rp->rp_channel); 894*/ 895 896 rp_num_ports_open++; 897 898 IntMask = sGetChanIntID(&rp->rp_channel); 899 IntMask = IntMask & rp->rp_intmask; 900 ChanStatus = sGetChanStatus(&rp->rp_channel); 901 902 if(rp_num_ports_open == 1) 903 rp_callout_handle = timeout(rp_do_poll, 904 (void *)NULL, POLL_INTERVAL); 905 906 device_busy(rp->rp_ctlp->dev); 907 return(0); 908} 909 910static void 911rpclose(struct tty *tp) 912{ 913 struct rp_port *rp; 914 915 rp = tty_softc(tp); 916 rphardclose(tp); 917 device_unbusy(rp->rp_ctlp->dev); 918} 919 920static void 921rphardclose(struct tty *tp) 922{ 923 struct rp_port *rp; 924 CHANNEL_t *cp; 925 926 rp = tty_softc(tp); 927 cp = &rp->rp_channel; 928 929 sFlushRxFIFO(cp); 930 sFlushTxFIFO(cp); 931 sDisTransmit(cp); 932 sDisInterrupts(cp, TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN); 933 sDisRTSFlowCtl(cp); 934 sDisCTSFlowCtl(cp); 935 sDisTxSoftFlowCtl(cp); 936 sClrTxXOFF(cp); 937 938#ifdef DJA 939 if(tp->t_cflag&HUPCL || !(tp->t_state&TS_ISOPEN) || !tp->t_actout) { 940 sClrDTR(cp); 941 } 942 if(ISCALLOUT(tp->t_dev)) { 943 sClrDTR(cp); 944 } 945 tp->t_actout = FALSE; 946 wakeup(&tp->t_actout); 947 wakeup(TSA_CARR_ON(tp)); 948#endif /* DJA */ 949} 950 951static int 952rpioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td) 953{ 954 struct rp_port *rp; 955 956 rp = tty_softc(tp); 957 switch (cmd) { 958 case TIOCSBRK: 959 sSendBreak(&rp->rp_channel); 960 return (0); 961 case TIOCCBRK: 962 sClrBreak(&rp->rp_channel); 963 return (0); 964 default: 965 return ENOIOCTL; 966 } 967} 968 969static int 970rpmodem(struct tty *tp, int sigon, int sigoff) 971{ 972 struct rp_port *rp; 973 int i, j, k; 974 975 rp = tty_softc(tp); 976 if (sigon != 0 || sigoff != 0) { 977 i = j = 0; 978 if (sigon & SER_DTR) 979 i = SET_DTR; 980 if (sigoff & SER_DTR) 981 j = SET_DTR; 982 if (sigon & SER_RTS) 983 i = SET_RTS; 984 if (sigoff & SER_RTS) 985 j = SET_RTS; 986 rp->rp_channel.TxControl[3] &= ~i; 987 rp->rp_channel.TxControl[3] |= j; 988 rp_writech4(&rp->rp_channel,_INDX_ADDR, 989 le32dec(rp->rp_channel.TxControl)); 990 } else { 991 i = sGetChanStatusLo(&rp->rp_channel); 992 j = rp->rp_channel.TxControl[3]; 993 k = 0; 994 if (j & SET_DTR) 995 k |= SER_DTR; 996 if (j & SET_RTS) 997 k |= SER_RTS; 998 if (i & CD_ACT) 999 k |= SER_DCD; 1000 if (i & DSR_ACT) 1001 k |= SER_DSR; 1002 if (i & CTS_ACT) 1003 k |= SER_CTS; 1004 return(k); 1005 } 1006 return (0); 1007} 1008 1009static struct 1010{ 1011 int baud; 1012 int conversion; 1013} baud_table[] = { 1014 {B0, 0}, {B50, BRD50}, {B75, BRD75}, 1015 {B110, BRD110}, {B134, BRD134}, {B150, BRD150}, 1016 {B200, BRD200}, {B300, BRD300}, {B600, BRD600}, 1017 {B1200, BRD1200}, {B1800, BRD1800}, {B2400, BRD2400}, 1018 {B4800, BRD4800}, {B9600, BRD9600}, {B19200, BRD19200}, 1019 {B38400, BRD38400}, {B7200, BRD7200}, {B14400, BRD14400}, 1020 {B57600, BRD57600}, {B76800, BRD76800}, 1021 {B115200, BRD115200}, {B230400, BRD230400}, 1022 {-1, -1} 1023}; 1024 1025static int rp_convert_baud(int baud) { 1026 int i; 1027 1028 for (i = 0; baud_table[i].baud >= 0; i++) { 1029 if (baud_table[i].baud == baud) 1030 break; 1031 } 1032 1033 return baud_table[i].conversion; 1034} 1035 1036static int 1037rpparam(tp, t) 1038 struct tty *tp; 1039 struct termios *t; 1040{ 1041 struct rp_port *rp; 1042 CHANNEL_t *cp; 1043 int cflag, iflag, oflag, lflag; 1044 int ospeed; 1045#ifdef RPCLOCAL 1046 int devshift; 1047#endif 1048 1049 rp = tty_softc(tp); 1050 cp = &rp->rp_channel; 1051 1052 cflag = t->c_cflag; 1053#ifdef RPCLOCAL 1054 devshift = umynor / 32; 1055 devshift = 1 << devshift; 1056 if ( devshift & RPCLOCAL ) { 1057 cflag |= CLOCAL; 1058 } 1059#endif 1060 iflag = t->c_iflag; 1061 oflag = t->c_oflag; 1062 lflag = t->c_lflag; 1063 1064 ospeed = rp_convert_baud(t->c_ispeed); 1065 if(ospeed < 0 || t->c_ispeed != t->c_ospeed) 1066 return(EINVAL); 1067 1068 if(t->c_ospeed == 0) { 1069 sClrDTR(cp); 1070 return(0); 1071 } 1072 rp->rp_fifo_lw = ((t->c_ospeed*2) / 1000) +1; 1073 1074 /* Set baud rate ----- we only pay attention to ispeed */ 1075 sSetDTR(cp); 1076 sSetRTS(cp); 1077 sSetBaud(cp, ospeed); 1078 1079 if(cflag & CSTOPB) { 1080 sSetStop2(cp); 1081 } else { 1082 sSetStop1(cp); 1083 } 1084 1085 if(cflag & PARENB) { 1086 sEnParity(cp); 1087 if(cflag & PARODD) { 1088 sSetOddParity(cp); 1089 } else { 1090 sSetEvenParity(cp); 1091 } 1092 } 1093 else { 1094 sDisParity(cp); 1095 } 1096 if((cflag & CSIZE) == CS8) { 1097 sSetData8(cp); 1098 rp->rp_imask = 0xFF; 1099 } else { 1100 sSetData7(cp); 1101 rp->rp_imask = 0x7F; 1102 } 1103 1104 if(iflag & ISTRIP) { 1105 rp->rp_imask &= 0x7F; 1106 } 1107 1108 if(cflag & CLOCAL) { 1109 rp->rp_intmask &= ~DELTA_CD; 1110 } else { 1111 rp->rp_intmask |= DELTA_CD; 1112 } 1113 1114 /* Put flow control stuff here */ 1115 1116 if(cflag & CCTS_OFLOW) { 1117 sEnCTSFlowCtl(cp); 1118 } else { 1119 sDisCTSFlowCtl(cp); 1120 } 1121 1122 if(cflag & CRTS_IFLOW) { 1123 rp->rp_rts_iflow = 1; 1124 } else { 1125 rp->rp_rts_iflow = 0; 1126 } 1127 1128 if(cflag & CRTS_IFLOW) { 1129 sEnRTSFlowCtl(cp); 1130 } else { 1131 sDisRTSFlowCtl(cp); 1132 } 1133 1134 return(0); 1135} 1136 1137static void 1138rpstart(struct tty *tp) 1139{ 1140 struct rp_port *rp; 1141 CHANNEL_t *cp; 1142 char flags; 1143 int xmit_fifo_room; 1144 int i, count, wcount; 1145 1146 rp = tty_softc(tp); 1147 cp = &rp->rp_channel; 1148 flags = rp->rp_channel.TxControl[3]; 1149 1150 if(rp->rp_xmit_stopped) { 1151 sEnTransmit(cp); 1152 rp->rp_xmit_stopped = 0; 1153 } 1154 1155 xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); 1156 count = ttydisc_getc(tp, &rp->TxBuf, xmit_fifo_room); 1157 if(xmit_fifo_room > 0) { 1158 for( i = 0, wcount = count >> 1; wcount > 0; i += 2, wcount-- ) { 1159 rp_writech2(cp, sGetTxRxDataIO(cp), le16dec(&rp->TxBuf[i])); 1160 } 1161 if ( count & 1 ) { 1162 rp_writech1(cp, sGetTxRxDataIO(cp), rp->TxBuf[(count-1)]); 1163 } 1164 } 1165} 1166