No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / ic / iavc.c
blob6d49d4414839837aa9ca378b2c301f75b9596cc2
1 /* $NetBSD: iavc.c,v 1.7 2008/04/08 12:07:26 cegger Exp $ */
3 /*
4 * Copyright (c) 2001-2003 Cubical Solutions Ltd. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
27 * The AVM ISDN controllers' card specific support routines.
29 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_card.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: iavc.c,v 1.7 2008/04/08 12:07:26 cegger Exp $");
35 #include <sys/param.h>
36 #include <sys/kernel.h>
37 #include <sys/systm.h>
38 #include <sys/mbuf.h>
39 #include <sys/socket.h>
40 #include <sys/device.h>
41 #include <sys/callout.h>
42 #include <sys/reboot.h>
43 #include <net/if.h>
45 #include <sys/bus.h>
47 #include <netisdn/i4b_debug.h>
48 #include <netisdn/i4b_ioctl.h>
49 #include <netisdn/i4b_trace.h>
50 #include <netisdn/i4b_global.h>
51 #include <netisdn/i4b_l3l4.h>
52 #include <netisdn/i4b_mbuf.h>
53 #include <netisdn/i4b_capi.h>
54 #include <netisdn/i4b_capi_msgs.h>
56 #include <dev/ic/iavcvar.h>
57 #include <dev/ic/iavcreg.h>
60 // AVM B1 (active BRI, PIO mode)
63 int
64 iavc_b1_detect(iavc_softc_t *sc)
66 if ((iavc_read_port(sc, B1_INSTAT) & 0xfc) ||
67 (iavc_read_port(sc, B1_OUTSTAT) & 0xfc))
68 return (1);
70 b1io_outp(sc, B1_INSTAT, 0x02);
71 b1io_outp(sc, B1_OUTSTAT, 0x02);
72 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) != 2 ||
73 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe) != 2)
74 return (2);
76 b1io_outp(sc, B1_INSTAT, 0x00);
77 b1io_outp(sc, B1_OUTSTAT, 0x00);
78 if ((iavc_read_port(sc, B1_INSTAT) & 0xfe) ||
79 (iavc_read_port(sc, B1_OUTSTAT) & 0xfe))
80 return (3);
82 return (0); /* found */
85 void
86 iavc_b1_disable_irq(iavc_softc_t *sc)
88 b1io_outp(sc, B1_INSTAT, 0x00);
91 void
92 iavc_b1_reset(iavc_softc_t *sc)
94 b1io_outp(sc, B1_RESET, 0);
95 DELAY(55*2*1000);
97 b1io_outp(sc, B1_RESET, 1);
98 DELAY(55*2*1000);
100 b1io_outp(sc, B1_RESET, 0);
101 DELAY(55*2*1000);
105 // Newer PCI-based B1's, and T1's, supports DMA
109 iavc_b1dma_detect(iavc_softc_t *sc)
111 AMCC_WRITE(sc, AMCC_MCSR, 0);
112 DELAY(10*1000);
113 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
114 DELAY(10*1000);
115 AMCC_WRITE(sc, AMCC_MCSR, 0);
116 DELAY(42*1000);
118 AMCC_WRITE(sc, AMCC_RXLEN, 0);
119 AMCC_WRITE(sc, AMCC_TXLEN, 0);
120 sc->sc_csr = 0;
121 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
123 if (AMCC_READ(sc, AMCC_INTCSR) != 0)
124 return 1;
126 AMCC_WRITE(sc, AMCC_RXPTR, 0xffffffff);
127 AMCC_WRITE(sc, AMCC_TXPTR, 0xffffffff);
128 if ((AMCC_READ(sc, AMCC_RXPTR) != 0xfffffffc) ||
129 (AMCC_READ(sc, AMCC_TXPTR) != 0xfffffffc))
130 return 2;
132 AMCC_WRITE(sc, AMCC_RXPTR, 0);
133 AMCC_WRITE(sc, AMCC_TXPTR, 0);
134 if ((AMCC_READ(sc, AMCC_RXPTR) != 0) ||
135 (AMCC_READ(sc, AMCC_TXPTR) != 0))
136 return 3;
138 iavc_write_port(sc, 0x10, 0x00);
139 iavc_write_port(sc, 0x07, 0x00);
141 iavc_write_port(sc, 0x02, 0x02);
142 iavc_write_port(sc, 0x03, 0x02);
144 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x02) ||
145 (iavc_read_port(sc, 0x03) != 0x03))
146 return 4;
148 iavc_write_port(sc, 0x02, 0x00);
149 iavc_write_port(sc, 0x03, 0x00);
151 if (((iavc_read_port(sc, 0x02) & 0xfe) != 0x00) ||
152 (iavc_read_port(sc, 0x03) != 0x01))
153 return 5;
155 return (0); /* found */
158 void
159 iavc_b1dma_reset(iavc_softc_t *sc)
161 int s = splnet();
163 sc->sc_csr = 0;
164 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
165 AMCC_WRITE(sc, AMCC_MCSR, 0);
166 AMCC_WRITE(sc, AMCC_RXLEN, 0);
167 AMCC_WRITE(sc, AMCC_TXLEN, 0);
169 iavc_write_port(sc, 0x10, 0x00); /* XXX magic numbers from */
170 iavc_write_port(sc, 0x07, 0x00); /* XXX the linux driver */
172 splx(s);
174 AMCC_WRITE(sc, AMCC_MCSR, 0);
175 DELAY(10 * 1000);
176 AMCC_WRITE(sc, AMCC_MCSR, 0x0f000000);
177 DELAY(10 * 1000);
178 AMCC_WRITE(sc, AMCC_MCSR, 0);
179 DELAY(42 * 1000);
183 // AVM T1 (active PRI)
186 #define b1dma_tx_empty(sc) (b1io_read_reg((sc), T1_OUTSTAT) & 1)
187 #define b1dma_rx_full(sc) (b1io_read_reg((sc), T1_INSTAT) & 1)
189 static int b1dma_tolink(iavc_softc_t *sc, void *buf, int len)
191 volatile int spin;
192 char *s = (char*) buf;
193 while (len--) {
194 spin = 0;
195 while (!b1dma_tx_empty(sc) && spin < 100000)
196 spin++;
197 if (!b1dma_tx_empty(sc))
198 return -1;
199 t1io_outp(sc, 1, *s++);
201 return 0;
204 static int b1dma_fromlink(iavc_softc_t *sc, void *buf, int len)
206 volatile int spin;
207 char *s = (char*) buf;
208 while (len--) {
209 spin = 0;
210 while (!b1dma_rx_full(sc) && spin < 100000)
211 spin++;
212 if (!b1dma_rx_full(sc))
213 return -1;
214 *s++ = t1io_inp(sc, 0);
216 return 0;
219 static int WriteReg(iavc_softc_t *sc, u_int32_t reg, u_int8_t val)
221 u_int8_t cmd = 0;
222 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
223 b1dma_tolink(sc, &reg, 4) == 0) {
224 u_int32_t tmp = val;
225 return b1dma_tolink(sc, &tmp, 4);
227 return -1;
230 static u_int8_t ReadReg(iavc_softc_t *sc, u_int32_t reg)
232 u_int8_t cmd = 1;
233 if (b1dma_tolink(sc, &cmd, 1) == 0 &&
234 b1dma_tolink(sc, &reg, 4) == 0) {
235 u_int32_t tmp;
236 if (b1dma_fromlink(sc, &tmp, 4) == 0)
237 return (u_int8_t) tmp;
239 return 0xff;
243 iavc_t1_detect(iavc_softc_t *sc)
245 int ret = iavc_b1dma_detect(sc);
246 if (ret) return ret;
248 if ((WriteReg(sc, 0x80001000, 0x11) != 0) ||
249 (WriteReg(sc, 0x80101000, 0x22) != 0) ||
250 (WriteReg(sc, 0x80201000, 0x33) != 0) ||
251 (WriteReg(sc, 0x80301000, 0x44) != 0))
252 return 6;
254 if ((ReadReg(sc, 0x80001000) != 0x11) ||
255 (ReadReg(sc, 0x80101000) != 0x22) ||
256 (ReadReg(sc, 0x80201000) != 0x33) ||
257 (ReadReg(sc, 0x80301000) != 0x44))
258 return 7;
260 if ((WriteReg(sc, 0x80001000, 0x55) != 0) ||
261 (WriteReg(sc, 0x80101000, 0x66) != 0) ||
262 (WriteReg(sc, 0x80201000, 0x77) != 0) ||
263 (WriteReg(sc, 0x80301000, 0x88) != 0))
264 return 8;
266 if ((ReadReg(sc, 0x80001000) != 0x55) ||
267 (ReadReg(sc, 0x80101000) != 0x66) ||
268 (ReadReg(sc, 0x80201000) != 0x77) ||
269 (ReadReg(sc, 0x80301000) != 0x88))
270 return 9;
272 return 0; /* found */
275 void
276 iavc_t1_disable_irq(iavc_softc_t *sc)
278 iavc_write_port(sc, T1_IRQMASTER, 0x00);
281 void
282 iavc_t1_reset(iavc_softc_t *sc)
284 iavc_b1_reset(sc);
285 iavc_write_port(sc, B1_INSTAT, 0x00);
286 iavc_write_port(sc, B1_OUTSTAT, 0x00);
287 iavc_write_port(sc, T1_IRQMASTER, 0x00);
288 iavc_write_port(sc, T1_RESETBOARD, 0x0f);
291 /* Forward declarations of local subroutines... */
293 static int iavc_send_init(iavc_softc_t *);
295 static void iavc_handle_rx(iavc_softc_t *);
296 static void iavc_start_tx(iavc_softc_t *);
298 static uint32_t iavc_tx_capimsg(iavc_softc_t *, struct mbuf *);
299 static uint32_t iavc_tx_ctrlmsg(iavc_softc_t *, struct mbuf *);
302 // Callbacks from the upper (capi) layer:
303 // --------------------------------------
305 // iavc_load
306 // Resets the board and loads the firmware, then initiates
307 // board startup.
309 // iavc_register
310 // Registers a CAPI application id.
312 // iavc_release
313 // Releases a CAPI application id.
315 // iavc_send
316 // Sends a capi message.
319 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
321 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
322 u_int8_t val;
324 aprint_debug_dev(&sc->sc_dev, "reset card ....\n");
326 if (sc->sc_dma)
327 iavc_b1dma_reset(sc); /* PCI cards */
328 else if (sc->sc_t1)
329 iavc_t1_reset(sc); /* ISA attachment T1 */
330 else
331 iavc_b1_reset(sc); /* ISA attachment B1 */
333 DELAY(1000);
335 aprint_debug_dev(&sc->sc_dev, "start loading %d bytes firmware\n", len);
337 while (len && b1io_save_put_byte(sc, *cp++) == 0)
338 len--;
340 if (len) {
341 aprint_error_dev(&sc->sc_dev, "loading failed, can't write to card, len = %d\n", len);
342 return (EIO);
345 aprint_debug_dev(&sc->sc_dev, "firmware loaded, wait for ACK\n");
347 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
348 iavc_put_byte(sc, SEND_POLL);
349 else
350 iavc_put_byte(sc, SEND_POLLACK);
352 for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
353 DELAY(100);
355 if (!iavc_rx_full(sc)) {
356 aprint_error_dev(&sc->sc_dev, "loading failed, no ack\n");
357 return (EIO);
360 val = iavc_get_byte(sc);
362 if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
363 (!sc->sc_dma && val != RECEIVE_POLL)) {
364 aprint_error_dev(&sc->sc_dev, "loading failed, bad ack = %02x\n", val);
365 return (EIO);
368 aprint_debug_dev(&sc->sc_dev, "got ACK = 0x%02x\n", val);
370 /* Start the DMA engine */
371 if (sc->sc_dma) {
372 int s;
374 s = splnet();
376 sc->sc_csr = AVM_FLAG;
377 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
378 AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
379 A2P_HI_PRIORITY|P2A_HI_PRIORITY|
380 RESET_A2P_FLAGS|RESET_P2A_FLAGS));
382 iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
383 iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
385 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
386 BUS_DMASYNC_PREREAD);
388 sc->sc_recv1 = 0;
389 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
390 AMCC_WRITE(sc, AMCC_RXLEN, 4);
391 sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
392 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
394 splx(s);
397 #ifdef notyet
398 /* good happy place */
399 if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
400 b1isa_setup_irq(sc);
401 #endif
403 iavc_send_init(sc);
405 return 0;
408 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
410 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
411 struct mbuf *m = i4b_Dgetmbuf(23);
412 u_int8_t *p;
414 if (!m) {
415 aprint_error("iavc%d: can't get memory\n", sc->sc_unit);
416 return (ENOMEM);
420 * byte 0x12 = SEND_REGISTER
421 * dword ApplId
422 * dword NumMessages
423 * dword NumB3Connections 0..nbch
424 * dword NumB3Blocks
425 * dword B3Size
428 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
429 p = amcc_put_byte(p, 0);
430 p = amcc_put_byte(p, SEND_REGISTER);
431 p = amcc_put_word(p, applid);
432 #if 0
433 p = amcc_put_word(p, 1024 + (nchan + 1));
434 #else
435 p = amcc_put_word(p, 1024 * (nchan + 1));
436 #endif
437 p = amcc_put_word(p, nchan);
438 p = amcc_put_word(p, 8);
439 p = amcc_put_word(p, 2048);
441 IF_ENQUEUE(&sc->sc_txq, m);
443 iavc_start_tx(sc);
445 return 0;
448 int iavc_release(capi_softc_t *capi_sc, int applid)
450 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
451 struct mbuf *m = i4b_Dgetmbuf(7);
452 u_int8_t *p;
454 if (!m) {
455 aprint_error_dev(&sc->sc_dev, "can't get memory\n");
456 return (ENOMEM);
460 * byte 0x14 = SEND_RELEASE
461 * dword ApplId
464 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
465 p = amcc_put_byte(p, 0);
466 p = amcc_put_byte(p, SEND_RELEASE);
467 p = amcc_put_word(p, applid);
469 IF_ENQUEUE(&sc->sc_txq, m);
471 iavc_start_tx(sc);
472 return 0;
475 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
477 iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
479 if (sc->sc_state != IAVC_UP) {
480 aprint_error_dev(&sc->sc_dev, "attempt to send before device up\n");
482 if (m->m_next) i4b_Bfreembuf(m->m_next);
483 i4b_Dfreembuf(m);
485 return (ENXIO);
488 if (IF_QFULL(&sc->sc_txq)) {
489 IF_DROP(&sc->sc_txq);
491 aprint_error_dev(&sc->sc_dev, "tx overflow, message dropped\n");
493 if (m->m_next) i4b_Bfreembuf(m->m_next);
494 i4b_Dfreembuf(m);
496 } else {
497 IF_ENQUEUE(&sc->sc_txq, m);
499 iavc_start_tx(sc);
502 return 0;
506 // Functions called by ourself during the initialization sequence:
507 // ---------------------------------------------------------------
509 // iavc_send_init
510 // Sends the system initialization message to a newly loaded
511 // board, and sets state to INIT.
514 static int iavc_send_init(iavc_softc_t *sc)
516 struct mbuf *m = i4b_Dgetmbuf(15);
517 u_int8_t *p;
518 int s;
520 if (!m) {
521 aprint_error_dev(&sc->sc_dev, "can't get memory\n");
522 return (ENOMEM);
526 * byte 0x11 = SEND_INIT
527 * dword NumApplications
528 * dword NumNCCIs
529 * dword BoardNumber
532 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
533 p = amcc_put_byte(p, 0);
534 p = amcc_put_byte(p, SEND_INIT);
535 p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
536 p = amcc_put_word(p, sc->sc_capi.sc_nbch);
537 p = amcc_put_word(p, sc->sc_unit);
539 s = splnet();
540 IF_ENQUEUE(&sc->sc_txq, m);
542 iavc_start_tx(sc);
544 sc->sc_state = IAVC_INIT;
545 splx(s);
546 return 0;
550 // Functions called during normal operation:
551 // -----------------------------------------
553 // iavc_receive_init
554 // Reads the initialization reply and calls capi_ll_control().
556 // iavc_receive_new_ncci
557 // Reads a new NCCI notification and calls capi_ll_control().
559 // iavc_receive_free_ncci
560 // Reads a freed NCCI notification and calls capi_ll_control().
562 // iavc_receive_task_ready
563 // Reads a task ready message -- which should not occur XXX.
565 // iavc_receive_debugmsg
566 // Reads a debug message -- which should not occur XXX.
568 // iavc_receive_start
569 // Reads a START TRANSMIT message and unblocks device.
571 // iavc_receive_stop
572 // Reads a STOP TRANSMIT message and blocks device.
574 // iavc_receive
575 // Reads an incoming message and calls capi_ll_receive().
578 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
580 u_int32_t Length;
581 u_int8_t *p;
582 u_int8_t *cardtype, *serial, *profile, *vers, *caps, *prot;
584 if (sc->sc_dma) {
585 p = amcc_get_word(dmabuf, &Length);
586 } else {
587 Length = iavc_get_slice(sc, sc->sc_recvbuf);
588 p = sc->sc_recvbuf;
591 #if 0
593 int len = 0;
594 printf("%s: rx_init: ", device_xname(&sc->sc_dev));
595 while (len < Length) {
596 printf(" %02x", p[len]);
597 if (len && (len % 16) == 0) printf("\n");
598 len++;
600 if (len % 16) printf("\n");
602 #endif
604 vers = (p + 1);
605 p += (*p + 1); /* driver version */
606 cardtype = (p + 1);
607 p += (*p + 1); /* card type */
608 p += (*p + 1); /* hardware ID */
609 serial = (p + 1);
610 p += (*p + 1); /* serial number */
611 caps = (p + 1);
612 p += (*p + 1); /* supported options */
613 prot = (p + 1);
614 p += (*p + 1); /* supported protocols */
615 profile = (p + 1);
617 if (cardtype && serial && profile) {
618 int nbch = ((profile[3]<<8) | profile[2]);
620 aprint_normal_dev(&sc->sc_dev, "AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
621 cardtype, serial, nbch, vers, prot);
622 aprint_verbose_dev(&sc->sc_dev, "%s\n", caps);
624 capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
626 } else {
627 printf("%s: no profile data in info response?\n", device_xname(&sc->sc_dev));
630 sc->sc_blocked = 1; /* controller will send START when ready */
631 return 0;
634 static int iavc_receive_start(iavc_softc_t *sc)
636 struct mbuf *m = i4b_Dgetmbuf(3);
637 u_int8_t *p;
639 if (sc->sc_blocked && sc->sc_state == IAVC_UP)
640 printf("%s: receive_start\n", device_xname(&sc->sc_dev));
642 if (!m) {
643 aprint_error_dev(&sc->sc_dev, "can't get memory\n");
644 return (ENOMEM);
648 * byte 0x73 = SEND_POLLACK
651 p = amcc_put_byte(mtod(m, u_int8_t*), 0);
652 p = amcc_put_byte(p, 0);
653 p = amcc_put_byte(p, SEND_POLLACK);
655 IF_PREPEND(&sc->sc_txq, m);
657 NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d",
658 device_xname(&sc->sc_dev), sc->sc_blocked, sc->sc_state);
660 sc->sc_blocked = 0;
661 iavc_start_tx(sc);
663 /* If this was our first START, register our readiness */
664 if (sc->sc_state != IAVC_UP) {
665 sc->sc_state = IAVC_UP;
666 capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1);
669 return 0;
672 static int iavc_receive_stop(iavc_softc_t *sc)
674 printf("%s: receive_stop\n", device_xname(&sc->sc_dev));
675 sc->sc_blocked = 1;
676 return 0;
679 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
681 u_int32_t ApplId, NCCI, WindowSize;
683 if (sc->sc_dma) {
684 dmabuf = amcc_get_word(dmabuf, &ApplId);
685 dmabuf = amcc_get_word(dmabuf, &NCCI);
686 dmabuf = amcc_get_word(dmabuf, &WindowSize);
687 } else {
688 ApplId = iavc_get_word(sc);
689 NCCI = iavc_get_word(sc);
690 WindowSize = iavc_get_word(sc);
693 capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
694 return 0;
697 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
699 u_int32_t ApplId, NCCI;
701 if (sc->sc_dma) {
702 dmabuf = amcc_get_word(dmabuf, &ApplId);
703 dmabuf = amcc_get_word(dmabuf, &NCCI);
704 } else {
705 ApplId = iavc_get_word(sc);
706 NCCI = iavc_get_word(sc);
709 capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
710 return 0;
713 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
715 u_int32_t TaskId, Length;
716 u_int8_t *p;
717 printf("%s: receive_task_ready\n", device_xname(&sc->sc_dev));
719 if (sc->sc_dma) {
720 p = amcc_get_word(dmabuf, &TaskId);
721 p = amcc_get_word(p, &Length);
722 } else {
723 TaskId = iavc_get_word(sc);
724 Length = iavc_get_slice(sc, sc->sc_recvbuf);
725 p = sc->sc_recvbuf;
728 /* XXX could show the message if trace enabled? XXX */
729 return 0;
732 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
734 u_int32_t Length;
735 u_int8_t *p;
736 printf("%s: receive_debugmsg\n", device_xname(&sc->sc_dev));
738 if (sc->sc_dma) {
739 p = amcc_get_word(dmabuf, &Length);
740 } else {
741 Length = iavc_get_slice(sc, sc->sc_recvbuf);
742 p = sc->sc_recvbuf;
745 /* XXX could show the message if trace enabled? XXX */
746 return 0;
749 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
751 struct mbuf *m;
752 u_int32_t ApplId, Length;
755 * byte 0x21 = RECEIVE_MESSAGE
756 * dword ApplId
757 * dword length
758 * ... CAPI msg
760 * --or--
762 * byte 0x22 = RECEIVE_DATA_B3_IND
763 * dword ApplId
764 * dword length
765 * ... CAPI msg
766 * dword datalen
767 * ... B3 data
770 if (sc->sc_dma) {
771 dmabuf = amcc_get_word(dmabuf, &ApplId);
772 dmabuf = amcc_get_word(dmabuf, &Length);
773 } else {
774 ApplId = iavc_get_word(sc);
775 Length = iavc_get_slice(sc, sc->sc_recvbuf);
776 dmabuf = sc->sc_recvbuf;
779 m = i4b_Dgetmbuf(Length);
780 if (!m) {
781 aprint_error_dev(&sc->sc_dev, "can't get memory for receive\n");
782 return (ENOMEM);
785 memcpy(mtod(m, u_int8_t*), dmabuf, Length);
787 #if 0
789 u_int8_t *p = mtod(m, u_int8_t*);
790 int len = 0;
791 printf("%s: applid=%d, len=%d\n", device_xname(&sc->sc_dev),
792 ApplId, Length);
793 while (len < m->m_len) {
794 printf(" %02x", p[len]);
795 if (len && (len % 16) == 0) printf("\n");
796 len++;
798 if (len % 16) printf("\n");
800 #endif
802 if (b3data) {
803 if (sc->sc_dma) {
804 dmabuf = amcc_get_word(dmabuf + Length, &Length);
805 } else {
806 Length = iavc_get_slice(sc, sc->sc_recvbuf);
807 dmabuf = sc->sc_recvbuf;
810 m->m_next = i4b_Bgetmbuf(Length);
811 if (!m->m_next) {
812 aprint_error_dev(&sc->sc_dev, "can't get memory for receive\n");
813 i4b_Dfreembuf(m);
814 return (ENOMEM);
817 memcpy(mtod(m->m_next, u_int8_t*), dmabuf, Length);
820 capi_ll_receive(&sc->sc_capi, m);
821 return 0;
825 // iavc_handle_intr
826 // Checks device interrupt status and calls iavc_handle_{rx,tx}()
827 // as necessary.
829 // iavc_handle_rx
830 // Reads in the command byte and calls the subroutines above.
832 // iavc_start_tx
833 // Initiates DMA on the next queued message if possible.
836 int iavc_handle_intr(iavc_softc_t *sc)
838 u_int32_t status;
839 u_int32_t newcsr;
841 if (!sc->sc_dma) {
842 while (iavc_rx_full(sc))
843 iavc_handle_rx(sc);
844 return 0;
847 status = AMCC_READ(sc, AMCC_INTCSR);
848 if ((status & ANY_S5933_INT) == 0)
849 return 0;
851 newcsr = sc->sc_csr | (status & ALL_INT);
852 if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
853 if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
854 AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
855 sc->sc_intr = 1;
857 if (status & RX_TC_INT) {
858 u_int32_t rxlen;
860 bus_dmamap_sync(sc->dmat, sc->rx_map, 0, sc->rx_map->dm_mapsize,
861 BUS_DMASYNC_POSTREAD);
863 if (sc->sc_recv1 == 0) {
864 sc->sc_recv1 = *(u_int32_t*)(sc->sc_recvbuf);
865 rxlen = (sc->sc_recv1 + 3) & ~3;
867 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
868 AMCC_WRITE(sc, AMCC_RXLEN, rxlen ? rxlen : 4);
869 } else {
870 iavc_handle_rx(sc);
871 sc->sc_recv1 = 0;
872 AMCC_WRITE(sc, AMCC_RXPTR, sc->rx_map->dm_segs[0].ds_addr);
873 AMCC_WRITE(sc, AMCC_RXLEN, 4);
877 if (status & TX_TC_INT) {
878 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, sc->tx_map->dm_mapsize,
879 BUS_DMASYNC_POSTWRITE);
880 sc->sc_csr &= ~EN_TX_TC_INT;
881 iavc_start_tx(sc);
884 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
885 sc->sc_intr = 0;
887 return 0;
890 static void iavc_handle_rx(iavc_softc_t *sc)
892 u_int8_t *dmabuf = 0, cmd;
894 if (sc->sc_dma) {
895 dmabuf = amcc_get_byte(sc->sc_recvbuf, &cmd);
896 } else {
897 cmd = iavc_get_byte(sc);
900 NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
902 switch (cmd) {
903 case RECEIVE_DATA_B3_IND:
904 iavc_receive(sc, dmabuf, 1);
905 break;
907 case RECEIVE_MESSAGE:
908 iavc_receive(sc, dmabuf, 0);
909 break;
911 case RECEIVE_NEW_NCCI:
912 iavc_receive_new_ncci(sc, dmabuf);
913 break;
915 case RECEIVE_FREE_NCCI:
916 iavc_receive_free_ncci(sc, dmabuf);
917 break;
919 case RECEIVE_START:
920 iavc_receive_start(sc);
921 break;
923 case RECEIVE_STOP:
924 iavc_receive_stop(sc);
925 break;
927 case RECEIVE_INIT:
928 iavc_receive_init(sc, dmabuf);
929 break;
931 case RECEIVE_TASK_READY:
932 iavc_receive_task_ready(sc, dmabuf);
933 break;
935 case RECEIVE_DEBUGMSG:
936 iavc_receive_debugmsg(sc, dmabuf);
937 break;
939 default:
940 aprint_error_dev(&sc->sc_dev, "unknown msg %02x\n", cmd);
944 static void iavc_start_tx(iavc_softc_t *sc)
946 struct mbuf *m;
947 u_int32_t txlen;
949 /* If device has put us on hold, punt. */
951 if (sc->sc_blocked) {
952 return;
955 /* If using DMA and transmitter busy, punt. */
956 if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
957 return;
960 /* Else, see if we have messages to send. */
961 IF_DEQUEUE(&sc->sc_txq, m);
962 if (!m) {
963 return;
966 /* Have message, will send. */
967 if (CAPIMSG_LEN(m->m_data)) {
968 /* A proper CAPI message, possibly with B3 data */
969 txlen = iavc_tx_capimsg(sc, m);
970 } else {
971 /* A board control message to be sent as is */
972 txlen = iavc_tx_ctrlmsg(sc, m);
975 if (m->m_next) {
976 i4b_Bfreembuf(m->m_next);
977 m->m_next = NULL;
979 i4b_Dfreembuf(m);
981 /* Kick DMA into motion if applicable */
982 if (sc->sc_dma) {
983 txlen = (txlen + 3) & ~3;
985 bus_dmamap_sync(sc->dmat, sc->tx_map, 0, txlen,
986 BUS_DMASYNC_PREWRITE);
988 AMCC_WRITE(sc, AMCC_TXPTR, sc->tx_map->dm_segs[0].ds_addr);
989 AMCC_WRITE(sc, AMCC_TXLEN, txlen);
990 sc->sc_csr |= EN_TX_TC_INT;
992 if (!sc->sc_intr)
993 AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
997 static uint32_t
998 iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m)
1000 uint32_t txlen = 0;
1001 u_int8_t *dmabuf;
1003 if (sc->sc_dma) {
1004 /* Copy message to DMA buffer. */
1006 if (m->m_next)
1007 dmabuf = amcc_put_byte(sc->sc_sendbuf, SEND_DATA_B3_REQ);
1008 else
1009 dmabuf = amcc_put_byte(sc->sc_sendbuf, SEND_MESSAGE);
1011 dmabuf = amcc_put_word(dmabuf, m->m_len);
1012 memcpy(dmabuf, m->m_data, m->m_len);
1013 dmabuf += m->m_len;
1014 txlen = 5 + m->m_len;
1016 if (m->m_next) {
1017 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
1018 memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len);
1019 txlen += 4 + m->m_next->m_len;
1022 } else {
1023 /* Use PIO. */
1025 if (m->m_next) {
1026 iavc_put_byte(sc, SEND_DATA_B3_REQ);
1027 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d",
1028 sc->sc_unit, m->m_len);
1029 } else {
1030 iavc_put_byte(sc, SEND_MESSAGE);
1031 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d",
1032 sc->sc_unit, m->m_len);
1034 #if 0
1036 u_int8_t *p = mtod(m, u_int8_t*);
1037 int len;
1038 for (len = 0; len < m->m_len; len++) {
1039 printf(" %02x", *p++);
1040 if (len && (len % 16) == 0)
1041 printf("\n");
1043 if (len % 16)
1044 printf("\n");
1046 #endif
1048 iavc_put_slice(sc, m->m_data, m->m_len);
1050 if (m->m_next)
1051 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
1054 return txlen;
1057 static uint32_t
1058 iavc_tx_ctrlmsg(iavc_softc_t *sc, struct mbuf *m)
1060 uint32_t txlen = 0;
1061 uint8_t *dmabuf;
1063 if (sc->sc_dma) {
1064 memcpy(sc->sc_sendbuf, m->m_data + 2, m->m_len - 2);
1065 txlen = m->m_len - 2;
1066 } else {
1068 #if 0
1070 u_int8_t *p = mtod(m, u_int8_t*) + 2;
1071 int len;
1073 printf("%s: tx BDC msg, len = %d, msg =", device_xname(&sc->sc_dev),
1074 m->m_len-2);
1075 for (len = 0; len < m->m_len-2; len++) {
1076 printf(" %02x", *p++);
1077 if (len && (len % 16) == 0) printf("\n");
1079 if (len % 16)
1080 printf("\n");
1082 #endif
1084 /* no DMA */
1085 txlen = m->m_len - 2;
1086 dmabuf = mtod(m, char*) + 2;
1087 while(txlen--)
1088 b1io_put_byte(sc, *dmabuf++);
1091 return txlen;