1/*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31#include <sys/cdefs.h>
32__KERNEL_RCSID(0, "$NetBSD: daic.c,v 1.29 2009/05/12 14:25:17 cegger Exp $");
33
34/*
35 * daic.c: MI driver for Diehl active ISDN cards (S, SX, SXn, SCOM, QUADRO)
36 */
37
38#include <sys/param.h>
39#include <sys/systm.h>
40#include <sys/kernel.h>
41#include <sys/errno.h>
42#include <sys/ioctl.h>
43#include <sys/device.h>
44#include <sys/malloc.h>
45#include <sys/proc.h>
46#include <sys/socket.h>
47#include <net/if.h>
48
49#include <netisdn/i4b_ioctl.h>
50#include <netisdn/i4b_l3l4.h>
51#include <netisdn/i4b_isdnq931.h>
52#include <netisdn/i4b_q931.h>
53#include <netisdn/i4b_l3fsm.h>
54#include <netisdn/i4b_l4.h>
55
56#include <sys/bus.h>
57#include <dev/ic/daicvar.h>
58#include <dev/ic/daicreg.h>
59#include <dev/microcode/daic/dnload.h>
60
61#ifdef NetBSD1_3
62#if NetBSD1_3 < 2
63/* the device is MI, only the attach struct is in the bus
64   dependent frontend. And only on old versions... */
65struct cfdriver daic_cd = {
66	NULL, "daic", DV_DULL
67};
68#endif
69#endif
70
71/* local function prototypes */
72static const char * cardtypename(int cardtype);
73static int daic_download(void *, int portcount, struct isdn_dr_prot *data);
74static int daic_diagnostic(void *, struct isdn_diagnostic_request *req);
75static void daic_connect_request(struct call_desc *cd);
76static void daic_connect_response(struct call_desc *cd, int, int);
77static void daic_disconnect_request(struct call_desc *cd, int);
78static int daic_reset(bus_space_tag_t bus, bus_space_handle_t io, int port, int *memsize);
79static int daic_handle_intr(struct daic_softc *sc, int port);
80static void daic_register_port(struct daic_softc *sc, int port);
81static void daic_request(struct daic_softc *sc, int port, u_int req, u_int id, bus_size_t parmsize, const u_int8_t *parms);
82static u_int daic_assign(struct daic_softc *sc, int port, u_int instance, bus_size_t parmsize, const u_int8_t *parms);
83static void daic_indicate_ind(struct daic_softc *sc, int port);
84static void daic_bch_config(void *, int channel, int bprot, int updown);
85static void daic_bch_tx_start(void *, int channel);
86static void daic_set_link(void *softc, int channel,
87	const struct isdn_l4_driver_functions *l4_driver, void *l4_inst );
88static void daic_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm);
89static void daic_alert_request(struct call_desc *cd);
90
91static isdn_link_t *daic_ret_linktab(void *softc, int channel);
92
93#ifdef DAIC_DEBUG
94static void daic_dump_request(struct daic_softc *sc, int port, u_int req, u_int id, bus_size_t parmsize, u_int8_t *parms);
95#endif
96
97/* static data */
98static const char * const cardnames[] = {
99	"S", "SX", "SCOM", "QUADRO"
100};
101
102static const char * const err_codes[DAIC_RC_ERRMASK+1] = {
103	"NO ERROR",
104	"UNKNOWN COMMAND",
105	"WRONG COMMAND",
106	"WRONG ID",
107	"WRONG CH",
108	"UNKNOWN IE",
109	"WRONG IE",
110	"OUT OF RESOURCES"
111};
112
113/* fixed parameters */
114
115/* no parameters */
116static u_int8_t parm_none[] = { 0 };
117#define	VOIDREQ(sc,port,req,id)	daic_request(sc, port, req, id, sizeof parm_none, parm_none)
118
119/* assign request for the global d-channel instance */
120static u_int8_t parm_global_assign[] = {
121/*	BC	len	cap	rate	A-law	*/
122	0x04,	0x03,	0x80,	0x90,	0xa3,	/* 64k speech */
123	0x04,	0x02,	0x88,	0x90,		/* 64k data */
124	0x04,	0x03,	0x89,	0x90,	0xa3,	/* restricted digital info */
125	0x04,	0x03,	0x90,	0x90,	0xa3,	/* 3.1k speech */
126/*	shift6	SIN	len	service		*/
127	0x96,	0x01,	0x02,	0x00, 0x00,	/* any service */
128/*	end of parms */
129	0x00
130};
131
132/*---------------------------------------------------------------------------*
133 *	Return the name of a card with given cardtype
134 *---------------------------------------------------------------------------*/
135static const char *
136cardtypename(int cardtype)
137{
138	if (cardtype >= 0 && cardtype < (sizeof(cardnames) / sizeof(cardnames[0])))
139		return cardnames[cardtype];
140	else
141		return "unknown type";
142}
143
144/*---------------------------------------------------------------------------*
145 * Probe for presence of device at given io space.
146 * Return the card type (stupid ISA needs to know this in advance, to
147 * calculate the share memory size).
148 *---------------------------------------------------------------------------*/
149int
150daic_probe(bus_space_tag_t bus, bus_space_handle_t io)
151{
152	return (daic_reset(bus, io, 0, NULL));
153}
154
155/*---------------------------------------------------------------------------*
156 * Attach and initialize the card at given io space.
157 *---------------------------------------------------------------------------*/
158void
159daic_attach(device_t self, struct daic_softc *sc)
160{
161	int i, num_ports, memsize = 0;
162
163	/* init sc */
164	memset(sc->sc_port, 0, sizeof sc->sc_port);
165	memset(sc->sc_con, 0, sizeof sc->sc_con);
166	sc->sc_cardtype = -1;
167
168	/* init card */
169	sc->sc_cardtype = daic_reset(sc->sc_iot, sc->sc_ioh, 0, &memsize);
170	if (sc->sc_cardtype == 0) {
171		printf(": unknown card, can not attach.\n");
172		return;
173	}
174
175	printf("\n");
176	printf("%s: EICON.Diehl %s\n", device_xname(&sc->sc_dev),
177	    cardtypename(sc->sc_cardtype));
178	printf("%s: %d kByte on board RAM\n", device_xname(&sc->sc_dev), memsize);
179	num_ports = sc->sc_cardtype == DAIC_TYPE_QUAD ? 4 : 1;
180	for (i = 0; i < num_ports; i++)
181		sc->sc_port[i].du_state = DAIC_STATE_DOWNLOAD;
182
183	/* register all ports this card has */
184	for (i = 0; i < num_ports; i++)
185		daic_register_port(sc, i);
186}
187
188/*---------------------------------------------------------------------------*
189 * handle interrupts for one port of the card
190 *---------------------------------------------------------------------------*/
191static int
192daic_handle_intr(struct daic_softc *sc, int port)
193{
194	struct outcallentry *assoc;
195	struct daic_unit * du = &sc->sc_port[port];
196	int off = port * DAIC_ISA_MEMSIZE;
197	u_int8_t rc, rcid;
198	u_int8_t ind, indid;
199	int chan;
200
201	/* check if we caused the interrupt */
202	if (!bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_IRQ+off))
203		return 0;	/* nope, exit */
204
205	/* is the card in running state yet? */
206	if (du->du_state == DAIC_STATE_TESTING) {
207		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
208		du->du_state = DAIC_STATE_RUNNING;
209		wakeup(du);
210		goto done;
211	}
212
213	/* what caused the interrupt? */
214	/* (1) Check for a return code */
215	rc = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off);
216	rcid = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RCID+off);
217	if (!rc) goto check_ind;
218
219	/* maybe an assign answer (positive or negative) */
220	if (rc == DAIC_RC_ASSIGN_OK) {
221		du->du_assign_res = rcid;
222		/* assing rc is special, we tell the card it's done */
223		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 0);
224		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
225		/* we handle some types of assigns to global dchannel id's automaticaly */
226		if (du->du_assign & DAIC_ASSIGN_GLOBAL) {
227			du->du_global_dchan = rcid;
228			du->du_assign &= ~(DAIC_ASSIGN_GLOBAL|DAIC_ASSIGN_PENDING);
229			if (du->du_assign & DAIC_ASSIGN_SLEEPING) {
230				du->du_assign = 0;
231				wakeup(&du->du_assign_res);
232			}
233		} else {
234			wakeup(&du->du_assign);
235		}
236		goto check_ind;
237	} else if ((rc & DAIC_RC_ASSIGN_MASK) == DAIC_RC_ASSIGN_RC) {
238		aprint_error_dev(&sc->sc_dev, "assign request failed, error 0x%02x: %s\n",
239			rc & DAIC_RC_ERRMASK,
240			err_codes[rc & DAIC_RC_ERRMASK]);
241		du->du_assign_res = 0;
242		/* assing rc is special, we tell the card it's done */
243		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 0);
244		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
245		/* that's it */
246		wakeup(&du->du_assign);
247		goto check_ind;
248	}
249	if (rcid == du->du_global_dchan) {
250		du->du_request_res = rc;
251		wakeup(&du->du_request_res);
252		goto req_done;
253	}
254	for (chan = 0; chan < 2; chan++) {
255		if (rcid == sc->sc_con[port*2+chan].dchan_inst) {
256			sc->sc_con[port*2+chan].dchan_rc = rc;
257			wakeup(&sc->sc_con[port*2+chan].dchan_rc);
258			goto req_done;
259		} else if (rcid == sc->sc_con[port*2+chan].bchan_inst) {
260			sc->sc_con[port*2+chan].bchan_rc = rc;
261			wakeup(&sc->sc_con[port*2+chan].bchan_rc);
262			goto req_done;
263		}
264	}
265	TAILQ_FOREACH(assoc, &sc->sc_outcalls[port], queue) {
266		if (rcid == assoc->dchan_id) {
267			assoc->rc = rc;
268			wakeup(assoc);
269			goto req_done;
270		}
271	}
272
273	/* not found? */
274	printf("%s: unknown id 0x%02x got rc 0x%02x: %s\n",
275		device_xname(&sc->sc_dev), rcid, rc,
276		err_codes[rc & DAIC_RC_ERRMASK]);
277
278req_done:
279	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
280
281check_ind:
282	/* (2) Check for an indication */
283	ind = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_IND+off);
284	indid = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_INDID+off);
285	if (!ind) goto done;
286
287	/* incoming call routed to global dchannel task? */
288	if (indid == du->du_global_dchan) {
289		if (ind == DAIC_IND_INDICATE) {
290			daic_indicate_ind(sc, port);
291		} else if (ind == DAIC_IND_INFO) {
292			int i;
293
294			printf("%s: got info indication\n",
295				device_xname(&sc->sc_dev));
296
297			for (i = 0; i < 48; i++) {
298				if (!(i % 16))
299					printf("\n%02x:", i);
300				printf(" %02x", bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+off+i));
301			}
302			printf("\n");
303		} else if (ind == DAIC_IND_HANGUP) {
304			printf("%s: got global HANGUP indication\n",
305				device_xname(&sc->sc_dev));
306		} else {
307			printf("%s: unknown global indication: 0x%02x\n",
308				device_xname(&sc->sc_dev), ind);
309		}
310		goto ind_done;
311	}
312
313	for (chan = 0; chan < 2; chan++) {
314		if (indid == sc->sc_con[port*2+chan].dchan_inst) {
315			printf("%s: D-Channel indication 0x%02x for channel %d\n",
316				device_xname(&sc->sc_dev), ind, chan);
317			goto ind_done;
318		} else if (indid == sc->sc_con[port*2+chan].bchan_inst) {
319			printf("%s: B-Channel indication 0x%02x for channel %d\n",
320				device_xname(&sc->sc_dev), ind, chan);
321			goto ind_done;
322		}
323	}
324
325	TAILQ_FOREACH(assoc, &sc->sc_outcalls[port], queue) {
326		if (indid == assoc->dchan_id) {
327			printf("%s: D-Channel indication 0x%02x for outgoing call with cdid %d\n",
328				device_xname(&sc->sc_dev), ind, assoc->cdid);
329			goto ind_done;
330		}
331	}
332
333	/* not found - something's wrong! */
334	printf("%s: got ind 0x%02x for id 0x%02x\n", device_xname(&sc->sc_dev), ind, indid);
335
336ind_done:
337	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_IND+off, 0);
338
339done:
340	/* tell card we're ready for more... */
341	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_IRQ+off, 0);
342
343	return 1;
344}
345
346/*---------------------------------------------------------------------------*
347 * Handle interrupts
348 *---------------------------------------------------------------------------*/
349int
350daic_intr(struct daic_softc *sc)
351{
352	int handeld = 0;
353	if (sc->sc_cardtype == DAIC_TYPE_QUAD) {
354		int i;
355		for (i = 0; i < 4; i++)
356			handeld |= daic_handle_intr(sc, i);
357	} else
358		handeld = daic_handle_intr(sc, 0);
359	return handeld;
360}
361
362/*---------------------------------------------------------------------------*
363 * Download primary protocol microcode to on-board processor
364 *---------------------------------------------------------------------------*/
365static int
366daic_download(void *token, int count, struct isdn_dr_prot *data)
367{
368	struct daic_unit *du = token;
369	struct daic_softc *sc = du->du_sc;
370	int i;
371
372	if (sc->sc_cardtype != DAIC_TYPE_QUAD)
373		count = 1;	/* XXX - or signal error ? */
374
375	for (i = 0; i < count; i++) {
376		int off = DAIC_ISA_MEMSIZE * i;
377		u_int8_t *p = data[i].microcode;
378		size_t s = data[i].bytecount;
379		u_int32_t sw_id;
380		int cnt, x;
381		for (p = data[i].microcode+4, cnt = 0; *p && cnt < 70; p++, cnt++)
382			;
383		sw_id = p[1] | (p[2] << 8) | (p[3] << 16) | (p[4] << 24);
384		if (sc->sc_cardtype == DAIC_TYPE_QUAD)
385			printf("%s port %d: downloading %s\n",
386				device_xname(&sc->sc_dev), i, data[i].microcode+4);
387		else
388			printf("%s: downloading %s\n",
389				device_xname(&sc->sc_dev), data[i].microcode+4);
390		x = splnet();
391		p = data[i].microcode;
392		while (s > 0) {
393		    size_t size = (s > 256) ? 256 : s;
394		    bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_BUF+off, p, size);
395		    p += size;
396		    s -= size;
397		    bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off, 1);
398		    splx(x);
399		    for (cnt = 0; cnt < 2*hz; cnt++) {
400		    	x = splnet();
401		    	if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off) == 0)
402		    	    break;
403		    	splx(x);
404		    	tsleep(sc, 0, "daic download", 1);
405		    }
406	    	    if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off) != 0) {
407	    	    	splx(x);
408	    	    	aprint_error_dev(&sc->sc_dev, "download of microcode failed\n");
409	    	    	return EIO;
410	    	    }
411		}
412
413		/* configure microcode - no parameters yet - XXX */
414		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_TEI+off, 0);
415		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_NT2+off, 0);
416		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_ZERO+off, 0);
417		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_WATCHDOG+off, 0);
418		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_PERMANENT+off, 0);
419		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_XINTERFACE+off, 0);
420
421		/* start protocol */
422		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off, 2);
423
424		/* wait for signature */
425		for (cnt = 0; cnt < 2*hz; cnt++) {
426			u_int16_t signature;
427			signature = bus_space_read_2(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_SIGNATURE+off);
428			if (signature == DAIC_SIGNATURE_VALUE)
429				break;
430			if (signature) {
431				if (signature != DAIC_SIGNATURE_VALUE) {
432					splx(x);
433					aprint_error_dev(&sc->sc_dev, "microcode signature bad: should be %04x, is %04x\n",
434						DAIC_SIGNATURE_VALUE,signature);
435					return EIO;
436				}
437				break;
438			}
439			splx(x);
440			tsleep(&sc->sc_port[i].du_state, 0, "daic protocol init", hz/25);
441			x = splnet();
442		}
443
444		/* real check: send an invalid request and wait for an interrupt */
445		sc->sc_port[i].du_state = DAIC_STATE_TESTING;
446		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
447		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQID+off, 0xff);
448		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, 1);
449		splx(x);
450		tsleep(&sc->sc_port[i].du_state, 0, "daic irq test", 2*hz);
451		x = splnet();
452		if (sc->sc_port[i].du_state != DAIC_STATE_RUNNING) {
453			splx(x);
454			printf("%s: download interrupt test timeout\n",
455				device_xname(&sc->sc_dev));
456			return EIO;
457		}
458
459		/* finish card configuration */
460		bus_space_write_4(sc->sc_iot, sc->sc_ioh, DAIC_SWID+off, sw_id);
461		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_SET_CARD+off, sc->sc_cardtype);
462		splx(x);
463
464		/* assign global d-channel id for that port */
465		sc->sc_port[i].du_global_dchan =
466			daic_assign(sc, i, DAIC_GLOBALID_DCHAN,
467				sizeof parm_global_assign, parm_global_assign);
468
469		/* send an INDICATE request to get incoming calls on this id */
470		x = splnet();
471		VOIDREQ(sc, i, DAIC_REQ_INDICATE, sc->sc_port[i].du_global_dchan);
472		splx(x);
473		tsleep(&sc->sc_port[i].du_request_res, 0, "daic request", 0);
474		x = splnet();
475		if (sc->sc_port[i].du_request_res != DAIC_RC_OK) {
476			aprint_error_dev(&sc->sc_dev, "INDICATE request error (0x%02x): %s\n",
477				sc->sc_port[i].du_request_res,
478				err_codes[sc->sc_port[i].du_request_res & DAIC_RC_ERRMASK]);
479			splx(x);
480			return EIO;
481		}
482		splx(x);
483	}
484	return 0;
485}
486
487/*---------------------------------------------------------------------------*
488 *	Reset the card, download primary bootstrap, let it check the
489 *	card and return the cardtype identified by the microcode
490 *	or -1 if no known card is detected.
491 *---------------------------------------------------------------------------*/
492static int
493daic_reset(bus_space_tag_t bus, bus_space_handle_t io, int port, int *memsize)
494{
495	int i, off = port * DAIC_ISA_MEMSIZE;
496	int cardtype, mem, quiet = memsize == NULL;	/* no output if we are only probing */
497
498	/* clear any pending interrupt */
499	bus_space_read_1(bus, io, DAIC_IRQ+off);
500	/* reset card */
501	bus_space_write_1(bus, io, DAIC_BOOT_SET_RESET+off, 0);
502
503	/* download primary bootstrap */
504	bus_space_set_region_1(bus, io, DAIC_BOOT_START+off, 0, DAIC_BOOT_CODE-DAIC_BOOT_START);
505	bus_space_write_region_1(bus, io, DAIC_BOOT_CODE+off, dnload, DAIC_BOOT_END-DAIC_BOOT_CODE+1);
506	if (bus_space_read_1(bus, io, DAIC_BOOT_CTRL+off)
507	  || bus_space_read_1(bus, io, DAIC_BOOT_EBIT+off)) {
508	  	if (!quiet) printf(": shared memory test failed!\n");
509	  	return -1;
510	}
511	/* let card perform memory test */
512	bus_space_write_1(bus, io, DAIC_BOOT_CTRL+off, DAIC_TEST_MEM);
513	/* and off we go... */
514	bus_space_write_1(bus, io, DAIC_BOOT_CLR_RESET+off, 0);
515	/* wait for response from bootstrap */
516	for (i = 0; i < 15000 && bus_space_read_1(bus, io, DAIC_BOOT_CTRL+off) != DAIC_TEST_RDY; i++)
517		DELAY(100);
518	if (i >= 15000) {
519		if (!quiet) printf(": on board processor test failed!\n");
520		return -1;
521	}
522	if (bus_space_read_1(bus, io, DAIC_BOOT_EBIT+off)) {
523		if (!quiet) printf(": on board memory test failed at %x\n",
524			bus_space_read_2(bus, io, DAIC_BOOT_ELOC+off));
525		return -1;
526	}
527
528	/* fetch info from primary bootstrap code */
529	cardtype = bus_space_read_1(bus, io, DAIC_BOOT_CARD+off);
530	mem = bus_space_read_1(bus, io, DAIC_BOOT_MSIZE+off) << 4;
531	if (memsize)
532		*memsize = mem;
533
534	return cardtype;
535}
536
537/*---------------------------------------------------------------------------*
538 * Generic diagnostic interface - pass through the microcode data
539 * without knowing too much about it. This passes a lot work to
540 * userland, but hey, this is only a diagnostic tool...
541 *---------------------------------------------------------------------------*/
542static int
543daic_diagnostic(void *token, struct isdn_diagnostic_request *req)
544{
545	struct daic_unit *du = token;
546	struct daic_softc *sc = du->du_sc;
547	int port = du->du_port;
548	int off = port * DAIC_ISA_MEMSIZE;
549	int rc, cnt;
550	int s, err = 0;
551
552	/* validate parameters */
553	if (req->cmd > DAIC_DIAG_MAXCMD) {
554		aprint_error_dev(&sc->sc_dev, "daic_diagnostic: illegal cmd %d\n",
555			req->cmd);
556		return EIO;
557	}
558	if (req->out_param_len > (DAIC_DIAG_DATA_SIZE+1)) {
559		aprint_error_dev(&sc->sc_dev, "daic_diagnostic: illegal out_param_len %d\n",
560			req->out_param_len);
561		return EIO;
562	}
563
564	/* XXX - only for debug */
565	if (req->cmd == 0x05) {
566		/* pass through request from userland */
567
568		u_int8_t id;
569		static u_int8_t parms[] = {
570			IEI_CALLID, 0x01, 0x81,
571			IEI_CALLINGPN, 7, NUMBER_TYPEPLAN, '9', '8', '9',  '0', '2', '0',
572			0x96, 0x01, 0x02, 0x01, 0x00,
573			0x00
574		};
575
576		/* create the d-channel task for this call */
577		printf("%s: assigning id for pass-through call\n", device_xname(&sc->sc_dev));
578		id = daic_assign(sc, port, DAIC_GLOBALID_DCHAN, sizeof(parms), parms);
579		printf("%s: got id 0x%02x\n", device_xname(&sc->sc_dev), id);
580
581#ifdef DAIC_DEBUG
582		daic_dump_request(sc, port, DAIC_REQ_CALL, id, req->in_param_len, req->in_param);
583#endif
584		daic_request(sc, port, DAIC_REQ_CALL, id, req->in_param_len, req->in_param);
585		return 0;
586	}
587
588	/* all these need an output parameter */
589	if (req->out_param == NULL)
590		return EIO;
591
592	/* check state and switch to DIAGNOSTIC */
593	s = splnet();
594	if (sc->sc_port[port].du_state != DAIC_STATE_RUNNING) {
595		splx(s);
596		return EWOULDBLOCK;
597	}
598	sc->sc_port[port].du_state = DAIC_STATE_DIAGNOSTIC;
599	splx(s);
600
601	/* set new request */
602	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off, req->cmd);
603
604	/* sorry, no interrupt on completition - have to poll */
605	for (cnt = 0; cnt < 3*hz; cnt++) {
606		if (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off) == 0
607		   && bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off) != 0)
608			break;
609		tsleep(sc, 0, "daic diagnostic", 1);
610	}
611	rc = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off);
612	if (rc == 0) {
613		/* stop request and return error */
614		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off, 0);
615		bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off, 0);
616		err = EIO;
617		goto done;
618	}
619	/* out param gets rc and all the data */
620	if (req->out_param_len >= 2) {
621		((u_int8_t*)(req->out_param))[0] = (u_int8_t)rc;
622		bus_space_read_region_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_DATA+off, ((u_int8_t*)req->out_param)+1, req->out_param_len-1);
623	}
624	/* acknowledge data */
625	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off, 0);
626
627done:	/* back to normal state */
628	s = splnet();
629	sc->sc_port[port].du_state = DAIC_STATE_RUNNING;
630	splx(s);
631
632	return err;
633}
634
635static void daic_stat(void *port, int channel, bchan_statistics_t *bsp)
636{
637}
638
639static const struct isdn_l4_bchannel_functions
640daic_l4_driver = {
641	daic_bch_config,
642	daic_bch_tx_start,
643	daic_stat
644};
645
646static const struct isdn_l3_driver_functions
647daic_l3_functions =  {
648	daic_ret_linktab,
649	daic_set_link,
650	daic_connect_request,
651	daic_connect_response,
652	daic_disconnect_request,
653	daic_alert_request,
654	daic_download,
655	daic_diagnostic,
656	daic_mgmt_command
657};
658
659/*---------------------------------------------------------------------------*
660 *	Register one port and attach it to the upper layers
661 *---------------------------------------------------------------------------*/
662static void
663daic_register_port(struct daic_softc *sc, int port)
664{
665	int chan;
666	char cardname[80], devname[80];
667	struct isdn_l3_driver * l3drv;
668
669	sc->sc_port[port].du_port = port;
670	sc->sc_port[port].du_sc = sc;
671
672	/* make sure this hardware driver type is known to layer 4 */
673	if (sc->sc_cardtype == DAIC_TYPE_QUAD)
674		snprintf(devname, sizeof(devname), "%s port %d",
675		    device_xname(&sc->sc_dev), port);
676	else
677		strlcpy(devname, device_xname(&sc->sc_dev), sizeof(devname));
678	snprintf(cardname, sizeof(cardname), "EICON.Diehl %s",
679	    cardtypename(sc->sc_cardtype));
680	l3drv = isdn_attach_isdnif(
681	    devname, cardname, &sc->sc_port[port], &daic_l3_functions,
682	    NBCH_BRI);
683	sc->sc_port[port].du_l3 = l3drv;
684
685	/* initialize linktabs for this port */
686	for (chan = 0; chan < 2; chan++) {
687		isdn_link_t *lt = &sc->sc_con[port*2+chan].isdn_linktab;
688		lt->l1token = &sc->sc_port[port];
689		lt->channel = chan;
690		lt->tx_queue = &sc->sc_con[port*2+chan].tx_queue;
691		lt->rx_queue = &sc->sc_con[port*2+chan].rx_queue;
692	}
693	TAILQ_INIT(&sc->sc_outcalls[port]);
694
695	isdn_isdnif_ready(l3drv->isdnif);
696}
697
698/*---------------------------------------------------------------------------*
699 *	return the address of daic drivers linktab
700 *---------------------------------------------------------------------------*/
701static isdn_link_t *
702daic_ret_linktab(void *token, int channel)
703{
704	struct daic_unit *du = token;
705	struct daic_softc *sc = du->du_sc;
706	int port = du->du_port;
707	struct daic_connection *con = &sc->sc_con[port*2+channel];
708
709	return(&con->isdn_linktab);
710}
711
712/*---------------------------------------------------------------------------*
713 *	set the driver linktab in the b channel softc
714 *---------------------------------------------------------------------------*/
715static void
716daic_set_link(void *token, int channel, const struct isdn_l4_driver_functions *l4_driver, void *l4_inst)
717{
718	struct daic_unit *du = token;
719	struct daic_softc *sc = du->du_sc;
720	int port = du->du_port;
721	struct daic_connection *con = &sc->sc_con[port*2+channel];
722
723	con->l4_driver = l4_driver;
724	con->l4_driver_softc = l4_inst;
725}
726
727/*---------------------------------------------------------------------------*
728 *	Send a request to the card.
729 *---------------------------------------------------------------------------*/
730static void
731daic_request(
732	struct daic_softc *sc,		/* ourself */
733	int port, 			/* and the port on this card */
734	u_int req, 			/* the request to send */
735	u_int id, 			/* id of communication task */
736	bus_size_t parmsize, 		/* size of parms including the terminating zero */
737	const u_int8_t *parms)		/* pointer to parms to pass */
738{
739	int off = port*DAIC_ISA_MEMSIZE;
740
741	/* spin while card is yet busy */
742	while (bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ))
743		;	/* unlikely to happen with this driver */
744
745	/* output parameters */
746	bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_XBUFFER+off, parms, parmsize);
747
748	/* output request and id */
749	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQID+off, id);
750	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_REQ+off, req);
751}
752
753/*---------------------------------------------------------------------------*
754 *	Assign a unique instance id for some communication class
755 *	on the card. Only one assign request may be running on a
756 *	port at any time, handle this and return the instance id.
757 *---------------------------------------------------------------------------*/
758static u_int
759daic_assign(
760	struct daic_softc *sc,	/* our state and port no */
761	int port,
762	u_int classid,		/* Diehl calls this "global instance id" */
763	bus_size_t parmsize, 	/* sizeof parameter arra */
764	const u_int8_t *parms)	/* task instance parameters */
765{
766	static char wchan[] = "daic assign";
767	u_int8_t id;
768	int x;
769
770	/* there only may be one assignment running concurrently */
771		x = splnet();
772	for (;;) {
773		if (!(sc->sc_port[port].du_assign & DAIC_ASSIGN_PENDING))
774			break;	/* we got it! */
775
776		/* somebody else is assigning, record state and sleep */
777		sc->sc_port[port].du_assign |= DAIC_ASSIGN_SLEEPING;
778		tsleep(&sc->sc_port[port].du_assign_res, 0, wchan, 0);
779	}
780
781	/* put parameters and request to card */
782	sc->sc_port[port].du_assign |= DAIC_ASSIGN_PENDING;
783	daic_request(sc, port, DAIC_REQ_ASSIGN, classid, parmsize, parms);
784
785	/* wait for completition of assignment by the card */
786	tsleep(&sc->sc_port[port].du_assign, 0, wchan, 0);
787	id = sc->sc_port[port].du_assign_res;
788
789	/* have we lost our global dchannel id in the meantime? */
790	if (sc->sc_port[port].du_assign & DAIC_ASSIGN_NOGLOBAL) {
791		/* start an assign request and let the result
792		   be handled by the interrupt handler - we don't
793		   have to wait for it here. As the assign lock
794		   isn't freed, we don't wake up others... */
795		sc->sc_port[port].du_assign &= ~DAIC_ASSIGN_NOGLOBAL;
796		sc->sc_port[port].du_assign |= DAIC_ASSIGN_PENDING|DAIC_ASSIGN_GLOBAL;
797		daic_request(sc, port, DAIC_REQ_ASSIGN, DAIC_GLOBALID_DCHAN,
798			sizeof parm_global_assign, parm_global_assign);
799		splx(x);
800		return id;
801	}
802
803	/* XXX - review this, can't remember why I did it this complicated */
804
805	/* unlock and wakup others, if any */
806	if (sc->sc_port[port].du_assign & DAIC_ASSIGN_SLEEPING) {
807		sc->sc_port[port].du_assign = 0;
808		wakeup(&sc->sc_port[port].du_assign_res);
809	} else
810		sc->sc_port[port].du_assign = 0;
811	splx(x);
812
813	return id;
814}
815
816#ifdef DAIC_DEBUG
817/*---------------------------------------------------------------------------*
818 *	Debug output of request parameters
819 *---------------------------------------------------------------------------*/
820static void
821daic_dump_request(struct daic_softc *sc, int port, u_int req, u_int id, bus_size_t parmsize, u_int8_t *parms)
822{
823	int i;
824	printf("%s: request 0x%02x to task id 0x%02x:",
825		device_xname(&sc->sc_dev), req, id);
826	for (i = 0; i < parmsize; i++) {
827		if (i % 16 == 0)
828			printf("\n%02x:", i);
829		printf(" %02x", parms[i]);
830	}
831	printf("\n");
832}
833#endif
834
835/*---------------------------------------------------------------------------*
836 *	Decode parameters of an INDICATE indication from the card
837 *	and pass them to layer 4. Called from within an interrupt
838 *	context.
839 *---------------------------------------------------------------------------*/
840static void
841daic_indicate_ind(struct daic_softc *sc, int port)
842{
843	int offset = port*DAIC_ISA_MEMSIZE;
844	int i;
845	u_int8_t ie, ielen;
846	call_desc_t *cd;
847
848	/* get and init new calldescriptor */
849	cd = reserve_cd();	/* cdid filled in */
850	cd->bprot = BPROT_NONE;
851	cd->cause_in = 0;
852	cd->cause_out = 0;
853	cd->dst_telno[0] = '\0';
854	cd->src_telno[0] = '\0';
855	cd->channelid = CHAN_NO;
856	cd->channelexcl = 0;
857	cd->cr = -1;
858	cd->crflag = CRF_DEST;
859	cd->ilt = NULL;		/* reset link tab ptrs */
860
861	i = 0;
862	for (;;) {
863		ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i);
864		if (!ie) break;
865		i++;
866		if (ie & 0x80) continue;
867		ielen = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i);
868		i++;
869		switch (ie) {
870		  case IEI_BEARERCAP:
871		  	ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i);
872		  	if (ie == 0x80 || ie == 0x89 || ie == 0x90)
873		  		cd->bprot = BPROT_NONE;
874		  	else if (ie == 0x88)
875		  		cd->bprot = BPROT_RHDLC;
876		  	break;
877		  case IEI_CALLINGPN:
878		  	{
879		  		int off;
880			  	ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i);
881			  	if (ie & 0x80)
882			  		off = 1;
883			  	else
884			  		off = 2;
885			  	bus_space_read_region_1(sc->sc_iot, sc->sc_ioh,
886					DAIC_COM_RBUFFER+offset+i+off, cd->src_telno,
887					ielen - off);
888				cd->src_telno[ielen-off+1] = '\0';
889			}
890		  	break;
891		  case IEI_CALLEDPN:
892		  	bus_space_read_region_1(sc->sc_iot, sc->sc_ioh,
893		  		DAIC_COM_RBUFFER+offset+i+1,
894				cd->dst_telno, ielen-1);
895			cd->dst_telno[ielen] = '\0';
896		  	break;
897		  case IEI_CHANNELID:
898		  	ie = bus_space_read_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RBUFFER+offset+i);
899		  	if ((ie & 0xf4) != 0x80)
900		  		cd->channelid = CHAN_NO;
901		  	else {
902		  		switch(ie & 0x03) {
903		  		  case IE_CHAN_ID_NO:	cd->channelid = CHAN_NO; break;
904		  		  case IE_CHAN_ID_B1:	cd->channelid = CHAN_B1; break;
905		  		  case IE_CHAN_ID_B2:	cd->channelid = CHAN_B2; break;
906		  		  case IE_CHAN_ID_ANY:	cd->channelid = CHAN_ANY; break;
907		  		}
908		  		cd->channelexcl = (ie & 0x08) >> 3;
909		  	}
910		}
911		i += ielen;
912	}
913	cd->event = EV_SETUP;
914	/* ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_RSVD; */
915
916	/* record the dchannel id for this call and the call descriptor */
917	sc->sc_con[port*2+cd->channelid].dchan_inst = sc->sc_port[port].du_global_dchan;
918	sc->sc_con[port*2+cd->channelid].cdid = cd->cdid;
919
920	/* this task is busy now, we need a new global dchan id */
921	if (sc->sc_port[port].du_assign & DAIC_ASSIGN_PENDING) {
922		/* argh - can't assign right now */
923		sc->sc_port[port].du_assign |= DAIC_ASSIGN_NOGLOBAL;
924	} else {
925		/* yeah - can request the assign right away, but let the
926		   interrupt handler autohandle the result */
927		sc->sc_port[port].du_assign |= DAIC_ASSIGN_PENDING|DAIC_ASSIGN_GLOBAL;
928		daic_request(sc, port, DAIC_REQ_ASSIGN, DAIC_GLOBALID_DCHAN,
929			sizeof parm_global_assign, parm_global_assign);
930	}
931
932	if (cd->bprot == BPROT_NONE)
933		printf("\nincoming voice call from \"%s\" to \"%s\"\n",
934			cd->src_telno, cd->dst_telno);
935	else
936		printf("\nincoming data call from \"%s\" to \"%s\"\n",
937			cd->src_telno, cd->dst_telno);
938
939	/* hand up call to layer 4 */
940	i4b_l4_connect_ind(cd);
941}
942
943/*---------------------------------------------------------------------------*
944 *	Layer 4 request a call setup
945 *---------------------------------------------------------------------------*/
946static void
947daic_connect_request(struct call_desc *cd)
948{
949	u_int8_t id, cpn[TELNO_MAX+4], parms[TELNO_MAX+16], *p;
950	struct daic_unit *du = cd->ilt->l1token;
951	struct daic_softc *sc = du->du_sc;
952	int port = du->du_port;
953	int x, len;
954	struct outcallentry *assoc;
955
956	/* to associate the cdid with the communication task
957	   we are going to create for this outgoing call,
958	   we maintain a queue of pending outgoing calls.
959	   As soon as a SETUP response is received, we move
960	   the association to the allocated b-channel. */
961
962	/* configure d-channel task parameters */
963	p = parms;
964	*p++ = IEI_CALLID; *p++ = 0x01;
965	if (cd->bprot == BPROT_NONE) {
966		*p++ = 0x82;
967	} else if (cd->bprot == BPROT_RHDLC) {
968		*p++ = 0x85;
969	} else {
970		printf("%s: daic_connect_request for unknown bchan protocol 0x%x\n",
971			device_xname(&sc->sc_dev), cd->bprot);
972		return;
973	}
974	if (cd->src_telno[0]) {
975		*p++ = IEI_CALLINGPN;
976		*p++ = strlen(cd->src_telno)+1;
977		*p++ = NUMBER_TYPEPLAN;
978		strcpy(p, cd->src_telno);
979		p += strlen(p);
980	}
981	if (cd->channelid == CHAN_B1 || cd->channelid == CHAN_B2) {
982		*p++ = IEI_CHANNELID;
983		*p++ = 0x01;
984		*p++ = 0x81 + cd->channelid;
985	}
986	if (cd->bprot == BPROT_NONE) {
987		*p++ = 0x96;	/* shift6 */
988		*p++ = 0x01;	/* SIN */
989		*p++ = 0x02;	/* len */
990		*p++ = 0x01;	/* Telephony */
991		*p++ = 0x00;	/* add.info */
992	}
993	*p++ = 0;
994
995	/* create the d-channel task for this call */
996	id = daic_assign(sc, port, DAIC_GLOBALID_DCHAN, p - parms, parms);
997
998	/* map it to the call descriptor id */
999	assoc = malloc(sizeof(struct outcallentry), M_DEVBUF, 0);
1000	assoc->cdid = cd->cdid;
1001	assoc->dchan_id = id;
1002	x = splnet();
1003	TAILQ_INSERT_TAIL(&sc->sc_outcalls[port], assoc, queue);
1004
1005	/* send a call request */
1006	len = strlen(cd->dst_telno);
1007	cpn[0] = IEI_CALLEDPN;
1008	cpn[1] = len+1;
1009	cpn[2] = NUMBER_TYPEPLAN;
1010	strcpy(cpn+3, cd->dst_telno);
1011#ifdef DAIC_DEBUG
1012	daic_dump_request(sc, port, DAIC_REQ_CALL, id, len+4, cpn);
1013#endif
1014	daic_request(sc, port, DAIC_REQ_CALL, id, len+4, cpn);
1015	splx(x);
1016	tsleep(assoc, 0, "daic call", 0);
1017	if (assoc->rc != DAIC_RC_OK) {
1018		aprint_error_dev(&sc->sc_dev, "call request failed, error 0x%02x: %s\n",
1019			assoc->rc & DAIC_RC_ERRMASK,
1020			err_codes[assoc->rc & DAIC_RC_ERRMASK]);
1021	}
1022}
1023
1024/*---------------------------------------------------------------------------*
1025 *	TODO:
1026 *---------------------------------------------------------------------------*/
1027static void daic_connect_response(struct call_desc *cd, int response, int cause)
1028{
1029}
1030
1031/*---------------------------------------------------------------------------*
1032 *	TODO:
1033 *---------------------------------------------------------------------------*/
1034static void daic_disconnect_request(struct call_desc *cd, int cause)
1035{
1036}
1037
1038/*---------------------------------------------------------------------------*
1039 *	TODO:
1040 *---------------------------------------------------------------------------*/
1041static void daic_bch_config(void *token, int channel, int bprot, int updown)
1042{
1043	printf("daic: bch_config\n");
1044}
1045
1046/*---------------------------------------------------------------------------*
1047 *	TODO:
1048 *---------------------------------------------------------------------------*/
1049static void daic_bch_tx_start(void *token, int channel)
1050{
1051	printf("daic: bch_tx_start\n");
1052}
1053
1054/*---------------------------------------------------------------------------*
1055 *	TODO:
1056 *---------------------------------------------------------------------------*/
1057static void
1058daic_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm)
1059{
1060}
1061
1062/*---------------------------------------------------------------------------*
1063 *	TODO:
1064 *---------------------------------------------------------------------------*/
1065static void
1066daic_alert_request(struct call_desc *cd)
1067{
1068}
1069
1070