2 * SPDX-License-Identifier: BSD-4-Clause
4 * Copyright (c) Comtrol Corporation <support@comtrol.com>
7 * ISA-specific part separated from:
8 * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted prodived that the follwoing conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notive, this list of conditions and the following disclainer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials prodided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by Comtrol Corporation.
21 * 4. The name of Comtrol Corporation may not be used to endorse or
22 * promote products derived from this software without specific
23 * prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY COMTROL CORPORATION ``AS IS'' AND ANY
26 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL COMTROL CORPORATION BE LIABLE FOR
29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <sys/cdefs.h>
40 __FBSDID("$FreeBSD$");
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/fcntl.h>
45 #include <sys/malloc.h>
48 #include <sys/kernel.h>
49 #include <sys/module.h>
50 #include <machine/resource.h>
51 #include <machine/bus.h>
56 #include <dev/rp/rpreg.h>
57 #include <dev/rp/rpvar.h>
59 #include <isa/isavar.h>
61 /* ISA-specific part of CONTROLLER_t */
62 struct ISACONTROLLER_T {
63 int MBaseIO; /* rid of the Mudbac controller for this controller */
64 int MReg0IO; /* offset0 of the Mudbac controller for this controller */
65 int MReg1IO; /* offset1 of the Mudbac controller for this controller */
66 int MReg2IO; /* offset2 of the Mudbac controller for this controller */
67 int MReg3IO; /* offset3 of the Mudbac controller for this controller */
71 typedef struct ISACONTROLLER_T ISACONTROLLER_t;
73 #define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp))
75 /***************************************************************************
76 Function: sControllerEOI
77 Purpose: Strobe the MUDBAC's End Of Interrupt bit.
78 Call: sControllerEOI(MudbacCtlP,CtlP)
79 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
80 CONTROLLER_T *CtlP; Ptr to controller structure
82 #define sControllerEOI(MudbacCtlP,CtlP) \
83 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB)
85 /***************************************************************************
87 Purpose: Disable I/O access to an AIOP
88 Call: sDisAiop(MudbacCtlP,CtlP)
89 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
90 CONTROLLER_T *CtlP; Ptr to controller structure
91 int AiopNum; Number of AIOP on controller
93 #define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \
95 ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \
96 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
99 /***************************************************************************
101 Purpose: Enable I/O access to an AIOP
102 Call: sEnAiop(MudbacCtlP,CtlP)
103 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
104 CONTROLLER_T *CtlP; Ptr to controller structure
105 int AiopNum; Number of AIOP on controller
107 #define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \
109 ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \
110 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
113 /***************************************************************************
114 Function: sGetControllerIntStatus
115 Purpose: Get the controller interrupt status
116 Call: sGetControllerIntStatus(MudbacCtlP,CtlP)
117 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
118 CONTROLLER_T *CtlP; Ptr to controller structure
119 Return: Byte_t: The controller interrupt status in the lower 4
120 bits. Bits 0 through 3 represent AIOP's 0
121 through 3 respectively. If a bit is set that
122 AIOP is interrupting. Bits 4 through 7 will
125 #define sGetControllerIntStatus(MudbacCtlP,CtlP) \
126 (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f)
128 static devclass_t rp_devclass;
129 static CONTROLLER_t *rp_controller;
130 static int rp_nisadevs;
132 static int rp_probe(device_t dev);
133 static int rp_attach(device_t dev);
134 static void rp_isareleaseresource(CONTROLLER_t *ctlp);
135 static int sInitController(CONTROLLER_T *CtlP,
136 CONTROLLER_T *MudbacCtlP,
141 static rp_aiop2rid_t rp_isa_aiop2rid;
142 static rp_aiop2off_t rp_isa_aiop2off;
143 static rp_ctlmask_t rp_isa_ctlmask;
146 rp_probe(device_t dev)
149 CONTROLLER_t *controller;
155 * We have no PnP RocketPort cards.
156 * (At least according to LINT)
158 if (isa_get_logicalid(dev) != 0)
161 /* We need IO port resource to configure an ISA device. */
162 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0)
165 unit = device_get_unit(dev);
167 device_printf(dev, "rpprobe: unit number %d invalid.\n", unit);
170 device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit);
172 ctlp = device_get_softc(dev);
173 bzero(ctlp, sizeof(*ctlp));
175 ctlp->aiop2rid = rp_isa_aiop2rid;
176 ctlp->aiop2off = rp_isa_aiop2off;
177 ctlp->ctlmask = rp_isa_ctlmask;
179 /* The IO ports of AIOPs for an ISA controller are discrete. */
181 ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO);
182 ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD, M_DEVBUF, M_NOWAIT | M_ZERO);
183 if (ctlp->io_rid == NULL || ctlp->io == NULL) {
184 device_printf(dev, "rp_attach: Out of memory.\n");
189 ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1, M_DEVBUF, M_NOWAIT | M_ZERO);
190 if (ctlp->bus_ctlp == NULL) {
191 device_printf(dev, "rp_attach: Out of memory.\n");
197 if (rp_controller != NULL) {
198 controller = rp_controller;
199 ctlp->io[0] = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0x40, RF_ACTIVE);
201 controller = rp_controller = ctlp;
202 ctlp->io[0] = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0x44, RF_ACTIVE);
204 if (ctlp->io[0] == NULL) {
205 device_printf(dev, "rp_attach: Resource not available.\n");
210 num_aiops = sInitController(ctlp,
212 MAX_AIOPS_PER_BOARD, 0,
214 if (num_aiops <= 0) {
215 device_printf(dev, "board%d init failed.\n", unit);
220 if (rp_controller == NULL)
221 rp_controller = controller;
224 device_set_desc(dev, "RocketPort ISA");
229 rp_isareleaseresource(ctlp);
235 rp_attach(device_t dev)
238 int num_ports, num_aiops;
243 unit = device_get_unit(dev);
245 ctlp = device_get_softc(dev);
248 num_aiops = sInitController(ctlp,
250 MAX_AIOPS_PER_BOARD, 0,
253 num_aiops = ctlp->NumAiop;
257 for(aiop=0; aiop < num_aiops; aiop++) {
258 sResetAiopByNum(ctlp, aiop);
259 sEnAiop(rp_controller, ctlp, aiop);
260 num_ports += sGetAiopNumChan(ctlp, aiop);
263 retval = rp_attachcommon(ctlp, num_aiops, num_ports);
270 rp_isareleaseresource(ctlp);
276 rp_isareleaseresource(CONTROLLER_t *ctlp)
280 rp_releaseresource(ctlp);
282 if (ctlp == rp_controller)
283 rp_controller = NULL;
284 if (ctlp->io != NULL) {
285 for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++)
286 if (ctlp->io[i] != NULL)
287 bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]);
288 free(ctlp->io, M_DEVBUF);
290 if (ctlp->io_rid != NULL)
291 free(ctlp->io_rid, M_DEVBUF);
292 if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) {
293 bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]);
294 rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL;
295 rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0;
297 if (ctlp->bus_ctlp != NULL)
298 free(ctlp->bus_ctlp, M_DEVBUF);
301 /***************************************************************************
302 Function: sInitController
303 Purpose: Initialization of controller global registers and controller
305 Call: sInitController(CtlP,MudbacCtlP,AiopNum,
306 IRQNum,Frequency,PeriodicOnly)
307 CONTROLLER_T *CtlP; Ptr to controller structure
308 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
309 int AiopNum; Number of Aiops
310 int IRQNum; Interrupt Request number. Can be any of the following:
311 0: Disable global interrupts
320 Byte_t Frequency: A flag identifying the frequency
321 of the periodic interrupt, can be any one of the following:
322 FREQ_DIS - periodic interrupt disabled
323 FREQ_137HZ - 137 Hertz
329 If IRQNum is set to 0 the Frequency parameter is
330 overidden, it is forced to a value of FREQ_DIS.
331 int PeriodicOnly: TRUE if all interrupts except the periodic
332 interrupt are to be blocked.
333 FALSE is both the periodic interrupt and
334 other channel interrupts are allowed.
335 If IRQNum is set to 0 the PeriodicOnly parameter is
336 overidden, it is forced to a value of FALSE.
337 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
338 initialization failed.
341 If periodic interrupts are to be disabled but AIOP interrupts
342 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
344 If interrupts are to be completely disabled set IRQNum to 0.
346 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
349 This function performs initialization of global interrupt modes,
350 but it does not actually enable global interrupts. To enable
351 and disable global interrupts use functions sEnGlobalInt() and
352 sDisGlobalInt(). Enabling of global interrupts is normally not
353 done until all other initializations are complete.
355 Even if interrupts are globally enabled, they must also be
356 individually enabled for each channel that is to generate
359 Warnings: No range checking on any of the parameters is done.
361 No context switches are allowed while executing this function.
363 After this function all AIOPs on the controller are disabled,
364 they can be enabled with sEnAiop().
367 sInitController( CONTROLLER_T *CtlP,
368 CONTROLLER_T *MudbacCtlP,
375 int ctl_base, aiop_base, aiop_size;
377 CtlP->CtlID = CTLID_0001; /* controller release 1 */
379 ISACTL(CtlP)->MBaseIO = rp_nisadevs;
380 if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) {
381 ISACTL(CtlP)->MReg0IO = 0x40 + 0;
382 ISACTL(CtlP)->MReg1IO = 0x40 + 1;
383 ISACTL(CtlP)->MReg2IO = 0x40 + 2;
384 ISACTL(CtlP)->MReg3IO = 0x40 + 3;
386 MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO;
387 ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs;
388 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);
389 ISACTL(CtlP)->MReg0IO = 0;
390 ISACTL(CtlP)->MReg1IO = 1;
391 ISACTL(CtlP)->MReg2IO = 2;
392 ISACTL(CtlP)->MReg3IO = 3;
395 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
396 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
398 if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */
400 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
401 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
405 ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
406 ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */
407 if(PeriodicOnly) /* periodic interrupt only */
409 ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY;
413 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2);
414 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3);
415 sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */
419 for(i=0; i < AiopNum; i++)
421 if (CtlP->io[i] == NULL) {
423 aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i;
424 if (rp_nisadevs == 0)
428 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);
430 aiop_base = rman_get_start(CtlP->io[i]);
431 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
432 ISACTL(CtlP)->MReg2IO,
433 ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */
434 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
435 ISACTL(CtlP)->MReg0IO,
436 (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */
437 sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */
439 CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */
440 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
442 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
443 bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]);
445 break; /* done looking for AIOPs */
448 CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */
449 rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */
450 rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC);
451 CtlP->NumAiop++; /* bump count of AIOPs */
452 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
455 if(CtlP->NumAiop == 0)
458 return(CtlP->NumAiop);
463 * Maps (aiop, offset) to rid.
466 rp_isa_aiop2rid(int aiop, int offset)
468 /* rid equals to aiop for an ISA controller. */
474 * Maps (aiop, offset) to the offset of resource.
477 rp_isa_aiop2off(int aiop, int offset)
479 /* Each aiop has its own resource. */
483 /* Read the int status for an ISA controller. */
485 rp_isa_ctlmask(CONTROLLER_t *ctlp)
487 return sGetControllerIntStatus(rp_controller,ctlp);
490 static device_method_t rp_methods[] = {
491 /* Device interface */
492 DEVMETHOD(device_probe, rp_probe),
493 DEVMETHOD(device_attach, rp_attach),
498 static driver_t rp_driver = {
501 sizeof(CONTROLLER_t),
505 * rp can be attached to an isa bus.
507 DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0);