Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / serial / si / si_isa.c
1 /*
2  * Device driver for Specialix range (SI/XIO) of serial line multiplexors.
3  *
4  * Copyright (C) 2000, Peter Wemm <peter@netplex.com.au>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notices, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notices, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY ``AS IS'' AND ANY EXPRESS OR IMPLIED
16  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
17  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
18  * NO EVENT SHALL THE AUTHORS BE LIABLE.
19  *
20  * $FreeBSD: src/sys/dev/si/si_isa.c,v 1.1 2000/01/24 07:24:01 peter Exp $
21  */
22
23 #include "opt_debug_si.h"
24
25 #include <sys/param.h>
26 #include <sys/systm.h>
27 #include <sys/kernel.h>
28 #include <sys/bus.h>
29 #include <machine/bus.h>
30 #include <sys/rman.h>
31 #include <machine/resource.h>
32
33 #include <dev/si/sireg.h>
34 #include <dev/si/sivar.h>
35
36 #include <isa/isavar.h>
37
38 /* Look for a valid board at the given mem addr */
39 static int
40 si_isa_probe(device_t dev)
41 {
42         struct si_softc *sc;
43         int type;
44         u_int i, ramsize;
45         volatile unsigned char was, *ux;
46         volatile unsigned char *maddr;
47         unsigned char *paddr;
48         int unit;
49
50         sc = device_get_softc(dev);
51         unit = device_get_unit(dev);
52
53         sc->sc_mem_rid = 0;
54         sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
55                                             &sc->sc_mem_rid,
56                                             0, ~0, SIPROBEALLOC, RF_ACTIVE);
57         if (!sc->sc_mem_res)
58                 return ENXIO;
59         paddr = (caddr_t)rman_get_start(sc->sc_mem_res);/* physical */
60         maddr = rman_get_virtual(sc->sc_mem_res);       /* in kvm */
61
62         DPRINT((0, DBG_AUTOBOOT, "si%d: probe at virtual=0x%x physical=0x%x\n",
63                 unit, maddr, paddr));
64
65         /*
66          * this is a lie, but it's easier than trying to handle caching
67          * and ram conflicts in the >1M and <16M region.
68          */
69         if ((caddr_t)paddr < (caddr_t)0xA0000 ||
70             (caddr_t)paddr >= (caddr_t)0x100000) {
71                 printf("si%d: iomem (%p) out of range\n",
72                         unit, (void *)paddr);
73                 goto fail;
74         }
75
76         if (((u_int)paddr & 0x7fff) != 0) {
77                 DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
78                         "si%d: iomem (%x) not on 32k boundary\n", unit, paddr));
79                 goto fail;
80         }
81
82         /* Is there anything out there? (0x17 is just an arbitrary number) */
83         *maddr = 0x17;
84         if (*maddr != 0x17) {
85                 DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
86                         "si%d: 0x17 check fail at phys 0x%x\n", unit, paddr));
87                 goto fail;
88         }
89         /*
90          * Let's look first for a JET ISA card, since that's pretty easy
91          *
92          * All jet hosts are supposed to have this string in the IDROM,
93          * but it's not worth checking on self-IDing busses like PCI.
94          */
95         {
96                 unsigned char *jet_chk_str = "JET HOST BY KEV#";
97
98                 for (i = 0; i < strlen(jet_chk_str); i++)
99                         if (jet_chk_str[i] != *(maddr + SIJETIDSTR + 2 * i))
100                                 goto try_mk2;
101         }
102         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET first check - 0x%x\n",
103                 unit, (*(maddr+SIJETIDBASE))));
104         if (*(maddr+SIJETIDBASE) != (SISPLXID&0xff))
105                 goto try_mk2;
106         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET second check - 0x%x\n",
107                 unit, (*(maddr+SIJETIDBASE+2))));
108         if (*(maddr+SIJETIDBASE+2) != ((SISPLXID&0xff00)>>8))
109                 goto try_mk2;
110         /* It must be a Jet ISA or RIO card */
111         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL, "si%d: JET id check - 0x%x\n",
112                 unit, (*(maddr+SIUNIQID))));
113         if ((*(maddr+SIUNIQID) & 0xf0) != 0x20)
114                 goto try_mk2;
115         /* It must be a Jet ISA SI/XIO card */
116         *(maddr + SIJETCONFIG) = 0;
117         type = SIJETISA;
118         ramsize = SIJET_RAMSIZE;
119         goto got_card;
120
121 try_mk2:
122         /*
123          * OK, now to see if whatever responded is really an SI card.
124          * Try for a MK II next (SIHOST2)
125          */
126         for (i = SIPLSIG; i < SIPLSIG + 8; i++)
127                 if ((*(maddr+i) & 7) != (~(unsigned char)i & 7))
128                         goto try_mk1;
129
130         /* It must be an SIHOST2 */
131         *(maddr + SIPLRESET) = 0;
132         *(maddr + SIPLIRQCLR) = 0;
133         *(maddr + SIPLIRQSET) = 0x10;
134         type = SIHOST2;
135         ramsize = SIHOST2_RAMSIZE;
136         goto got_card;
137
138 try_mk1:
139         /*
140          * Its not a MK II, so try for a MK I (SIHOST)
141          */
142         *(maddr+SIRESET) = 0x0;         /* reset the card */
143         *(maddr+SIINTCL) = 0x0;         /* clear int */
144         *(maddr+SIRAM) = 0x17;
145         if (*(maddr+SIRAM) != (unsigned char)0x17)
146                 goto fail;
147         *(maddr+0x7ff8) = 0x17;
148         if (*(maddr+0x7ff8) != (unsigned char)0x17) {
149                 DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
150                         "si%d: 0x17 check fail at phys 0x%x = 0x%x\n",
151                         unit, paddr+0x77f8, *(maddr+0x77f8)));
152                 goto fail;
153         }
154
155         /* It must be an SIHOST (maybe?) - there must be a better way XXX */
156         type = SIHOST;
157         ramsize = SIHOST_RAMSIZE;
158
159 got_card:
160         DPRINT((0, DBG_AUTOBOOT, "si%d: found type %d card, try memory test\n",
161                 unit, type));
162         /* Try the acid test */
163         ux = maddr + SIRAM;
164         for (i = 0; i < ramsize; i++, ux++)
165                 *ux = (unsigned char)(i&0xff);
166         ux = maddr + SIRAM;
167         for (i = 0; i < ramsize; i++, ux++) {
168                 if ((was = *ux) != (unsigned char)(i&0xff)) {
169                         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
170                                 "si%d: match fail at phys 0x%x, was %x should be %x\n",
171                                 unit, paddr + i, was, i&0xff));
172                         goto fail;
173                 }
174         }
175
176         /* clear out the RAM */
177         ux = maddr + SIRAM;
178         for (i = 0; i < ramsize; i++)
179                 *ux++ = 0;
180         ux = maddr + SIRAM;
181         for (i = 0; i < ramsize; i++) {
182                 if ((was = *ux++) != 0) {
183                         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
184                                 "si%d: clear fail at phys 0x%x, was %x\n",
185                                 unit, paddr + i, was));
186                         goto fail;
187                 }
188         }
189
190         /*
191          * Success, we've found a valid board, now fill in
192          * the adapter structure.
193          */
194         switch (type) {
195         case SIHOST2:
196                 switch (isa_get_irq(dev)) {
197                 case 11:
198                 case 12:
199                 case 15:
200                         break;
201                 default:
202 bad_irq:
203                         DPRINT((0, DBG_AUTOBOOT|DBG_FAIL,
204                                 "si%d: bad IRQ value - %d\n",
205                                 unit, isa_get_irq(dev)));
206                         goto fail;
207                 }
208                 sc->sc_memsize = SIHOST2_MEMSIZE;
209                 break;
210         case SIHOST:
211                 switch (isa_get_irq(dev)) {
212                 case 11:
213                 case 12:
214                 case 15:
215                         break;
216                 default:
217                         goto bad_irq;
218                 }
219                 sc->sc_memsize = SIHOST_MEMSIZE;
220                 break;
221         case SIJETISA:
222                 switch (isa_get_irq(dev)) {
223                 case 9:
224                 case 10:
225                 case 11:
226                 case 12:
227                 case 15:
228                         break;
229                 default:
230                         goto bad_irq;
231                 }
232                 sc->sc_memsize = SIJETISA_MEMSIZE;
233                 break;
234         case SIMCA:             /* MCA */
235         default:
236                 printf("si%d: card type %d not supported\n", unit, type);
237                 goto fail;
238         }
239         sc->sc_type = type;
240         bus_release_resource(dev, SYS_RES_MEMORY,
241                              sc->sc_mem_rid, sc->sc_mem_res);
242         sc->sc_mem_res = 0;
243         return (0);             /* success! */
244
245 fail:
246         if (sc->sc_mem_res) {
247                 bus_release_resource(dev, SYS_RES_MEMORY,
248                                      sc->sc_mem_rid, sc->sc_mem_res);
249                 sc->sc_mem_res = 0;
250         }
251         return(EINVAL);
252 }
253
254 static int
255 si_isa_attach(device_t dev)
256 {
257         int error;
258         void *ih;
259         struct si_softc *sc;
260
261         error = 0;
262         ih = NULL;
263         sc = device_get_softc(dev);
264
265         sc->sc_mem_rid = 0;
266         sc->sc_mem_res = bus_alloc_resource(dev, SYS_RES_MEMORY,
267                                             &sc->sc_mem_rid,
268                                             0, ~0, 1, RF_ACTIVE);
269         if (!sc->sc_mem_res) {
270                 device_printf(dev, "couldn't map memory\n");
271                 goto fail;
272         }
273         sc->sc_paddr = (caddr_t)rman_get_start(sc->sc_mem_res);
274         sc->sc_maddr = rman_get_virtual(sc->sc_mem_res);
275
276         sc->sc_irq_rid = 0;
277         sc->sc_irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, &sc->sc_irq_rid,
278                                             0, ~0, 1, RF_ACTIVE | RF_SHAREABLE);
279         if (!sc->sc_irq_res) {
280                 device_printf(dev, "couldn't allocate interrupt\n");
281                 goto fail;
282         }
283         sc->sc_irq = rman_get_start(sc->sc_irq_res);
284         error = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_TTY,
285                                si_intr, sc,&ih);
286         if (error) {
287                 device_printf(dev, "couldn't activate interrupt\n");
288                 goto fail;
289         }
290
291         error = siattach(dev);
292         if (error)
293                 goto fail;
294         return (0);             /* success */
295
296 fail:
297         if (error == 0)
298                 error = ENXIO;
299         if (sc->sc_irq_res) {
300                 if (ih)
301                         bus_teardown_intr(dev, sc->sc_irq_res, ih);
302                 bus_release_resource(dev, SYS_RES_IRQ,
303                                      sc->sc_irq_rid, sc->sc_irq_res);
304                 sc->sc_irq_res = 0;
305         }
306         if (sc->sc_mem_res) {
307                 bus_release_resource(dev, SYS_RES_MEMORY,
308                                      sc->sc_mem_rid, sc->sc_mem_res);
309                 sc->sc_mem_res = 0;
310         }
311         return (error);
312 }
313
314 static device_method_t si_isa_methods[] = {
315         /* Device interface */
316         DEVMETHOD(device_probe,         si_isa_probe),
317         DEVMETHOD(device_attach,        si_isa_attach),
318
319         { 0, 0 }
320 };
321
322 static driver_t si_isa_driver = {
323         "si",
324         si_isa_methods,
325         sizeof(struct si_softc),
326 };
327
328 DRIVER_MODULE(si, isa, si_isa_driver, si_devclass, 0, 0);