1/*
2 *   Copyright (c) 1999 Udo Schweigert. All rights reserved.
3 *
4 *   Redistribution and use in source and binary forms, with or without
5 *   modification, are permitted provided that the following conditions
6 *   are met:
7 *
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 *   3. Neither the name of the author nor the names of any co-contributors
14 *      may be used to endorse or promote products derived from this software
15 *      without specific prior written permission.
16 *   4. Altered versions must be plainly marked as such, and must not be
17 *      misrepresented as being the original software and/or documentation.
18 *
19 *   THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 *   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 *   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 *   ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 *   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 *   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 *   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 *   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 *   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 *   SUCH DAMAGE.
30 *
31 *---------------------------------------------------------------------------
32 *   Based on ELSA Quickstep 1000pro PCI driver (i4b_elsa_qs1p.c)
33 *---------------------------------------------------------------------------
34 *   In case of trouble please contact Udo Schweigert <ust@cert.siemens.de>
35 *---------------------------------------------------------------------------
36 *
37 *	Siemens I-Surf 2.0 PnP specific routines for isic driver
38 *	--------------------------------------------------------
39 *
40 *	$Id: isic_isapnp_siemens_isurf.c,v 1.11 2007/10/19 12:00:32 ad Exp $
41 *
42 *      last edit-date: [Fri Jan  5 11:38:29 2001]
43 *
44 *---------------------------------------------------------------------------*/
45
46#include <sys/cdefs.h>
47__KERNEL_RCSID(0, "$NetBSD: isic_isapnp_siemens_isurf.c,v 1.10 2007/03/04 06:02:13 christos Exp $");
48
49#include <sys/param.h>
50#include <sys/kernel.h>
51#include <sys/systm.h>
52#include <sys/mbuf.h>
53
54#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
55#include <sys/callout.h>
56#endif
57
58#if defined(__FreeBSD__)
59#if __FreeBSD__ >= 3
60#include <sys/ioccom.h>
61#else
62#include <sys/ioctl.h>
63#endif
64
65#include <machine/clock.h>
66#include <i386/isa/isa_device.h>
67
68#else
69#include <sys/bus.h>
70#include <sys/device.h>
71#endif
72
73#include <sys/socket.h>
74#include <net/if.h>
75
76#if defined(__FreeBSD__)
77#include <machine/i4b_ioctl.h>
78#else
79#include <netisdn/i4b_ioctl.h>
80#endif
81
82#include <netisdn/i4b_global.h>
83#include <netisdn/i4b_debug.h>
84#include <netisdn/i4b_l2.h>
85#include <netisdn/i4b_l1l2.h>
86#include <netisdn/i4b_mbuf.h>
87
88#include <dev/ic/isic_l1.h>
89#include <dev/ic/ipac.h>
90#include <dev/ic/isac.h>
91#include <dev/ic/hscx.h>
92
93#if !defined(__FreeBSD__)
94void isic_attach_siemens_isurf(struct isic_softc *sc);
95#endif
96
97/* masks for register encoded in base addr */
98
99#define SIE_ISURF_BASE_MASK		0x0ffff
100#define SIE_ISURF_OFF_MASK		0xf0000
101
102/* register id's to be encoded in base addr */
103
104#define SIE_ISURF_IDISAC		0x00000
105#define SIE_ISURF_IDHSCXA		0x10000
106#define SIE_ISURF_IDHSCXB		0x20000
107#define SIE_ISURF_IDIPAC		0x40000
108
109/* offsets from base address */
110
111#define SIE_ISURF_OFF_ALE		0x00
112#define SIE_ISURF_OFF_RW		0x01
113
114/*---------------------------------------------------------------------------*
115 *      Siemens I-Surf 2.0 PnP ISAC get fifo routine
116 *---------------------------------------------------------------------------*/
117#if defined(__FreeBSD__)
118
119static void
120siemens_isurf_read_fifo(void *buf, const void *base, size_t len)
121{
122	if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
123	{
124	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
125		insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
126	}
127	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
128	{
129	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
130		insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
131	}
132	else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */
133	{
134	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
135		insb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (u_char *)buf, (u_int)len);
136	}
137}
138
139#else
140
141static void
142siemens_isurf_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
143{
144	bus_space_tag_t t = sc->sc_maps[0].t;
145	bus_space_handle_t h = sc->sc_maps[0].h;
146	switch (what) {
147	case ISIC_WHAT_ISAC:
148		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
149		bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
150		break;
151	case ISIC_WHAT_HSCXA:
152		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
153		bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
154		break;
155	case ISIC_WHAT_HSCXB:
156		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
157		bus_space_read_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
158		break;
159	}
160}
161
162#endif
163
164/*---------------------------------------------------------------------------*
165 *      Siemens I-Surf 2.0 PnP ISAC put fifo routine
166 *---------------------------------------------------------------------------*/
167#if defined(__FreeBSD__)
168
169static void
170siemens_isurf_write_fifo(void *base, const void *buf, size_t len)
171{
172	if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
173	{
174	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
175		outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
176	}
177	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
178	{
179	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
180		outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
181	}
182	else /* if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC) */
183	{
184	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
185		outsb((((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW), (const u_char *)buf, (u_int)len);
186	}
187}
188
189#else
190
191static void
192siemens_isurf_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
193{
194	bus_space_tag_t t = sc->sc_maps[0].t;
195	bus_space_handle_t h = sc->sc_maps[0].h;
196	switch (what) {
197	case ISIC_WHAT_ISAC:
198		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF);
199		bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
200		break;
201	case ISIC_WHAT_HSCXA:
202		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF);
203		bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
204		break;
205	case ISIC_WHAT_HSCXB:
206		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF);
207		bus_space_write_multi_1(t, h, SIE_ISURF_OFF_RW, buf, size);
208		break;
209	}
210}
211
212#endif
213
214/*---------------------------------------------------------------------------*
215 *      Siemens I-Surf 2.0 PnP ISAC put register routine
216 *---------------------------------------------------------------------------*/
217#if defined(__FreeBSD__)
218
219static void
220siemens_isurf_write_reg(u_char *base, u_int offset, u_int v)
221{
222	if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
223	{
224	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
225	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
226	}
227	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
228	{
229	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
230	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
231	}
232	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC)
233	{
234	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
235	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
236	}
237	else /* IPAC */
238	{
239	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
240	        outb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW, (u_char)v);
241	}
242}
243
244#else
245
246static void
247siemens_isurf_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
248{
249	bus_space_tag_t t = sc->sc_maps[0].t;
250	bus_space_handle_t h = sc->sc_maps[0].h;
251	switch (what) {
252	case ISIC_WHAT_ISAC:
253		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF+offs);
254		bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data);
255		break;
256	case ISIC_WHAT_HSCXA:
257		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF+offs);
258		bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data);
259		break;
260	case ISIC_WHAT_HSCXB:
261		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF+offs);
262		bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data);
263		break;
264	case ISIC_WHAT_IPAC:
265		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_IPAC_OFF+offs);
266		bus_space_write_1(t, h, SIE_ISURF_OFF_RW, data);
267		break;
268	}
269}
270
271#endif
272
273/*---------------------------------------------------------------------------*
274 *	Siemens I-Surf 2.0 PnP ISAC get register routine
275 *---------------------------------------------------------------------------*/
276#if defined(__FreeBSD__)
277
278static u_char
279siemens_isurf_read_reg(u_char *base, u_int offset)
280{
281	if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXB)
282	{
283	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXB_OFF));
284		return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
285	}
286	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDHSCXA)
287	{
288	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_HSCXA_OFF));
289		return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
290	}
291	else if(((u_int)base & SIE_ISURF_OFF_MASK) == SIE_ISURF_IDISAC)
292	{
293	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_ISAC_OFF));
294		return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
295	}
296	else /* IPAC */
297	{
298	        outb((u_int)((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_ALE, (u_char)(offset+IPAC_IPAC_OFF));
299		return(inb(((u_int)base & SIE_ISURF_BASE_MASK) + SIE_ISURF_OFF_RW));
300	}
301}
302
303#else
304
305static u_int8_t
306siemens_isurf_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
307{
308	bus_space_tag_t t = sc->sc_maps[0].t;
309	bus_space_handle_t h = sc->sc_maps[0].h;
310	switch (what) {
311	case ISIC_WHAT_ISAC:
312		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_ISAC_OFF+offs);
313		return bus_space_read_1(t, h, SIE_ISURF_OFF_RW);
314	case ISIC_WHAT_HSCXA:
315		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXA_OFF+offs);
316		return bus_space_read_1(t, h, SIE_ISURF_OFF_RW);
317	case ISIC_WHAT_HSCXB:
318		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_HSCXB_OFF+offs);
319		return bus_space_read_1(t, h, SIE_ISURF_OFF_RW);
320	case ISIC_WHAT_IPAC:
321		bus_space_write_1(t, h, SIE_ISURF_OFF_ALE, IPAC_IPAC_OFF+offs);
322		return bus_space_read_1(t, h, SIE_ISURF_OFF_RW);
323	}
324	return 0;
325}
326
327#endif
328
329/*---------------------------------------------------------------------------*
330 *	isic_probe_siemens_isurf - probe for Siemens I-Surf 2.0 PnP
331 *---------------------------------------------------------------------------*/
332#if defined(__FreeBSD__)
333
334int
335isic_probe_siemens_isurf(struct isa_device *dev, unsigned int iobase2)
336{
337	struct isic_softc *sc = &l1_sc[dev->id_unit];
338
339	/* check max unit range */
340
341	if(dev->id_unit >= ISIC_MAXUNIT)
342	{
343		printf("isic%d: Error, unit %d >= ISIC_MAXUNIT for Siemens I-Surf 2.0 PnP\n",
344				dev->id_unit, dev->id_unit);
345		return(0);
346	}
347	sc->sc_unit = dev->id_unit;
348
349	/* check IRQ validity */
350
351	switch(ffs(dev->id_irq) - 1)
352	{
353		case 3:
354		case 4:
355		case 5:
356		case 7:
357		case 10:
358		case 11:
359		case 12:
360		case 15:
361			break;
362
363		default:
364			printf("isic%d: Error, invalid IRQ [%d] specified for Siemens I-Surf 2.0 PnP!\n",
365				dev->id_unit, ffs(dev->id_irq)-1);
366			return(0);
367			break;
368	}
369	sc->sc_irq = dev->id_irq;
370
371	/* check if memory addr specified */
372
373	if(dev->id_maddr)
374	{
375		printf("isic%d: Error, mem addr 0x%lx specified for Siemens I-Surf 2.0 PnP!\n",
376			dev->id_unit, (u_long)dev->id_maddr);
377		return(0);
378	}
379	dev->id_msize = 0;
380
381	/* check if we got an iobase */
382
383	if(!((dev->id_iobase >= 0x100) && (dev->id_iobase <= 0xfffc)))
384	{
385		printf("isic%d: Error, invalid iobase 0x%x specified for Siemens I-Surf 2.0 PnP!\n",
386			dev->id_unit, dev->id_iobase);
387		return(0);
388	}
389	sc->sc_port = dev->id_iobase;
390
391
392	/* setup access routines */
393
394	sc->clearirq = NULL;
395	sc->readreg = siemens_isurf_read_reg;
396	sc->writereg = siemens_isurf_write_reg;
397
398	sc->readfifo = siemens_isurf_read_fifo;
399	sc->writefifo = siemens_isurf_write_fifo;
400
401	/* setup card type */
402
403	sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2;
404
405	/* setup IOM bus type */
406
407	sc->sc_bustyp = BUS_TYPE_IOM2;
408
409	/* setup chip type = IPAC ! */
410
411	sc->sc_ipac = 1;
412	sc->sc_bfifolen = IPAC_BFIFO_LEN;
413
414
415	return (1);
416}
417
418/*---------------------------------------------------------------------------*
419 *	isic_attach_siemens_isurf - attach for Siemens I-Surf 2.0 PnP
420 *---------------------------------------------------------------------------*/
421int
422isic_attach_siemens_isurf(struct isa_device *dev, unsigned int iobase2)
423{
424	struct isic_softc *sc = &l1_sc[dev->id_unit];
425
426	/* setup ISAC and HSCX base addr */
427
428	ISAC_BASE   = (void *) ((u_int)sc->sc_port | SIE_ISURF_IDISAC);
429	HSCX_A_BASE = (void *) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXA);
430	HSCX_B_BASE = (void *) ((u_int)sc->sc_port | SIE_ISURF_IDHSCXB);
431	IPAC_BASE   = (void *) ((u_int)sc->sc_port | SIE_ISURF_IDIPAC);
432
433	/* enable hscx/isac irq's */
434	IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
435
436	IPAC_WRITE(IPAC_ACFG, 0);	/* outputs are open drain */
437	IPAC_WRITE(IPAC_AOE,		/* aux 5..2 are inputs, 7, 6 outputs */
438		(IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
439	IPAC_WRITE(IPAC_ATX, 0xff);	/* set all output lines high */
440
441	return(1);
442}
443
444#else
445
446void
447isic_attach_siemens_isurf(struct isic_softc *sc)
448{
449	/* setup access routines */
450
451	sc->clearirq = NULL;
452	sc->readreg = siemens_isurf_read_reg;
453	sc->writereg = siemens_isurf_write_reg;
454
455	sc->readfifo = siemens_isurf_read_fifo;
456	sc->writefifo = siemens_isurf_write_fifo;
457
458	/* setup card type */
459
460	sc->sc_cardtyp = CARD_TYPEP_SIE_ISURF2;
461
462	/* setup IOM bus type */
463
464	sc->sc_bustyp = BUS_TYPE_IOM2;
465
466	/* setup chip type = IPAC ! */
467
468	sc->sc_ipac = 1;
469	sc->sc_bfifolen = IPAC_BFIFO_LEN;
470
471	/* enable hscx/isac irq's */
472
473	IPAC_WRITE(IPAC_MASK, (IPAC_MASK_INT1 | IPAC_MASK_INT0));
474
475	IPAC_WRITE(IPAC_ACFG, 0);	/* outputs are open drain */
476	IPAC_WRITE(IPAC_AOE,		/* aux 5..2 are inputs, 7, 6 outputs */
477		(IPAC_AOE_OE5 | IPAC_AOE_OE4 | IPAC_AOE_OE3 | IPAC_AOE_OE2));
478	IPAC_WRITE(IPAC_ATX, 0xff);	/* set all output lines high */
479}
480
481#endif
482