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