2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: isic_isa_itk_ix1.c,v 1.16 2008/04/08 20:08:50 cegger Exp $");
33 #include "opt_isicisa.h"
36 * The ITK ix1 micro ISDN card is an ISA card with one region
37 * of four io ports mapped and a fixed irq all jumpered on the card.
38 * Access to the board is straight forward and simmilar to
39 * the ELSA and DYNALINK cards. If a PCI version of this card
40 * exists all we need is probably a pci-bus attachment, all
41 * this low level routines should work immediately.
44 * - write 0x01 to ITK_CONFIG
46 * - write 0x00 to ITK_CONFIG
48 * To read or write data:
49 * - write address to ITK_ALE port
50 * - read data from or write data to ITK_ISAC_DATA port or ITK_HSCX_DATA port
51 * The two HSCX channel registers are offset by HSCXA (0x00) and HSCXB (0x40).
53 * The probe routine was derived by trial and error from a representative
54 * sample of two cards ;-) The standard way (checking HSCX versions)
55 * was extended by reading a zero from a non existent HSCX register (register
56 * 0xff). Reading the config register gives varying results, so this doesn't
57 * seem to be used as an id register (like the Teles S0/16.3).
59 * If the probe fails for your card use "options ITK_PROBE_DEBUG" to get
60 * additional debug output.
66 #include <sys/param.h>
67 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
68 #include <sys/ioccom.h>
70 #include <sys/ioctl.h>
72 #include <sys/kernel.h>
73 #include <sys/systm.h>
76 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
77 #include <sys/callout.h>
81 #include <machine/clock.h>
82 #include <i386/isa/isa_device.h>
85 #include <sys/device.h>
88 #include <sys/socket.h>
92 #include <machine/i4b_debug.h>
93 #include <machine/i4b_ioctl.h>
95 #include <netisdn/i4b_global.h>
96 #include <netisdn/i4b_debug.h>
97 #include <netisdn/i4b_ioctl.h>
98 #include <netisdn/i4b_l2.h>
99 #include <netisdn/i4b_l1l2.h>
102 #include <dev/ic/isic_l1.h>
103 #include <dev/ic/isac.h>
104 #include <dev/ic/hscx.h>
106 #include <netisdn/i4b_global.h>
108 /* Register offsets */
109 #define ITK_ISAC_DATA 0
110 #define ITK_HSCX_DATA 1
114 /* Size of IO range to allocate for this card */
115 #define ITK_IO_SIZE 4
117 /* Register offsets for the two HSCX channels */
122 * Local function prototypes
125 /* FreeBSD version */
126 static void itkix1_read_fifo(void *buf
, const void *base
, size_t len
);
127 static void itkix1_write_fifo(void *base
, const void *buf
, size_t len
);
128 static void itkix1_write_reg(u_char
*base
, u_int offset
, u_int v
);
129 static u_char
itkix1_read_reg(u_char
*base
, u_int offset
);
131 /* NetBSD/OpenBSD version */
132 static void itkix1_read_fifo(struct isic_softc
*sc
, int what
, void *buf
, size_t size
);
133 static void itkix1_write_fifo(struct isic_softc
*sc
, int what
, const void *buf
, size_t size
);
134 static void itkix1_write_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
, u_int8_t data
);
135 static u_int8_t
itkix1_read_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
);
143 isic_probe_itkix1(struct isa_device
*dev
)
145 u_int8_t hd
, hv1
, hv2
, saveale
;
148 /* save old value of this port, we're stomping over it */
149 saveale
= inb(dev
->id_iobase
+ ITK_ALE
);
151 /* select invalid register */
152 outb(dev
->id_iobase
+ ITK_ALE
, 0xff);
153 /* get HSCX data for this non existent register */
154 hd
= inb(dev
->id_iobase
+ ITK_HSCX_DATA
);
155 /* get HSCX version info */
156 outb(dev
->id_iobase
+ ITK_ALE
, HSCXA
+ H_VSTR
);
157 hv1
= inb(dev
->id_iobase
+ ITK_HSCX_DATA
);
158 outb(dev
->id_iobase
+ ITK_ALE
, HSCXB
+ H_VSTR
);
159 hv2
= inb(dev
->id_iobase
+ ITK_HSCX_DATA
);
161 /* succeed if version bits are OK and we got a zero from the
162 * non existent register. we found verison 0x05 and 0x04
165 && (((hv1
& 0x0f) == 0x05) || ((hv1
& 0x0f) == 0x04))
166 && (((hv2
& 0x0f) == 0x05) || ((hv2
& 0x0f) == 0x04));
168 /* retstore save value if we fail (if we succeed the old value
171 outb(dev
->id_iobase
+ ITK_ALE
, saveale
);
173 #ifdef ITK_PROBE_DEBUG
174 printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n",
175 hd
, hv1
, hv2
, ret
? "succeeded" : "failed");
183 isic_probe_itkix1(struct isic_attach_args
*ia
)
185 bus_space_tag_t t
= ia
->ia_maps
[0].t
;
186 bus_space_handle_t h
= ia
->ia_maps
[0].h
;
187 u_int8_t hd
, hv1
, hv2
, saveale
;
190 /* save old value of this port, we're stomping over it */
191 saveale
= bus_space_read_1(t
, h
, ITK_ALE
);
193 /* select invalid register */
194 bus_space_write_1(t
, h
, ITK_ALE
, 0xff);
195 /* get HSCX data for this non existent register */
196 hd
= bus_space_read_1(t
, h
, ITK_HSCX_DATA
);
197 /* get HSCX version info */
198 bus_space_write_1(t
, h
, ITK_ALE
, HSCXA
+ H_VSTR
);
199 hv1
= bus_space_read_1(t
, h
, ITK_HSCX_DATA
);
200 bus_space_write_1(t
, h
, ITK_ALE
, HSCXB
+ H_VSTR
);
201 hv2
= bus_space_read_1(t
, h
, ITK_HSCX_DATA
);
203 ret
= (hd
== 0) && ((hv1
& 0x0f) == 0x05) && ((hv2
& 0x0f) == 0x05);
204 /* succeed if version bits are OK and we got a zero from the
205 * non existent register. we found verison 0x05 and 0x04
208 && (((hv1
& 0x0f) == 0x05) || ((hv1
& 0x0f) == 0x04))
209 && (((hv2
& 0x0f) == 0x05) || ((hv2
& 0x0f) == 0x04));
211 /* retstore save value if we fail (if we succeed the old value
214 bus_space_write_1(t
, h
, ITK_ALE
, saveale
);
216 #ifdef ITK_PROBE_DEBUG
217 printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n",
218 hd
, hv1
, hv2
, ret
? "succeeded" : "failed");
231 isic_attach_itkix1(struct isa_device
*dev
)
233 struct isic_softc
*sc
= &l1_sc
[dev
->id_unit
];
236 sc
->sc_irq
= dev
->id_irq
;
240 /* check if we got an iobase */
241 sc
->sc_port
= dev
->id_iobase
;
243 /* setup access routines */
245 sc
->readreg
= itkix1_read_reg
;
246 sc
->writereg
= itkix1_write_reg
;
247 sc
->readfifo
= itkix1_read_fifo
;
248 sc
->writefifo
= itkix1_write_fifo
;
250 /* setup card type */
251 sc
->sc_cardtyp
= CARD_TYPEP_ITKIX1
;
253 /* setup IOM bus type */
254 sc
->sc_bustyp
= BUS_TYPE_IOM2
;
257 sc
->sc_bfifolen
= HSCX_FIFO_LEN
;
259 /* setup ISAC and HSCX base addr */
260 ISAC_BASE
= (void *) sc
->sc_port
;
261 HSCX_A_BASE
= (void *) sc
->sc_port
+ 1;
262 HSCX_B_BASE
= (void *) sc
->sc_port
+ 2;
264 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */
265 hv1
= HSCX_READ(0, H_VSTR
) & 0xf;
266 hv2
= HSCX_READ(1, H_VSTR
) & 0xf;
267 if((hv1
!= 0x05 && hv1
!= 0x04) || (hv2
!= 0x05 && hv2
!= 0x04))
269 printf("isic%d: HSCX VSTR test failed for ITK ix1 micro\n",
271 printf("isic%d: HSC0: VSTR: %#x\n",
272 dev
->id_unit
, HSCX_READ(0, H_VSTR
));
273 printf("isic%d: HSC1: VSTR: %#x\n",
274 dev
->id_unit
, HSCX_READ(1, H_VSTR
));
278 outb((dev
->id_iobase
)+ITK_CONFIG
, 1);
279 DELAY(SEC_DELAY
/ 10);
280 outb((dev
->id_iobase
)+ITK_CONFIG
, 0);
281 DELAY(SEC_DELAY
/ 10);
287 int isic_attach_itkix1(struct isic_softc
*sc
)
291 /* setup access routines */
293 sc
->readreg
= itkix1_read_reg
;
294 sc
->writereg
= itkix1_write_reg
;
295 sc
->readfifo
= itkix1_read_fifo
;
296 sc
->writefifo
= itkix1_write_fifo
;
298 /* setup card type */
299 sc
->sc_cardtyp
= CARD_TYPEP_ITKIX1
;
301 /* setup IOM bus type */
302 sc
->sc_bustyp
= BUS_TYPE_IOM2
;
305 sc
->sc_bfifolen
= HSCX_FIFO_LEN
;
307 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */
308 hv1
= HSCX_READ(0, H_VSTR
) & 0xf;
309 hv2
= HSCX_READ(1, H_VSTR
) & 0xf;
310 if((hv1
!= 0x05 && hv1
!= 0x04) || (hv2
!= 0x05 && hv2
!= 0x04))
312 printf("%s: HSCX VSTR test failed for ITK ix1 micro\n",
313 device_xname(&sc
->sc_dev
));
314 printf("%s: HSC0: VSTR: %#x\n",
315 device_xname(&sc
->sc_dev
), HSCX_READ(0, H_VSTR
));
316 printf("%s: HSC1: VSTR: %#x\n",
317 device_xname(&sc
->sc_dev
), HSCX_READ(1, H_VSTR
));
321 bus_space_write_1(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
, ITK_CONFIG
, 1);
322 DELAY(SEC_DELAY
/ 10);
323 bus_space_write_1(sc
->sc_maps
[0].t
, sc
->sc_maps
[0].h
, ITK_CONFIG
, 0);
324 DELAY(SEC_DELAY
/ 10);
332 itkix1_read_fifo(void *buf
, const void *base
, size_t len
)
334 u_int port
= (u_int
)base
& ~0x0003;
335 switch ((u_int
)base
& 3) {
337 outb(port
+ITK_ALE
, 0);
338 insb(port
+ITK_ISAC_DATA
, (u_char
*)buf
, (u_int
)len
);
341 outb(port
+ITK_ALE
, HSCXA
);
342 insb(port
+ITK_HSCX_DATA
, (u_char
*)buf
, (u_int
)len
);
345 outb(port
+ITK_ALE
, HSCXB
);
346 insb(port
+ITK_HSCX_DATA
, (u_char
*)buf
, (u_int
)len
);
352 itkix1_read_fifo(struct isic_softc
*sc
, int what
, void *buf
, size_t size
)
354 bus_space_tag_t t
= sc
->sc_maps
[0].t
;
355 bus_space_handle_t h
= sc
->sc_maps
[0].h
;
358 bus_space_write_1(t
, h
, ITK_ALE
, 0);
359 bus_space_read_multi_1(t
, h
, ITK_ISAC_DATA
, buf
, size
);
361 case ISIC_WHAT_HSCXA
:
362 bus_space_write_1(t
, h
, ITK_ALE
, HSCXA
);
363 bus_space_read_multi_1(t
, h
, ITK_HSCX_DATA
, buf
, size
);
365 case ISIC_WHAT_HSCXB
:
366 bus_space_write_1(t
, h
, ITK_ALE
, HSCXB
);
367 bus_space_read_multi_1(t
, h
, ITK_HSCX_DATA
, buf
, size
);
375 itkix1_write_fifo(void *base
, const void *buf
, size_t len
)
377 u_int port
= (u_int
)base
& ~0x0003;
378 switch ((u_int
)base
& 3) {
380 outb(port
+ITK_ALE
, 0);
381 outsb(port
+ITK_ISAC_DATA
, (u_char
*)buf
, (u_int
)len
);
384 outb(port
+ITK_ALE
, HSCXA
);
385 outsb(port
+ITK_HSCX_DATA
, (u_char
*)buf
, (u_int
)len
);
388 outb(port
+ITK_ALE
, HSCXB
);
389 outsb(port
+ITK_HSCX_DATA
, (u_char
*)buf
, (u_int
)len
);
394 static void itkix1_write_fifo(struct isic_softc
*sc
, int what
, const void *buf
, size_t size
)
396 bus_space_tag_t t
= sc
->sc_maps
[0].t
;
397 bus_space_handle_t h
= sc
->sc_maps
[0].h
;
400 bus_space_write_1(t
, h
, ITK_ALE
, 0);
401 bus_space_write_multi_1(t
, h
, ITK_ISAC_DATA
, buf
, size
);
403 case ISIC_WHAT_HSCXA
:
404 bus_space_write_1(t
, h
, ITK_ALE
, HSCXA
);
405 bus_space_write_multi_1(t
, h
, ITK_HSCX_DATA
, buf
, size
);
407 case ISIC_WHAT_HSCXB
:
408 bus_space_write_1(t
, h
, ITK_ALE
, HSCXB
);
409 bus_space_write_multi_1(t
, h
, ITK_HSCX_DATA
, buf
, size
);
417 itkix1_write_reg(u_char
*base
, u_int offset
, u_int v
)
419 u_int port
= (u_int
)base
& ~0x0003;
420 switch ((u_int
)base
& 3) {
422 outb(port
+ITK_ALE
, offset
);
423 outb(port
+ITK_ISAC_DATA
, (u_char
)v
);
426 outb(port
+ITK_ALE
, HSCXA
+offset
);
427 outb(port
+ITK_HSCX_DATA
, (u_char
)v
);
430 outb(port
+ITK_ALE
, HSCXB
+offset
);
431 outb(port
+ITK_HSCX_DATA
, (u_char
)v
);
436 static void itkix1_write_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
, u_int8_t data
)
438 bus_space_tag_t t
= sc
->sc_maps
[0].t
;
439 bus_space_handle_t h
= sc
->sc_maps
[0].h
;
442 bus_space_write_1(t
, h
, ITK_ALE
, offs
);
443 bus_space_write_1(t
, h
, ITK_ISAC_DATA
, data
);
445 case ISIC_WHAT_HSCXA
:
446 bus_space_write_1(t
, h
, ITK_ALE
, HSCXA
+offs
);
447 bus_space_write_1(t
, h
, ITK_HSCX_DATA
, data
);
449 case ISIC_WHAT_HSCXB
:
450 bus_space_write_1(t
, h
, ITK_ALE
, HSCXB
+offs
);
451 bus_space_write_1(t
, h
, ITK_HSCX_DATA
, data
);
459 itkix1_read_reg(u_char
*base
, u_int offset
)
461 u_int port
= (u_int
)base
& ~0x0003;
462 switch ((u_int
)base
& 3) {
464 outb(port
+ITK_ALE
, offset
);
465 return (inb(port
+ITK_ISAC_DATA
));
467 outb(port
+ITK_ALE
, HSCXA
+offset
);
468 return (inb(port
+ITK_HSCX_DATA
));
470 outb(port
+ITK_ALE
, HSCXB
+offset
);
471 return (inb(port
+ITK_HSCX_DATA
));
475 static u_int8_t
itkix1_read_reg(struct isic_softc
*sc
, int what
, bus_size_t offs
)
477 bus_space_tag_t t
= sc
->sc_maps
[0].t
;
478 bus_space_handle_t h
= sc
->sc_maps
[0].h
;
481 bus_space_write_1(t
, h
, ITK_ALE
, offs
);
482 return bus_space_read_1(t
, h
, ITK_ISAC_DATA
);
483 case ISIC_WHAT_HSCXA
:
484 bus_space_write_1(t
, h
, ITK_ALE
, HSCXA
+offs
);
485 return bus_space_read_1(t
, h
, ITK_HSCX_DATA
);
486 case ISIC_WHAT_HSCXB
:
487 bus_space_write_1(t
, h
, ITK_ALE
, HSCXB
+offs
);
488 return bus_space_read_1(t
, h
, ITK_HSCX_DATA
);
494 #endif /* ISICISA_ITKIX1 */