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