1 /*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
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 the NetBSD
19 * Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: isic_isa_itk_ix1.c,v 1.9 2003/12/04 13:57:30 keihan Exp $");
39
40 #include "opt_isicisa.h"
41
42 /*
43 * The ITK ix1 micro ISDN card is an ISA card with one region
44 * of four io ports mapped and a fixed irq all jumpered on the card.
45 * Access to the board is straight forward and simmilar to
46 * the ELSA and DYNALINK cards. If a PCI version of this card
47 * exists all we need is probably a pci-bus attachment, all
48 * this low level routines should work imediately.
49 *
50 * To reset the card:
51 * - write 0x01 to ITK_CONFIG
52 * - wait >= 10 ms
53 * - write 0x00 to ITK_CONFIG
54 *
55 * To read or write data:
56 * - write address to ITK_ALE port
57 * - read data from or write data to ITK_ISAC_DATA port or ITK_HSCX_DATA port
58 * The two HSCX channel registers are offset by HSCXA (0x00) and HSCXB (0x40).
59 *
60 * The probe routine was derived by trial and error from a representative
61 * sample of two cards ;-) The standard way (checking HSCX versions)
62 * was extended by reading a zero from a non existent HSCX register (register
63 * 0xff). Reading the config register gives varying results, so this doesn't
64 * seem to be used as an id register (like the Teles S0/16.3).
65 *
66 * If the probe fails for your card use "options ITK_PROBE_DEBUG" to get
67 * additional debug output.
68 *
69 */
70
71 #ifdef ISICISA_ITKIX1
72
73 #include <sys/param.h>
74 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
75 #include <sys/ioccom.h>
76 #else
77 #include <sys/ioctl.h>
78 #endif
79 #include <sys/kernel.h>
80 #include <sys/systm.h>
81 #include <sys/mbuf.h>
82
83 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
84 #include <sys/callout.h>
85 #endif
86
87 #ifdef __FreeBSD__
88 #include <machine/clock.h>
89 #include <i386/isa/isa_device.h>
90 #else
91 #include <machine/bus.h>
92 #include <sys/device.h>
93 #endif
94
95 #include <sys/socket.h>
96 #include <net/if.h>
97
98 #ifdef __FreeBSD__
99 #include <machine/i4b_debug.h>
100 #include <machine/i4b_ioctl.h>
101 #else
102 #include <netisdn/i4b_global.h>
103 #include <netisdn/i4b_debug.h>
104 #include <netisdn/i4b_ioctl.h>
105 #include <netisdn/i4b_l2.h>
106 #include <netisdn/i4b_l1l2.h>
107 #endif
108
109 #include <dev/ic/isic_l1.h>
110 #include <dev/ic/isac.h>
111 #include <dev/ic/hscx.h>
112
113 #include <netisdn/i4b_global.h>
114
115 /* Register offsets */
116 #define ITK_ISAC_DATA 0
117 #define ITK_HSCX_DATA 1
118 #define ITK_ALE 2
119 #define ITK_CONFIG 3
120
121 /* Size of IO range to allocate for this card */
122 #define ITK_IO_SIZE 4
123
124 /* Register offsets for the two HSCX channels */
125 #define HSCXA 0
126 #define HSCXB 0x40
127
128 /*
129 * Local function prototypes
130 */
131 #ifdef __FreeBSD__
132 /* FreeBSD version */
133 static void itkix1_read_fifo(void *buf, const void *base, size_t len);
134 static void itkix1_write_fifo(void *base, const void *buf, size_t len);
135 static void itkix1_write_reg(u_char *base, u_int offset, u_int v);
136 static u_char itkix1_read_reg(u_char *base, u_int offset);
137 #else
138 /* NetBSD/OpenBSD version */
139 static void itkix1_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size);
140 static void itkix1_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size);
141 static void itkix1_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data);
142 static u_int8_t itkix1_read_reg(struct isic_softc *sc, int what, bus_size_t offs);
143 #endif
144
145 /*
146 * Probe for card
147 */
148 #ifdef __FreeBSD__
149 int
150 isic_probe_itkix1(struct isa_device *dev)
151 {
152 u_int8_t hd, hv1, hv2, saveale;
153 int ret;
154
155 /* save old value of this port, we're stomping over it */
156 saveale = inb(dev->id_iobase + ITK_ALE);
157
158 /* select invalid register */
159 outb(dev->id_iobase + ITK_ALE, 0xff);
160 /* get HSCX data for this non existent register */
161 hd = inb(dev->id_iobase + ITK_HSCX_DATA);
162 /* get HSCX version info */
163 outb(dev->id_iobase + ITK_ALE, HSCXA + H_VSTR);
164 hv1 = inb(dev->id_iobase + ITK_HSCX_DATA);
165 outb(dev->id_iobase + ITK_ALE, HSCXB + H_VSTR);
166 hv2 = inb(dev->id_iobase + ITK_HSCX_DATA);
167
168 /* succeed if version bits are OK and we got a zero from the
169 * non existent register. we found verison 0x05 and 0x04
170 * out there... */
171 ret = (hd == 0)
172 && (((hv1 & 0x0f) == 0x05) || ((hv1 & 0x0f) == 0x04))
173 && (((hv2 & 0x0f) == 0x05) || ((hv2 & 0x0f) == 0x04));
174
175 /* retstore save value if we fail (if we succeed the old value
176 * has no meaning) */
177 if (!ret)
178 outb(dev->id_iobase + ITK_ALE, saveale);
179
180 #ifdef ITK_PROBE_DEBUG
181 printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n",
182 hd, hv1, hv2, ret ? "succeeded" : "failed");
183 return 1;
184 #else
185 return ret;
186 #endif
187 }
188 #else
189 int
190 isic_probe_itkix1(struct isic_attach_args *ia)
191 {
192 bus_space_tag_t t = ia->ia_maps[0].t;
193 bus_space_handle_t h = ia->ia_maps[0].h;
194 u_int8_t hd, hv1, hv2, saveale;
195 int ret;
196
197 /* save old value of this port, we're stomping over it */
198 saveale = bus_space_read_1(t, h, ITK_ALE);
199
200 /* select invalid register */
201 bus_space_write_1(t, h, ITK_ALE, 0xff);
202 /* get HSCX data for this non existent register */
203 hd = bus_space_read_1(t, h, ITK_HSCX_DATA);
204 /* get HSCX version info */
205 bus_space_write_1(t, h, ITK_ALE, HSCXA + H_VSTR);
206 hv1 = bus_space_read_1(t, h, ITK_HSCX_DATA);
207 bus_space_write_1(t, h, ITK_ALE, HSCXB + H_VSTR);
208 hv2 = bus_space_read_1(t, h, ITK_HSCX_DATA);
209
210 ret = (hd == 0) && ((hv1 & 0x0f) == 0x05) && ((hv2 & 0x0f) == 0x05);
211 /* succeed if version bits are OK and we got a zero from the
212 * non existent register. we found verison 0x05 and 0x04
213 * out there... */
214 ret = (hd == 0)
215 && (((hv1 & 0x0f) == 0x05) || ((hv1 & 0x0f) == 0x04))
216 && (((hv2 & 0x0f) == 0x05) || ((hv2 & 0x0f) == 0x04));
217
218 /* retstore save value if we fail (if we succeed the old value
219 * has no meaning) */
220 if (!ret)
221 bus_space_write_1(t, h, ITK_ALE, saveale);
222
223 #ifdef ITK_PROBE_DEBUG
224 printf("\nITK ix1 micro probe: hscx = 0x%02x, v1 = 0x%02x, v2 = 0x%02x, would have %s\n",
225 hd, hv1, hv2, ret ? "succeeded" : "failed");
226 return 1;
227 #else
228 return ret;
229 #endif
230 }
231 #endif
232
233 /*
234 * Attach card
235 */
236 #ifdef __FreeBSD__
237 int
238 isic_attach_itkix1(struct isa_device *dev)
239 {
240 struct isic_softc *sc = &l1_sc[dev->id_unit];
241 u_int8_t hv1, hv2;
242
243 sc->sc_irq = dev->id_irq;
244
245 dev->id_msize = 0;
246
247 /* check if we got an iobase */
248 sc->sc_port = dev->id_iobase;
249
250 /* setup access routines */
251 sc->clearirq = NULL;
252 sc->readreg = itkix1_read_reg;
253 sc->writereg = itkix1_write_reg;
254 sc->readfifo = itkix1_read_fifo;
255 sc->writefifo = itkix1_write_fifo;
256
257 /* setup card type */
258 sc->sc_cardtyp = CARD_TYPEP_ITKIX1;
259
260 /* setup IOM bus type */
261 sc->sc_bustyp = BUS_TYPE_IOM2;
262
263 sc->sc_ipac = 0;
264 sc->sc_bfifolen = HSCX_FIFO_LEN;
265
266 /* setup ISAC and HSCX base addr */
267 ISAC_BASE = (caddr_t) sc->sc_port;
268 HSCX_A_BASE = (caddr_t) sc->sc_port + 1;
269 HSCX_B_BASE = (caddr_t) sc->sc_port + 2;
270
271 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */
272 hv1 = HSCX_READ(0, H_VSTR) & 0xf;
273 hv2 = HSCX_READ(1, H_VSTR) & 0xf;
274 if((hv1 != 0x05 && hv1 != 0x04) || (hv2 != 0x05 && hv2 != 0x04))
275 {
276 printf("isic%d: HSCX VSTR test failed for ITK ix1 micro\n",
277 dev->id_unit);
278 printf("isic%d: HSC0: VSTR: %#x\n",
279 dev->id_unit, HSCX_READ(0, H_VSTR));
280 printf("isic%d: HSC1: VSTR: %#x\n",
281 dev->id_unit, HSCX_READ(1, H_VSTR));
282 return (0);
283 }
284
285 outb((dev->id_iobase)+ITK_CONFIG, 1);
286 DELAY(SEC_DELAY / 10);
287 outb((dev->id_iobase)+ITK_CONFIG, 0);
288 DELAY(SEC_DELAY / 10);
289 return(1);
290 }
291
292 #else
293
294 int isic_attach_itkix1(struct isic_softc *sc)
295 {
296 u_int8_t hv1, hv2;
297
298 /* setup access routines */
299 sc->clearirq = NULL;
300 sc->readreg = itkix1_read_reg;
301 sc->writereg = itkix1_write_reg;
302 sc->readfifo = itkix1_read_fifo;
303 sc->writefifo = itkix1_write_fifo;
304
305 /* setup card type */
306 sc->sc_cardtyp = CARD_TYPEP_ITKIX1;
307
308 /* setup IOM bus type */
309 sc->sc_bustyp = BUS_TYPE_IOM2;
310
311 sc->sc_ipac = 0;
312 sc->sc_bfifolen = HSCX_FIFO_LEN;
313
314 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1) or 0x04 (V2.0). */
315 hv1 = HSCX_READ(0, H_VSTR) & 0xf;
316 hv2 = HSCX_READ(1, H_VSTR) & 0xf;
317 if((hv1 != 0x05 && hv1 != 0x04) || (hv2 != 0x05 && hv2 != 0x04))
318 {
319 printf("%s: HSCX VSTR test failed for ITK ix1 micro\n",
320 sc->sc_dev.dv_xname);
321 printf("%s: HSC0: VSTR: %#x\n",
322 sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR));
323 printf("%s: HSC1: VSTR: %#x\n",
324 sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR));
325 return 0;
326 }
327
328 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 1);
329 DELAY(SEC_DELAY / 10);
330 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ITK_CONFIG, 0);
331 DELAY(SEC_DELAY / 10);
332 return 1;
333 }
334
335 #endif
336
337 #ifdef __FreeBSD__
338 static void
339 itkix1_read_fifo(void *buf, const void *base, size_t len)
340 {
341 u_int port = (u_int)base & ~0x0003;
342 switch ((u_int)base & 3) {
343 case 0: /* ISAC */
344 outb(port+ITK_ALE, 0);
345 insb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len);
346 break;
347 case 1: /* HSCXA */
348 outb(port+ITK_ALE, HSCXA);
349 insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len);
350 break;
351 case 2: /* HSCXB */
352 outb(port+ITK_ALE, HSCXB);
353 insb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len);
354 break;
355 }
356 }
357 #else
358 static void
359 itkix1_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
360 {
361 bus_space_tag_t t = sc->sc_maps[0].t;
362 bus_space_handle_t h = sc->sc_maps[0].h;
363 switch (what) {
364 case ISIC_WHAT_ISAC:
365 bus_space_write_1(t, h, ITK_ALE, 0);
366 bus_space_read_multi_1(t, h, ITK_ISAC_DATA, buf, size);
367 break;
368 case ISIC_WHAT_HSCXA:
369 bus_space_write_1(t, h, ITK_ALE, HSCXA);
370 bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size);
371 break;
372 case ISIC_WHAT_HSCXB:
373 bus_space_write_1(t, h, ITK_ALE, HSCXB);
374 bus_space_read_multi_1(t, h, ITK_HSCX_DATA, buf, size);
375 break;
376 }
377 }
378 #endif
379
380 #ifdef __FreeBSD__
381 static void
382 itkix1_write_fifo(void *base, const void *buf, size_t len)
383 {
384 u_int port = (u_int)base & ~0x0003;
385 switch ((u_int)base & 3) {
386 case 0: /* ISAC */
387 outb(port+ITK_ALE, 0);
388 outsb(port+ITK_ISAC_DATA, (u_char *)buf, (u_int)len);
389 break;
390 case 1: /* HSCXA */
391 outb(port+ITK_ALE, HSCXA);
392 outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len);
393 break;
394 case 2: /* HSCXB */
395 outb(port+ITK_ALE, HSCXB);
396 outsb(port+ITK_HSCX_DATA, (u_char *)buf, (u_int)len);
397 break;
398 }
399 }
400 #else
401 static void itkix1_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
402 {
403 bus_space_tag_t t = sc->sc_maps[0].t;
404 bus_space_handle_t h = sc->sc_maps[0].h;
405 switch (what) {
406 case ISIC_WHAT_ISAC:
407 bus_space_write_1(t, h, ITK_ALE, 0);
408 bus_space_write_multi_1(t, h, ITK_ISAC_DATA, (u_int8_t*)buf, size);
409 break;
410 case ISIC_WHAT_HSCXA:
411 bus_space_write_1(t, h, ITK_ALE, HSCXA);
412 bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size);
413 break;
414 case ISIC_WHAT_HSCXB:
415 bus_space_write_1(t, h, ITK_ALE, HSCXB);
416 bus_space_write_multi_1(t, h, ITK_HSCX_DATA, (u_int8_t*)buf, size);
417 break;
418 }
419 }
420 #endif
421
422 #ifdef __FreeBSD__
423 static void
424 itkix1_write_reg(u_char *base, u_int offset, u_int v)
425 {
426 u_int port = (u_int)base & ~0x0003;
427 switch ((u_int)base & 3) {
428 case 0: /* ISAC */
429 outb(port+ITK_ALE, offset);
430 outb(port+ITK_ISAC_DATA, (u_char)v);
431 break;
432 case 1: /* HSCXA */
433 outb(port+ITK_ALE, HSCXA+offset);
434 outb(port+ITK_HSCX_DATA, (u_char)v);
435 break;
436 case 2: /* HSCXB */
437 outb(port+ITK_ALE, HSCXB+offset);
438 outb(port+ITK_HSCX_DATA, (u_char)v);
439 break;
440 }
441 }
442 #else
443 static void itkix1_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
444 {
445 bus_space_tag_t t = sc->sc_maps[0].t;
446 bus_space_handle_t h = sc->sc_maps[0].h;
447 switch (what) {
448 case ISIC_WHAT_ISAC:
449 bus_space_write_1(t, h, ITK_ALE, offs);
450 bus_space_write_1(t, h, ITK_ISAC_DATA, data);
451 break;
452 case ISIC_WHAT_HSCXA:
453 bus_space_write_1(t, h, ITK_ALE, HSCXA+offs);
454 bus_space_write_1(t, h, ITK_HSCX_DATA, data);
455 break;
456 case ISIC_WHAT_HSCXB:
457 bus_space_write_1(t, h, ITK_ALE, HSCXB+offs);
458 bus_space_write_1(t, h, ITK_HSCX_DATA, data);
459 break;
460 }
461 }
462 #endif
463
464 #ifdef __FreeBSD__
465 static u_char
466 itkix1_read_reg(u_char *base, u_int offset)
467 {
468 u_int port = (u_int)base & ~0x0003;
469 switch ((u_int)base & 3) {
470 case 0: /* ISAC */
471 outb(port+ITK_ALE, offset);
472 return (inb(port+ITK_ISAC_DATA));
473 case 1: /* HSCXA */
474 outb(port+ITK_ALE, HSCXA+offset);
475 return (inb(port+ITK_HSCX_DATA));
476 case 2: /* HSCXB */
477 outb(port+ITK_ALE, HSCXB+offset);
478 return (inb(port+ITK_HSCX_DATA));
479 }
480 }
481 #else
482 static u_int8_t itkix1_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
483 {
484 bus_space_tag_t t = sc->sc_maps[0].t;
485 bus_space_handle_t h = sc->sc_maps[0].h;
486 switch (what) {
487 case ISIC_WHAT_ISAC:
488 bus_space_write_1(t, h, ITK_ALE, offs);
489 return bus_space_read_1(t, h, ITK_ISAC_DATA);
490 case ISIC_WHAT_HSCXA:
491 bus_space_write_1(t, h, ITK_ALE, HSCXA+offs);
492 return bus_space_read_1(t, h, ITK_HSCX_DATA);
493 case ISIC_WHAT_HSCXB:
494 bus_space_write_1(t, h, ITK_ALE, HSCXB+offs);
495 return bus_space_read_1(t, h, ITK_HSCX_DATA);
496 }
497 return 0;
498 }
499 #endif
500
501 #endif /* ISICISA_ITKIX1 */
Cache object: a954fe639971c946bb1b20ddbf6d5d34
|