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