1 /* ISDN4BSD code */
2 /*
3 * Copyright (c) 1998 Martijn Plak. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the names of any co-contributors
15 * may be used to endorse or promote products derived from this software
16 * without specific prior written permission.
17 * 4. Altered versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software and/or documentation.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 *---------------------------------------------------------------------------
33 *
34 * isdn4bsd layer1 driver for Dynalink IS64PH isdn TA
35 * ==================================================
36 *
37 * $Id: isic_isapnp_dynalink.c,v 1.2 2003/05/14 19:55:07 tg Stab $
38 *
39 * last edit-date: [Fri Jan 5 11:38:29 2001]
40 *
41 * written by Martijn Plak (martijn@be3.com)
42 *
43 * -mp 11 jun 1998 first try, code borrowed from Creatix driver
44 * -mp 18 jun 1998 cleaned up code
45 * -hm FreeBSD PnP
46 * -mp 17 dec 1998 made it compile again
47 *
48 *---------------------------------------------------------------------------*/
49
50 /* NOTES:
51
52 This driver was written for the Dynalink IS64PH ISDN TA, based on two
53 Siemens chips (HSCX 21525 and ISAC 2186). It is sold in the Netherlands.
54
55 model numbers found on (my) card:
56 IS64PH, TAS100H-N, P/N:89590555, TA200S100045521
57
58 chips:
59 Siemens PSB 21525N, HSCX TE V2.1
60 Siemens PSB 2186N, ISAC-S TE V1.1
61 95MS14, PNP
62
63 plug-and-play info:
64 device id "ASU1688"
65 vendor id 0x88167506
66 serial 0x00000044
67 i/o port 4 byte alignment, 4 bytes requested,
68 10 bit i/o decoding, 0x100-0x3f8 (?)
69 irq 3,4,5,9,10,11,12,15, high true, edge sensitive
70
71 At the moment I'm writing this Dynalink is replacing this card with
72 one based on a single Siemens chip (IPAC). It will apparently be sold
73 under the same model name.
74
75 This driver might also work for Asuscom cards.
76 */
77
78 #include <sys/cdefs.h>
79 __KERNEL_RCSID(0, "$NetBSD: isic_isapnp_dynalink.c,v 1.4 2002/03/24 20:35:51 martin Exp $");
80
81 #ifdef ISICPNP_DYNALINK
82
83 /* HEADERS
84 */
85
86 #include <sys/param.h>
87 #include <sys/kernel.h>
88 #include <sys/systm.h>
89 #include <sys/mbuf.h>
90 #include <sys/socket.h>
91 #include <net/if.h>
92
93 #include <sys/timeout.h>
94
95 #ifdef __FreeBSD__
96 #if __FreeBSD__ >= 3
97 #include <sys/ioccom.h>
98 #else
99 #include <sys/ioctl.h>
100 #endif
101 #include <machine/clock.h>
102 #include <i386/isa/isa_device.h>
103 #include <i386/isa/pnp.h>
104 #elif defined(__bsdi__)
105 #include <i386/isa/pnp.h>
106 #else
107 #include <machine/bus.h>
108 #include <sys/device.h>
109 #endif
110
111 #ifdef __FreeBSD__
112 #include <machine/i4b_debug.h>
113 #include <machine/i4b_ioctl.h>
114 #else
115 #include <netisdn/i4b_debug.h>
116 #include <netisdn/i4b_ioctl.h>
117 #endif
118
119 #include <netisdn/i4b_global.h>
120 #include <netisdn/i4b_l2.h>
121 #include <netisdn/i4b_l1l2.h>
122 #include <netisdn/i4b_mbuf.h>
123
124 #include <dev/ic/isic_l1.h>
125 #include <dev/ic/isac.h>
126 #include <dev/ic/hscx.h>
127
128 #if defined(__FreeBSD__) || defined(__bsdi__)
129 static void dynalink_read_fifo(void *buf, const void *base, size_t len);
130 static void dynalink_write_fifo(void *base, const void *buf, size_t len);
131 static void dynalink_write_reg(u_char *base, u_int offset, u_int v);
132 static u_char dynalink_read_reg(u_char *base, u_int offset);
133 #endif
134
135 #ifdef __FreeBSD__
136 extern struct isa_driver isicdriver;
137 #endif
138 #ifdef __bsdi__
139 extern struct cfdriver isiccd;
140 #endif
141
142 #if !defined(__FreeBSD__) && !defined(__bsdi__)
143 static void dynalink_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size);
144 static void dynalink_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size);
145 static void dynalink_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data);
146 static u_int8_t dynalink_read_reg(struct isic_softc *sc, int what, bus_size_t offs);
147 void isic_attach_Dyn(struct isic_softc *sc);
148 #endif
149
150 /* io address mapping */
151 #define ISAC 0
152 #define HSCX 1
153 #define ADDR 2
154
155 /* ADDR bits */
156 #define ADDRMASK 0x7F
157 #define RESET 0x80
158
159 /* HSCX register offsets */
160 #define HSCXA 0x00
161 #define HSCXB 0x40
162
163 #if defined(__FreeBSD__) || defined(__bsdi__)
164 /* base address juggling */
165 #define HSCXB_HACK 0x400
166 #define IOBASE(addr) (((int)addr)&0x3FC)
167 #define IOADDR(addr) (((int)addr)&0x3FF)
168 #define IS_HSCXB_HACK(addr) ((((int)addr)&HSCXB_HACK)?HSCXB:HSCXA)
169 #endif
170
171 #ifdef __FreeBSD__
172 /* ISIC probe and attach
173 */
174
175 int
isic_probe_Dyn(struct isa_device * dev,unsigned int iobase2)176 isic_probe_Dyn(struct isa_device *dev, unsigned int iobase2)
177 {
178
179 struct isic_softc *sc = &l1_sc[dev->id_unit];
180
181 if(dev->id_unit >= ISIC_MAXUNIT)
182 {
183 printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dynalink IS64PH.\n",
184 dev->id_unit, dev->id_unit);
185 return(0);
186 }
187 sc->sc_unit = dev->id_unit;
188
189 /* check IRQ validity */
190
191 switch(ffs(dev->id_irq) - 1)
192 {
193 case 3:
194 case 4:
195 case 5:
196 case 9:
197 case 10:
198 case 11:
199 case 12:
200 case 15:
201 break;
202
203 default:
204 printf("isic%d: Error, invalid IRQ [%d] specified for Dynalink IS64PH.\n",
205 dev->id_unit, ffs(dev->id_irq)-1);
206 return(0);
207 break;
208 }
209 sc->sc_irq = dev->id_irq;
210
211 /* check if memory addr specified */
212
213 if(dev->id_maddr)
214 {
215 printf("isic%d: Error, mem addr 0x%lx specified for Dynalink IS64PH.\n",
216 dev->id_unit, (u_long)dev->id_maddr);
217 return (0);
218 }
219 dev->id_msize = 0;
220
221 /* check if we got an iobase */
222 if ( (dev->id_iobase < 0x100) ||
223 (dev->id_iobase > 0x3f8) ||
224 (dev->id_iobase & 3) )
225 {
226 printf("isic%d: Error, invalid iobase 0x%x specified for Dynalink!\n", dev->id_unit, dev->id_iobase);
227 return(0);
228 }
229 sc->sc_port = dev->id_iobase;
230
231 /* setup access routines */
232 sc->clearirq = NULL;
233 sc->readreg = dynalink_read_reg;
234 sc->writereg = dynalink_write_reg;
235 sc->readfifo = dynalink_read_fifo;
236 sc->writefifo = dynalink_write_fifo;
237
238 /* setup card type */
239 sc->sc_cardtyp = CARD_TYPEP_DYNALINK;
240
241 /* setup IOM bus type */
242 sc->sc_bustyp = BUS_TYPE_IOM2;
243
244 sc->sc_ipac = 0;
245 sc->sc_bfifolen = HSCX_FIFO_LEN;
246
247 /* setup ISAC and HSCX base addr */
248 ISAC_BASE = (caddr_t) sc->sc_port;
249 HSCX_A_BASE = (caddr_t) sc->sc_port + 1;
250 HSCX_B_BASE = (caddr_t) sc->sc_port + 1 + HSCXB_HACK;
251
252 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */
253 if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
254 ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
255 {
256 printf("isic%d: HSCX VSTR test failed for Dynalink\n",
257 dev->id_unit);
258 printf("isic%d: HSC0: VSTR: %#x\n",
259 dev->id_unit, HSCX_READ(0, H_VSTR));
260 printf("isic%d: HSC1: VSTR: %#x\n",
261 dev->id_unit, HSCX_READ(1, H_VSTR));
262 return (0);
263 }
264
265 return (1);
266 }
267
268 int
isic_attach_Dyn(struct isa_device * dev,unsigned int iobase2)269 isic_attach_Dyn(struct isa_device *dev, unsigned int iobase2)
270 {
271 outb((dev->id_iobase)+ADDR, RESET);
272 DELAY(SEC_DELAY / 10);
273 outb((dev->id_iobase)+ADDR, 0);
274 DELAY(SEC_DELAY / 10);
275 return(1);
276 }
277
278 #elif defined(__bsdi__)
279
280 /* ISIC probe and attach
281 */
282
283 static int
set_softc(struct isic_softc * sc,struct isa_attach_args * ia,int unit)284 set_softc(struct isic_softc *sc, struct isa_attach_args *ia, int unit)
285 {
286 if (unit >= NISIC)
287 return 0;
288 sc->sc_unit = unit;
289 switch(ffs(ia->ia_irq) - 1)
290 {
291 case 3:
292 case 4:
293 case 5:
294 case 9:
295 case 10:
296 case 11:
297 case 12:
298 case 15:
299 break;
300
301 default:
302 printf("isic%d: Error, invalid IRQ [%d] specified for Dynalink IS64PH.\n",
303 unit, ffs(ia->ia_irq)-1);
304 return(0);
305 break;
306 }
307 sc->sc_irq = ia->ia_irq;
308
309 /* check if memory addr specified */
310
311 if(ia->ia_maddr)
312 {
313 printf("isic%d: Error, mem addr 0x%lx specified for Dynalink IS64PH.\n",
314 unit, (u_long)ia->ia_maddr);
315 return (0);
316 }
317
318 /* check if we got an iobase */
319 if ( (ia->ia_iobase < 0x100) ||
320 (ia->ia_iobase > 0x3f8) ||
321 (ia->ia_iobase & 3) )
322 {
323 printf("isic%d: Error, invalid iobase 0x%x specified for Dynalink!\n", unit, ia->ia_iobase);
324 return(0);
325 }
326 sc->sc_port = ia->ia_iobase;
327
328 /* setup access routines */
329 sc->clearirq = NULL;
330 sc->readreg = dynalink_read_reg;
331 sc->writereg = dynalink_write_reg;
332 sc->readfifo = dynalink_read_fifo;
333 sc->writefifo = dynalink_write_fifo;
334
335 /* setup card type */
336 sc->sc_cardtyp = CARD_TYPEP_DYNALINK;
337
338 /* setup IOM bus type */
339 sc->sc_bustyp = BUS_TYPE_IOM2;
340
341 sc->sc_ipac = 0;
342 sc->sc_bfifolen = HSCX_FIFO_LEN;
343
344 /* setup ISAC and HSCX base addr */
345 ISAC_BASE = (caddr_t) sc->sc_port;
346 HSCX_A_BASE = (caddr_t) sc->sc_port + 1;
347 HSCX_B_BASE = (caddr_t) sc->sc_port + 1 + HSCXB_HACK;
348 return 1;
349 }
350
351 int
isapnp_match_dynalink(struct device * parent,struct cfdata * cf,struct isa_attach_args * ia)352 isapnp_match_dynalink(struct device *parent, struct cfdata *cf,
353 struct isa_attach_args *ia)
354 {
355 struct isic_softc dummysc, *sc = &dummysc;
356 pnp_resource_t res;
357 char *ids[] = {"ASU1688", NULL};
358 bzero(&res, sizeof res);
359 res.res_irq[0].irq_level = ia->ia_irq;
360 res.res_port[0].prt_base = ia->ia_iobase;
361 res.res_port[0].prt_length = 4;
362
363 if (!pnp_assigndev(ids, isiccd.cd_name, &res))
364 return (0);
365
366 ia->ia_irq = res.res_irq[0].irq_level;
367 ia->ia_iobase = res.res_port[0].prt_base;
368 ia->ia_iosize = res.res_port[0].prt_length;
369
370 if (set_softc(sc, ia, cf->cf_unit) == 0)
371 return 0;
372
373 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */
374 if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
375 ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
376 {
377 printf("isic%d: HSCX VSTR test failed for Dynalink\n",
378 cf->cf_unit);
379 printf("isic%d: HSC0: VSTR: %#x\n",
380 cf->cf_unit, HSCX_READ(0, H_VSTR));
381 printf("isic%d: HSC1: VSTR: %#x\n",
382 cf->cf_unit, HSCX_READ(1, H_VSTR));
383 return (0);
384 }
385
386 cf->cf_flags = FLAG_DYNALINK;
387 return (1);
388 }
389
390 int
isic_attach_Dyn(struct device * parent,struct device * self,struct isa_attach_args * ia)391 isic_attach_Dyn(struct device *parent, struct device *self,
392 struct isa_attach_args *ia)
393 {
394 struct isic_softc *sc = (struct isic_softc *)self;
395 int unit = sc->sc_dev.dv_unit;
396
397 /* Commit the probed attachment values */
398 if (set_softc(sc, ia, unit) == 0)
399 panic("isic_attach_Dyn: set_softc");
400
401 outb((ia->ia_iobase)+ADDR, RESET);
402 DELAY(SEC_DELAY / 10);
403 outb((ia->ia_iobase)+ADDR, 0);
404 DELAY(SEC_DELAY / 10);
405 return(1);
406 }
407
408 #else
409
isic_attach_Dyn(struct isic_softc * sc)410 void isic_attach_Dyn(struct isic_softc *sc)
411 {
412 /* setup access routines */
413 sc->clearirq = NULL;
414 sc->readreg = dynalink_read_reg;
415 sc->writereg = dynalink_write_reg;
416 sc->readfifo = dynalink_read_fifo;
417 sc->writefifo = dynalink_write_fifo;
418
419 /* setup card type */
420 sc->sc_cardtyp = CARD_TYPEP_DYNALINK;
421
422 /* setup IOM bus type */
423 sc->sc_bustyp = BUS_TYPE_IOM2;
424
425 sc->sc_ipac = 0;
426 sc->sc_bfifolen = HSCX_FIFO_LEN;
427
428 /* Read HSCX A/B VSTR. Expected value is 0x05 (V2.1). */
429 if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) || ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
430 {
431 printf("%s: HSCX VSTR test failed for Dynalink PnP\n",
432 sc->sc_dev.dv_xname);
433 printf("%s: HSC0: VSTR: %#x\n",
434 sc->sc_dev.dv_xname, HSCX_READ(0, H_VSTR));
435 printf("%s: HSC1: VSTR: %#x\n",
436 sc->sc_dev.dv_xname, HSCX_READ(1, H_VSTR));
437 return;
438 }
439
440 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, RESET);
441 DELAY(SEC_DELAY / 10);
442 bus_space_write_1(sc->sc_maps[0].t, sc->sc_maps[0].h, ADDR, 0);
443 DELAY(SEC_DELAY / 10);
444 }
445
446 #endif
447
448 /* LOW-LEVEL DEVICE ACCESS
449
450 NOTE: The isdn4bsd code expects the two HSCX channels at different
451 base addresses. I'm faking this, and remap them to the same address
452 in the low-level routines. Search for HSCXB_HACK and IS_HSCXB_HACK.
453
454 REM: this is only true for the FreeBSD version of I4B!
455 */
456
457 #if defined(__FreeBSD__) || defined(__bsdi__)
458 static void
dynalink_read_fifo(void * buf,const void * base,size_t len)459 dynalink_read_fifo(void *buf, const void *base, size_t len)
460 {
461 outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base));
462 insb(IOADDR(base), (u_char *)buf, (u_int)len);
463 }
464 #else
465 static void
dynalink_read_fifo(struct isic_softc * sc,int what,void * buf,size_t size)466 dynalink_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
467 {
468 bus_space_tag_t t = sc->sc_maps[0].t;
469 bus_space_handle_t h = sc->sc_maps[0].h;
470 switch (what) {
471 case ISIC_WHAT_ISAC:
472 bus_space_write_1(t, h, ADDR, 0);
473 bus_space_read_multi_1(t, h, ISAC, buf, size);
474 break;
475 case ISIC_WHAT_HSCXA:
476 bus_space_write_1(t, h, ADDR, HSCXA);
477 bus_space_read_multi_1(t, h, HSCX, buf, size);
478 break;
479 case ISIC_WHAT_HSCXB:
480 bus_space_write_1(t, h, ADDR, HSCXB);
481 bus_space_read_multi_1(t, h, HSCX, buf, size);
482 break;
483 }
484 }
485 #endif
486
487 #if defined(__FreeBSD__) || defined(__bsdi__)
488 static void
dynalink_write_fifo(void * base,const void * buf,size_t len)489 dynalink_write_fifo(void *base, const void *buf, size_t len)
490 {
491 outb(IOBASE(base)+ADDR, 0+IS_HSCXB_HACK(base));
492 outsb(IOADDR(base), (u_char *)buf, (u_int)len);
493 }
494 #else
dynalink_write_fifo(struct isic_softc * sc,int what,const void * buf,size_t size)495 static void dynalink_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
496 {
497 bus_space_tag_t t = sc->sc_maps[0].t;
498 bus_space_handle_t h = sc->sc_maps[0].h;
499 switch (what) {
500 case ISIC_WHAT_ISAC:
501 bus_space_write_1(t, h, ADDR, 0);
502 bus_space_write_multi_1(t, h, ISAC, (u_int8_t*)buf, size);
503 break;
504 case ISIC_WHAT_HSCXA:
505 bus_space_write_1(t, h, ADDR, HSCXA);
506 bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size);
507 break;
508 case ISIC_WHAT_HSCXB:
509 bus_space_write_1(t, h, ADDR, HSCXB);
510 bus_space_write_multi_1(t, h, HSCX, (u_int8_t*)buf, size);
511 break;
512 }
513 }
514 #endif
515
516 #if defined(__FreeBSD__) || defined(__bsdi__)
517 static void
dynalink_write_reg(u_char * base,u_int offset,u_int v)518 dynalink_write_reg(u_char *base, u_int offset, u_int v)
519 {
520 outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK);
521 outb(IOADDR(base), (u_char)v);
522 }
523 #else
dynalink_write_reg(struct isic_softc * sc,int what,bus_size_t offs,u_int8_t data)524 static void dynalink_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
525 {
526 bus_space_tag_t t = sc->sc_maps[0].t;
527 bus_space_handle_t h = sc->sc_maps[0].h;
528 switch (what) {
529 case ISIC_WHAT_ISAC:
530 bus_space_write_1(t, h, ADDR, offs);
531 bus_space_write_1(t, h, ISAC, data);
532 break;
533 case ISIC_WHAT_HSCXA:
534 bus_space_write_1(t, h, ADDR, HSCXA+offs);
535 bus_space_write_1(t, h, HSCX, data);
536 break;
537 case ISIC_WHAT_HSCXB:
538 bus_space_write_1(t, h, ADDR, HSCXB+offs);
539 bus_space_write_1(t, h, HSCX, data);
540 break;
541 }
542 }
543 #endif
544
545 #if defined(__FreeBSD__) || defined(__bsdi__)
546 static u_char
dynalink_read_reg(u_char * base,u_int offset)547 dynalink_read_reg(u_char *base, u_int offset)
548 {
549 outb(IOBASE(base)+ADDR, (offset+IS_HSCXB_HACK(base))&ADDRMASK);
550 return (inb(IOADDR(base)));
551 }
552 #else
dynalink_read_reg(struct isic_softc * sc,int what,bus_size_t offs)553 static u_int8_t dynalink_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
554 {
555 bus_space_tag_t t = sc->sc_maps[0].t;
556 bus_space_handle_t h = sc->sc_maps[0].h;
557 switch (what) {
558 case ISIC_WHAT_ISAC:
559 bus_space_write_1(t, h, ADDR, offs);
560 return bus_space_read_1(t, h, ISAC);
561 case ISIC_WHAT_HSCXA:
562 bus_space_write_1(t, h, ADDR, HSCXA+offs);
563 return bus_space_read_1(t, h, HSCX);
564 case ISIC_WHAT_HSCXB:
565 bus_space_write_1(t, h, ADDR, HSCXB+offs);
566 return bus_space_read_1(t, h, HSCX);
567 }
568 return 0;
569 }
570 #endif
571
572 #endif /* ISICPNP_DYNALINK */
573