Sync usage with man page.
[netbsd-mini2440.git] / sys / dev / ic / daic.c
blobb8d0373494d1ad7df911d6278d66b9a63d2d7402
1 /*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
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.
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.
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: daic.c,v 1.28 2009/03/14 15:36:17 dsl Exp $");
35 * daic.c: MI driver for Diehl active ISDN cards (S, SX, SXn, SCOM, QUADRO)
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>
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>
56 #include <sys/bus.h>
57 #include <dev/ic/daicvar.h>
58 #include <dev/ic/daicreg.h>
59 #include <dev/microcode/daic/dnload.h>
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... */
65 struct cfdriver daic_cd = {
66 NULL, "daic", DV_DULL
68 #endif
69 #endif
71 /* local function prototypes */
72 static const char * cardtypename(int cardtype);
73 static int daic_download(void *, int portcount, struct isdn_dr_prot *data);
74 static int daic_diagnostic(void *, struct isdn_diagnostic_request *req);
75 static void daic_connect_request(struct call_desc *cd);
76 static void daic_connect_response(struct call_desc *cd, int, int);
77 static void daic_disconnect_request(struct call_desc *cd, int);
78 static int daic_reset(bus_space_tag_t bus, bus_space_handle_t io, int port, int *memsize);
79 static int daic_handle_intr(struct daic_softc *sc, int port);
80 static void daic_register_port(struct daic_softc *sc, int port);
81 static void daic_request(struct daic_softc *sc, int port, u_int req, u_int id, bus_size_t parmsize, const u_int8_t *parms);
82 static u_int daic_assign(struct daic_softc *sc, int port, u_int instance, bus_size_t parmsize, const u_int8_t *parms);
83 static void daic_indicate_ind(struct daic_softc *sc, int port);
84 static void daic_bch_config(void *, int channel, int bprot, int updown);
85 static void daic_bch_tx_start(void *, int channel);
86 static void daic_set_link(void *softc, int channel,
87 const struct isdn_l4_driver_functions *l4_driver, void *l4_inst );
88 static void daic_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm);
89 static void daic_alert_request(struct call_desc *cd);
91 static isdn_link_t *daic_ret_linktab(void *softc, int channel);
93 #ifdef DAIC_DEBUG
94 static 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
97 /* static data */
98 static const char * const cardnames[] = {
99 "S", "SX", "SCOM", "QUADRO"
102 static 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"
113 /* fixed parameters */
115 /* no parameters */
116 static u_int8_t parm_none[] = { 0 };
117 #define VOIDREQ(sc,port,req,id) daic_request(sc, port, req, id, sizeof parm_none, parm_none)
119 /* assign request for the global d-channel instance */
120 static 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
132 /*---------------------------------------------------------------------------*
133 * Return the name of a card with given cardtype
134 *---------------------------------------------------------------------------*/
135 static const char *
136 cardtypename(int cardtype)
138 if (cardtype >= 0 && cardtype < (sizeof(cardnames) / sizeof(cardnames[0])))
139 return cardnames[cardtype];
140 else
141 return "unknown type";
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 *---------------------------------------------------------------------------*/
150 daic_probe(bus_space_tag_t bus, bus_space_handle_t io)
152 return (daic_reset(bus, io, 0, NULL));
155 /*---------------------------------------------------------------------------*
156 * Attach and initialize the card at given io space.
157 *---------------------------------------------------------------------------*/
158 void
159 daic_attach(device_t self, struct daic_softc *sc)
161 int i, num_ports, memsize = 0;
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;
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;
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;
183 /* register all ports this card has */
184 for (i = 0; i < num_ports; i++)
185 daic_register_port(sc, i);
188 /*---------------------------------------------------------------------------*
189 * handle interrupts for one port of the card
190 *---------------------------------------------------------------------------*/
191 static int
192 daic_handle_intr(struct daic_softc *sc, int port)
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;
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 */
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;
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;
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);
233 } else {
234 wakeup(&du->du_assign);
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;
249 if (rcid == du->du_global_dchan) {
250 du->du_request_res = rc;
251 wakeup(&du->du_request_res);
252 goto req_done;
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;
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;
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]);
278 req_done:
279 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_RC+off, 0);
281 check_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;
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;
294 printf("%s: got info indication\n",
295 device_xname(&sc->sc_dev));
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));
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);
310 goto ind_done;
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;
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 sc-device_xname(&>sc_dev), ind, assoc->cdid);
329 goto ind_done;
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);
336 ind_done:
337 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_IND+off, 0);
339 done:
340 /* tell card we're ready for more... */
341 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_IRQ+off, 0);
343 return 1;
346 /*---------------------------------------------------------------------------*
347 * Handle interrupts
348 *---------------------------------------------------------------------------*/
350 daic_intr(struct daic_softc *sc)
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;
362 /*---------------------------------------------------------------------------*
363 * Download primary protocol microcode to on-board processor
364 *---------------------------------------------------------------------------*/
365 static int
366 daic_download(void *token, int count, struct isdn_dr_prot *data)
368 struct daic_unit *du = token;
369 struct daic_softc *sc = du->du_sc;
370 int i;
372 if (sc->sc_cardtype != DAIC_TYPE_QUAD)
373 count = 1; /* XXX - or signal error ? */
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++)
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);
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;
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);
421 /* start protocol */
422 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_BOOT_CTRL+off, 2);
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;
437 break;
439 splx(x);
440 tsleep(&sc->sc_port[i].du_state, 0, "daic protocol init", hz/25);
441 x = splnet();
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;
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);
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);
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;
482 splx(x);
484 return 0;
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 *---------------------------------------------------------------------------*/
492 static int
493 daic_reset(bus_space_tag_t bus, bus_space_handle_t io, int port, int *memsize)
495 int i, off = port * DAIC_ISA_MEMSIZE;
496 int cardtype, mem, quiet = memsize == NULL; /* no output if we are only probing */
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);
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;
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;
522 if (bus_space_read_1(bus, io, DAIC_BOOT_EBIT+off)) {
523 if (!quiet) printf(": on board memory test failed at %p\n",
524 (void*)bus_space_read_2(bus, io, DAIC_BOOT_ELOC+off));
525 return -1;
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;
534 return cardtype;
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 *---------------------------------------------------------------------------*/
542 static int
543 daic_diagnostic(void *token, struct isdn_diagnostic_request *req)
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;
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;
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;
564 /* XXX - only for debug */
565 if (req->cmd == 0x05) {
566 /* pass through request from userland */
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
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);
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;
588 /* all these need an output parameter */
589 if (req->out_param == NULL)
590 return EIO;
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;
598 sc->sc_port[port].du_state = DAIC_STATE_DIAGNOSTIC;
599 splx(s);
601 /* set new request */
602 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_REQ+off, req->cmd);
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);
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;
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);
624 /* acknowledge data */
625 bus_space_write_1(sc->sc_iot, sc->sc_ioh, DAIC_DIAG_RC+off, 0);
627 done: /* back to normal state */
628 s = splnet();
629 sc->sc_port[port].du_state = DAIC_STATE_RUNNING;
630 splx(s);
632 return err;
635 static void daic_stat(void *port, int channel, bchan_statistics_t *bsp)
639 static const struct isdn_l4_bchannel_functions
640 daic_l4_driver = {
641 daic_bch_config,
642 daic_bch_tx_start,
643 daic_stat
646 static const struct isdn_l3_driver_functions
647 daic_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
659 /*---------------------------------------------------------------------------*
660 * Register one port and attach it to the upper layers
661 *---------------------------------------------------------------------------*/
662 static void
663 daic_register_port(struct daic_softc *sc, int port)
665 int chan;
666 char cardname[80], devname[80];
667 struct isdn_l3_driver * l3drv;
669 sc->sc_port[port].du_port = port;
670 sc->sc_port[port].du_sc = sc;
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;
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;
693 TAILQ_INIT(&sc->sc_outcalls[port]);
695 isdn_isdnif_ready(l3drv->isdnif);
698 /*---------------------------------------------------------------------------*
699 * return the address of daic drivers linktab
700 *---------------------------------------------------------------------------*/
701 static isdn_link_t *
702 daic_ret_linktab(void *token, int channel)
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];
709 return(&con->isdn_linktab);
712 /*---------------------------------------------------------------------------*
713 * set the driver linktab in the b channel softc
714 *---------------------------------------------------------------------------*/
715 static void
716 daic_set_link(void *token, int channel, const struct isdn_l4_driver_functions *l4_driver, void *l4_inst)
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];
723 con->l4_driver = l4_driver;
724 con->l4_driver_softc = l4_inst;
727 /*---------------------------------------------------------------------------*
728 * Send a request to the card.
729 *---------------------------------------------------------------------------*/
730 static void
731 daic_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 */
739 int off = port*DAIC_ISA_MEMSIZE;
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 */
745 /* output parameters */
746 bus_space_write_region_1(sc->sc_iot, sc->sc_ioh, DAIC_COM_XBUFFER+off, parms, parmsize);
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);
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 *---------------------------------------------------------------------------*/
758 static u_int
759 daic_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 */
766 static char wchan[] = "daic assign";
767 u_int8_t id;
768 int x;
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! */
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);
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);
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;
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;
803 /* XXX - review this, can't remember why I did it this complicated */
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);
813 return id;
816 #ifdef DAIC_DEBUG
817 /*---------------------------------------------------------------------------*
818 * Debug output of request parameters
819 *---------------------------------------------------------------------------*/
820 static void
821 daic_dump_request(struct daic_softc *sc, int port, u_int req, u_int id, bus_size_t parmsize, u_int8_t *parms)
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]);
831 printf("\n");
833 #endif
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 *---------------------------------------------------------------------------*/
840 static void
841 daic_indicate_ind(struct daic_softc *sc, int port)
843 int offset = port*DAIC_ISA_MEMSIZE;
844 int i;
845 u_int8_t ie, ielen;
846 call_desc_t *cd;
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 */
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:
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';
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;
908 cd->channelexcl = (ie & 0x08) >> 3;
911 i += ielen;
913 cd->event = EV_SETUP;
914 /* ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_RSVD; */
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;
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);
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);
939 /* hand up call to layer 4 */
940 i4b_l4_connect_ind(cd);
943 /*---------------------------------------------------------------------------*
944 * Layer 4 request a call setup
945 *---------------------------------------------------------------------------*/
946 static void
947 daic_connect_request(struct call_desc *cd)
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;
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. */
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;
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);
981 if (cd->channelid == CHAN_B1 || cd->channelid == CHAN_B2) {
982 *p++ = IEI_CHANNELID;
983 *p++ = 0x01;
984 *p++ = 0x81 + cd->channelid;
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 */
993 *p++ = 0;
995 /* create the d-channel task for this call */
996 id = daic_assign(sc, port, DAIC_GLOBALID_DCHAN, p - parms, parms);
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);
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]);
1024 /*---------------------------------------------------------------------------*
1025 * TODO:
1026 *---------------------------------------------------------------------------*/
1027 static void daic_connect_response(struct call_desc *cd, int response, int cause)
1031 /*---------------------------------------------------------------------------*
1032 * TODO:
1033 *---------------------------------------------------------------------------*/
1034 static void daic_disconnect_request(struct call_desc *cd, int cause)
1038 /*---------------------------------------------------------------------------*
1039 * TODO:
1040 *---------------------------------------------------------------------------*/
1041 static void daic_bch_config(void *token, int channel, int bprot, int updown)
1043 printf("daic: bch_config\n");
1046 /*---------------------------------------------------------------------------*
1047 * TODO:
1048 *---------------------------------------------------------------------------*/
1049 static void daic_bch_tx_start(void *token, int channel)
1051 printf("daic: bch_tx_start\n");
1054 /*---------------------------------------------------------------------------*
1055 * TODO:
1056 *---------------------------------------------------------------------------*/
1057 static void
1058 daic_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm)
1062 /*---------------------------------------------------------------------------*
1063 * TODO:
1064 *---------------------------------------------------------------------------*/
1065 static void
1066 daic_alert_request(struct call_desc *cd)