2 * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
3 * based on work by Slawa Olhovchenkov
4 * John Prince <johnp@knight-trosoft.com>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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 provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/sys/dev/digi/digi_isa.c,v 1.12 2003/08/24 17:46:03 obrien Exp $
30 * $DragonFly: src/sys/dev/serial/digi/digi_isa.c,v 1.2 2006/10/25 22:56:01 dillon Exp $
35 * Figure out how to make the non-Xi boards use memory addresses other
39 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
50 #include <dev/serial/digi/digiio.h>
51 #include <dev/serial/digi/digireg.h>
52 #include <dev/serial/digi/digi.h>
54 /* Valid i/o addresses are any of these with either 0 or 4 added */
55 static u_long digi_validio
[] = {
56 0x100, 0x110, 0x120, 0x200, 0x220, 0x300, 0x320
58 #define DIGI_NVALIDIO (sizeof(digi_validio) / sizeof(digi_validio[0]))
61 static u_long digi_validmem
[] = {
62 0x80000, 0x88000, 0x90000, 0x98000, 0xa0000, 0xa8000, 0xb0000, 0xb8000,
63 0xc0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000, 0xe8000, 0xf0000, 0xf8000,
64 0xf0000000, 0xf1000000, 0xf2000000, 0xf3000000, 0xf4000000, 0xf5000000,
65 0xf6000000, 0xf7000000, 0xf8000000, 0xf9000000, 0xfa000000, 0xfb000000,
66 0xfc000000, 0xfd000000, 0xfe000000, 0xff000000
68 #define DIGI_NVALIDMEM (sizeof(digi_validmem) / sizeof(digi_validmem[0]))
71 digi_isa_setwin(struct digi_softc
*sc
, unsigned int addr
)
73 outb(sc
->wport
, sc
->window
= FEPWIN
| (addr
>> sc
->win_bits
));
74 return (sc
->vmem
+ (addr
% sc
->win_size
));
78 digi_xi_setwin(struct digi_softc
*sc
, unsigned int addr
)
80 outb(sc
->wport
, sc
->window
= FEPMEM
);
81 return (sc
->vmem
+ addr
);
85 digi_isa_hidewin(struct digi_softc
*sc
)
87 outb(sc
->wport
, sc
->window
= 0);
88 /* outb(sc->port, 0); */
92 digi_isa_towin(struct digi_softc
*sc
, int win
)
94 outb(sc
->wport
, sc
->window
= win
);
98 digi_xi_towin(struct digi_softc
*sc
, int win
)
100 outb(sc
->wport
, sc
->window
= FEPMEM
);
104 * sc->port should be set and its resource allocated.
107 digi_isa_check(struct digi_softc
*sc
)
113 /* Invasive probe - reset the card */
114 outb(sc
->port
, FEPRST
);
115 for (i
= 0; (inb(sc
->port
) & FEPMASK
) != FEPRST
; i
++) {
118 digi_delay(sc
, "digirst", 1);
120 DLOG(DIGIDB_INIT
, (sc
->dev
, "got reset after %d iterations\n", i
));
122 ident
= inb(sc
->port
);
125 * NOTE, this probe is all wrong. I haven't got the data sheets !
128 DLOG(DIGIDB_INIT
, (sc
->dev
, "board type is 0x%x\n", ident
));
136 sc
->csigs
= &digi_xixe_signals
;
137 switch (ident
& 0x30) {
139 sc
->name
= "Digiboard PC/Xi 64K";
140 sc
->mem_seg
= 0xf000;
141 sc
->win_size
= 0x10000;
145 sc
->name
= "Digiboard PC/Xi 128K";
146 sc
->mem_seg
= 0xE000;
147 sc
->win_size
= 0x20000;
151 sc
->name
= "Digiboard PC/Xi 256K";
152 sc
->mem_seg
= 0xC000;
153 sc
->win_size
= 0x40000;
157 sc
->name
= "Digiboard PC/Xi 512K";
158 sc
->mem_seg
= 0x8000;
159 sc
->win_size
= 0x80000;
163 sc
->wport
= sc
->port
;
166 sc
->setwin
= digi_xi_setwin
;
167 sc
->hidewin
= digi_isa_hidewin
;
168 sc
->towin
= digi_xi_towin
;
172 sc
->name
= "Digiboard PC/Xem";
174 sc
->csigs
= &digi_normal_signals
;
175 sc
->win_size
= 0x8000;
177 sc
->wport
= sc
->port
+ 1;
180 sc
->setwin
= digi_isa_setwin
;
181 sc
->hidewin
= digi_isa_hidewin
;
182 sc
->towin
= digi_isa_towin
;
187 ident
= inb(sc
->port
);
190 device_printf(sc
->dev
, "PC/Xm is unsupported\n");
194 sc
->mem_seg
= 0xf000;
196 if (!(ident
& 0xc0)) {
197 sc
->name
= "Digiboard PC/Xe 64K";
199 sc
->csigs
= &digi_xixe_signals
;
200 sc
->win_size
= 0x10000;
202 sc
->wport
= sc
->port
;
204 sc
->name
= "Digiboard PC/Xe 64/8K (windowed)";
206 sc
->csigs
= &digi_normal_signals
;
207 sc
->win_size
= 0x2000;
209 sc
->wport
= sc
->port
+ 1;
213 sc
->setwin
= digi_isa_setwin
;
214 sc
->hidewin
= digi_isa_hidewin
;
215 sc
->towin
= digi_isa_towin
;
218 return (sc
->name
!= NULL
);
222 digi_isa_probe(device_t dev
)
224 struct digi_softc
*sc
= device_get_softc(dev
);
227 KASSERT(sc
, ("digi%d: softc not allocated in digi_isa_probe\n",
228 device_get_unit(dev
)));
230 bzero(sc
, sizeof(*sc
));
231 sc
->status
= DIGI_STATUS_NOTINIT
;
233 sc
->res
.unit
= device_get_unit(dev
);
234 if (sc
->res
.unit
>= 16) {
235 /* Don't overflow our control mask */
236 device_printf(dev
, "At most 16 digiboards may be used\n");
239 DLOG(DIGIDB_INIT
, (sc
->dev
, "probing on isa bus\n"));
241 /* Check that we've got a valid i/o address */
242 if ((sc
->port
= bus_get_resource_start(dev
, SYS_RES_IOPORT
, 0)) == 0) {
243 DLOG(DIGIDB_INIT
, (sc
->dev
, "io address not given\n"));
246 for (i
= 0; i
< DIGI_NVALIDIO
; i
++)
247 if (sc
->port
== digi_validio
[i
] ||
248 sc
->port
== digi_validio
[i
] + 4)
250 if (i
== DIGI_NVALIDIO
) {
251 device_printf(dev
, "0x%03x: Invalid i/o address\n", sc
->port
);
255 /* Ditto for our memory address */
256 if ((sc
->pmem
= bus_get_resource_start(dev
, SYS_RES_MEMORY
, 0)) == 0)
258 for (i
= 0; i
< DIGI_NVALIDMEM
; i
++)
259 if (sc
->pmem
== digi_validmem
[i
])
261 if (i
== DIGI_NVALIDMEM
) {
262 device_printf(dev
, "0x%lx: Invalid memory address\n", sc
->pmem
);
265 if ((sc
->pmem
& 0xfffffful
) != sc
->pmem
) {
266 device_printf(dev
, "0x%lx: Memory address not supported\n",
270 sc
->vmem
= (u_char
*)sc
->pmem
;
272 DLOG(DIGIDB_INIT
, (sc
->dev
, "isa? port 0x%03x mem 0x%lx\n",
273 sc
->port
, sc
->pmem
));
275 /* Temporarily map our io ports */
277 sc
->res
.io
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &sc
->res
.iorid
,
278 0ul, ~0ul, IO_SIZE
, RF_ACTIVE
);
279 if (sc
->res
.io
== NULL
)
282 /* Check the type of card and get internal memory characteristics */
283 if (!digi_isa_check(sc
)) {
284 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->res
.iorid
,
289 /* Temporarily map our memory */
291 sc
->res
.mem
= bus_alloc_resource(dev
, SYS_RES_MEMORY
, &sc
->res
.mrid
,
292 0ul, ~0ul, sc
->win_size
, RF_ALLOCATED
);
293 if (sc
->res
.mem
== NULL
) {
294 device_printf(dev
, "0x%lx: Memory range is in use\n", sc
->pmem
);
295 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->res
.iorid
,
300 outb(sc
->port
, FEPCLR
); /* drop RESET */
301 sc
->hidewin(sc
); /* set initial sc->window */
303 bus_release_resource(dev
, SYS_RES_MEMORY
, sc
->res
.mrid
, sc
->res
.mem
);
304 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->res
.iorid
, sc
->res
.io
);
306 /* Let digi_isa_attach() know what we've found */
307 bus_set_resource(dev
, SYS_RES_IOPORT
, 0, sc
->port
, IO_SIZE
);
308 bus_set_resource(dev
, SYS_RES_MEMORY
, 0, sc
->pmem
, sc
->win_size
);
310 DLOG(DIGIDB_INIT
, (sc
->dev
, "Probe returns -10\n"));
312 return (-10); /* Other drivers are preferred for now */
316 digi_isa_attach(device_t dev
)
318 struct digi_softc
*sc
= device_get_softc(dev
);
322 u_long msize
, iosize
;
325 KASSERT(sc
, ("digi%d: softc not allocated in digi_isa_attach\n",
326 device_get_unit(dev
)));
329 bzero(sc
, sizeof(*sc
));
330 sc
->status
= DIGI_STATUS_NOTINIT
;
332 sc
->res
.unit
= device_get_unit(dev
);
333 DLOG(DIGIDB_INIT
, (sc
->dev
, "attaching\n"));
335 bus_get_resource(dev
, SYS_RES_IOPORT
, 0, &scport
, &iosize
);
336 bus_get_resource(dev
, SYS_RES_MEMORY
, 0, &sc
->pmem
, &msize
);
338 /* sc->altpin = !!(device_get_flags(dev) & DGBFLAG_ALTPIN); */
340 /* Allocate resources (verified in digi_isa_probe()) */
342 sc
->res
.io
= bus_alloc_resource(dev
, SYS_RES_IOPORT
, &sc
->res
.iorid
,
343 0ul, ~0ul, iosize
, RF_ACTIVE
);
344 if (sc
->res
.io
== NULL
)
347 /* Check the type of card and get internal memory characteristics */
348 DLOG(DIGIDB_INIT
, (sc
->dev
, "Checking card type\n"));
349 if (!digi_isa_check(sc
))
352 callout_init(&sc
->callout
);
353 callout_init(&sc
->inttest
);
356 sc
->res
.mem
= bus_alloc_resource(dev
, SYS_RES_MEMORY
, &sc
->res
.mrid
,
357 0ul, ~0ul, msize
, RF_ACTIVE
);
358 if (sc
->res
.mem
== NULL
) {
359 device_printf(dev
, "0x%lx: Memory range is in use\n", sc
->pmem
);
365 sc
->vmem
= pmap_mapdev(sc
->pmem
, msize
);
367 DLOG(DIGIDB_INIT
, (sc
->dev
, "internal memory segment 0x%x\n",
370 /* Start by resetting the card */
372 if (sc
->model
== PCXI
)
375 outb(sc
->port
, reset
);
376 for (i
= 0; (inb(sc
->port
) & FEPMASK
) != reset
; i
++) {
378 device_printf(dev
, "1st reset failed\n");
382 digi_delay(sc
, "digirst1", 1);
384 DLOG(DIGIDB_INIT
, (sc
->dev
, "got reset after %d iterations\n", i
));
386 if (sc
->model
!= PCXI
) {
387 t
= (sc
->pmem
>> 8) & 0xffe0;
388 if (sc
->model
== PCXEVE
)
389 t
|= 0x10; /* enable windowing */
390 outb(sc
->port
+ 2, t
& 0xff);
391 outb(sc
->port
+ 3, t
>> 8);
394 if (sc
->model
== PCXI
|| sc
->model
== PCXE
) {
395 outb(sc
->port
, FEPRST
| FEPMEM
);
396 for (i
= 0; (inb(sc
->port
) & FEPMASK
) != FEPRST
; i
++) {
399 "memory reservation failed (0x%02x)\n",
404 digi_delay(sc
, "digirst2", 1);
406 DLOG(DIGIDB_INIT
, (sc
->dev
, "got memory after %d iterations\n",
410 DLOG(DIGIDB_INIT
, (sc
->dev
, "short memory test\n"));
411 ptr
= sc
->setwin(sc
, BOTWIN
);
412 vD(ptr
) = 0xA55A3CC3;
413 if (vD(ptr
) != 0xA55A3CC3) {
414 device_printf(dev
, "1st memory test failed\n");
418 DLOG(DIGIDB_INIT
, (sc
->dev
, "1st memory test ok\n"));
420 ptr
= sc
->setwin(sc
, TOPWIN
);
421 vD(ptr
) = 0x5AA5C33C;
422 if (vD(ptr
) != 0x5AA5C33C) {
423 device_printf(dev
, "2nd memory test failed\n");
427 DLOG(DIGIDB_INIT
, (sc
->dev
, "2nd memory test ok\n"));
429 ptr
= sc
->setwin(sc
, BIOSCODE
+ ((0xf000 - sc
->mem_seg
) << 4));
430 vD(ptr
) = 0x5AA5C33C;
431 if (vD(ptr
) != 0x5AA5C33C) {
432 device_printf(dev
, "3rd (BIOS) memory test failed\n");
436 DLOG(DIGIDB_INIT
, (sc
->dev
, "3rd memory test ok\n"));
438 if ((res
= digi_attach(sc
)) == 0)
442 if (sc
->res
.mem
!= NULL
) {
443 bus_release_resource(dev
, SYS_RES_MEMORY
, sc
->res
.mrid
,
447 if (sc
->res
.io
!= NULL
) {
448 bus_release_resource(dev
, SYS_RES_IOPORT
, sc
->res
.iorid
,
456 static device_method_t digi_isa_methods
[] = {
457 /* Device interface */
458 DEVMETHOD(device_probe
, digi_isa_probe
),
459 DEVMETHOD(device_attach
, digi_isa_attach
),
460 DEVMETHOD(device_detach
, digi_detach
),
461 DEVMETHOD(device_shutdown
, digi_shutdown
),
465 static driver_t digi_isa_drv
= {
468 sizeof(struct digi_softc
),
470 DRIVER_MODULE(digi
, isa
, digi_isa_drv
, digi_devclass
, 0, 0);