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