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