1 /* ISDN4BSD code */
2 /* $MirOS: src/sys/dev/ic/iavc.c,v 1.1.7.1 2005/03/06 16:33:43 tg Exp $ */
3 /* $NetBSD: iavc.c,v 1.1 2003/09/25 15:53:26 pooka Exp $ */
4
5 /*
6 * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * The AVM ISDN controllers' card specific support routines.
30 *
31 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_card.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
32 */
33
34 #include <sys/cdefs.h>
35
36 #include <sys/param.h>
37 #include <sys/kernel.h>
38 #include <sys/systm.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/device.h>
42 #include <sys/timeout.h>
43 #include <sys/reboot.h>
44 #include <net/if.h>
45
46 #include <machine/bus.h>
47
48 #include <netisdn/i4b_debug.h>
49 #include <netisdn/i4b_ioctl.h>
50 #include <netisdn/i4b_trace.h>
51 #include <netisdn/i4b_global.h>
52 #include <netisdn/i4b_l3l4.h>
53 #include <netisdn/i4b_mbuf.h>
54 #include <netisdn/i4b_capi.h>
55 #include <netisdn/i4b_capi_msgs.h>
56
57 #include <dev/ic/iavcvar.h>
58 #include <dev/ic/iavcreg.h>
59
60 /*
61 // AVM B1 (active BRI, PIO mode)
62 */
63
64 int
iavc_b1_detect(iavc_softc_t * sc)65 iavc_b1_detect(iavc_softc_t *sc)
66 {
67 if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
68 (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
69 return (1);
70
71 b1io_outp(sc, B1_INSTAT, 0x02);
72 b1io_outp(sc, B1_OUTSTAT, 0x02);
73 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
74 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
75 return (2);
76
77 b1io_outp(sc, B1_INSTAT, 0x00);
78 b1io_outp(sc, B1_OUTSTAT, 0x00);
79 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
80 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
81 return (3);
82
83 return (0); /* found */
84 }
85
86 void
iavc_b1_disable_irq(iavc_softc_t * sc)87 iavc_b1_disable_irq(iavc_softc_t *sc)
88 {
89 b1io_outp(sc, B1_INSTAT, 0x00);
90 }
91
92 void
iavc_b1_reset(iavc_softc_t * sc)93 iavc_b1_reset(iavc_softc_t *sc)
94 {
95 b1io_outp(sc, B1_RESET, 0);
96 DELAY(55*2*1000);
97
98 b1io_outp(sc, B1_RESET, 1);
99 DELAY(55*2*1000);
100
101 b1io_outp(sc, B1_RESET, 0);
102 DELAY(55*2*1000);
103 }
104
105 /*
106 // Newer PCI-based B1's, and T1's, supports DMA
107 */
108
109 int
iavc_b1dma_detect(iavc_softc_t * sc)110 iavc_b1dma_detect(iavc_softc_t *sc)
111 {
112 AMCC_WRITE(sc, AMCC_MCSR, 0);
113 DELAY(10*1000);
114 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
115 DELAY(10*1000);
116 AMCC_WRITE(sc, AMCC_MCSR, 0);
117 DELAY(42*1000);
118
119 AMCC_WRITE(sc, AMCC_RXLEN, 0);
120 AMCC_WRITE(sc, AMCC_TXLEN, 0);
121 sc->sc_csr = 0;
122 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
123
124 if (AMCC_READ(sc, AMCC_INTCSR) != 0)
125 return 1;
126
127 AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
128 AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
129 if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
130 (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
131 return 2;
132
133 AMCC_WRITE(sc, AMCC_RXPTR, 0);
134 AMCC_WRITE(sc, AMCC_TXPTR, 0);
135 if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
136 (AMCC_READ(sc, AMCC_TXPTR) != 0))
137 return 3;
138
139 iavc_write_port(sc, 0x10, 0x00);
140 iavc_write_port(sc, 0x07, 0x00);
141
142 iavc_write_port(sc, 0x02, 0x02);
143 iavc_write_port(sc, 0x03, 0x02);
144
145 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
146 (iavc_read_port(sc, 0x03) != 0x03))
147 return 4;
148
149 iavc_write_port(sc, 0x02, 0x00);
150 iavc_write_port(sc, 0x03, 0x00);
151
152 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
153 (iavc_read_port(sc, 0x03) != 0x01))
154 return 5;
155
156 return (0); /* found */
157 }
158
159 void
iavc_b1dma_reset(iavc_softc_t * sc)160 iavc_b1dma_reset(iavc_softc_t *sc)
161 {
162 int s = splnet();
163
164 sc->sc_csr = 0;
165 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
166 AMCC_WRITE(sc, AMCC_MCSR, 0);
167 AMCC_WRITE(sc, AMCC_RXLEN, 0);
168 AMCC_WRITE(sc, AMCC_TXLEN, 0);
169
170 iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
171 iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
172
173 splx(s);
174
175 AMCC_WRITE(sc, AMCC_MCSR, 0);
176 DELAY(10 * 1000);
177 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
178 DELAY(10 * 1000);
179 AMCC_WRITE(sc, AMCC_MCSR, 0);
180 DELAY(42 * 1000);
181 }
182
183 /*
184 // AVM T1 (active PRI)
185 */
186
187 #define b1dma_tx_empty(sc) (b1io_read_reg((sc), T1_OUTSTAT) & 1)
188 #define b1dma_rx_full(sc) (b1io_read_reg((sc), T1_INSTAT) & 1)
189
b1dma_tolink(iavc_softc_t * sc,void * buf,int len)190 static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
191 {
192 volatile int spin;
193 char *s = (char*) buf;
194 while (len--) {
195 spin = 0;
196 while (!b1dma_tx_empty(sc) && spin < 100000)
197 spin++;
198 if (!b1dma_tx_empty(sc))
199 return -1;
200 t1io_outp(sc, 1, *s++);
201 }
202 return 0;
203 }
204
b1dma_fromlink(iavc_softc_t * sc,void * buf,int len)205 static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
206 {
207 volatile int spin;
208 char *s = (char*) buf;
209 while (len--) {
210 spin = 0;
211 while (!b1dma_rx_full(sc) && spin < 100000)
212 spin++;
213 if (!b1dma_rx_full(sc))
214 return -1;
215 *s++ = t1io_inp(sc, 0);
216 }
217 return 0;
218 }
219
WriteReg(iavc_softc_t * sc,u_int32_t reg,u_int8_t val)220 static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
221 {
222 u_int8_t cmd = 0;
223 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
224 b1dma_tolink(sc, ®, 4) == 0) {
225 u_int32_t tmp = val;
226 return b1dma_tolink(sc, &tmp, 4);
227 }
228 return -1;
229 }
230
ReadReg(iavc_softc_t * sc,u_int32_t reg)231 static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg)
232 {
233 u_int8_t cmd = 1;
234 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
235 b1dma_tolink(sc, ®, 4) == 0) {
236 u_int32_t tmp;
237 if (b1dma_fromlink(sc, &tmp, 4) == 0)
238 return (u_int8_t) tmp;
239 }
240 return 0xff;
241 }
242
243 int
iavc_t1_detect(iavc_softc_t * sc)244 iavc_t1_detect(iavc_softc_t *sc)
245 {
246 int ret = iavc_b1dma_detect(sc);
247 if (ret) return ret;
248
249 if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
250 (WriteReg(sc, 0x80101000, 0x22) != 0) ||
251 (WriteReg(sc, 0x80201000, 0x33) != 0) ||
252 (WriteReg(sc, 0x80301000, 0x44) != 0))
253 return 6;
254
255 if ((ReadReg(sc, 0x80001000) != 0x11) ||
256 (ReadReg(sc, 0x80101000) != 0x22) ||
257 (ReadReg(sc, 0x80201000) != 0x33) ||
258 (ReadReg(sc, 0x80301000) != 0x44))
259 return 7;
260
261 if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
262 (WriteReg(sc, 0x80101000, 0x66) != 0) ||
263 (WriteReg(sc, 0x80201000, 0x77) != 0) ||
264 (WriteReg(sc, 0x80301000, 0x88) != 0))
265 return 8;
266
267 if ((ReadReg(sc, 0x80001000) != 0x55) ||
268 (ReadReg(sc, 0x80101000) != 0x66) ||
269 (ReadReg(sc, 0x80201000) != 0x77) ||
270 (ReadReg(sc, 0x80301000) != 0x88))
271 return 9;
272
273 return 0; /* found */
274 }
275
276 void
iavc_t1_disable_irq(iavc_softc_t * sc)277 iavc_t1_disable_irq(iavc_softc_t *sc)
278 {
279 iavc_write_port(sc, T1_IRQMASTER, 0x00);
280 }
281
282 void
iavc_t1_reset(iavc_softc_t * sc)283 iavc_t1_reset(iavc_softc_t *sc)
284 {
285 iavc_b1_reset(sc);
286 iavc_write_port(sc, B1_INSTAT, 0x00);
287 iavc_write_port(sc, B1_OUTSTAT, 0x00);
288 iavc_write_port(sc, T1_IRQMASTER, 0x00);
289 iavc_write_port(sc, T1_RESETBOARD, 0x0f);
290 }
291
292 /* Forward declarations of local subroutines... */
293
294 static int iavc_send_init(iavc_softc_t *);
295
296 static void iavc_handle_rx(iavc_softc_t *);
297 static void iavc_start_tx(iavc_softc_t *);
298
299 static uint32_t iavc_tx_capimsg(iavc_softc_t *, struct mbuf *);
300 static uint32_t iavc_tx_ctrlmsg(iavc_softc_t *, struct mbuf *);
301
302 /*
303 // Callbacks from the upper (capi) layer:
304 // --------------------------------------
305 //
306 // iavc_load
307 // Resets the board and loads the firmware, then initiates
308 // board startup.
309 //
310 // iavc_register
311 // Registers a CAPI application id.
312 //
313 // iavc_release
314 // Releases a CAPI application id.
315 //
316 // iavc_send
317 // Sends a capi message.
318 */
319
iavc_load(capi_softc_t * capi_sc,int len,u_int8_t * cp)320 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
321 {
322 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
323 u_int8_t val;
324
325 printf("%s: reset card ....\n", sc->sc_dev.dv_xname);
326
327 if (sc->sc_dma)
328 iavc_b1dma_reset(sc); /* PCI cards */
329 else if (sc->sc_t1)
330 iavc_t1_reset(sc); /* ISA attachment T1 */
331 else
332 iavc_b1_reset(sc); /* ISA attachment B1 */
333
334 DELAY(1000);
335
336 printf("%s: start loading %d bytes firmware\n",
337 sc->sc_dev.dv_xname, len);
338
339 while (len && b1io_save_put_byte(sc, *cp++) == 0)
340 len--;
341
342 if (len) {
343 printf("%s: loading failed, can't write to card, len = %d\n",
344 sc->sc_dev.dv_xname, len);
345 return (EIO);
346 }
347
348 printf("%s: firmware loaded, wait for ACK\n", sc->sc_dev.dv_xname);
349
350 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
351 iavc_put_byte(sc, SEND_POLL);
352 else
353 iavc_put_byte(sc, SEND_POLLACK);
354
355 for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
356 DELAY(100);
357
358 if (!iavc_rx_full(sc)) {
359 printf("%s: loading failed, no ack\n", sc->sc_dev.dv_xname);
360 return (EIO);
361 }
362
363 val = iavc_get_byte(sc);
364
365 if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
366 (!sc->sc_dma && val != RECEIVE_POLL)) {
367 printf("%s: loading failed, bad ack = %02x\n",
368 sc->sc_dev.dv_xname, val);
369 return (EIO);
370 }
371
372 printf("%s: got ACK = 0x%02x\n", sc->sc_dev.dv_xname, val);
373
374 /* Start the DMA engine */
375 if (sc->sc_dma) {
376 int s;
377
378 s = splnet();
379
380 sc->sc_csr = AVM_FLAG;
381 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
382 AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
383 A2P_HI_PRIORITY|P2A_HI_PRIORITY|
384 RESET_A2P_FLAGS|RESET_P2A_FLAGS));
385
386 iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
387 iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
388
389 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
390 BUS_DMASYNC_PREREAD);
391
392 sc->sc_recv1 = 0;
393 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
394 AMCC_WRITE(sc, AMCC_RXLEN, 4);
395 sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
396 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
397
398 splx(s);
399 }
400
401 #ifdef notyet
402 /* good happy place */
403 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
404 b1isa_setup_irq(sc);
405 #endif
406
407 iavc_send_init(sc);
408
409 return 0;
410 }
411
iavc_register(capi_softc_t * capi_sc,int applid,int nchan)412 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
413 {
414 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
415 struct mbuf *m = i4b_Dgetmbuf(23);
416 u_int8_t *p;
417
418 if (!m) {
419 printf("iavc%d: can't get memory\n", sc->sc_unit);
420 return (ENOMEM);
421 }
422
423 /*
424 * byte 0x12 = SEND_REGISTER
425 * dword ApplId
426 * dword NumMessages
427 * dword NumB3Connections 0..nbch
428 * dword NumB3Blocks
429 * dword B3Size
430 */
431
432 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
433 p = amcc_put_byte(p, 0);
434 p = amcc_put_byte(p, SEND_REGISTER);
435 p = amcc_put_word(p, applid);
436 #if 0
437 p = amcc_put_word(p, 1024 + (nchan + 1));
438 #else
439 p = amcc_put_word(p, 1024 * (nchan + 1));
440 #endif
441 p = amcc_put_word(p, nchan);
442 p = amcc_put_word(p, 8);
443 p = amcc_put_word(p, 2048);
444
445 IF_ENQUEUE(&sc->sc_txq, m);
446
447 iavc_start_tx(sc);
448
449 return 0;
450 }
451
iavc_release(capi_softc_t * capi_sc,int applid)452 int iavc_release(capi_softc_t *capi_sc, int applid)
453 {
454 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
455 struct mbuf *m = i4b_Dgetmbuf(7);
456 u_int8_t *p;
457
458 if (!m) {
459 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
460 return (ENOMEM);
461 }
462
463 /*
464 * byte 0x14 = SEND_RELEASE
465 * dword ApplId
466 */
467
468 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
469 p = amcc_put_byte(p, 0);
470 p = amcc_put_byte(p, SEND_RELEASE);
471 p = amcc_put_word(p, applid);
472
473 IF_ENQUEUE(&sc->sc_txq, m);
474
475 iavc_start_tx(sc);
476 return 0;
477 }
478
iavc_send(capi_softc_t * capi_sc,struct mbuf * m)479 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
480 {
481 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
482
483 if (sc->sc_state != IAVC_UP) {
484 printf("%s: attempt to send before device up\n", sc->sc_dev.dv_xname);
485
486 if (m->m_next) i4b_Bfreembuf(m->m_next);
487 i4b_Dfreembuf(m);
488
489 return (ENXIO);
490 }
491
492 if (IF_QFULL(&sc->sc_txq)) {
493 IF_DROP(&sc->sc_txq);
494
495 printf("%s: tx overflow, message dropped\n", sc->sc_dev.dv_xname);
496
497 if (m->m_next) i4b_Bfreembuf(m->m_next);
498 i4b_Dfreembuf(m);
499
500 } else {
501 IF_ENQUEUE(&sc->sc_txq, m);
502
503 iavc_start_tx(sc);
504 }
505
506 return 0;
507 }
508
509 /*
510 // Functions called by ourself during the initialization sequence:
511 // ---------------------------------------------------------------
512 //
513 // iavc_send_init
514 // Sends the system initialization message to a newly loaded
515 // board, and sets state to INIT.
516 */
517
iavc_send_init(iavc_softc_t * sc)518 static int iavc_send_init(iavc_softc_t *sc)
519 {
520 struct mbuf *m = i4b_Dgetmbuf(15);
521 u_int8_t *p;
522 int s;
523
524 if (!m) {
525 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
526 return (ENOMEM);
527 }
528
529 /*
530 * byte 0x11 = SEND_INIT
531 * dword NumApplications
532 * dword NumNCCIs
533 * dword BoardNumber
534 */
535
536 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
537 p = amcc_put_byte(p, 0);
538 p = amcc_put_byte(p, SEND_INIT);
539 p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
540 p = amcc_put_word(p, sc->sc_capi.sc_nbch);
541 p = amcc_put_word(p, sc->sc_unit);
542
543 s = splnet();
544 IF_ENQUEUE(&sc->sc_txq, m);
545
546 iavc_start_tx(sc);
547
548 sc->sc_state = IAVC_INIT;
549 splx(s);
550 return 0;
551 }
552
553 /*
554 // Functions called during normal operation:
555 // -----------------------------------------
556 //
557 // iavc_receive_init
558 // Reads the initialization reply and calls capi_ll_control().
559 //
560 // iavc_receive_new_ncci
561 // Reads a new NCCI notification and calls capi_ll_control().
562 //
563 // iavc_receive_free_ncci
564 // Reads a freed NCCI notification and calls capi_ll_control().
565 //
566 // iavc_receive_task_ready
567 // Reads a task ready message -- which should not occur XXX.
568 //
569 // iavc_receive_debugmsg
570 // Reads a debug message -- which should not occur XXX.
571 //
572 // iavc_receive_start
573 // Reads a START TRANSMIT message and unblocks device.
574 //
575 // iavc_receive_stop
576 // Reads a STOP TRANSMIT message and blocks device.
577 //
578 // iavc_receive
579 // Reads an incoming message and calls capi_ll_receive().
580 */
581
iavc_receive_init(iavc_softc_t * sc,u_int8_t * dmabuf)582 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
583 {
584 u_int32_t Length;
585 u_int8_t *p;
586 u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
587
588 if (sc->sc_dma) {
589 p = amcc_get_word(dmabuf, &Length);
590 } else {
591 Length = iavc_get_slice(sc, sc->sc_recvbuf);
592 p = sc->sc_recvbuf;
593 }
594
595 #if 0
596 {
597 int len = 0;
598 printf("%s: rx_init: ", sc->sc_dev.dv_xname);
599 while (len < Length) {
600 printf(" %02x", p[len]);
601 if (len && (len % 16) == 0) printf("\n");
602 len++;
603 }
604 if (len % 16) printf("\n");
605 }
606 #endif
607
608 version = (p + 1);
609 p += (*p + 1); /* driver version */
610 cardtype = (p + 1);
611 p += (*p + 1); /* card type */
612 p += (*p + 1); /* hardware ID */
613 serial = (p + 1);
614 p += (*p + 1); /* serial number */
615 caps = (p + 1);
616 p += (*p + 1); /* supported options */
617 prot = (p + 1);
618 p += (*p + 1); /* supported protocols */
619 profile = (p + 1);
620
621 if (cardtype && serial && profile) {
622 int nbch = ((profile[3]<<8) | profile[2]);
623
624 printf("%s: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
625 sc->sc_dev.dv_xname, cardtype, serial, nbch, version, prot);
626 printf("%s: %s\n", sc->sc_dev.dv_xname, caps);
627
628 capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
629
630 } else {
631 printf("%s: no profile data in info response?\n", sc->sc_dev.dv_xname);
632 }
633
634 sc->sc_blocked = 1; /* controller will send START when ready */
635 return 0;
636 }
637
iavc_receive_start(iavc_softc_t * sc,u_int8_t * dmabuf)638 static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
639 {
640 struct mbuf *m = i4b_Dgetmbuf(3);
641 u_int8_t *p;
642
643 if (sc->sc_blocked && sc->sc_state == IAVC_UP)
644 printf("%s: receive_start\n", sc->sc_dev.dv_xname);
645
646 if (!m) {
647 printf("%s: can't get memory\n", sc->sc_dev.dv_xname);
648 return (ENOMEM);
649 }
650
651 /*
652 * byte 0x73 = SEND_POLLACK
653 */
654
655 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
656 p = amcc_put_byte(p, 0);
657 p = amcc_put_byte(p, SEND_POLLACK);
658
659 IF_PREPEND(&sc->sc_txq, m);
660
661 NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d",
662 sc->sc_dev.dv_xname, sc->sc_blocked, sc->sc_state);
663
664 sc->sc_blocked = 0;
665 iavc_start_tx(sc);
666
667 /* If this was our first START, register our readiness */
668 if (sc->sc_state != IAVC_UP) {
669 sc->sc_state = IAVC_UP;
670 capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1);
671 }
672
673 return 0;
674 }
675
iavc_receive_stop(iavc_softc_t * sc,u_int8_t * dmabuf)676 static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
677 {
678 printf("%s: receive_stop\n", sc->sc_dev.dv_xname);
679 sc->sc_blocked = 1;
680 return 0;
681 }
682
iavc_receive_new_ncci(iavc_softc_t * sc,u_int8_t * dmabuf)683 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
684 {
685 u_int32_t ApplId, NCCI, WindowSize;
686
687 if (sc->sc_dma) {
688 dmabuf = amcc_get_word(dmabuf, &ApplId);
689 dmabuf = amcc_get_word(dmabuf, &NCCI);
690 dmabuf = amcc_get_word(dmabuf, &WindowSize);
691 } else {
692 ApplId = iavc_get_word(sc);
693 NCCI = iavc_get_word(sc);
694 WindowSize = iavc_get_word(sc);
695 }
696
697 capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
698 return 0;
699 }
700
iavc_receive_free_ncci(iavc_softc_t * sc,u_int8_t * dmabuf)701 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
702 {
703 u_int32_t ApplId, NCCI;
704
705 if (sc->sc_dma) {
706 dmabuf = amcc_get_word(dmabuf, &ApplId);
707 dmabuf = amcc_get_word(dmabuf, &NCCI);
708 } else {
709 ApplId = iavc_get_word(sc);
710 NCCI = iavc_get_word(sc);
711 }
712
713 capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
714 return 0;
715 }
716
iavc_receive_task_ready(iavc_softc_t * sc,u_int8_t * dmabuf)717 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
718 {
719 u_int32_t TaskId, Length;
720 u_int8_t *p;
721 printf("%s: receive_task_ready\n", sc->sc_dev.dv_xname);
722
723 if (sc->sc_dma) {
724 p = amcc_get_word(dmabuf, &TaskId);
725 p = amcc_get_word(p, &Length);
726 } else {
727 TaskId = iavc_get_word(sc);
728 Length = iavc_get_slice(sc, sc->sc_recvbuf);
729 p = sc->sc_recvbuf;
730 }
731
732 /* XXX could show the message if trace enabled? XXX */
733 return 0;
734 }
735
iavc_receive_debugmsg(iavc_softc_t * sc,u_int8_t * dmabuf)736 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
737 {
738 u_int32_t Length;
739 u_int8_t *p;
740 printf("%s: receive_debugmsg\n", sc->sc_dev.dv_xname);
741
742 if (sc->sc_dma) {
743 p = amcc_get_word(dmabuf, &Length);
744 } else {
745 Length = iavc_get_slice(sc, sc->sc_recvbuf);
746 p = sc->sc_recvbuf;
747 }
748
749 /* XXX could show the message if trace enabled? XXX */
750 return 0;
751 }
752
iavc_receive(iavc_softc_t * sc,u_int8_t * dmabuf,int b3data)753 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
754 {
755 struct mbuf *m;
756 u_int32_t ApplId, Length;
757
758 /*
759 * byte 0x21 = RECEIVE_MESSAGE
760 * dword ApplId
761 * dword length
762 * ... CAPI msg
763 *
764 * --or--
765 *
766 * byte 0x22 = RECEIVE_DATA_B3_IND
767 * dword ApplId
768 * dword length
769 * ... CAPI msg
770 * dword datalen
771 * ... B3 data
772 */
773
774 if (sc->sc_dma) {
775 dmabuf = amcc_get_word(dmabuf, &ApplId);
776 dmabuf = amcc_get_word(dmabuf, &Length);
777 } else {
778 ApplId = iavc_get_word(sc);
779 Length = iavc_get_slice(sc, sc->sc_recvbuf);
780 dmabuf = sc->sc_recvbuf;
781 }
782
783 m = i4b_Dgetmbuf(Length);
784 if (!m) {
785 printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
786 return (ENOMEM);
787 }
788
789 memcpy(mtod(m, u_int8_t*), dmabuf, Length);
790
791 #if 0
792 {
793 u_int8_t *p = mtod(m, u_int8_t*);
794 int len = 0;
795 printf("%s: applid=%d, len=%d\n", sc->sc_dev.dv_xname,
796 ApplId, Length);
797 while (len < m->m_len) {
798 printf(" %02x", p[len]);
799 if (len && (len % 16) == 0) printf("\n");
800 len++;
801 }
802 if (len % 16) printf("\n");
803 }
804 #endif
805
806 if (b3data) {
807 if (sc->sc_dma) {
808 dmabuf = amcc_get_word(dmabuf + Length, &Length);
809 } else {
810 Length = iavc_get_slice(sc, sc->sc_recvbuf);
811 dmabuf = sc->sc_recvbuf;
812 }
813
814 m->m_next = i4b_Bgetmbuf(Length);
815 if (!m->m_next) {
816 printf("%s: can't get memory for receive\n", sc->sc_dev.dv_xname);
817 i4b_Dfreembuf(m);
818 return (ENOMEM);
819 }
820
821 memcpy(mtod(m->m_next, u_int8_t*), dmabuf, Length);
822 }
823
824 capi_ll_receive(&sc->sc_capi, m);
825 return 0;
826 }
827
828 /*
829 // iavc_handle_intr
830 // Checks device interrupt status and calls iavc_handle_{rx,tx}()
831 // as necessary.
832 //
833 // iavc_handle_rx
834 // Reads in the command byte and calls the subroutines above.
835 //
836 // iavc_start_tx
837 // Initiates DMA on the next queued message if possible.
838 */
839
iavc_handle_intr(iavc_softc_t * sc)840 int iavc_handle_intr(iavc_softc_t *sc)
841 {
842 u_int32_t status;
843 u_int32_t newcsr;
844
845 if (!sc->sc_dma) {
846 while (iavc_rx_full(sc))
847 iavc_handle_rx(sc);
848 return 0;
849 }
850
851 status = AMCC_READ(sc, AMCC_INTCSR);
852 if ((status & ANY_S5933_INT) == 0)
853 return 0;
854
855 newcsr = sc->sc_csr | (status & ALL_INT);
856 if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
857 if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
858 AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
859 sc->sc_intr = 1;
860
861 if (status & RX_TC_INT) {
862 u_int32_t rxlen;
863
864 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
865 BUS_DMASYNC_POSTREAD);
866
867 if (sc->sc_recv1 == 0) {
868 sc->sc_recv1 = *(u_int32_t*)(sc->sc_recvbuf);
869 rxlen = (sc->sc_recv1 + 3) & ~3;
870
871 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
872 AMCC_WRITE(sc, AMCC_RXLEN, rxlen ? rxlen : 4);
873 } else {
874 iavc_handle_rx(sc);
875 sc->sc_recv1 = 0;
876 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
877 AMCC_WRITE(sc, AMCC_RXLEN, 4);
878 }
879 }
880
881 if (status & TX_TC_INT) {
882 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, sc->tx_map->dm_mapsize,
883 BUS_DMASYNC_POSTWRITE);
884 sc->sc_csr &= ~EN_TX_TC_INT;
885 iavc_start_tx(sc);
886 }
887
888 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
889 sc->sc_intr = 0;
890
891 return 0;
892 }
893
iavc_handle_rx(iavc_softc_t * sc)894 static void iavc_handle_rx(iavc_softc_t *sc)
895 {
896 u_int8_t *dmabuf = 0, cmd;
897
898 if (sc->sc_dma) {
899 dmabuf = amcc_get_byte(&sc->sc_recvbuf[0], &cmd);
900 } else {
901 cmd = iavc_get_byte(sc);
902 }
903
904 NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
905
906 switch (cmd) {
907 case RECEIVE_DATA_B3_IND:
908 iavc_receive(sc, dmabuf, 1);
909 break;
910
911 case RECEIVE_MESSAGE:
912 iavc_receive(sc, dmabuf, 0);
913 break;
914
915 case RECEIVE_NEW_NCCI:
916 iavc_receive_new_ncci(sc, dmabuf);
917 break;
918
919 case RECEIVE_FREE_NCCI:
920 iavc_receive_free_ncci(sc, dmabuf);
921 break;
922
923 case RECEIVE_START:
924 iavc_receive_start(sc, dmabuf);
925 break;
926
927 case RECEIVE_STOP:
928 iavc_receive_stop(sc, dmabuf);
929 break;
930
931 case RECEIVE_INIT:
932 iavc_receive_init(sc, dmabuf);
933 break;
934
935 case RECEIVE_TASK_READY:
936 iavc_receive_task_ready(sc, dmabuf);
937 break;
938
939 case RECEIVE_DEBUGMSG:
940 iavc_receive_debugmsg(sc, dmabuf);
941 break;
942
943 default:
944 printf("%s: unknown msg %02x\n", sc->sc_dev.dv_xname, cmd);
945 }
946 }
947
iavc_start_tx(iavc_softc_t * sc)948 static void iavc_start_tx(iavc_softc_t *sc)
949 {
950 struct mbuf *m;
951 u_int32_t txlen;
952
953 /* If device has put us on hold, punt. */
954
955 if (sc->sc_blocked) {
956 return;
957 }
958
959 /* If using DMA and transmitter busy, punt. */
960 if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
961 return;
962 }
963
964 /* Else, see if we have messages to send. */
965 IF_DEQUEUE(&sc->sc_txq, m);
966 if (!m) {
967 return;
968 }
969
970 /* Have message, will send. */
971 if (CAPIMSG_LEN(m->m_data)) {
972 /* A proper CAPI message, possibly with B3 data */
973 txlen = iavc_tx_capimsg(sc, m);
974 } else {
975 /* A board control message to be sent as is */
976 txlen = iavc_tx_ctrlmsg(sc, m);
977 }
978
979 if (m->m_next) {
980 i4b_Bfreembuf(m->m_next);
981 m->m_next = NULL;
982 }
983 i4b_Dfreembuf(m);
984
985 /* Kick DMA into motion if applicable */
986 if (sc->sc_dma) {
987 txlen = (txlen + 3) & ~3;
988
989 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, txlen,
990 BUS_DMASYNC_PREWRITE);
991
992 AMCC_WRITE(sc, AMCC_TXPTR, sc->tx_map->dm_segs[0].ds_addr);
993 AMCC_WRITE(sc, AMCC_TXLEN, txlen);
994 sc->sc_csr |= EN_TX_TC_INT;
995
996 if (!sc->sc_intr)
997 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
998 }
999 }
1000
1001 static uint32_t
iavc_tx_capimsg(iavc_softc_t * sc,struct mbuf * m)1002 iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m)
1003 {
1004 uint32_t txlen = 0;
1005 u_int8_t *dmabuf;
1006
1007 if (sc->sc_dma) {
1008 /* Copy message to DMA buffer. */
1009
1010 if (m->m_next)
1011 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
1012 else
1013 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
1014
1015 dmabuf = amcc_put_word(dmabuf, m->m_len);
1016 memcpy(dmabuf, m->m_data, m->m_len);
1017 dmabuf += m->m_len;
1018 txlen = 5 + m->m_len;
1019
1020 if (m->m_next) {
1021 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
1022 memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len);
1023 txlen += 4 + m->m_next->m_len;
1024 }
1025
1026 } else {
1027 /* Use PIO. */
1028
1029 if (m->m_next) {
1030 iavc_put_byte(sc, SEND_DATA_B3_REQ);
1031 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d",
1032 sc->sc_unit, m->m_len);
1033 } else {
1034 iavc_put_byte(sc, SEND_MESSAGE);
1035 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d",
1036 sc->sc_unit, m->m_len);
1037 }
1038 #if 0
1039 {
1040 u_int8_t *p = mtod(m, u_int8_t*);
1041 int len;
1042 for (len = 0; len < m->m_len; len++) {
1043 printf(" %02x", *p++);
1044 if (len && (len % 16) == 0)
1045 printf("\n");
1046 }
1047 if (len % 16)
1048 printf("\n");
1049 }
1050 #endif
1051
1052 iavc_put_slice(sc, m->m_data, m->m_len);
1053
1054 if (m->m_next)
1055 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
1056 }
1057
1058 return txlen;
1059 }
1060
1061 static uint32_t
iavc_tx_ctrlmsg(iavc_softc_t * sc,struct mbuf * m)1062 iavc_tx_ctrlmsg(iavc_softc_t *sc, struct mbuf *m)
1063 {
1064 uint32_t txlen = 0;
1065 uint8_t *dmabuf;
1066
1067 if (sc->sc_dma) {
1068 memcpy(&sc->sc_sendbuf[0], m->m_data + 2, m->m_len - 2);
1069 txlen = m->m_len - 2;
1070 } else {
1071
1072 #if 0
1073 {
1074 u_int8_t *p = mtod(m, u_int8_t*) + 2;
1075 int len;
1076
1077 printf("%s: tx BDC msg, len = %d, msg =", sc->sc_dev.dv_xname,
1078 m->m_len-2);
1079 for (len = 0; len < m->m_len-2; len++) {
1080 printf(" %02x", *p++);
1081 if (len && (len % 16) == 0) printf("\n");
1082 }
1083 if (len % 16)
1084 printf("\n");
1085 }
1086 #endif
1087
1088 /* no DMA */
1089 txlen = m->m_len - 2;
1090 dmabuf = mtod(m, char*) + 2;
1091 while(txlen--)
1092 b1io_put_byte(sc, *dmabuf++);
1093 }
1094
1095 return txlen;
1096 }
1097