Do a major clean-up of the BUSDMA architecture. A large number of
[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.9 2006/10/25 20:56:03 dillon Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/kernel.h>
34 #include <sys/systm.h>
35 #include <sys/mbuf.h>
36 #include <sys/socket.h>
37 #include <sys/malloc.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <sys/thread2.h>
41
42 #include <machine/clock.h>
43
44 #include <vm/vm.h>
45 #include <vm/pmap.h>
46
47 #include <net/if.h>
48 #include <net/i4b/include/machine/i4b_debug.h>
49 #include <net/i4b/include/machine/i4b_ioctl.h>
50 #include <net/i4b/include/machine/i4b_trace.h>
51
52 #include "../../include/i4b_global.h"
53 #include "../../include/i4b_l3l4.h"
54 #include "../../include/i4b_mbuf.h"
55 #include "../capi.h"
56 #include "../capi_msgs.h"
57
58 #include "iavc.h"
59
60 /* Forward declarations of local subroutines... */
61
62 static int iavc_send_init(iavc_softc_t *);
63
64 static void iavc_handle_rx(iavc_softc_t *);
65 static void iavc_start_tx(iavc_softc_t *);
66
67 /*
68 //  Callbacks from the upper (capi) layer:
69 //  --------------------------------------
70 //
71 //  iavc_load
72 //      Resets the board and loads the firmware, then initiates
73 //      board startup.
74 //
75 //  iavc_register
76 //      Registers a CAPI application id.
77 //
78 //  iavc_release
79 //      Releases a CAPI application id.
80 //
81 //  iavc_send
82 //      Sends a capi message.
83 */
84
85 int
86 iavc_load(capi_softc_t *capi_sc, int len, u_int8_t *cp)
87 {
88     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
89     u_int8_t val;
90
91     if(bootverbose)
92         printf("iavc%d: reset card ....\n", sc->sc_unit);
93
94     if (sc->sc_dma)
95         b1dma_reset(sc);        /* PCI cards */
96     else if (sc->sc_t1)
97         t1_reset(sc);           /* ISA attachment T1 */
98     else
99         b1_reset(sc);           /* ISA attachment B1 */
100
101     DELAY(1000);
102
103     if(bootverbose)
104             printf("iavc%d: start loading %d bytes firmware ....\n", sc->sc_unit, len);
105     
106     while (len && b1io_save_put_byte(sc, *cp++) == 0)
107         len--;
108
109     if (len) {
110         printf("iavc%d: loading failed, can't write to card, len = %d\n",
111                sc->sc_unit, len);
112         return (EIO);
113     }
114
115     if(bootverbose)
116         printf("iavc%d: firmware loaded, wait for ACK ....\n", sc->sc_unit);
117     
118     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
119             iavc_put_byte(sc, SEND_POLL);
120     else
121             iavc_put_byte(sc, SEND_POLLACK);            
122     
123     for (len = 0; len < 1000 && !iavc_rx_full(sc); len++)
124         DELAY(100);
125     
126     if (!iavc_rx_full(sc)) {
127         printf("iavc%d: loading failed, no ack\n", sc->sc_unit);
128         return (EIO);
129     }
130     
131     val = iavc_get_byte(sc);
132
133     if ((sc->sc_dma && val != RECEIVE_POLLDWORD) ||
134         (!sc->sc_dma && val != RECEIVE_POLL)) {
135         printf("iavc%d: loading failed, bad ack = %02x\n", sc->sc_unit, val);
136         return (EIO);
137     }
138
139     if(bootverbose)
140             printf("iavc%d: got ACK = 0x%02x\n", sc->sc_unit, val);    
141
142     if (sc->sc_dma) {
143         /* Start the DMA engine */
144
145         crit_enter();
146
147         sc->sc_csr = AVM_FLAG;
148         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
149         AMCC_WRITE(sc, AMCC_MCSR, (EN_A2P_TRANSFERS|EN_P2A_TRANSFERS|
150                                    A2P_HI_PRIORITY|P2A_HI_PRIORITY|
151                                    RESET_A2P_FLAGS|RESET_P2A_FLAGS));
152
153         iavc_write_port(sc, 0x07, 0x30); /* XXX magic numbers from */
154         iavc_write_port(sc, 0x10, 0xf0); /* XXX the linux driver */
155
156         sc->sc_recvlen = 0;
157         AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
158         AMCC_WRITE(sc, AMCC_RXLEN, 4);
159         sc->sc_csr |= EN_RX_TC_INT|EN_TX_TC_INT;
160         AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
161
162         crit_exit();
163     }
164
165     if(sc->sc_capi.card_type == CARD_TYPEC_AVM_B1_ISA)
166         b1isa_setup_irq(sc);
167     
168     iavc_send_init(sc);
169
170     return 0;
171 }
172
173 int
174 iavc_register(capi_softc_t *capi_sc, int applid, int nchan)
175 {
176     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
177     struct mbuf *m = i4b_Dgetmbuf(23);
178     u_int8_t *p;
179
180     if (!m) {
181         printf("iavc%d: can't get memory\n", sc->sc_unit);
182         return (ENOMEM);
183     }
184
185     /*
186      * byte  0x12 = SEND_REGISTER
187      * dword ApplId
188      * dword NumMessages
189      * dword NumB3Connections 0..nbch
190      * dword NumB3Blocks
191      * dword B3Size
192      */
193
194     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
195     p = amcc_put_byte(p, 0);
196     p = amcc_put_byte(p, SEND_REGISTER);
197     p = amcc_put_word(p, applid);
198 #if 0
199     p = amcc_put_word(p, 1024 + (nchan + 1));
200 #else
201     p = amcc_put_word(p, 1024 * (nchan + 1));
202 #endif    
203     p = amcc_put_word(p, nchan);
204     p = amcc_put_word(p, 8);
205     p = amcc_put_word(p, 2048);
206
207     IF_ENQUEUE(&sc->sc_txq, m);
208
209     iavc_start_tx(sc);
210
211     return 0;
212 }
213
214 int
215 iavc_release(capi_softc_t *capi_sc, int applid)
216 {
217     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
218     struct mbuf *m = i4b_Dgetmbuf(7);
219     u_int8_t *p;
220
221     if (!m) {
222         printf("iavc%d: can't get memory\n", sc->sc_unit);
223         return (ENOMEM);
224     }
225
226     /*
227      * byte  0x14 = SEND_RELEASE
228      * dword ApplId
229      */
230
231     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
232     p = amcc_put_byte(p, 0);
233     p = amcc_put_byte(p, SEND_RELEASE);
234     p = amcc_put_word(p, applid);
235
236     IF_ENQUEUE(&sc->sc_txq, m);
237
238     iavc_start_tx(sc);
239     return 0;
240 }
241
242 int
243 iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
244 {
245     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
246
247     if (sc->sc_state != IAVC_UP) {
248         printf("iavc%d: attempt to send before device up\n", sc->sc_unit);
249
250         if (m->m_next) i4b_Bfreembuf(m->m_next);
251         i4b_Dfreembuf(m);
252
253         return (ENXIO);
254     }
255
256     if (IF_QFULL(&sc->sc_txq)) {
257         IF_DROP(&sc->sc_txq);
258
259         printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit);
260
261         if (m->m_next) i4b_Bfreembuf(m->m_next);
262         i4b_Dfreembuf(m);
263
264     } else {
265         IF_ENQUEUE(&sc->sc_txq, m);
266
267         iavc_start_tx(sc);
268     }
269     
270     return 0;
271 }
272
273 /*
274 //  Functions called by ourself during the initialization sequence:
275 //  ---------------------------------------------------------------
276 //
277 //  iavc_send_init
278 //      Sends the system initialization message to a newly loaded
279 //      board, and sets state to INIT.
280 */
281
282 static int
283 iavc_send_init(iavc_softc_t *sc)
284 {
285     struct mbuf *m = i4b_Dgetmbuf(15);
286     u_int8_t *p;
287
288     if (!m) {
289         printf("iavc%d: can't get memory\n", sc->sc_unit);
290         return (ENOMEM);
291     }
292
293     /*
294      * byte  0x11 = SEND_INIT
295      * dword NumApplications
296      * dword NumNCCIs
297      * dword BoardNumber
298      */
299
300     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
301     p = amcc_put_byte(p, 0);
302     p = amcc_put_byte(p, SEND_INIT);
303     p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
304     p = amcc_put_word(p, sc->sc_capi.sc_nbch);
305     p = amcc_put_word(p, sc->sc_unit);
306
307     crit_enter();
308     IF_ENQUEUE(&sc->sc_txq, m);
309
310     iavc_start_tx(sc);
311
312     sc->sc_state = IAVC_INIT;
313     crit_exit();
314     return 0;
315 }
316
317 /*
318 //  Functions called during normal operation:
319 //  -----------------------------------------
320 //
321 //  iavc_receive_init
322 //      Reads the initialization reply and calls capi_ll_control().
323 //
324 //  iavc_receive_new_ncci
325 //      Reads a new NCCI notification and calls capi_ll_control().
326 //
327 //  iavc_receive_free_ncci
328 //      Reads a freed NCCI notification and calls capi_ll_control().
329 //
330 //  iavc_receive_task_ready
331 //      Reads a task ready message -- which should not occur XXX.
332 //
333 //  iavc_receive_debugmsg
334 //      Reads a debug message -- which should not occur XXX.
335 //
336 //  iavc_receive_start
337 //      Reads a START TRANSMIT message and unblocks device.
338 //
339 //  iavc_receive_stop
340 //      Reads a STOP TRANSMIT message and blocks device.
341 //
342 //  iavc_receive
343 //      Reads an incoming message and calls capi_ll_receive().
344 */
345
346 static int
347 iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
348 {
349     u_int32_t Length;
350     u_int8_t *p;
351     u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
352
353     if (sc->sc_dma) {
354         p = amcc_get_word(dmabuf, &Length);
355     } else {
356         Length = iavc_get_slice(sc, sc->sc_recvbuf);
357         p = sc->sc_recvbuf;
358     }
359
360 #if 0
361     {
362         int len = 0;
363         printf("iavc%d: rx_init: ", sc->sc_unit);
364             while (len < Length) {
365                 printf(" %02x", p[len]);
366                 if (len && (len % 16) == 0) printf("\n");
367                 len++;
368             }
369             if (len % 16) printf("\n");
370     }
371 #endif
372
373     version = (p + 1);
374     p += (*p + 1); /* driver version */
375     cardtype = (p + 1);
376     p += (*p + 1); /* card type */
377     p += (*p + 1); /* hardware ID */
378     serial = (p + 1);
379     p += (*p + 1); /* serial number */
380     caps = (p + 1);
381     p += (*p + 1); /* supported options */
382     prot = (p + 1);
383     p += (*p + 1); /* supported protocols */
384     profile = (p + 1);
385
386     if (cardtype && serial && profile) {
387         int nbch = ((profile[3]<<8) | profile[2]);
388
389         printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
390                 sc->sc_unit, cardtype, serial, nbch, version, prot);
391
392         if(bootverbose)
393                 printf("iavc%d: %s\n", sc->sc_unit, caps);
394
395         capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
396
397     } else {
398         printf("iavc%d: no profile data in info response?\n", sc->sc_unit);
399     }
400
401     sc->sc_blocked = TRUE; /* controller will send START when ready */
402     return 0;
403 }
404
405 static int
406 iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
407 {
408     struct mbuf *m = i4b_Dgetmbuf(3);
409     u_int8_t *p;
410
411     if (sc->sc_blocked && sc->sc_state == IAVC_UP)
412         printf("iavc%d: receive_start\n", sc->sc_unit);
413
414     if (!m) {
415         printf("iavc%d: can't get memory\n", sc->sc_unit);
416         return (ENOMEM);
417     }
418
419     /*
420      * byte  0x73 = SEND_POLLACK
421      */
422
423     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
424     p = amcc_put_byte(p, 0);
425     p = amcc_put_byte(p, SEND_POLLACK);
426     
427     IF_PREPEND(&sc->sc_txq, m);
428
429     NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d",
430                 sc->sc_unit, sc->sc_blocked, sc->sc_state);
431
432     sc->sc_blocked = FALSE;
433     iavc_start_tx(sc);
434     
435     /* If this was our first START, register our readiness */
436
437     if (sc->sc_state != IAVC_UP) {
438         sc->sc_state = IAVC_UP;
439         capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE);
440     }
441
442     return 0;
443 }
444
445 static int
446 iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
447 {
448     printf("iavc%d: receive_stop\n", sc->sc_unit);
449     sc->sc_blocked = TRUE;
450     return 0;
451 }
452
453 static int
454 iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
455 {
456     u_int32_t ApplId, NCCI, WindowSize;
457
458     if (sc->sc_dma) {
459         dmabuf = amcc_get_word(dmabuf, &ApplId);
460         dmabuf = amcc_get_word(dmabuf, &NCCI);
461         dmabuf = amcc_get_word(dmabuf, &WindowSize);
462     } else {
463         ApplId = iavc_get_word(sc);
464         NCCI   = iavc_get_word(sc);
465         WindowSize = iavc_get_word(sc);
466     }
467
468     capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
469     return 0;
470 }
471
472 static int
473 iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
474 {
475     u_int32_t ApplId, NCCI;
476
477     if (sc->sc_dma) {
478         dmabuf = amcc_get_word(dmabuf, &ApplId);
479         dmabuf = amcc_get_word(dmabuf, &NCCI);
480     } else {
481         ApplId = iavc_get_word(sc);
482         NCCI   = iavc_get_word(sc);
483     }
484
485     capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
486     return 0;
487 }
488
489 static int
490 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
510 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
528 iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
529 {
530     struct mbuf *m;
531     u_int32_t ApplId, Length;
532
533     /*
534      * byte  0x21 = RECEIVE_MESSAGE
535      * dword ApplId
536      * dword length
537      * ...   CAPI msg
538      *
539      * --or--
540      *
541      * byte  0x22 = RECEIVE_DATA_B3_IND
542      * dword ApplId
543      * dword length
544      * ...   CAPI msg
545      * dword datalen
546      * ...   B3 data
547      */
548
549     if (sc->sc_dma) {
550         dmabuf = amcc_get_word(dmabuf, &ApplId);
551         dmabuf = amcc_get_word(dmabuf, &Length);
552     } else {
553         ApplId = iavc_get_word(sc);
554         Length = iavc_get_slice(sc, sc->sc_recvbuf);
555         dmabuf = sc->sc_recvbuf;
556     }
557
558     m = i4b_Dgetmbuf(Length);
559     if (!m) {
560         printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
561         return (ENOMEM);
562     }
563
564     bcopy(dmabuf, mtod(m, u_int8_t*), Length);
565
566 #if 0
567         {
568             u_int8_t *p = mtod(m, u_int8_t*);
569             int len = 0;
570             printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length);
571             while (len < m->m_len) {
572                 printf(" %02x", p[len]);
573                 if (len && (len % 16) == 0) printf("\n");
574                 len++;
575             }
576             if (len % 16) printf("\n");
577         }
578 #endif
579
580     if (b3data) {
581         if (sc->sc_dma) {
582             dmabuf = amcc_get_word(dmabuf + Length, &Length);
583         } else {
584             Length = iavc_get_slice(sc, sc->sc_recvbuf);
585             dmabuf = sc->sc_recvbuf;
586         }
587
588         m->m_next = i4b_Bgetmbuf(Length);
589         if (!m->m_next) {
590             printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
591             i4b_Dfreembuf(m);
592             return (ENOMEM);
593         }
594
595         bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length);
596     }
597
598     capi_ll_receive(&sc->sc_capi, m);
599     return 0;
600 }
601
602 /*
603 //  iavc_handle_intr
604 //      Checks device interrupt status and calls iavc_handle_{rx,tx}()
605 //      as necessary.
606 //
607 //  iavc_handle_rx
608 //      Reads in the command byte and calls the subroutines above.
609 //
610 //  iavc_start_tx
611 //      Initiates DMA on the next queued message if possible.
612 */
613
614 void
615 iavc_handle_intr(iavc_softc_t *sc)
616 {
617     u_int32_t status;
618     u_int32_t newcsr;
619
620     if (!sc->sc_dma) {
621         while (iavc_rx_full(sc))
622             iavc_handle_rx(sc);
623         return;
624     }
625
626     status = AMCC_READ(sc, AMCC_INTCSR);
627     if ((status & ANY_S5933_INT) == 0)
628         return;
629
630     newcsr = sc->sc_csr | (status & ALL_INT);
631     if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
632     if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
633     AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
634     sc->sc_intr = TRUE;
635
636     if (status & RX_TC_INT) {
637         u_int32_t rxlen;
638
639         if (sc->sc_recvlen == 0) {
640             sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0]));
641             rxlen = (sc->sc_recvlen + 3) & ~3;
642             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4]));
643             AMCC_WRITE(sc, AMCC_RXLEN, rxlen);
644         } else {
645             iavc_handle_rx(sc);
646             sc->sc_recvlen = 0;
647             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
648             AMCC_WRITE(sc, AMCC_RXLEN, 4);
649         }
650     }
651
652     if (status & TX_TC_INT) {
653         sc->sc_csr &= ~EN_TX_TC_INT;
654         iavc_start_tx(sc);
655     }
656
657     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
658     sc->sc_intr = FALSE;
659 }
660
661 static void
662 iavc_handle_rx(iavc_softc_t *sc)
663 {
664     u_int8_t *dmabuf = 0, cmd;
665
666     if (sc->sc_dma) {
667         dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd);
668     } else {
669         cmd = iavc_get_byte(sc);
670     }
671
672     NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
673     
674     switch (cmd) {
675     case RECEIVE_DATA_B3_IND:
676         iavc_receive(sc, dmabuf, TRUE);
677         break;
678
679     case RECEIVE_MESSAGE:
680         iavc_receive(sc, dmabuf, FALSE);
681         break;
682
683     case RECEIVE_NEW_NCCI:
684         iavc_receive_new_ncci(sc, dmabuf);
685         break;
686
687     case RECEIVE_FREE_NCCI:
688         iavc_receive_free_ncci(sc, dmabuf);
689         break;
690
691     case RECEIVE_START:
692         iavc_receive_start(sc, dmabuf);
693         break;
694
695     case RECEIVE_STOP:
696         iavc_receive_stop(sc, dmabuf);
697         break;
698
699     case RECEIVE_INIT:
700         iavc_receive_init(sc, dmabuf);
701         break;
702
703     case RECEIVE_TASK_READY:
704         iavc_receive_task_ready(sc, dmabuf);
705         break;
706
707     case RECEIVE_DEBUGMSG:
708         iavc_receive_debugmsg(sc, dmabuf);
709         break;
710
711     default:
712         printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd);
713     }
714 }
715
716 static void
717 iavc_start_tx(iavc_softc_t *sc)
718 {
719     struct mbuf *m;
720     u_int8_t *dmabuf;
721     u_int32_t txlen = 0;
722     
723     /* If device has put us on hold, punt. */
724
725     if (sc->sc_blocked) {
726         return;
727     }
728
729     /* If using DMA and transmitter busy, punt. */
730     
731     if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
732         return;
733     }
734
735     /* Else, see if we have messages to send. */
736
737     IF_DEQUEUE(&sc->sc_txq, m);
738     if (!m) {
739         return;
740     }
741
742     /* Have message, will send. */
743
744     if (CAPIMSG_LEN(m->m_data)) {
745         /* A proper CAPI message, possibly with B3 data */
746
747         if (sc->sc_dma) {
748             /* Copy message to DMA buffer. */
749
750             if (m->m_next) {
751                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
752             } else {
753                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
754             }
755
756             dmabuf = amcc_put_word(dmabuf, m->m_len);
757             bcopy(m->m_data, dmabuf, m->m_len);
758             dmabuf += m->m_len;
759             txlen = 5 + m->m_len;
760
761             if (m->m_next) {
762                 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
763                 bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len);
764                 txlen += 4 + m->m_next->m_len;
765             }
766
767         } else {
768             /* Use PIO. */
769
770             if (m->m_next) {
771                 iavc_put_byte(sc, SEND_DATA_B3_REQ);
772                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len);
773             } else {
774                 iavc_put_byte(sc, SEND_MESSAGE);
775                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len);
776             }
777 #if 0
778     {
779         u_int8_t *p = mtod(m, u_int8_t*);
780         int len;
781         for (len = 0; len < m->m_len; len++) {
782             printf(" %02x", *p++);
783             if (len && (len % 16) == 0) printf("\n");
784         }
785         if (len % 16) printf("\n");
786     }
787 #endif
788
789             iavc_put_slice(sc, m->m_data, m->m_len);
790
791             if (m->m_next) {
792                 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
793             }
794         }
795
796     } else {
797         /* A board control message to be sent as is */
798
799         if (sc->sc_dma) {
800             bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2);
801             txlen = m->m_len - 2;
802
803         } else {
804 #if 0
805     {
806         u_int8_t *p = mtod(m, u_int8_t*) + 2;
807         int len;
808         printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2);
809         for (len = 0; len < m->m_len-2; len++) {
810             printf(" %02x", *p++);
811             if (len && (len % 16) == 0) printf("\n");
812         }
813         if (len % 16) printf("\n");
814     }
815 #endif
816
817             txlen = m->m_len - 2;
818             dmabuf = mtod(m, char*) + 2;
819             while(txlen--)
820                 b1io_put_byte(sc, *dmabuf++);
821         }
822     }
823
824     if (m->m_next) {
825         i4b_Bfreembuf(m->m_next);
826         m->m_next = NULL;
827     }
828     i4b_Dfreembuf(m);
829
830     if (sc->sc_dma) {
831         /* Start transmitter */
832
833         txlen = (txlen + 3) & ~3;
834         AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0]));
835         AMCC_WRITE(sc, AMCC_TXLEN, txlen);
836         sc->sc_csr |= EN_TX_TC_INT;
837
838         if (!sc->sc_intr)
839             AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
840     }
841 }
842
843 int
844 t1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
845 {
846     int len, i;
847     len = i = b1io_get_word(sc);
848     if (t1io_isfastlink(sc)) {
849         int status;
850         while (i) {
851             status = t1io_fifostatus(sc) & (T1F_IREADY|T1F_IHALF);
852             if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
853
854             switch (status) {
855             case T1F_IREADY|T1F_IHALF|T1F_IFULL:
856                 bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
857                                        T1_READ, dp, FIFO_INPBSIZE);
858                 dp += FIFO_INPBSIZE;
859                 i -= FIFO_INPBSIZE;
860                 break;
861
862             case T1F_IREADY|T1F_IHALF:
863                 bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
864                                        T1_READ, dp, i);
865                 dp += i;
866                 i = 0;
867                 break;
868
869             default:
870                 *dp++ = b1io_get_byte(sc);
871                 i--;
872             }
873         }
874     } else { /* not fastlink */
875         if (i--) *dp++ = b1io_get_byte(sc);
876     }
877     return len;
878 }
879
880 void
881 t1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
882 {
883     int i = len;
884     b1io_put_word(sc, i);
885     if (t1io_isfastlink(sc)) {
886         int status;
887         while (i) {
888             status = t1io_fifostatus(sc) & (T1F_OREADY|T1F_OHALF);
889             if (i >= FIFO_OUTBSIZE) status |= T1F_OFULL;
890
891             switch (status) {
892             case T1F_OREADY|T1F_OHALF|T1F_OFULL:
893                 bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
894                                         T1_WRITE, dp, FIFO_OUTBSIZE);
895                 dp += FIFO_OUTBSIZE;
896                 i -= FIFO_OUTBSIZE;
897                 break;
898
899             case T1F_OREADY|T1F_OHALF:
900                 bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
901                                         T1_WRITE, dp, i);
902                 dp += i;
903                 i = 0;
904                 break;
905
906             default:
907                 b1io_put_byte(sc, *dp++);
908                 i--;
909             }
910         }
911     } else {
912         while (i--) b1io_put_byte(sc, *dp++);
913     }
914 }
915
916 u_int32_t
917 b1io_get_word(iavc_softc_t *sc)
918 {
919     u_int32_t val = 0;
920     val |= b1io_get_byte(sc);
921     val |= (b1io_get_byte(sc) << 8);
922     val |= (b1io_get_byte(sc) << 16);
923     val |= (b1io_get_byte(sc) << 24);
924     return val;
925 }
926
927 void
928 b1io_put_word(iavc_softc_t *sc, u_int32_t val)
929 {
930     b1io_put_byte(sc, (val & 0xff));
931     b1io_put_byte(sc, (val >> 8) & 0xff);
932     b1io_put_byte(sc, (val >> 16) & 0xff);
933     b1io_put_byte(sc, (val >> 24) & 0xff);
934 }
935
936 int
937 b1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
938 {
939     int len, i;
940     len = i = b1io_get_word(sc);
941     while (i--) *dp++ = b1io_get_byte(sc);
942     return len;
943 }
944
945 void
946 b1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
947 {
948     b1io_put_word(sc, len);
949     while (len--) b1io_put_byte(sc, *dp++);
950 }
951
952 u_int32_t
953 b1io_read_reg(iavc_softc_t *sc, int reg)
954 {
955     b1io_put_byte(sc, READ_REGISTER);
956     b1io_put_word(sc, reg);
957     return b1io_get_word(sc);
958 }
959
960 u_int32_t
961 b1io_write_reg(iavc_softc_t *sc, int reg, u_int32_t val)
962 {
963     b1io_put_byte(sc, WRITE_REGISTER);
964     b1io_put_word(sc, reg);
965     b1io_put_word(sc, val);
966     return b1io_get_word(sc);
967 }
968
969 u_int8_t
970 b1io_get_byte(iavc_softc_t *sc)
971 {
972     int spin = 0;
973     while (!b1io_rx_full(sc) && spin < B1IO_WAIT_MAX) {
974         spin++; DELAY(B1IO_WAIT_DLY);
975     }
976     if (b1io_rx_full(sc))
977         return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_READ);
978     printf("iavc%d: rx not completed\n", sc->sc_unit);
979     return 0xff;
980 }
981
982 int
983 b1io_put_byte(iavc_softc_t *sc, u_int8_t val)
984 {
985     int spin = 0;
986     while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
987         spin++; DELAY(B1IO_WAIT_DLY);
988     }
989     if (b1io_tx_empty(sc)) {
990         bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, B1_WRITE, val);
991         return 0;
992     }
993     printf("iavc%d: tx not emptied\n", sc->sc_unit);
994     return -1;
995 }
996
997 int
998 b1io_save_put_byte(iavc_softc_t *sc, u_int8_t val)
999 {
1000     int spin = 0;
1001     while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
1002         spin++; DELAY(B1IO_WAIT_DLY);
1003     }
1004     if (b1io_tx_empty(sc)) {
1005         b1io_outp(sc, B1_WRITE, val);
1006         return 0;
1007     }
1008     printf("iavc%d: tx not emptied\n", sc->sc_unit);
1009     return -1;
1010 }