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