kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / dev / serial / 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: src/sys/dev/rp/rp_isa.c,v 1.3.2.1 2002/06/18 03:11:46 obrien Exp $
36  * $DragonFly: src/sys/dev/serial/rp/rp_isa.c,v 1.3 2003/08/07 21:17:11 dillon Exp $
37  */
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 "rpreg.h"
53 #include "rpvar.h"
54
55 #include <bus/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);