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