2 * Copyright (c) Comtrol Corporation <support@comtrol.com>
5 * ISA-specific part separated from:
6 * sys/i386/isa/rp.c,v 1.33 1999/09/28 11:45:27 phk Exp
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted prodived that the follwoing conditions
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.
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
35 * $FreeBSD: src/sys/dev/rp/rp_isa.c,v 1.3.2.1 2002/06/18 03:11:46 obrien Exp $
36 * $DragonFly: src/sys/dev/serial/rp/rp_isa.c,v 1.4 2004/09/18 20:02:36 dillon Exp $
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/fcntl.h>
42 #include <sys/malloc.h>
45 #include <sys/kernel.h>
46 #include <machine/resource.h>
47 #include <machine/bus.h>
55 #include <bus/isa/isavar.h>
57 /* ISA-specific part of CONTROLLER_t */
58 struct ISACONTROLLER_T {
59 int MBaseIO; /* rid of the Mudbac controller for this controller */
60 int MReg0IO; /* offset0 of the Mudbac controller for this controller */
61 int MReg1IO; /* offset1 of the Mudbac controller for this controller */
62 int MReg2IO; /* offset2 of the Mudbac controller for this controller */
63 int MReg3IO; /* offset3 of the Mudbac controller for this controller */
67 typedef struct ISACONTROLLER_T ISACONTROLLER_t;
69 #define ISACTL(ctlp) ((ISACONTROLLER_t *)((ctlp)->bus_ctlp))
71 /***************************************************************************
72 Function: sControllerEOI
73 Purpose: Strobe the MUDBAC's End Of Interrupt bit.
74 Call: sControllerEOI(MudbacCtlP,CtlP)
75 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
76 CONTROLLER_T *CtlP; Ptr to controller structure
78 #define sControllerEOI(MudbacCtlP,CtlP) \
79 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2 | INT_STROB)
81 /***************************************************************************
83 Purpose: Disable I/O access to an AIOP
84 Call: sDisAiop(MudbacCtlP,CtlP)
85 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
86 CONTROLLER_T *CtlP; Ptr to controller structure
87 int AiopNum; Number of AIOP on controller
89 #define sDisAiop(MudbacCtlP,CtlP,AIOPNUM) \
91 ISACTL(CtlP)->MReg3 &= rp_sBitMapClrTbl[AIOPNUM]; \
92 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
95 /***************************************************************************
97 Purpose: Enable I/O access to an AIOP
98 Call: sEnAiop(MudbacCtlP,CtlP)
99 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
100 CONTROLLER_T *CtlP; Ptr to controller structure
101 int AiopNum; Number of AIOP on controller
103 #define sEnAiop(MudbacCtlP,CtlP,AIOPNUM) \
105 ISACTL(CtlP)->MReg3 |= rp_sBitMapSetTbl[AIOPNUM]; \
106 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3); \
109 /***************************************************************************
110 Function: sGetControllerIntStatus
111 Purpose: Get the controller interrupt status
112 Call: sGetControllerIntStatus(MudbacCtlP,CtlP)
113 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
114 CONTROLLER_T *CtlP; Ptr to controller structure
115 Return: Byte_t: The controller interrupt status in the lower 4
116 bits. Bits 0 through 3 represent AIOP's 0
117 through 3 respectively. If a bit is set that
118 AIOP is interrupting. Bits 4 through 7 will
121 #define sGetControllerIntStatus(MudbacCtlP,CtlP) \
122 (rp_readio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg1IO) & 0x0f)
124 static devclass_t rp_devclass;
125 static CONTROLLER_t *rp_controller;
126 static int rp_nisadevs;
128 static int rp_probe(device_t dev);
129 static int rp_attach(device_t dev);
130 static void rp_isareleaseresource(CONTROLLER_t *ctlp);
131 static int sInitController(CONTROLLER_T *CtlP,
132 CONTROLLER_T *MudbacCtlP,
137 static rp_aiop2rid_t rp_isa_aiop2rid;
138 static rp_aiop2off_t rp_isa_aiop2off;
139 static rp_ctlmask_t rp_isa_ctlmask;
142 rp_probe(device_t dev)
145 CONTROLLER_t *controller;
151 * We have no PnP RocketPort cards.
152 * (At least according to LINT)
154 if (isa_get_logicalid(dev) != 0)
157 /* We need IO port resource to configure an ISA device. */
158 if (bus_get_resource_count(dev, SYS_RES_IOPORT, 0) == 0)
161 unit = device_get_unit(dev);
163 device_printf(dev, "rpprobe: unit number %d invalid.\n", unit);
166 device_printf(dev, "probing for RocketPort(ISA) unit %d.\n", unit);
168 ctlp = device_get_softc(dev);
169 bzero(ctlp, sizeof(*ctlp));
171 ctlp->aiop2rid = rp_isa_aiop2rid;
172 ctlp->aiop2off = rp_isa_aiop2off;
173 ctlp->ctlmask = rp_isa_ctlmask;
175 /* The IO ports of AIOPs for an ISA controller are discrete. */
177 ctlp->io_rid = malloc(sizeof(*(ctlp->io_rid)) * MAX_AIOPS_PER_BOARD,
178 M_DEVBUF, M_WAITOK | M_ZERO);
179 ctlp->io = malloc(sizeof(*(ctlp->io)) * MAX_AIOPS_PER_BOARD,
180 M_DEVBUF, M_WAITOK | M_ZERO);
182 ctlp->bus_ctlp = malloc(sizeof(ISACONTROLLER_t) * 1,
183 M_DEVBUF, M_WAITOK | M_ZERO);
186 if (rp_controller != NULL) {
187 controller = rp_controller;
188 ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x40, RF_ACTIVE);
190 controller = rp_controller = ctlp;
191 ctlp->io[0] = bus_alloc_resource(dev, SYS_RES_IOPORT, &ctlp->io_rid[0], 0, ~0, 0x44, RF_ACTIVE);
193 if (ctlp->io[0] == NULL) {
194 device_printf(dev, "rp_attach: Resource not available.\n");
199 num_aiops = sInitController(ctlp,
201 MAX_AIOPS_PER_BOARD, 0,
203 if (num_aiops <= 0) {
204 device_printf(dev, "board%d init failed.\n", unit);
209 if (rp_controller == NULL)
210 rp_controller = controller;
213 device_set_desc(dev, "RocketPort ISA");
218 rp_isareleaseresource(ctlp);
224 rp_attach(device_t dev)
227 int num_ports, num_aiops;
232 unit = device_get_unit(dev);
234 ctlp = device_get_softc(dev);
237 num_aiops = sInitController(ctlp,
239 MAX_AIOPS_PER_BOARD, 0,
242 num_aiops = ctlp->NumAiop;
246 for(aiop=0; aiop < num_aiops; aiop++) {
247 sResetAiopByNum(ctlp, aiop);
248 sEnAiop(rp_controller, ctlp, aiop);
249 num_ports += sGetAiopNumChan(ctlp, aiop);
252 retval = rp_attachcommon(ctlp, num_aiops, num_ports);
259 rp_isareleaseresource(ctlp);
265 rp_isareleaseresource(CONTROLLER_t *ctlp)
269 rp_releaseresource(ctlp);
271 if (ctlp == rp_controller)
272 rp_controller = NULL;
273 if (ctlp->io != NULL) {
274 for (i = 0 ; i < MAX_AIOPS_PER_BOARD ; i++)
275 if (ctlp->io[i] != NULL)
276 bus_release_resource(ctlp->dev, SYS_RES_IOPORT, ctlp->io_rid[i], ctlp->io[i]);
277 free(ctlp->io, M_DEVBUF);
279 if (ctlp->io_rid != NULL)
280 free(ctlp->io_rid, M_DEVBUF);
281 if (rp_controller != NULL && rp_controller->io[ISACTL(ctlp)->MBaseIO] != NULL) {
282 bus_release_resource(rp_controller->dev, SYS_RES_IOPORT, rp_controller->io_rid[ISACTL(ctlp)->MBaseIO], rp_controller->io[ISACTL(ctlp)->MBaseIO]);
283 rp_controller->io[ISACTL(ctlp)->MBaseIO] = NULL;
284 rp_controller->io_rid[ISACTL(ctlp)->MBaseIO] = 0;
286 if (ctlp->bus_ctlp != NULL)
287 free(ctlp->bus_ctlp, M_DEVBUF);
290 /***************************************************************************
291 Function: sInitController
292 Purpose: Initialization of controller global registers and controller
294 Call: sInitController(CtlP,MudbacCtlP,AiopNum,
295 IRQNum,Frequency,PeriodicOnly)
296 CONTROLLER_T *CtlP; Ptr to controller structure
297 CONTROLLER_T *MudbacCtlP; Ptr to Mudbac controller structure
298 int AiopNum; Number of Aiops
299 int IRQNum; Interrupt Request number. Can be any of the following:
300 0: Disable global interrupts
309 Byte_t Frequency: A flag identifying the frequency
310 of the periodic interrupt, can be any one of the following:
311 FREQ_DIS - periodic interrupt disabled
312 FREQ_137HZ - 137 Hertz
318 If IRQNum is set to 0 the Frequency parameter is
319 overidden, it is forced to a value of FREQ_DIS.
320 int PeriodicOnly: TRUE if all interrupts except the periodic
321 interrupt are to be blocked.
322 FALSE is both the periodic interrupt and
323 other channel interrupts are allowed.
324 If IRQNum is set to 0 the PeriodicOnly parameter is
325 overidden, it is forced to a value of FALSE.
326 Return: int: Number of AIOPs on the controller, or CTLID_NULL if controller
327 initialization failed.
330 If periodic interrupts are to be disabled but AIOP interrupts
331 are allowed, set Frequency to FREQ_DIS and PeriodicOnly to FALSE.
333 If interrupts are to be completely disabled set IRQNum to 0.
335 Setting Frequency to FREQ_DIS and PeriodicOnly to TRUE is an
338 This function performs initialization of global interrupt modes,
339 but it does not actually enable global interrupts. To enable
340 and disable global interrupts use functions sEnGlobalInt() and
341 sDisGlobalInt(). Enabling of global interrupts is normally not
342 done until all other initializations are complete.
344 Even if interrupts are globally enabled, they must also be
345 individually enabled for each channel that is to generate
348 Warnings: No range checking on any of the parameters is done.
350 No context switches are allowed while executing this function.
352 After this function all AIOPs on the controller are disabled,
353 they can be enabled with sEnAiop().
356 sInitController( CONTROLLER_T *CtlP,
357 CONTROLLER_T *MudbacCtlP,
364 int ctl_base, aiop_base, aiop_size;
366 CtlP->CtlID = CTLID_0001; /* controller release 1 */
368 ISACTL(CtlP)->MBaseIO = rp_nisadevs;
369 if (MudbacCtlP->io[ISACTL(CtlP)->MBaseIO] != NULL) {
370 ISACTL(CtlP)->MReg0IO = 0x40 + 0;
371 ISACTL(CtlP)->MReg1IO = 0x40 + 1;
372 ISACTL(CtlP)->MReg2IO = 0x40 + 2;
373 ISACTL(CtlP)->MReg3IO = 0x40 + 3;
375 MudbacCtlP->io_rid[ISACTL(CtlP)->MBaseIO] = ISACTL(CtlP)->MBaseIO;
376 ctl_base = rman_get_start(MudbacCtlP->io[0]) + 0x40 + 0x400 * rp_nisadevs;
377 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);
378 ISACTL(CtlP)->MReg0IO = 0;
379 ISACTL(CtlP)->MReg1IO = 1;
380 ISACTL(CtlP)->MReg2IO = 2;
381 ISACTL(CtlP)->MReg3IO = 3;
384 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
385 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
387 if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */
389 ISACTL(CtlP)->MReg2 = 0; /* interrupt disable */
390 ISACTL(CtlP)->MReg3 = 0; /* no periodic interrupts */
394 ISACTL(CtlP)->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */
395 ISACTL(CtlP)->MReg3 = Frequency; /* set frequency */
396 if(PeriodicOnly) /* periodic interrupt only */
398 ISACTL(CtlP)->MReg3 |= PERIODIC_ONLY;
402 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg2IO,ISACTL(CtlP)->MReg2);
403 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,ISACTL(CtlP)->MReg3IO,ISACTL(CtlP)->MReg3);
404 sControllerEOI(MudbacCtlP,CtlP); /* clear EOI if warm init */
408 for(i=0; i < AiopNum; i++)
410 if (CtlP->io[i] == NULL) {
412 aiop_base = rman_get_start(CtlP->io[0]) + 0x400 * i;
413 if (rp_nisadevs == 0)
417 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);
419 aiop_base = rman_get_start(CtlP->io[i]);
420 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
421 ISACTL(CtlP)->MReg2IO,
422 ISACTL(CtlP)->MReg2 | (i & 0x03)); /* AIOP index */
423 rp_writeio1(MudbacCtlP,ISACTL(CtlP)->MBaseIO,
424 ISACTL(CtlP)->MReg0IO,
425 (Byte_t)(aiop_base >> 6)); /* set up AIOP I/O in MUDBAC */
426 sEnAiop(MudbacCtlP,CtlP,i); /* enable the AIOP */
428 CtlP->AiopID[i] = sReadAiopID(CtlP, i); /* read AIOP ID */
429 if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */
431 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
432 bus_release_resource(CtlP->dev, SYS_RES_IOPORT, CtlP->io_rid[i], CtlP->io[i]);
434 break; /* done looking for AIOPs */
437 CtlP->AiopNumChan[i] = sReadAiopNumChan(CtlP, i); /* num channels in AIOP */
438 rp_writeaiop2(CtlP,i,_INDX_ADDR,_CLK_PRE); /* clock prescaler */
439 rp_writeaiop1(CtlP,i,_INDX_DATA,CLOCK_PRESC);
440 CtlP->NumAiop++; /* bump count of AIOPs */
441 sDisAiop(MudbacCtlP,CtlP,i); /* disable AIOP */
444 if(CtlP->NumAiop == 0)
447 return(CtlP->NumAiop);
452 * Maps (aiop, offset) to rid.
455 rp_isa_aiop2rid(int aiop, int offset)
457 /* rid equals to aiop for an ISA controller. */
463 * Maps (aiop, offset) to the offset of resource.
466 rp_isa_aiop2off(int aiop, int offset)
468 /* Each aiop has its own resource. */
472 /* Read the int status for an ISA controller. */
474 rp_isa_ctlmask(CONTROLLER_t *ctlp)
476 return sGetControllerIntStatus(rp_controller,ctlp);
479 static device_method_t rp_methods[] = {
480 /* Device interface */
481 DEVMETHOD(device_probe, rp_probe),
482 DEVMETHOD(device_attach, rp_attach),
487 static driver_t rp_driver = {
490 sizeof(CONTROLLER_t),
494 * rp can be attached to an isa bus.
496 DRIVER_MODULE(rp, isa, rp_driver, rp_devclass, 0, 0);