1 /* ISDN4BSD code */
2 /*
3 * Copyright (c) 1997, 1999 Hellmuth Michaelis. 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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 *
26 *---------------------------------------------------------------------------
27 *
28 * i4b_drn_ngo.c - Dr. Neuhaus Niccy GO@ and SAGEM Cybermod
29 * --------------------------------------------------------
30 *
31 * $Id: isic_isapnp_drn_ngo.c,v 1.2 2003/05/14 19:55:07 tg Stab $
32 *
33 * last edit-date: [Fri Jan 5 11:38:29 2001]
34 *
35 *---------------------------------------------------------------------------*/
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: isic_isapnp_drn_ngo.c,v 1.4 2002/03/24 20:35:50 martin Exp $");
39
40 #ifdef ISICPNP_DRN_NGO
41
42 #include <sys/param.h>
43 #if defined(__FreeBSD__) && __FreeBSD__ >= 3
44 #include <sys/ioccom.h>
45 #else
46 #include <sys/ioctl.h>
47 #endif
48 #include <sys/kernel.h>
49 #include <sys/systm.h>
50 #include <sys/mbuf.h>
51
52 #include <sys/timeout.h>
53
54 #ifdef __FreeBSD__
55 #include <machine/clock.h>
56 #include <i386/isa/isa_device.h>
57 #else
58 #include <machine/bus.h>
59 #include <sys/device.h>
60 #endif
61
62 #include <sys/socket.h>
63 #include <net/if.h>
64
65 #ifdef __FreeBSD__
66 #include <machine/i4b_debug.h>
67 #include <machine/i4b_ioctl.h>
68 #else
69 #include <netisdn/i4b_debug.h>
70 #include <netisdn/i4b_ioctl.h>
71 #endif
72
73 #include <netisdn/i4b_global.h>
74 #include <netisdn/i4b_l2.h>
75 #include <netisdn/i4b_l1l2.h>
76
77 #include <dev/ic/isic_l1.h>
78 #include <dev/ic/isac.h>
79 #include <dev/ic/hscx.h>
80
81 /*---------------------------------------------------------------------------*
82 * Niccy GO@ definitions
83 *
84 * the card uses 2 i/o addressranges each using 2 bytes
85 *
86 * addressrange 0:
87 * offset 0 - ISAC dataregister
88 * offset 1 - HSCX dataregister
89 * addressrange 1:
90 * offset 0 - ISAC addressregister
91 * offset 1 - HSCX addressregister
92 *
93 * to access an ISAC/HSCX register, you have to write the register
94 * number into the ISAC or HSCX addressregister and then read/write
95 * data for the ISAC/HSCX register into/from the corresponding
96 * dataregister.
97 *
98 * Thanks to Klaus Muehle of Dr. Neuhaus Telekommunikation for giving
99 * out this information!
100 *
101 *---------------------------------------------------------------------------*/
102 #define NICCY_PORT_MIN 0x200
103 #define NICCY_PORT_MAX 0x3e0
104
105 #define HSCX_ABIT 0x1000 /* flag, HSCX A is meant */
106 #define HSCX_BBIT 0x2000 /* flag, HSCX B is meant */
107
108 #define HSCX_BOFF 0x40
109
110 #define ADDR_OFF 2 /* address register range offset XXX */
111
112 #define ISAC_DATA 0
113 #define HSCX_DATA 1
114
115 #define ISAC_ADDR 0
116 #define HSCX_ADDR 1
117
118 #ifdef __FreeBSD__
119
120 #if 0
121 #define HSCXADEBUG
122 #define HSCXBDEBUG
123 #define ISACDEBUG
124 #else
125 #undef HSCXADEBUG
126 #undef HSCXBDEBUG
127 #undef ISACDEBUG
128 #endif
129
130 /*---------------------------------------------------------------------------*
131 * Dr. Neuhaus Niccy GO@ read fifo routine
132 *---------------------------------------------------------------------------*/
133 static void
drnngo_read_fifo(void * buf,const void * base,size_t len)134 drnngo_read_fifo(void *buf, const void *base, size_t len)
135 {
136 register int offset;
137 register u_int data;
138
139 int x = SPLI4B();
140
141 if((u_int)base & HSCX_ABIT)
142 {
143 (u_int)base &= ~HSCX_ABIT;
144 (u_int)data = ((u_int)base + HSCX_DATA);
145 (u_int)base += (ADDR_OFF + HSCX_ADDR);
146 offset = 0;
147 #ifdef HSCXADEBUG
148 printf("GO/A/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len);
149 #endif
150 }
151 else if((u_int)base & HSCX_BBIT)
152 {
153 (u_int)base &= ~HSCX_BBIT;
154 (u_int)data = ((u_int)base + HSCX_DATA);
155 (u_int)base += (ADDR_OFF + HSCX_ADDR);
156 offset = HSCX_BOFF;
157 #ifdef HSCXBDEBUG
158 printf("GO/B/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len);
159 #endif
160 }
161 else
162 {
163 (u_int)data = ((u_int)base + ISAC_DATA);
164 (u_int)base += (ADDR_OFF + ISAC_ADDR);
165 offset = 0;
166 #ifdef ISACDEBUG
167 printf("GO/I/frd: base=0x%x, data=0x%x, len=%d\n", base, data, len);
168 #endif
169 }
170
171 for(;len > 0; len--, offset++)
172 {
173 outb((int)base, (u_char)offset);
174 *((u_char *)buf + offset) = inb((int)data);
175 }
176
177 splx(x);
178 }
179
180 /*---------------------------------------------------------------------------*
181 * Dr. Neuhaus Niccy GO@ write fifo routine
182 *---------------------------------------------------------------------------*/
183 static void
drnngo_write_fifo(void * base,const void * buf,size_t len)184 drnngo_write_fifo(void *base, const void *buf, size_t len)
185 {
186 register int offset;
187 register u_int data;
188
189 int x = SPLI4B();
190
191 if((u_int)base & HSCX_ABIT)
192 {
193 (u_int)base &= ~HSCX_ABIT;
194 (u_int)data = ((u_int)base + HSCX_DATA);
195 (u_int)base += (ADDR_OFF + HSCX_ADDR);
196 offset = 0;
197 #ifdef HSCXADEBUG
198 printf("GO/A/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len);
199 #endif
200 }
201 else if((u_int)base & HSCX_BBIT)
202 {
203 (u_int)base &= ~HSCX_BBIT;
204 (u_int)data = ((u_int)base + HSCX_DATA);
205 (u_int)base += (ADDR_OFF + HSCX_ADDR);
206 offset = HSCX_BOFF;
207 #ifdef HSCXBDEBUG
208 printf("GO/B/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len);
209 #endif
210 }
211 else
212 {
213 (u_int)data = ((u_int)base + ISAC_DATA);
214 (u_int)base += (ADDR_OFF + ISAC_ADDR);
215 offset = 0;
216 #ifdef ISACDEBUG
217 printf("GO/I/fwr: base=0x%x, data=0x%x, len=%d\n", base, data, len);
218 #endif
219 }
220
221 for(;len > 0; len--, offset++)
222 {
223 outb((int)base, (u_char)offset);
224 outb((int)data, *((u_char *)buf + offset));
225 }
226
227 splx(x);
228 }
229
230 /*---------------------------------------------------------------------------*
231 * Dr. Neuhaus Niccy GO@ write register routine
232 *---------------------------------------------------------------------------*/
233 static void
drnngo_write_reg(u_char * base,u_int offset,u_int v)234 drnngo_write_reg(u_char *base, u_int offset, u_int v)
235 {
236 int x = SPLI4B();
237 if((u_int)base & HSCX_ABIT)
238 {
239 (u_int)base &= ~HSCX_ABIT;
240 outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset);
241 outb((int)base + HSCX_DATA, (u_char)v);
242 #ifdef HSCXADEBUG
243 printf("GO/A/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
244 (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA,
245 (u_char)offset, (u_char)v);
246 #endif
247 }
248 else if((u_int)base & HSCX_BBIT)
249 {
250 (u_int)base &= ~HSCX_BBIT;
251 outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF));
252 outb((int)base + HSCX_DATA, (u_char)v);
253 #ifdef HSCXBDEBUG
254 printf("GO/B/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
255 (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA,
256 (u_char)(offset + HSCX_BOFF), (u_char)v);
257 #endif
258 }
259 else
260 {
261 outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset);
262 outb((int)base + ISAC_DATA, (u_char)v);
263 #ifdef ISACDEBUG
264 printf("GO/I/rwr: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
265 (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA,
266 (u_char)offset, (u_char)v);
267 #endif
268 }
269 splx(x);
270 }
271
272 /*---------------------------------------------------------------------------*
273 * Dr. Neuhaus Niccy GO@ read register routine
274 *---------------------------------------------------------------------------*/
275 static u_char
drnngo_read_reg(u_char * base,u_int offset)276 drnngo_read_reg(u_char *base, u_int offset)
277 {
278 u_char val;
279 int x = SPLI4B();
280
281 if((u_int)base & HSCX_ABIT)
282 {
283 (u_int)base &= ~HSCX_ABIT;
284 outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)offset);
285 val = inb((int)base + HSCX_DATA);
286 #ifdef HSCXADEBUG
287 printf("GO/A/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
288 (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA,
289 (u_char)offset, (u_char)val);
290 #endif
291 }
292 else if((u_int)base & HSCX_BBIT)
293 {
294 (u_int)base &= ~HSCX_BBIT;
295 outb((int)base + ADDR_OFF + HSCX_ADDR, (u_char)(offset + HSCX_BOFF));
296 val = inb((int)base + HSCX_DATA);
297 #ifdef HSCXBDEBUG
298 printf("GO/B/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
299 (int)base + ADDR_OFF + HSCX_ADDR, (int)base + HSCX_DATA,
300 (u_char)(offset + HSCX_BOFF), (u_char)val);
301 #endif
302 }
303 else
304 {
305 outb((int)base + ADDR_OFF + ISAC_ADDR, (u_char)offset);
306 val = inb((int)base + ISAC_DATA);
307 #ifdef ISACDEBUG
308 printf("GO/I/rrd: base=0x%x, addr=0x%x, offset=0x%x, val=0x%x\n",
309 (int)base + ADDR_OFF + ISAC_ADDR, (int)base + ISAC_DATA,
310 (u_char)offset, (u_char)val);
311 #endif
312 }
313 splx(x);
314 return(val);
315 }
316
317 /*---------------------------------------------------------------------------*
318 * isic_probe_drnngo - probe for Dr. Neuhaus Niccy GO@
319 *---------------------------------------------------------------------------*/
320 int
isic_probe_drnngo(struct isa_device * dev,unsigned int iobase2)321 isic_probe_drnngo(struct isa_device *dev, unsigned int iobase2)
322 {
323 struct isic_softc *sc = &l1_sc[dev->id_unit];
324
325 /* check max unit range */
326
327 if(dev->id_unit >= ISIC_MAXUNIT)
328 {
329 printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Dr. Neuhaus Niccy GO@!\n",
330 dev->id_unit, dev->id_unit);
331 return(0);
332 }
333 sc->sc_unit = dev->id_unit;
334
335 /* check IRQ validity */
336
337 switch(ffs(dev->id_irq)-1)
338 {
339 case 3:
340 case 4:
341 case 5:
342 case 9:
343 case 10:
344 case 11:
345 case 12:
346 case 15:
347 break;
348
349 default:
350 printf("isic%d: Error, invalid IRQ [%d] specified for Dr. Neuhaus Niccy GO@!\n",
351 dev->id_unit, ffs(dev->id_irq)-1);
352 return(0);
353 break;
354 }
355 sc->sc_irq = dev->id_irq;
356
357 /* check if memory addr specified */
358
359 if(dev->id_maddr)
360 {
361 printf("isic%d: Error, mem addr 0x%lx specified for Dr. Neuhaus Niccy GO@!\n",
362 dev->id_unit, (u_long)dev->id_maddr);
363 return(0);
364 }
365 dev->id_msize = 0;
366
367 /* check if we got an iobase */
368
369 if(dev->id_iobase < NICCY_PORT_MIN || dev->id_iobase > NICCY_PORT_MAX)
370 {
371 printf("isic%d: Error, invalid iobase 0x%x specified for Dr. Neuhaus Niccy GO@!\n",
372 dev->id_unit, dev->id_iobase);
373 return(0);
374 }
375 sc->sc_port = dev->id_iobase;
376
377 if(iobase2 == 0)
378 {
379 printf("isic%d: Error, iobase2 is 0 for Dr. Neuhaus Niccy GO@!\n",
380 dev->id_unit);
381 return(0);
382 }
383
384 if(iobase2 < NICCY_PORT_MIN || iobase2 > NICCY_PORT_MAX)
385 {
386 printf("isic%d: Error, invalid port1 0x%x specified for Dr. Neuhaus Niccy GO@!\n",
387 dev->id_unit, iobase2);
388 return(0);
389 }
390
391 /*XXX*/ if((dev->id_iobase + 2) != iobase2)
392 {
393 printf("isic%d: Error, port1 must be (port0+2) for Dr.Neuhaus Niccy GO@!\n",
394 dev->id_unit);
395 return(0);
396 }
397
398 /* setup ISAC access routines */
399
400 sc->clearirq = NULL;
401 sc->readreg = drnngo_read_reg;
402 sc->writereg = drnngo_write_reg;
403
404 sc->readfifo = drnngo_read_fifo;
405 sc->writefifo = drnngo_write_fifo;
406
407 /* setup card type */
408
409 sc->sc_cardtyp = CARD_TYPEP_DRNNGO;
410
411 /* setup IOM bus type */
412
413 sc->sc_bustyp = BUS_TYPE_IOM2;
414
415 sc->sc_ipac = 0;
416 sc->sc_bfifolen = HSCX_FIFO_LEN;
417
418 /* setup ISAC and HSCX base addr */
419
420 ISAC_BASE = (caddr_t)dev->id_iobase;
421 HSCX_A_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_ABIT);
422 HSCX_B_BASE = (caddr_t)(((u_int)dev->id_iobase) | HSCX_BBIT);
423
424 /*
425 * Read HSCX A/B VSTR. Expected value for Dr. Neuhaus Niccy GO@ based
426 * boards is 0x05 in the least significant bits.
427 */
428
429 if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
430 ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
431 {
432 printf("isic%d: HSCX VSTR test failed for Dr. Neuhaus Niccy GO@\n",
433 dev->id_unit);
434 printf("isic%d: HSC0: VSTR: %#x\n",
435 dev->id_unit, HSCX_READ(0, H_VSTR));
436 printf("isic%d: HSC1: VSTR: %#x\n",
437 dev->id_unit, HSCX_READ(1, H_VSTR));
438 return (0);
439 }
440
441 return (1);
442 }
443
444 /*---------------------------------------------------------------------------*
445 * isic_attach_drnngo - attach Dr. Neuhaus Niccy GO@
446 *---------------------------------------------------------------------------*/
447 int
isic_attach_drnngo(struct isa_device * dev,unsigned int iobase2)448 isic_attach_drnngo(struct isa_device *dev, unsigned int iobase2)
449 {
450 return (1);
451 }
452
453 #else
454
455 static u_int8_t drnngo_read_reg __P((struct isic_softc *sc, int what, bus_size_t offs));
456 static void drnngo_write_reg __P((struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data));
457 static void drnngo_read_fifo __P((struct isic_softc *sc, int what, void *buf, size_t size));
458 static void drnngo_write_fifo __P((struct isic_softc *sc, int what, const void *data, size_t size));
459 void isic_attach_drnngo __P((struct isic_softc *sc));
460
461 /*
462 * Mapping from "what" parameter to offsets into the io map
463 */
464 static struct {
465 bus_size_t oa, /* address register offset */
466 od, /* data register offset */
467 or; /* additional chip register offset */
468 } offset[] =
469 {
470 { ISAC_ADDR, ISAC_DATA, 0 }, /* ISAC access */
471 { HSCX_ADDR, HSCX_DATA, 0 }, /* HSCX A access */
472 { HSCX_ADDR, HSCX_DATA, HSCX_BOFF } /* HSCX B access */
473 };
474
475 static void
drnngo_read_fifo(struct isic_softc * sc,int what,void * buf,size_t size)476 drnngo_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
477 {
478 bus_space_tag_t t = sc->sc_maps[0].t;
479 bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h;
480 bus_space_write_1(t, ha, offset[what].oa, offset[what].or);
481 bus_space_read_multi_1(t, hd, offset[what].od, buf, size);
482 }
483
484 static void
drnngo_write_fifo(struct isic_softc * sc,int what,const void * buf,size_t size)485 drnngo_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
486 {
487 bus_space_tag_t t = sc->sc_maps[0].t;
488 bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h;
489 bus_space_write_1(t, ha, offset[what].oa, offset[what].or);
490 bus_space_write_multi_1(t, hd, offset[what].od, (u_int8_t*)buf, size);
491 }
492
493 static void
drnngo_write_reg(struct isic_softc * sc,int what,bus_size_t offs,u_int8_t data)494 drnngo_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
495 {
496 bus_space_tag_t t = sc->sc_maps[0].t;
497 bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h;
498 bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or);
499 bus_space_write_1(t, hd, offset[what].od, data);
500 }
501
502 static u_int8_t
drnngo_read_reg(struct isic_softc * sc,int what,bus_size_t offs)503 drnngo_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
504 {
505 bus_space_tag_t t = sc->sc_maps[0].t;
506 bus_space_handle_t hd = sc->sc_maps[0].h, ha = sc->sc_maps[1].h;
507 bus_space_write_1(t, ha, offset[what].oa, offs+offset[what].or);
508 return bus_space_read_1(t, hd, offset[what].od);
509 }
510
511 void
isic_attach_drnngo(struct isic_softc * sc)512 isic_attach_drnngo(struct isic_softc *sc)
513 {
514 /* setup access routines */
515
516 sc->clearirq = NULL;
517 sc->readreg = drnngo_read_reg;
518 sc->writereg = drnngo_write_reg;
519
520 sc->readfifo = drnngo_read_fifo;
521 sc->writefifo = drnngo_write_fifo;
522
523 /* setup card type */
524
525 sc->sc_cardtyp = CARD_TYPEP_DRNNGO;
526
527 /* setup IOM bus type */
528
529 sc->sc_bustyp = BUS_TYPE_IOM2;
530
531 sc->sc_ipac = 0;
532 sc->sc_bfifolen = HSCX_FIFO_LEN;
533 }
534
535 #endif
536
537 #endif /* ISICPNP_DRN_NGO */
538