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