1/*
2 *   Copyright (c) 1998 German Tischler. 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 *
33 * Card format:
34 *
35 * iobase + 0 : reset on  (0x03)
36 * iobase + 1 : reset off (0x0)
37 * iobase + 2 : isac read/write
38 * iobase + 3 : hscx read/write ( offset 0-0x3f    hscx0 ,
39 *                                offset 0x40-0x7f hscx1 )
40 * iobase + 4 : offset for indirect addressing
41 *
42 *---------------------------------------------------------------------------
43 *
44 *	isic - I4B Siemens ISDN Chipset Driver for SWS cards
45 *	====================================================
46 *
47 *		EXPERIMENTAL !!!!
48 *		=================
49 *
50 *	$Id: isic_isapnp_sws.c,v 1.13 2008/04/08 20:09:27 cegger Exp $
51 *
52 *	last edit-date: [Fri Jan  5 11:38:29 2001]
53 *
54 *	-hm	adding driver to i4b
55 *	-hm	adjustments for FreeBSD < 2.2.6, no PnP support yet
56 *
57 *---------------------------------------------------------------------------*/
58
59#include <sys/cdefs.h>
60__KERNEL_RCSID(0, "$NetBSD: isic_isapnp_sws.c,v 1.12 2007/10/19 12:00:32 ad Exp $");
61
62#include "opt_isicpnp.h"
63#ifdef ISICPNP_SEDLBAUER
64
65#define SWS_RESON  0 /* reset on                 */
66#define SWS_RESOFF 1 /* reset off                */
67#define SWS_ISAC   2 /* ISAC                     */
68#define SWS_HSCX0  3 /* HSCX0                    */
69#define SWS_RW     4 /* indirect access register */
70#define SWS_HSCX1  5 /* this is for fakeing that we mean hscx1, though */
71                     /* access is done through hscx0                   */
72
73#define SWS_REGS   8 /* we use an area of 8 bytes for io */
74
75#define SWS_BASE(X)   ((unsigned int)X&~(SWS_REGS-1))
76#define SWS_PART(X)   ((unsigned int)X& (SWS_REGS-1))
77#define SWS_ADDR(X)   ((SWS_PART(X) == SWS_ISAC) ? (SWS_BASE(X)+SWS_ISAC) : (SWS_BASE(X)+SWS_HSCX0) )
78#define SWS_REG(X,Y)  ((SWS_PART(X) != SWS_HSCX1) ? Y : (Y+0x40) )
79#define SWS_IDO(X)    (SWS_BASE(X)+SWS_RW)
80
81#include <sys/param.h>
82#if defined(__FreeBSD__) && __FreeBSD__ >= 3
83#include <sys/ioccom.h>
84#else
85#include <sys/ioctl.h>
86#endif
87#include <sys/kernel.h>
88#include <sys/systm.h>
89#include <sys/mbuf.h>
90
91#if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
92#include <sys/callout.h>
93#endif
94
95#ifdef __FreeBSD__
96#include <machine/clock.h>
97#include <i386/isa/isa_device.h>
98#else
99#include <sys/bus.h>
100#include <sys/device.h>
101#endif
102
103#include <sys/socket.h>
104#include <net/if.h>
105
106#ifdef __FreeBSD__
107#include <machine/i4b_debug.h>
108#include <machine/i4b_ioctl.h>
109#else
110#include <netisdn/i4b_debug.h>
111#include <netisdn/i4b_ioctl.h>
112#include <netisdn/i4b_l2.h>
113#endif
114
115#include <dev/ic/isic_l1.h>
116#include <dev/ic/isac.h>
117#include <dev/ic/hscx.h>
118
119#include <netisdn/i4b_global.h>
120#include <netisdn/i4b_l1l2.h>
121#include <netisdn/i4b_mbuf.h>
122
123#ifndef __FreeBSD__
124static u_int8_t sws_read_reg  (struct isic_softc *sc, int what, bus_size_t offs);
125static void     sws_write_reg (struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data);
126static void     sws_read_fifo (struct isic_softc *sc, int what, void *buf, size_t size);
127static void     sws_write_fifo(struct isic_softc *sc, int what, const void *data, size_t size);
128void		isic_attach_sws(struct isic_softc *sc);
129#endif
130
131/*---------------------------------------------------------------------------*
132 *      SWS P&P ISAC get fifo routine
133 *---------------------------------------------------------------------------*/
134
135#ifdef __FreeBSD__
136
137static void
138sws_read_fifo(void *buf, const void *base, size_t len)
139{
140 outb(SWS_IDO(base),SWS_REG(base,0));
141 insb(SWS_ADDR(base),buf,len);
142}
143
144#else
145
146static void
147sws_read_fifo(struct isic_softc *sc, int what, void *buf, size_t size)
148{
149	bus_space_tag_t t = sc->sc_maps[0].t;
150	bus_space_handle_t h = sc->sc_maps[0].h;
151	switch (what) {
152		case ISIC_WHAT_ISAC:
153			bus_space_write_1(t, h, SWS_RW, 0);
154			bus_space_read_multi_1(t, h, SWS_ISAC, buf, size);
155			break;
156		case ISIC_WHAT_HSCXA:
157			bus_space_write_1(t, h, SWS_RW, 0);
158			bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size);
159			break;
160		case ISIC_WHAT_HSCXB:
161			bus_space_write_1(t, h, SWS_RW, 0x40);
162			bus_space_read_multi_1(t, h, SWS_HSCX0, buf, size);
163			break;
164	}
165}
166
167#endif
168
169/*---------------------------------------------------------------------------*
170 *      SWS P&P ISAC put fifo routine
171 *---------------------------------------------------------------------------*/
172
173#ifdef __FreeBSD__
174
175static void
176sws_write_fifo(void *base, const void *buf, size_t len)
177{
178 outb (SWS_IDO(base),SWS_REG(base,0));
179 outsb(SWS_ADDR(base),buf,len);
180}
181
182#else
183
184static void
185sws_write_fifo(struct isic_softc *sc, int what, const void *buf, size_t size)
186{
187	bus_space_tag_t t = sc->sc_maps[0].t;
188	bus_space_handle_t h = sc->sc_maps[0].h;
189	switch (what) {
190		case ISIC_WHAT_ISAC:
191			bus_space_write_1(t, h, SWS_RW, 0);
192			bus_space_write_multi_1(t, h, SWS_ISAC, buf, size);
193			break;
194		case ISIC_WHAT_HSCXA:
195			bus_space_write_1(t, h, SWS_RW, 0);
196			bus_space_write_multi_1(t, h, SWS_HSCX0, buf, size);
197			break;
198		case ISIC_WHAT_HSCXB:
199			bus_space_write_1(t, h, SWS_RW, 0x40);
200			bus_space_write_multi_1(t, h, SWS_HSCX0, buf, size);
201			break;
202	}
203}
204
205#endif
206
207/*---------------------------------------------------------------------------*
208 *      SWS P&P ISAC put register routine
209 *---------------------------------------------------------------------------*/
210
211#ifdef __FreeBSD__
212
213static void
214sws_write_reg(u_char *base, u_int offset, u_int v)
215{
216 outb(SWS_IDO(base),SWS_REG(base,offset));
217 outb(SWS_ADDR(base),v);
218}
219
220#else
221
222static void
223sws_write_reg(struct isic_softc *sc, int what, bus_size_t offs, u_int8_t data)
224{
225	bus_space_tag_t t = sc->sc_maps[0].t;
226	bus_space_handle_t h = sc->sc_maps[0].h;
227	switch (what) {
228		case ISIC_WHAT_ISAC:
229			bus_space_write_1(t, h, SWS_RW, offs);
230			bus_space_write_1(t, h, SWS_ISAC, data);
231			break;
232		case ISIC_WHAT_HSCXA:
233			bus_space_write_1(t, h, SWS_RW, offs);
234			bus_space_write_1(t, h, SWS_HSCX0, data);
235			break;
236		case ISIC_WHAT_HSCXB:
237			bus_space_write_1(t, h, SWS_RW, 0x40+offs);
238			bus_space_write_1(t, h, SWS_HSCX0, data);
239			break;
240	}
241}
242
243#endif
244
245/*---------------------------------------------------------------------------*
246 *	SWS P&P ISAC get register routine
247 *---------------------------------------------------------------------------*/
248#ifdef __FreeBSD__
249
250static u_char
251sws_read_reg(u_char *base, u_int offset)
252{
253 outb(SWS_IDO(base),SWS_REG(base,offset));
254 return inb(SWS_ADDR(base));
255}
256
257#else
258
259static u_int8_t
260sws_read_reg(struct isic_softc *sc, int what, bus_size_t offs)
261{
262	bus_space_tag_t t = sc->sc_maps[0].t;
263	bus_space_handle_t h = sc->sc_maps[0].h;
264	switch (what) {
265		case ISIC_WHAT_ISAC:
266			bus_space_write_1(t, h, SWS_RW, offs);
267			return bus_space_read_1(t, h, SWS_ISAC);
268		case ISIC_WHAT_HSCXA:
269			bus_space_write_1(t, h, SWS_RW, offs);
270			return bus_space_read_1(t, h, SWS_HSCX0);
271		case ISIC_WHAT_HSCXB:
272			bus_space_write_1(t, h, SWS_RW, 0x40+offs);
273			return bus_space_read_1(t, h, SWS_HSCX0);
274	}
275	return 0;
276}
277
278#endif
279
280#ifdef __FreeBSD__
281
282/* attach callback routine */
283
284int
285isic_attach_sws(struct isa_device *dev)
286{
287	struct isic_softc *sc = &l1_sc[dev->id_unit];
288
289	/* fill in isic_softc structure */
290
291	sc->readreg     = sws_read_reg;
292	sc->writereg    = sws_write_reg;
293	sc->readfifo    = sws_read_fifo;
294	sc->writefifo   = sws_write_fifo;
295	sc->clearirq    = NULL;
296	sc->sc_unit     = dev->id_unit;
297	sc->sc_irq      = dev->id_irq;
298	sc->sc_port     = dev->id_iobase;
299	sc->sc_cardtyp  = CARD_TYPEP_SWS;
300	sc->sc_bustyp   = BUS_TYPE_IOM2;
301	sc->sc_ipac     = 0;
302	sc->sc_bfifolen = HSCX_FIFO_LEN;
303	dev->id_msize   = 0;
304
305	ISAC_BASE   = (void *) (((u_int) sc->sc_port) + SWS_ISAC);
306	HSCX_A_BASE = (void *) (((u_int) sc->sc_port) + SWS_HSCX0);
307	HSCX_B_BASE = (void *) (((u_int) sc->sc_port) + SWS_HSCX1);
308
309	/*
310	 * Read HSCX A/B VSTR.  Expected value for the SWS PnP card is
311	 * 0x05 ( = version 2.1 ) in the least significant bits.
312	 */
313
314	if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
315            ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
316	{
317		printf("isic%d: HSCX VSTR test failed for SWS PnP\n",
318			dev->id_unit);
319		printf("isic%d: HSC0: VSTR: %#x\n",
320			dev->id_unit, HSCX_READ(0, H_VSTR));
321		printf("isic%d: HSC1: VSTR: %#x\n",
322			dev->id_unit, HSCX_READ(1, H_VSTR));
323		return (0);
324	}
325
326	/* reset card */
327
328	outb( ((u_int) sc->sc_port) + SWS_RESON , 0x3);
329	DELAY(SEC_DELAY / 5);
330	outb( ((u_int) sc->sc_port) + SWS_RESOFF, 0);
331	DELAY(SEC_DELAY / 5);
332
333	return(1);
334}
335
336#else /* !__FreeBSD__ */
337
338void
339isic_attach_sws(struct isic_softc *sc)
340{
341	/* setup access routines */
342
343	sc->readreg   = sws_read_reg;
344	sc->writereg  = sws_write_reg;
345
346	sc->readfifo  = sws_read_fifo;
347	sc->writefifo = sws_write_fifo;
348
349	/* setup card type */
350
351	sc->sc_cardtyp = CARD_TYPEP_SWS;
352
353	/* setup IOM bus type */
354
355	sc->sc_bustyp = BUS_TYPE_IOM2;
356
357	sc->sc_ipac = 0;
358	sc->sc_bfifolen = HSCX_FIFO_LEN;
359
360	/*
361	 * Read HSCX A/B VSTR.  Expected value for the SWS PnP card is
362	 * 0x05 ( = version 2.1 ) in the least significant bits.
363	 */
364
365	if( ((HSCX_READ(0, H_VSTR) & 0xf) != 0x5) ||
366            ((HSCX_READ(1, H_VSTR) & 0xf) != 0x5) )
367	{
368		printf("%s: HSCX VSTR test failed for SWS PnP\n",
369			device_xname(&sc->sc_dev));
370		printf("%s: HSC0: VSTR: %#x\n",
371			device_xname(&sc->sc_dev), HSCX_READ(0, H_VSTR));
372		printf("%s: HSC1: VSTR: %#x\n",
373			device_xname(&sc->sc_dev), HSCX_READ(1, H_VSTR));
374		return;
375	}
376
377	/* reset card */
378        {
379        	bus_space_tag_t t = sc->sc_maps[0].t;
380        	bus_space_handle_t h = sc->sc_maps[0].h;
381        	bus_space_write_1(t, h, SWS_RESON, 0x3);
382		DELAY(SEC_DELAY / 5);
383		bus_space_write_1(t, h, SWS_RESOFF, 0);
384		DELAY(SEC_DELAY / 5);
385	}
386}
387
388#endif /* !__FreeBSD__ */
389
390#endif /* ISICPNP_SEDLBAUER */
391