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