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