kernel tree reorganization stage 1: Major cvs repository work (not logged as
[dragonfly.git] / sys / net / i4b / capi / iavc / iavc_lli.c
1 /*
2  * Copyright (c) 2001 Cubical Solutions Ltd. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * capi/iavc/iavc_lli.c
26  *              The AVM ISDN controllers' Low Level Interface.
27  *
28  * $FreeBSD: src/sys/i4b/capi/iavc/iavc_lli.c,v 1.2.2.1 2001/08/10 14:08:34 obrien Exp $
29  * $DragonFly: src/sys/net/i4b/capi/iavc/iavc_lli.c,v 1.3 2003/08/07 21:17:24 dillon Exp $
30  */
31
32 #include "use_iavc.h"
33 #include "use_i4bcapi.h"
34 #include "use_pci.h"
35
36 #if (NIAVC > 0) && (NI4BCAPI > 0)
37
38 #include <sys/param.h>
39 #include <sys/kernel.h>
40 #include <sys/systm.h>
41 #include <sys/mbuf.h>
42 #include <sys/socket.h>
43 #include <sys/malloc.h>
44 #include <net/if.h>
45
46 #include <machine/clock.h>
47
48 #include <machine/bus.h>
49 #include <sys/bus.h>
50 #include <sys/rman.h>
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53
54 #include <machine/i4b_debug.h>
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_trace.h>
57
58 #include "../../include/i4b_global.h"
59 #include "../../include/i4b_l3l4.h"
60 #include "../../include/i4b_mbuf.h"
61 #include "../capi.h"
62 #include "../capi_msgs.h"
63
64 #include "iavc.h"
65
66 /* Forward declarations of local subroutines... */
67
68 static int iavc_send_init(iavc_softc_t *);
69
70 static void iavc_handle_rx(iavc_softc_t *);
71 static void iavc_start_tx(iavc_softc_t *);
72
73 /*
74 //  Callbacks from the upper (capi) layer:
75 //  --------------------------------------
76 //
77 //  iavc_load
78 //      Resets the board and loads the firmware, then initiates
79 //      board startup.
80 //
81 //  iavc_register
82 //      Registers a CAPI application id.
83 //
84 //  iavc_release
85 //      Releases a CAPI application id.
86 //
87 //  iavc_send
88 //      Sends a capi message.
89 */
90
91 int iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
92 {
93     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
94     u_int8_t val;
95
96     if(bootverbose)
97         printf("iavc%d: reset card ....\n", sc->sc_unit);
98
99     if (sc->sc_dma)
100         b1dma_reset(sc);        /* PCI cards */
101     else if (sc->sc_t1)
102         t1_reset(sc);           /* ISA attachment T1 */
103     else
104         b1_reset(sc);           /* ISA attachment B1 */
105
106     DELAY(1000);
107
108     if(bootverbose)
109             printf("iavc%d: start loading %d bytes firmware ....\n", sc->sc_unit, len);
110     
111     while (len && b1io_save_put_byte(sc, *cp++) == 0)
112         len--;
113
114     if (len) {
115         printf("iavc%d: loading failed, can't write to card, len = %d\n",
116                sc->sc_unit, len);
117         return (EIO);
118     }
119
120     if(bootverbose)
121         printf("iavc%d: firmware loaded, wait for ACK ....\n", sc->sc_unit);
122     
123     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
124             iavc_put_byte(sc, SEND_POLL);
125     else
126             iavc_put_byte(sc, SEND_POLLACK);            
127     
128     for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
129         DELAY(100);
130     
131     if (!iavc_rx_full(sc)) {
132         printf("iavc%d: loading failed, no ack\n", sc->sc_unit);
133         return (EIO);
134     }
135     
136     val = iavc_get_byte(sc);
137
138     if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
139         (!sc->sc_dma && val != RECEIVE_POLL)) {
140         printf("iavc%d: loading failed, bad ack = %02x\n", sc->sc_unit, val);
141         return (EIO);
142     }
143
144     if(bootverbose)
145             printf("iavc%d: got ACK = 0x%02x\n", sc->sc_unit, val);    
146
147     if (sc->sc_dma) {
148         /* Start the DMA engine */
149
150         int s = SPLI4B();
151
152         sc->sc_csr = AVM_FLAG;
153         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
154         AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
155                                    A2P_HI_PRIORITY|P2A_HI_PRIORITY|
156                                    RESET_A2P_FLAGS|RESET_P2A_FLAGS));
157
158         iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
159         iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
160
161         sc->sc_recvlen = 0;
162         AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
163         AMCC_WRITE(sc, AMCC_RXLEN, 4);
164         sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
165         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
166
167         splx(s);
168     }
169
170     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
171         b1isa_setup_irq(sc);
172     
173     iavc_send_init(sc);
174
175     return 0;
176 }
177
178 int iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
179 {
180     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
181     struct mbuf *m = i4b_Dgetmbuf(23);
182     u_int8_t *p;
183
184     if (!m) {
185         printf("iavc%d: can't get memory\n", sc->sc_unit);
186         return (ENOMEM);
187     }
188
189     /*
190      * byte  0x12 = SEND_REGISTER
191      * dword ApplId
192      * dword NumMessages
193      * dword NumB3Connections 0..nbch
194      * dword NumB3Blocks
195      * dword B3Size
196      */
197
198     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
199     p = amcc_put_byte(p, 0);
200     p = amcc_put_byte(p, SEND_REGISTER);
201     p = amcc_put_word(p, applid);
202 #if 0
203     p = amcc_put_word(p, 1024 + (nchan + 1));
204 #else
205     p = amcc_put_word(p, 1024 * (nchan + 1));
206 #endif    
207     p = amcc_put_word(p, nchan);
208     p = amcc_put_word(p, 8);
209     p = amcc_put_word(p, 2048);
210
211     _IF_ENQUEUE(&sc->sc_txq, m);
212
213     iavc_start_tx(sc);
214
215     return 0;
216 }
217
218 int iavc_release(capi_softc_t *capi_sc, int applid)
219 {
220     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
221     struct mbuf *m = i4b_Dgetmbuf(7);
222     u_int8_t *p;
223
224     if (!m) {
225         printf("iavc%d: can't get memory\n", sc->sc_unit);
226         return (ENOMEM);
227     }
228
229     /*
230      * byte  0x14 = SEND_RELEASE
231      * dword ApplId
232      */
233
234     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
235     p = amcc_put_byte(p, 0);
236     p = amcc_put_byte(p, SEND_RELEASE);
237     p = amcc_put_word(p, applid);
238
239     _IF_ENQUEUE(&sc->sc_txq, m);
240
241     iavc_start_tx(sc);
242     return 0;
243 }
244
245 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
246 {
247     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
248
249     if (sc->sc_state != IAVC_UP) {
250         printf("iavc%d: attempt to send before device up\n", sc->sc_unit);
251
252         if (m->m_next) i4b_Bfreembuf(m->m_next);
253         i4b_Dfreembuf(m);
254
255         return (ENXIO);
256     }
257
258     if (_IF_QFULL(&sc->sc_txq)) {
259 #if defined (__FreeBSD__) && __FreeBSD__ > 4
260         _IF_DROP(&sc->sc_txq);
261 #else
262         IF_DROP(&sc->sc_txq);
263 #endif
264
265         printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit);
266
267         if (m->m_next) i4b_Bfreembuf(m->m_next);
268         i4b_Dfreembuf(m);
269
270     } else {
271         _IF_ENQUEUE(&sc->sc_txq, m);
272
273         iavc_start_tx(sc);
274     }
275     
276     return 0;
277 }
278
279 /*
280 //  Functions called by ourself during the initialization sequence:
281 //  ---------------------------------------------------------------
282 //
283 //  iavc_send_init
284 //      Sends the system initialization message to a newly loaded
285 //      board, and sets state to INIT.
286 */
287
288 static int iavc_send_init(iavc_softc_t *sc)
289 {
290     struct mbuf *m = i4b_Dgetmbuf(15);
291     u_int8_t *p;
292     int s;
293
294     if (!m) {
295         printf("iavc%d: can't get memory\n", sc->sc_unit);
296         return (ENOMEM);
297     }
298
299     /*
300      * byte  0x11 = SEND_INIT
301      * dword NumApplications
302      * dword NumNCCIs
303      * dword BoardNumber
304      */
305
306     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
307     p = amcc_put_byte(p, 0);
308     p = amcc_put_byte(p, SEND_INIT);
309     p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
310     p = amcc_put_word(p, sc->sc_capi.sc_nbch);
311     p = amcc_put_word(p, sc->sc_unit);
312
313     s = SPLI4B();
314     _IF_ENQUEUE(&sc->sc_txq, m);
315
316     iavc_start_tx(sc);
317
318     sc->sc_state = IAVC_INIT;
319     splx(s);
320     return 0;
321 }
322
323 /*
324 //  Functions called during normal operation:
325 //  -----------------------------------------
326 //
327 //  iavc_receive_init
328 //      Reads the initialization reply and calls capi_ll_control().
329 //
330 //  iavc_receive_new_ncci
331 //      Reads a new NCCI notification and calls capi_ll_control().
332 //
333 //  iavc_receive_free_ncci
334 //      Reads a freed NCCI notification and calls capi_ll_control().
335 //
336 //  iavc_receive_task_ready
337 //      Reads a task ready message -- which should not occur XXX.
338 //
339 //  iavc_receive_debugmsg
340 //      Reads a debug message -- which should not occur XXX.
341 //
342 //  iavc_receive_start
343 //      Reads a START TRANSMIT message and unblocks device.
344 //
345 //  iavc_receive_stop
346 //      Reads a STOP TRANSMIT message and blocks device.
347 //
348 //  iavc_receive
349 //      Reads an incoming message and calls capi_ll_receive().
350 */
351
352 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
353 {
354     u_int32_t Length;
355     u_int8_t *p;
356     u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
357
358     if (sc->sc_dma) {
359         p = amcc_get_word(dmabuf, &Length);
360     } else {
361         Length = iavc_get_slice(sc, sc->sc_recvbuf);
362         p = sc->sc_recvbuf;
363     }
364
365 #if 0
366     {
367         int len = 0;
368         printf("iavc%d: rx_init: ", sc->sc_unit);
369             while (len < Length) {
370                 printf(" %02x", p[len]);
371                 if (len && (len % 16) == 0) printf("\n");
372                 len++;
373             }
374             if (len % 16) printf("\n");
375     }
376 #endif
377
378     version = (p + 1);
379     p += (*p + 1); /* driver version */
380     cardtype = (p + 1);
381     p += (*p + 1); /* card type */
382     p += (*p + 1); /* hardware ID */
383     serial = (p + 1);
384     p += (*p + 1); /* serial number */
385     caps = (p + 1);
386     p += (*p + 1); /* supported options */
387     prot = (p + 1);
388     p += (*p + 1); /* supported protocols */
389     profile = (p + 1);
390
391     if (cardtype && serial && profile) {
392         int nbch = ((profile[3]<<8) | profile[2]);
393
394         printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
395                 sc->sc_unit, cardtype, serial, nbch, version, prot);
396
397         if(bootverbose)
398                 printf("iavc%d: %s\n", sc->sc_unit, caps);
399
400         capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
401
402     } else {
403         printf("iavc%d: no profile data in info response?\n", sc->sc_unit);
404     }
405
406     sc->sc_blocked = TRUE; /* controller will send START when ready */
407     return 0;
408 }
409
410 static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
411 {
412     struct mbuf *m = i4b_Dgetmbuf(3);
413     u_int8_t *p;
414
415     if (sc->sc_blocked && sc->sc_state == IAVC_UP)
416         printf("iavc%d: receive_start\n", sc->sc_unit);
417
418     if (!m) {
419         printf("iavc%d: can't get memory\n", sc->sc_unit);
420         return (ENOMEM);
421     }
422
423     /*
424      * byte  0x73 = SEND_POLLACK
425      */
426
427     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
428     p = amcc_put_byte(p, 0);
429     p = amcc_put_byte(p, SEND_POLLACK);
430     
431     _IF_PREPEND(&sc->sc_txq, m);
432
433     NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d",
434                 sc->sc_unit, sc->sc_blocked, sc->sc_state);
435
436     sc->sc_blocked = FALSE;
437     iavc_start_tx(sc);
438     
439     /* If this was our first START, register our readiness */
440
441     if (sc->sc_state != IAVC_UP) {
442         sc->sc_state = IAVC_UP;
443         capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE);
444     }
445
446     return 0;
447 }
448
449 static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
450 {
451     printf("iavc%d: receive_stop\n", sc->sc_unit);
452     sc->sc_blocked = TRUE;
453     return 0;
454 }
455
456 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
457 {
458     u_int32_t ApplId, NCCI, WindowSize;
459
460     if (sc->sc_dma) {
461         dmabuf = amcc_get_word(dmabuf, &ApplId);
462         dmabuf = amcc_get_word(dmabuf, &NCCI);
463         dmabuf = amcc_get_word(dmabuf, &WindowSize);
464     } else {
465         ApplId = iavc_get_word(sc);
466         NCCI   = iavc_get_word(sc);
467         WindowSize = iavc_get_word(sc);
468     }
469
470     capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
471     return 0;
472 }
473
474 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
475 {
476     u_int32_t ApplId, NCCI;
477
478     if (sc->sc_dma) {
479         dmabuf = amcc_get_word(dmabuf, &ApplId);
480         dmabuf = amcc_get_word(dmabuf, &NCCI);
481     } else {
482         ApplId = iavc_get_word(sc);
483         NCCI   = iavc_get_word(sc);
484     }
485
486     capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
487     return 0;
488 }
489
490 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
491 {
492     u_int32_t TaskId, Length;
493     u_int8_t *p;
494     printf("iavc%d: receive_task_ready\n", sc->sc_unit);
495     
496     if (sc->sc_dma) {
497         p = amcc_get_word(dmabuf, &TaskId);
498         p = amcc_get_word(p, &Length);
499     } else {
500         TaskId = iavc_get_word(sc);
501         Length = iavc_get_slice(sc, sc->sc_recvbuf);
502         p = sc->sc_recvbuf;
503     }
504
505     /* XXX could show the message if trace enabled? XXX */
506     return 0;
507 }
508
509 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
510 {
511     u_int32_t Length;
512     u_int8_t *p;
513     printf("iavc%d: receive_debugmsg\n", sc->sc_unit);
514     
515     if (sc->sc_dma) {
516         p = amcc_get_word(dmabuf, &Length);
517     } else {
518         Length = iavc_get_slice(sc, sc->sc_recvbuf);
519         p = sc->sc_recvbuf;
520     }
521
522     /* XXX could show the message if trace enabled? XXX */
523     return 0;
524 }
525
526 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
527 {
528     struct mbuf *m;
529     u_int32_t ApplId, Length;
530
531     /*
532      * byte  0x21 = RECEIVE_MESSAGE
533      * dword ApplId
534      * dword length
535      * ...   CAPI msg
536      *
537      * --or--
538      *
539      * byte  0x22 = RECEIVE_DATA_B3_IND
540      * dword ApplId
541      * dword length
542      * ...   CAPI msg
543      * dword datalen
544      * ...   B3 data
545      */
546
547     if (sc->sc_dma) {
548         dmabuf = amcc_get_word(dmabuf, &ApplId);
549         dmabuf = amcc_get_word(dmabuf, &Length);
550     } else {
551         ApplId = iavc_get_word(sc);
552         Length = iavc_get_slice(sc, sc->sc_recvbuf);
553         dmabuf = sc->sc_recvbuf;
554     }
555
556     m = i4b_Dgetmbuf(Length);
557     if (!m) {
558         printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
559         return (ENOMEM);
560     }
561
562     bcopy(dmabuf, mtod(m, u_int8_t*), Length);
563
564 #if 0
565         {
566             u_int8_t *p = mtod(m, u_int8_t*);
567             int len = 0;
568             printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length);
569             while (len < m->m_len) {
570                 printf(" %02x", p[len]);
571                 if (len && (len % 16) == 0) printf("\n");
572                 len++;
573             }
574             if (len % 16) printf("\n");
575         }
576 #endif
577
578     if (b3data) {
579         if (sc->sc_dma) {
580             dmabuf = amcc_get_word(dmabuf + Length, &Length);
581         } else {
582             Length = iavc_get_slice(sc, sc->sc_recvbuf);
583             dmabuf = sc->sc_recvbuf;
584         }
585
586         m->m_next = i4b_Bgetmbuf(Length);
587         if (!m->m_next) {
588             printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
589             i4b_Dfreembuf(m);
590             return (ENOMEM);
591         }
592
593         bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length);
594     }
595
596     capi_ll_receive(&sc->sc_capi, m);
597     return 0;
598 }
599
600 /*
601 //  iavc_handle_intr
602 //      Checks device interrupt status and calls iavc_handle_{rx,tx}()
603 //      as necessary.
604 //
605 //  iavc_handle_rx
606 //      Reads in the command byte and calls the subroutines above.
607 //
608 //  iavc_start_tx
609 //      Initiates DMA on the next queued message if possible.
610 */
611
612 void iavc_handle_intr(iavc_softc_t *sc)
613 {
614     u_int32_t status;
615     u_int32_t newcsr;
616
617     if (!sc->sc_dma) {
618         while (iavc_rx_full(sc))
619             iavc_handle_rx(sc);
620         return;
621     }
622
623     status = AMCC_READ(sc, AMCC_INTCSR);
624     if ((status & ANY_S5933_INT) == 0)
625         return;
626
627     newcsr = sc->sc_csr | (status & ALL_INT);
628     if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
629     if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
630     AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
631     sc->sc_intr = TRUE;
632
633     if (status & RX_TC_INT) {
634         u_int32_t rxlen;
635
636         if (sc->sc_recvlen == 0) {
637             sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0]));
638             rxlen = (sc->sc_recvlen + 3) & ~3;
639             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4]));
640             AMCC_WRITE(sc, AMCC_RXLEN, rxlen);
641         } else {
642             iavc_handle_rx(sc);
643             sc->sc_recvlen = 0;
644             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
645             AMCC_WRITE(sc, AMCC_RXLEN, 4);
646         }
647     }
648
649     if (status & TX_TC_INT) {
650         sc->sc_csr &= ~EN_TX_TC_INT;
651         iavc_start_tx(sc);
652     }
653
654     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
655     sc->sc_intr = FALSE;
656 }
657
658 static void iavc_handle_rx(iavc_softc_t *sc)
659 {
660     u_int8_t *dmabuf = 0, cmd;
661
662     if (sc->sc_dma) {
663         dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd);
664     } else {
665         cmd = iavc_get_byte(sc);
666     }
667
668     NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
669     
670     switch (cmd) {
671     case RECEIVE_DATA_B3_IND:
672         iavc_receive(sc, dmabuf, TRUE);
673         break;
674
675     case RECEIVE_MESSAGE:
676         iavc_receive(sc, dmabuf, FALSE);
677         break;
678
679     case RECEIVE_NEW_NCCI:
680         iavc_receive_new_ncci(sc, dmabuf);
681         break;
682
683     case RECEIVE_FREE_NCCI:
684         iavc_receive_free_ncci(sc, dmabuf);
685         break;
686
687     case RECEIVE_START:
688         iavc_receive_start(sc, dmabuf);
689         break;
690
691     case RECEIVE_STOP:
692         iavc_receive_stop(sc, dmabuf);
693         break;
694
695     case RECEIVE_INIT:
696         iavc_receive_init(sc, dmabuf);
697         break;
698
699     case RECEIVE_TASK_READY:
700         iavc_receive_task_ready(sc, dmabuf);
701         break;
702
703     case RECEIVE_DEBUGMSG:
704         iavc_receive_debugmsg(sc, dmabuf);
705         break;
706
707     default:
708         printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd);
709     }
710 }
711
712 static void iavc_start_tx(iavc_softc_t *sc)
713 {
714     struct mbuf *m;
715     u_int8_t *dmabuf;
716     u_int32_t txlen = 0;
717     
718     /* If device has put us on hold, punt. */
719
720     if (sc->sc_blocked) {
721         return;
722     }
723
724     /* If using DMA and transmitter busy, punt. */
725     
726     if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
727         return;
728     }
729
730     /* Else, see if we have messages to send. */
731
732     _IF_DEQUEUE(&sc->sc_txq, m);
733     if (!m) {
734         return;
735     }
736
737     /* Have message, will send. */
738
739     if (CAPIMSG_LEN(m->m_data)) {
740         /* A proper CAPI message, possibly with B3 data */
741
742         if (sc->sc_dma) {
743             /* Copy message to DMA buffer. */
744
745             if (m->m_next) {
746                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
747             } else {
748                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
749             }
750
751             dmabuf = amcc_put_word(dmabuf, m->m_len);
752             bcopy(m->m_data, dmabuf, m->m_len);
753             dmabuf += m->m_len;
754             txlen = 5 + m->m_len;
755
756             if (m->m_next) {
757                 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
758                 bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len);
759                 txlen += 4 + m->m_next->m_len;
760             }
761
762         } else {
763             /* Use PIO. */
764
765             if (m->m_next) {
766                 iavc_put_byte(sc, SEND_DATA_B3_REQ);
767                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len);
768             } else {
769                 iavc_put_byte(sc, SEND_MESSAGE);
770                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len);
771             }
772 #if 0
773     {
774         u_int8_t *p = mtod(m, u_int8_t*);
775         int len;
776         for (len = 0; len < m->m_len; len++) {
777             printf(" %02x", *p++);
778             if (len && (len % 16) == 0) printf("\n");
779         }
780         if (len % 16) printf("\n");
781     }
782 #endif
783
784             iavc_put_slice(sc, m->m_data, m->m_len);
785
786             if (m->m_next) {
787                 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
788             }
789         }
790
791     } else {
792         /* A board control message to be sent as is */
793
794         if (sc->sc_dma) {
795             bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2);
796             txlen = m->m_len - 2;
797
798         } else {
799 #if 0
800     {
801         u_int8_t *p = mtod(m, u_int8_t*) + 2;
802         int len;
803         printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2);
804         for (len = 0; len < m->m_len-2; len++) {
805             printf(" %02x", *p++);
806             if (len && (len % 16) == 0) printf("\n");
807         }
808         if (len % 16) printf("\n");
809     }
810 #endif
811
812             txlen = m->m_len - 2;
813             dmabuf = mtod(m, char*) + 2;
814             while(txlen--)
815                 b1io_put_byte(sc, *dmabuf++);
816         }
817     }
818
819     if (m->m_next) {
820         i4b_Bfreembuf(m->m_next);
821         m->m_next = NULL;
822     }
823     i4b_Dfreembuf(m);
824
825     if (sc->sc_dma) {
826         /* Start transmitter */
827
828         txlen = (txlen + 3) & ~3;
829         AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0]));
830         AMCC_WRITE(sc, AMCC_TXLEN, txlen);
831         sc->sc_csr |= EN_TX_TC_INT;
832
833         if (!sc->sc_intr)
834             AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
835     }
836 }
837
838 #endif