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