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