rp_isa.c revision 105215
1/* 2 * Copyright (c) Comtrol Corporation <support@comtrol.com> 3 * All rights reserved. 4 * 5 * ISA-specific part separated from: 6 * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted prodived that the follwoing conditions 10 * are met. 11 * 1. Redistributions of source code must retain the above copyright 12 * notive, this list of conditions and the following disclainer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials prodided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Comtrol Corporation. 19 * 4. The name of Comtrol Corporation may not be used to endorse or 20 * promote products derived from this software without specific 21 * prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY 24 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * $FreeBSD: head/sys/dev/rp/rp_isa.c 105215 2002-10-16 08:48:39Z phk $ 36 */ 37 38#include <sys/param.h> 39#include <sys/systm.h> 40#include <sys/fcntl.h> 41#include <sys/malloc.h> 42#include <sys/tty.h> 43#include <sys/conf.h> 44#include <sys/kernel.h> 45#include <machine/resource.h> 46#include <machine/bus.h> 47#include <sys/bus.h> 48#include <sys/rman.h> 49 50#define ROCKET_C 51#include <dev/rp/rpreg.h> 52#include <dev/rp/rpvar.h> 53 54#include <isa/isavar.h> 55 56/* ISA-specific part of CONTROLLER_t */ 57struct ISACONTROLLER_T { 58 int MBaseIO; /* rid of the Mudbac controller for this controller */ 59 int MReg0IO; /* offset0 of the Mudbac controller for this controller */ 60 int MReg1IO; /* offset1 of the Mudbac controller for this controller */ 61 int MReg2IO; /* offset2 of the Mudbac controller for this controller */ 62 int MReg3IO; /* offset3 of the Mudbac controller for this controller */ 63 Byte_t MReg2; 64 Byte_t MReg3; 65}; 66typedef struct ISACONTROLLER_T ISACONTROLLER_t; 67 68#define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp)) 69 70/*************************************************************************** 71Function: sControllerEOI 72Purpose: Strobe the MUDBAC's End Of Interrupt bit. 73Call: sControllerEOI(MudbacCtlP,CtlP) 74 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure 75 CONTROLLER_T *CtlP; Ptr to controller structure 76*/ 77#define sControllerEOI(MudbacCtlP,CtlP) \ 78 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB) 79 80/*************************************************************************** 81Function: sDisAiop 82Purpose: Disable I/O access to an AIOP 83Call: sDisAiop(MudbacCtlP,CtlP) 84 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure 85 CONTROLLER_T *CtlP; Ptr to controller structure 86 int AiopNum; Number of AIOP on controller 87*/ 88#define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \ 89{ \ 90 ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \ 91 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ 92} 93 94/*************************************************************************** 95Function: sEnAiop 96Purpose: Enable I/O access to an AIOP 97Call: sEnAiop(MudbacCtlP,CtlP) 98 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure 99 CONTROLLER_T *CtlP; Ptr to controller structure 100 int AiopNum; Number of AIOP on controller 101*/ 102#define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \ 103{ \ 104 ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \ 105 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \ 106} 107 108/*************************************************************************** 109Function: sGetControllerIntStatus 110Purpose: Get the controller interrupt status 111Call: sGetControllerIntStatus(MudbacCtlP,CtlP) 112 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure 113 CONTROLLER_T *CtlP; Ptr to controller structure 114Return: Byte_t: The controller interrupt status in the lower 4 115 bits. Bits 0 through 3 represent AIOP's 0 116 through 3 respectively. If a bit is set that 117 AIOP is interrupting. Bits 4 through 7 will 118 always be cleared. 119*/ 120#define sGetControllerIntStatus(MudbacCtlP,CtlP) \ 121 (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f) 122 123static devclass_t rp_devclass; 124static CONTROLLER_t *rp_controller; 125static int rp_nisadevs; 126 127static int rp_probe(device_t dev); 128static int rp_attach(device_t dev); 129static void rp_isareleaseresource(CONTROLLER_t *ctlp); 130static int sInitController(CONTROLLER_T *CtlP, 131 CONTROLLER_T *MudbacCtlP, 132 int AiopNum, 133 int IRQNum, 134 Byte_t Frequency, 135 int PeriodicOnly); 136static rp_aiop2rid_t rp_isa_aiop2rid; 137static rp_aiop2off_t rp_isa_aiop2off; 138static rp_ctlmask_t rp_isa_ctlmask; 139 140static int 141rp_probe(device_t dev) 142{ 143 int unit; 144 CONTROLLER_t *controller; 145 int num_aiops; 146 CONTROLLER_t *ctlp; 147 int retval; 148 149 /* 150 * We have no PnP RocketPort cards. 151 * (At least according to LINT) 152 */ 153 if (isa_get_logicalid(dev) != 0) 154 return (ENXIO); 155 156 /* We need IO port resource to configure an ISA device. */ 157 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0) 158 return (ENXIO); 159 160 unit = device_get_unit(dev); 161 if (unit >= 4) { 162 device_printf(dev, "rpprobe: unit number %d invalid.\n", unit); 163 return (ENXIO); 164 } 165 device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit); 166 167 ctlp = device_get_softc(dev); 168 bzero(ctlp, sizeof(*ctlp)); 169 ctlp->dev = dev; 170 ctlp->aiop2rid = rp_isa_aiop2rid; 171 ctlp->aiop2off = rp_isa_aiop2off; 172 ctlp->ctlmask = rp_isa_ctlmask; 173 174 /* The IO ports of AIOPs for an ISA controller are discrete. */ 175 ctlp->io_num = 1; 176 ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO); 177 ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO); 178 if (ctlp->io_rid == NULL || ctlp->io == NULL) { 179 device_printf(dev, "rp_attach: Out of memory.\n"); 180 retval = ENOMEM; 181 goto nogo; 182 } 183 184 ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1, M_DEVBUF, M_NOWAIT | M_ZERO); 185 if (ctlp->bus_ctlp == NULL) { 186 device_printf(dev, "rp_attach: Out of memory.\n"); 187 retval = ENOMEM; 188 goto nogo; 189 } 190 191 ctlp->io_rid[0] = 0; 192 if (rp_controller != NULL) { 193 controller = rp_controller; 194 ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x40, RF_ACTIVE); 195 } else { 196 controller = rp_controller = ctlp; 197 ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x44, RF_ACTIVE); 198 } 199 if (ctlp->io[0] == NULL) { 200 device_printf(dev, "rp_attach: Resource not available.\n"); 201 retval = ENXIO; 202 goto nogo; 203 } 204 205 num_aiops = sInitController(ctlp, 206 controller, 207 MAX_AIOPS_PER_BOARD, 0, 208 FREQ_DIS, 0); 209 if (num_aiops <= 0) { 210 device_printf(dev, "board%d init failed.\n", unit); 211 retval = ENXIO; 212 goto nogo; 213 } 214 215 if (rp_controller == NULL) 216 rp_controller = controller; 217 rp_nisadevs++; 218 219 device_set_desc(dev, "RocketPort ISA"); 220 221 return (0); 222 223nogo: 224 rp_isareleaseresource(ctlp); 225 226 return (retval); 227} 228 229static int 230rp_attach(device_t dev) 231{ 232 int unit; 233 int num_ports, num_aiops; 234 int aiop; 235 CONTROLLER_t *ctlp; 236 int retval; 237 238 unit = device_get_unit(dev); 239 240 ctlp = device_get_softc(dev); 241 242#if notdef 243 num_aiops = sInitController(ctlp, 244 rp_controller, 245 MAX_AIOPS_PER_BOARD, 0, 246 FREQ_DIS, 0); 247#else 248 num_aiops = ctlp->NumAiop; 249#endif /* notdef */ 250 251 num_ports = 0; 252 for(aiop=0; aiop < num_aiops; aiop++) { 253 sResetAiopByNum(ctlp, aiop); 254 sEnAiop(rp_controller, ctlp, aiop); 255 num_ports += sGetAiopNumChan(ctlp, aiop); 256 } 257 258 retval = rp_attachcommon(ctlp, num_aiops, num_ports); 259 if (retval != 0) 260 goto nogo; 261 262 return (0); 263 264nogo: 265 rp_isareleaseresource(ctlp); 266 267 return (retval); 268} 269 270static void 271rp_isareleaseresource(CONTROLLER_t *ctlp) 272{ 273 int i; 274 275 rp_releaseresource(ctlp); 276 277 if (ctlp == rp_controller) 278 rp_controller = NULL; 279 if (ctlp->io != NULL) { 280 for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++) 281 if (ctlp->io[i] != NULL) 282 bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]); 283 free(ctlp->io, M_DEVBUF); 284 } 285 if (ctlp->io_rid != NULL) 286 free(ctlp->io_rid, M_DEVBUF); 287 if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) { 288 bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]); 289 rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL; 290 rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0; 291 } 292 if (ctlp->bus_ctlp != NULL) 293 free(ctlp->bus_ctlp, M_DEVBUF); 294} 295 296/*************************************************************************** 297Function: sInitController 298Purpose: Initialization of controller global registers and controller 299 structure. 300Call: sInitController(CtlP,MudbacCtlP,AiopNum, 301 IRQNum,Frequency,PeriodicOnly) 302 CONTROLLER_T *CtlP; Ptr to controller structure 303 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure 304 int AiopNum; Number of Aiops 305 int IRQNum; Interrupt Request number. Can be any of the following: 306 0: Disable global interrupts 307 3: IRQ 3 308 4: IRQ 4 309 5: IRQ 5 310 9: IRQ 9 311 10: IRQ 10 312 11: IRQ 11 313 12: IRQ 12 314 15: IRQ 15 315 Byte_t Frequency: A flag identifying the frequency 316 of the periodic interrupt, can be any one of the following: 317 FREQ_DIS - periodic interrupt disabled 318 FREQ_137HZ - 137 Hertz 319 FREQ_69HZ - 69 Hertz 320 FREQ_34HZ - 34 Hertz 321 FREQ_17HZ - 17 Hertz 322 FREQ_9HZ - 9 Hertz 323 FREQ_4HZ - 4 Hertz 324 If IRQNum is set to 0 the Frequency parameter is 325 overidden, it is forced to a value of FREQ_DIS. 326 int PeriodicOnly: TRUE if all interrupts except the periodic 327 interrupt are to be blocked. 328 FALSE is both the periodic interrupt and 329 other channel interrupts are allowed. 330 If IRQNum is set to 0 the PeriodicOnly parameter is 331 overidden, it is forced to a value of FALSE. 332Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller 333 initialization failed. 334 335Comments: 336 If periodic interrupts are to be disabled but AIOP interrupts 337 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE. 338 339 If interrupts are to be completely disabled set IRQNum to 0. 340 341 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an 342 invalid combination. 343 344 This function performs initialization of global interrupt modes, 345 but it does not actually enable global interrupts. To enable 346 and disable global interrupts use functions sEnGlobalInt() and 347 sDisGlobalInt(). Enabling of global interrupts is normally not 348 done until all other initializations are complete. 349 350 Even if interrupts are globally enabled, they must also be 351 individually enabled for each channel that is to generate 352 interrupts. 353 354Warnings: No range checking on any of the parameters is done. 355 356 No context switches are allowed while executing this function. 357 358 After this function all AIOPs on the controller are disabled, 359 they can be enabled with sEnAiop(). 360*/ 361static int 362sInitController( CONTROLLER_T *CtlP, 363 CONTROLLER_T *MudbacCtlP, 364 int AiopNum, 365 int IRQNum, 366 Byte_t Frequency, 367 int PeriodicOnly) 368{ 369 int i; 370 int ctl_base, aiop_base, aiop_size; 371 372 CtlP->CtlID = CTLID_0001; /* controller release 1 */ 373 374 ISACTL(CtlP)->MBaseIO = rp_nisadevs; 375 if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) { 376 ISACTL(CtlP)->MReg0IO = 0x40 + 0; 377 ISACTL(CtlP)->MReg1IO = 0x40 + 1; 378 ISACTL(CtlP)->MReg2IO = 0x40 + 2; 379 ISACTL(CtlP)->MReg3IO = 0x40 + 3; 380 } else { 381 MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO; 382 ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs; 383 MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] = bus_alloc_resource(MudbacCtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[ISACTL(CtlP)->MBaseIO], ctl_base, ctl_base + 3, 4, RF_ACTIVE); 384 ISACTL(CtlP)->MReg0IO = 0; 385 ISACTL(CtlP)->MReg1IO = 1; 386 ISACTL(CtlP)->MReg2IO = 2; 387 ISACTL(CtlP)->MReg3IO = 3; 388 } 389#if 1 390 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ 391 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ 392#else 393 if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */ 394 { 395 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */ 396 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */ 397 } 398 else 399 { 400 ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ 401 ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */ 402 if(PeriodicOnly) /* periodic interrupt only */ 403 { 404 ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY; 405 } 406 } 407#endif 408 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2); 409 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); 410 sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */ 411 412 /* Init AIOPs */ 413 CtlP->NumAiop = 0; 414 for(i=0; i < AiopNum; i++) 415 { 416 if (CtlP->io[i] == NULL) { 417 CtlP->io_rid[i] = i; 418 aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i; 419 if (rp_nisadevs == 0) 420 aiop_size = 0x44; 421 else 422 aiop_size = 0x40; 423 CtlP->io[i] = bus_alloc_resource(CtlP->dev, SYS_RES_IOPORT, &CtlP->io_rid[i], aiop_base, aiop_base + aiop_size - 1, aiop_size, RF_ACTIVE); 424 } else 425 aiop_base = rman_get_start(CtlP->io[i]); 426 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, 427 ISACTL(CtlP)->MReg2IO, 428 ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */ 429 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO, 430 ISACTL(CtlP)->MReg0IO, 431 (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */ 432 sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */ 433 434 CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */ 435 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ 436 { 437 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ 438 bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]); 439 CtlP->io[i] = NULL; 440 break; /* done looking for AIOPs */ 441 } 442 443 CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */ 444 rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */ 445 rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC); 446 CtlP->NumAiop++; /* bump count of AIOPs */ 447 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */ 448 } 449 450 if(CtlP->NumAiop == 0) 451 return(-1); 452 else 453 return(CtlP->NumAiop); 454} 455 456/* 457 * ARGSUSED 458 * Maps (aiop, offset) to rid. 459 */ 460static int 461rp_isa_aiop2rid(int aiop, int offset) 462{ 463 /* rid equals to aiop for an ISA controller. */ 464 return aiop; 465} 466 467/* 468 * ARGSUSED 469 * Maps (aiop, offset) to the offset of resource. 470 */ 471static int 472rp_isa_aiop2off(int aiop, int offset) 473{ 474 /* Each aiop has its own resource. */ 475 return offset; 476} 477 478/* Read the int status for an ISA controller. */ 479static unsigned char 480rp_isa_ctlmask(CONTROLLER_t *ctlp) 481{ 482 return sGetControllerIntStatus(rp_controller,ctlp); 483} 484 485static device_method_t rp_methods[] = { 486 /* Device interface */ 487 DEVMETHOD(device_probe, rp_probe), 488 DEVMETHOD(device_attach, rp_attach), 489 490 { 0, 0 } 491}; 492 493static driver_t rp_driver = { 494 "rp", 495 rp_methods, 496 sizeof(CONTROLLER_t), 497}; 498 499/* 500 * rp can be attached to an isa bus. 501 */ 502DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0); 503