76ad08dd9252239590d6ce55f67700f72758cb00
[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.7 2005/06/03 16:49:55 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 <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 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 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         printf("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 iavc_release(capi_softc_t *capi_sc, int applid)
214 {
215     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
216     struct mbuf *m = i4b_Dgetmbuf(7);
217     u_int8_t *p;
218
219     if (!m) {
220         printf("iavc%d: can't get memory\n", sc->sc_unit);
221         return (ENOMEM);
222     }
223
224     /*
225      * byte  0x14 = SEND_RELEASE
226      * dword ApplId
227      */
228
229     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
230     p = amcc_put_byte(p, 0);
231     p = amcc_put_byte(p, SEND_RELEASE);
232     p = amcc_put_word(p, applid);
233
234     IF_ENQUEUE(&sc->sc_txq, m);
235
236     iavc_start_tx(sc);
237     return 0;
238 }
239
240 int iavc_send(capi_softc_t *capi_sc, struct mbuf *m)
241 {
242     iavc_softc_t *sc = (iavc_softc_t*) capi_sc->ctx;
243
244     if (sc->sc_state != IAVC_UP) {
245         printf("iavc%d: attempt to send before device up\n", sc->sc_unit);
246
247         if (m->m_next) i4b_Bfreembuf(m->m_next);
248         i4b_Dfreembuf(m);
249
250         return (ENXIO);
251     }
252
253     if (IF_QFULL(&sc->sc_txq)) {
254         IF_DROP(&sc->sc_txq);
255
256         printf("iavc%d: tx overflow, message dropped\n", sc->sc_unit);
257
258         if (m->m_next) i4b_Bfreembuf(m->m_next);
259         i4b_Dfreembuf(m);
260
261     } else {
262         IF_ENQUEUE(&sc->sc_txq, m);
263
264         iavc_start_tx(sc);
265     }
266     
267     return 0;
268 }
269
270 /*
271 //  Functions called by ourself during the initialization sequence:
272 //  ---------------------------------------------------------------
273 //
274 //  iavc_send_init
275 //      Sends the system initialization message to a newly loaded
276 //      board, and sets state to INIT.
277 */
278
279 static int iavc_send_init(iavc_softc_t *sc)
280 {
281     struct mbuf *m = i4b_Dgetmbuf(15);
282     u_int8_t *p;
283
284     if (!m) {
285         printf("iavc%d: can't get memory\n", sc->sc_unit);
286         return (ENOMEM);
287     }
288
289     /*
290      * byte  0x11 = SEND_INIT
291      * dword NumApplications
292      * dword NumNCCIs
293      * dword BoardNumber
294      */
295
296     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
297     p = amcc_put_byte(p, 0);
298     p = amcc_put_byte(p, SEND_INIT);
299     p = amcc_put_word(p, 1); /* XXX MaxAppl XXX */
300     p = amcc_put_word(p, sc->sc_capi.sc_nbch);
301     p = amcc_put_word(p, sc->sc_unit);
302
303     crit_enter();
304     IF_ENQUEUE(&sc->sc_txq, m);
305
306     iavc_start_tx(sc);
307
308     sc->sc_state = IAVC_INIT;
309     crit_exit();
310     return 0;
311 }
312
313 /*
314 //  Functions called during normal operation:
315 //  -----------------------------------------
316 //
317 //  iavc_receive_init
318 //      Reads the initialization reply and calls capi_ll_control().
319 //
320 //  iavc_receive_new_ncci
321 //      Reads a new NCCI notification and calls capi_ll_control().
322 //
323 //  iavc_receive_free_ncci
324 //      Reads a freed NCCI notification and calls capi_ll_control().
325 //
326 //  iavc_receive_task_ready
327 //      Reads a task ready message -- which should not occur XXX.
328 //
329 //  iavc_receive_debugmsg
330 //      Reads a debug message -- which should not occur XXX.
331 //
332 //  iavc_receive_start
333 //      Reads a START TRANSMIT message and unblocks device.
334 //
335 //  iavc_receive_stop
336 //      Reads a STOP TRANSMIT message and blocks device.
337 //
338 //  iavc_receive
339 //      Reads an incoming message and calls capi_ll_receive().
340 */
341
342 static int iavc_receive_init(iavc_softc_t *sc, u_int8_t *dmabuf)
343 {
344     u_int32_t Length;
345     u_int8_t *p;
346     u_int8_t *cardtype, *serial, *profile, *version, *caps, *prot;
347
348     if (sc->sc_dma) {
349         p = amcc_get_word(dmabuf, &Length);
350     } else {
351         Length = iavc_get_slice(sc, sc->sc_recvbuf);
352         p = sc->sc_recvbuf;
353     }
354
355 #if 0
356     {
357         int len = 0;
358         printf("iavc%d: rx_init: ", sc->sc_unit);
359             while (len < Length) {
360                 printf(" %02x", p[len]);
361                 if (len && (len % 16) == 0) printf("\n");
362                 len++;
363             }
364             if (len % 16) printf("\n");
365     }
366 #endif
367
368     version = (p + 1);
369     p += (*p + 1); /* driver version */
370     cardtype = (p + 1);
371     p += (*p + 1); /* card type */
372     p += (*p + 1); /* hardware ID */
373     serial = (p + 1);
374     p += (*p + 1); /* serial number */
375     caps = (p + 1);
376     p += (*p + 1); /* supported options */
377     prot = (p + 1);
378     p += (*p + 1); /* supported protocols */
379     profile = (p + 1);
380
381     if (cardtype && serial && profile) {
382         int nbch = ((profile[3]<<8) | profile[2]);
383
384         printf("iavc%d: AVM %s, s/n %s, %d chans, f/w rev %s, prot %s\n",
385                 sc->sc_unit, cardtype, serial, nbch, version, prot);
386
387         if(bootverbose)
388                 printf("iavc%d: %s\n", sc->sc_unit, caps);
389
390         capi_ll_control(&sc->sc_capi, CAPI_CTRL_PROFILE, (int) profile);
391
392     } else {
393         printf("iavc%d: no profile data in info response?\n", sc->sc_unit);
394     }
395
396     sc->sc_blocked = TRUE; /* controller will send START when ready */
397     return 0;
398 }
399
400 static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf)
401 {
402     struct mbuf *m = i4b_Dgetmbuf(3);
403     u_int8_t *p;
404
405     if (sc->sc_blocked && sc->sc_state == IAVC_UP)
406         printf("iavc%d: receive_start\n", sc->sc_unit);
407
408     if (!m) {
409         printf("iavc%d: can't get memory\n", sc->sc_unit);
410         return (ENOMEM);
411     }
412
413     /*
414      * byte  0x73 = SEND_POLLACK
415      */
416
417     p = amcc_put_byte(mtod(m, u_int8_t*), 0);
418     p = amcc_put_byte(p, 0);
419     p = amcc_put_byte(p, SEND_POLLACK);
420     
421     IF_PREPEND(&sc->sc_txq, m);
422
423     NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d",
424                 sc->sc_unit, sc->sc_blocked, sc->sc_state);
425
426     sc->sc_blocked = FALSE;
427     iavc_start_tx(sc);
428     
429     /* If this was our first START, register our readiness */
430
431     if (sc->sc_state != IAVC_UP) {
432         sc->sc_state = IAVC_UP;
433         capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE);
434     }
435
436     return 0;
437 }
438
439 static int iavc_receive_stop(iavc_softc_t *sc, u_int8_t *dmabuf)
440 {
441     printf("iavc%d: receive_stop\n", sc->sc_unit);
442     sc->sc_blocked = TRUE;
443     return 0;
444 }
445
446 static int iavc_receive_new_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
447 {
448     u_int32_t ApplId, NCCI, WindowSize;
449
450     if (sc->sc_dma) {
451         dmabuf = amcc_get_word(dmabuf, &ApplId);
452         dmabuf = amcc_get_word(dmabuf, &NCCI);
453         dmabuf = amcc_get_word(dmabuf, &WindowSize);
454     } else {
455         ApplId = iavc_get_word(sc);
456         NCCI   = iavc_get_word(sc);
457         WindowSize = iavc_get_word(sc);
458     }
459
460     capi_ll_control(&sc->sc_capi, CAPI_CTRL_NEW_NCCI, NCCI);
461     return 0;
462 }
463
464 static int iavc_receive_free_ncci(iavc_softc_t *sc, u_int8_t *dmabuf)
465 {
466     u_int32_t ApplId, NCCI;
467
468     if (sc->sc_dma) {
469         dmabuf = amcc_get_word(dmabuf, &ApplId);
470         dmabuf = amcc_get_word(dmabuf, &NCCI);
471     } else {
472         ApplId = iavc_get_word(sc);
473         NCCI   = iavc_get_word(sc);
474     }
475
476     capi_ll_control(&sc->sc_capi, CAPI_CTRL_FREE_NCCI, NCCI);
477     return 0;
478 }
479
480 static int iavc_receive_task_ready(iavc_softc_t *sc, u_int8_t *dmabuf)
481 {
482     u_int32_t TaskId, Length;
483     u_int8_t *p;
484     printf("iavc%d: receive_task_ready\n", sc->sc_unit);
485     
486     if (sc->sc_dma) {
487         p = amcc_get_word(dmabuf, &TaskId);
488         p = amcc_get_word(p, &Length);
489     } else {
490         TaskId = iavc_get_word(sc);
491         Length = iavc_get_slice(sc, sc->sc_recvbuf);
492         p = sc->sc_recvbuf;
493     }
494
495     /* XXX could show the message if trace enabled? XXX */
496     return 0;
497 }
498
499 static int iavc_receive_debugmsg(iavc_softc_t *sc, u_int8_t *dmabuf)
500 {
501     u_int32_t Length;
502     u_int8_t *p;
503     printf("iavc%d: receive_debugmsg\n", sc->sc_unit);
504     
505     if (sc->sc_dma) {
506         p = amcc_get_word(dmabuf, &Length);
507     } else {
508         Length = iavc_get_slice(sc, sc->sc_recvbuf);
509         p = sc->sc_recvbuf;
510     }
511
512     /* XXX could show the message if trace enabled? XXX */
513     return 0;
514 }
515
516 static int iavc_receive(iavc_softc_t *sc, u_int8_t *dmabuf, int b3data)
517 {
518     struct mbuf *m;
519     u_int32_t ApplId, Length;
520
521     /*
522      * byte  0x21 = RECEIVE_MESSAGE
523      * dword ApplId
524      * dword length
525      * ...   CAPI msg
526      *
527      * --or--
528      *
529      * byte  0x22 = RECEIVE_DATA_B3_IND
530      * dword ApplId
531      * dword length
532      * ...   CAPI msg
533      * dword datalen
534      * ...   B3 data
535      */
536
537     if (sc->sc_dma) {
538         dmabuf = amcc_get_word(dmabuf, &ApplId);
539         dmabuf = amcc_get_word(dmabuf, &Length);
540     } else {
541         ApplId = iavc_get_word(sc);
542         Length = iavc_get_slice(sc, sc->sc_recvbuf);
543         dmabuf = sc->sc_recvbuf;
544     }
545
546     m = i4b_Dgetmbuf(Length);
547     if (!m) {
548         printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
549         return (ENOMEM);
550     }
551
552     bcopy(dmabuf, mtod(m, u_int8_t*), Length);
553
554 #if 0
555         {
556             u_int8_t *p = mtod(m, u_int8_t*);
557             int len = 0;
558             printf("iavc%d: applid=%d, len=%d\n", sc->sc_unit, ApplId, Length);
559             while (len < m->m_len) {
560                 printf(" %02x", p[len]);
561                 if (len && (len % 16) == 0) printf("\n");
562                 len++;
563             }
564             if (len % 16) printf("\n");
565         }
566 #endif
567
568     if (b3data) {
569         if (sc->sc_dma) {
570             dmabuf = amcc_get_word(dmabuf + Length, &Length);
571         } else {
572             Length = iavc_get_slice(sc, sc->sc_recvbuf);
573             dmabuf = sc->sc_recvbuf;
574         }
575
576         m->m_next = i4b_Bgetmbuf(Length);
577         if (!m->m_next) {
578             printf("iavc%d: can't get memory for receive\n", sc->sc_unit);
579             i4b_Dfreembuf(m);
580             return (ENOMEM);
581         }
582
583         bcopy(dmabuf, mtod(m->m_next, u_int8_t*), Length);
584     }
585
586     capi_ll_receive(&sc->sc_capi, m);
587     return 0;
588 }
589
590 /*
591 //  iavc_handle_intr
592 //      Checks device interrupt status and calls iavc_handle_{rx,tx}()
593 //      as necessary.
594 //
595 //  iavc_handle_rx
596 //      Reads in the command byte and calls the subroutines above.
597 //
598 //  iavc_start_tx
599 //      Initiates DMA on the next queued message if possible.
600 */
601
602 void iavc_handle_intr(iavc_softc_t *sc)
603 {
604     u_int32_t status;
605     u_int32_t newcsr;
606
607     if (!sc->sc_dma) {
608         while (iavc_rx_full(sc))
609             iavc_handle_rx(sc);
610         return;
611     }
612
613     status = AMCC_READ(sc, AMCC_INTCSR);
614     if ((status & ANY_S5933_INT) == 0)
615         return;
616
617     newcsr = sc->sc_csr | (status & ALL_INT);
618     if (status & TX_TC_INT) newcsr &= ~EN_TX_TC_INT;
619     if (status & RX_TC_INT) newcsr &= ~EN_RX_TC_INT;
620     AMCC_WRITE(sc, AMCC_INTCSR, newcsr);
621     sc->sc_intr = TRUE;
622
623     if (status & RX_TC_INT) {
624         u_int32_t rxlen;
625
626         if (sc->sc_recvlen == 0) {
627             sc->sc_recvlen = *((u_int32_t*)(&sc->sc_recvbuf[0]));
628             rxlen = (sc->sc_recvlen + 3) & ~3;
629             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[4]));
630             AMCC_WRITE(sc, AMCC_RXLEN, rxlen);
631         } else {
632             iavc_handle_rx(sc);
633             sc->sc_recvlen = 0;
634             AMCC_WRITE(sc, AMCC_RXPTR, vtophys(&sc->sc_recvbuf[0]));
635             AMCC_WRITE(sc, AMCC_RXLEN, 4);
636         }
637     }
638
639     if (status & TX_TC_INT) {
640         sc->sc_csr &= ~EN_TX_TC_INT;
641         iavc_start_tx(sc);
642     }
643
644     AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
645     sc->sc_intr = FALSE;
646 }
647
648 static void iavc_handle_rx(iavc_softc_t *sc)
649 {
650     u_int8_t *dmabuf = 0, cmd;
651
652     if (sc->sc_dma) {
653         dmabuf = amcc_get_byte(&sc->sc_recvbuf[4], &cmd);
654     } else {
655         cmd = iavc_get_byte(sc);
656     }
657
658     NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd);
659     
660     switch (cmd) {
661     case RECEIVE_DATA_B3_IND:
662         iavc_receive(sc, dmabuf, TRUE);
663         break;
664
665     case RECEIVE_MESSAGE:
666         iavc_receive(sc, dmabuf, FALSE);
667         break;
668
669     case RECEIVE_NEW_NCCI:
670         iavc_receive_new_ncci(sc, dmabuf);
671         break;
672
673     case RECEIVE_FREE_NCCI:
674         iavc_receive_free_ncci(sc, dmabuf);
675         break;
676
677     case RECEIVE_START:
678         iavc_receive_start(sc, dmabuf);
679         break;
680
681     case RECEIVE_STOP:
682         iavc_receive_stop(sc, dmabuf);
683         break;
684
685     case RECEIVE_INIT:
686         iavc_receive_init(sc, dmabuf);
687         break;
688
689     case RECEIVE_TASK_READY:
690         iavc_receive_task_ready(sc, dmabuf);
691         break;
692
693     case RECEIVE_DEBUGMSG:
694         iavc_receive_debugmsg(sc, dmabuf);
695         break;
696
697     default:
698         printf("iavc%d: unknown msg %02x\n", sc->sc_unit, cmd);
699     }
700 }
701
702 static void iavc_start_tx(iavc_softc_t *sc)
703 {
704     struct mbuf *m;
705     u_int8_t *dmabuf;
706     u_int32_t txlen = 0;
707     
708     /* If device has put us on hold, punt. */
709
710     if (sc->sc_blocked) {
711         return;
712     }
713
714     /* If using DMA and transmitter busy, punt. */
715     
716     if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) {
717         return;
718     }
719
720     /* Else, see if we have messages to send. */
721
722     IF_DEQUEUE(&sc->sc_txq, m);
723     if (!m) {
724         return;
725     }
726
727     /* Have message, will send. */
728
729     if (CAPIMSG_LEN(m->m_data)) {
730         /* A proper CAPI message, possibly with B3 data */
731
732         if (sc->sc_dma) {
733             /* Copy message to DMA buffer. */
734
735             if (m->m_next) {
736                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ);
737             } else {
738                 dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE);
739             }
740
741             dmabuf = amcc_put_word(dmabuf, m->m_len);
742             bcopy(m->m_data, dmabuf, m->m_len);
743             dmabuf += m->m_len;
744             txlen = 5 + m->m_len;
745
746             if (m->m_next) {
747                 dmabuf = amcc_put_word(dmabuf, m->m_next->m_len);
748                 bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len);
749                 txlen += 4 + m->m_next->m_len;
750             }
751
752         } else {
753             /* Use PIO. */
754
755             if (m->m_next) {
756                 iavc_put_byte(sc, SEND_DATA_B3_REQ);
757                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len);
758             } else {
759                 iavc_put_byte(sc, SEND_MESSAGE);
760                 NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len);
761             }
762 #if 0
763     {
764         u_int8_t *p = mtod(m, u_int8_t*);
765         int len;
766         for (len = 0; len < m->m_len; len++) {
767             printf(" %02x", *p++);
768             if (len && (len % 16) == 0) printf("\n");
769         }
770         if (len % 16) printf("\n");
771     }
772 #endif
773
774             iavc_put_slice(sc, m->m_data, m->m_len);
775
776             if (m->m_next) {
777                 iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len);
778             }
779         }
780
781     } else {
782         /* A board control message to be sent as is */
783
784         if (sc->sc_dma) {
785             bcopy(m->m_data + 2, &sc->sc_sendbuf[0], m->m_len - 2);
786             txlen = m->m_len - 2;
787
788         } else {
789 #if 0
790     {
791         u_int8_t *p = mtod(m, u_int8_t*) + 2;
792         int len;
793         printf("iavc%d: tx BDC msg, len = %d, msg =", sc->sc_unit, m->m_len-2);
794         for (len = 0; len < m->m_len-2; len++) {
795             printf(" %02x", *p++);
796             if (len && (len % 16) == 0) printf("\n");
797         }
798         if (len % 16) printf("\n");
799     }
800 #endif
801
802             txlen = m->m_len - 2;
803             dmabuf = mtod(m, char*) + 2;
804             while(txlen--)
805                 b1io_put_byte(sc, *dmabuf++);
806         }
807     }
808
809     if (m->m_next) {
810         i4b_Bfreembuf(m->m_next);
811         m->m_next = NULL;
812     }
813     i4b_Dfreembuf(m);
814
815     if (sc->sc_dma) {
816         /* Start transmitter */
817
818         txlen = (txlen + 3) & ~3;
819         AMCC_WRITE(sc, AMCC_TXPTR, vtophys(&sc->sc_sendbuf[0]));
820         AMCC_WRITE(sc, AMCC_TXLEN, txlen);
821         sc->sc_csr |= EN_TX_TC_INT;
822
823         if (!sc->sc_intr)
824             AMCC_WRITE(sc, AMCC_INTCSR, sc->sc_csr);
825     }
826 }
827
828 int t1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
829 {
830     int len, i;
831     len = i = b1io_get_word(sc);
832     if (t1io_isfastlink(sc)) {
833         int status;
834         while (i) {
835             status = t1io_fifostatus(sc) & (T1F_IREADY|T1F_IHALF);
836             if (i >= FIFO_INPBSIZE) status |= T1F_IFULL;
837
838             switch (status) {
839             case T1F_IREADY|T1F_IHALF|T1F_IFULL:
840                 bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
841                                        T1_READ, dp, FIFO_INPBSIZE);
842                 dp += FIFO_INPBSIZE;
843                 i -= FIFO_INPBSIZE;
844                 break;
845
846             case T1F_IREADY|T1F_IHALF:
847                 bus_space_read_multi_1(sc->sc_io_bt, sc->sc_io_bh,
848                                        T1_READ, dp, i);
849                 dp += i;
850                 i = 0;
851                 break;
852
853             default:
854                 *dp++ = b1io_get_byte(sc);
855                 i--;
856             }
857         }
858     } else { /* not fastlink */
859         if (i--) *dp++ = b1io_get_byte(sc);
860     }
861     return len;
862 }
863
864 void t1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
865 {
866     int i = len;
867     b1io_put_word(sc, i);
868     if (t1io_isfastlink(sc)) {
869         int status;
870         while (i) {
871             status = t1io_fifostatus(sc) & (T1F_OREADY|T1F_OHALF);
872             if (i >= FIFO_OUTBSIZE) status |= T1F_OFULL;
873
874             switch (status) {
875             case T1F_OREADY|T1F_OHALF|T1F_OFULL:
876                 bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
877                                         T1_WRITE, dp, FIFO_OUTBSIZE);
878                 dp += FIFO_OUTBSIZE;
879                 i -= FIFO_OUTBSIZE;
880                 break;
881
882             case T1F_OREADY|T1F_OHALF:
883                 bus_space_write_multi_1(sc->sc_io_bt, sc->sc_io_bh,
884                                         T1_WRITE, dp, i);
885                 dp += i;
886                 i = 0;
887                 break;
888
889             default:
890                 b1io_put_byte(sc, *dp++);
891                 i--;
892             }
893         }
894     } else {
895         while (i--) b1io_put_byte(sc, *dp++);
896     }
897 }
898
899 u_int32_t b1io_get_word(iavc_softc_t *sc)
900 {
901     u_int32_t val = 0;
902     val |= b1io_get_byte(sc);
903     val |= (b1io_get_byte(sc) << 8);
904     val |= (b1io_get_byte(sc) << 16);
905     val |= (b1io_get_byte(sc) << 24);
906     return val;
907 }
908
909 void b1io_put_word(iavc_softc_t *sc, u_int32_t val)
910 {
911     b1io_put_byte(sc, (val & 0xff));
912     b1io_put_byte(sc, (val >> 8) & 0xff);
913     b1io_put_byte(sc, (val >> 16) & 0xff);
914     b1io_put_byte(sc, (val >> 24) & 0xff);
915 }
916
917 int b1io_get_slice(iavc_softc_t *sc, u_int8_t *dp)
918 {
919     int len, i;
920     len = i = b1io_get_word(sc);
921     while (i--) *dp++ = b1io_get_byte(sc);
922     return len;
923 }
924
925 void b1io_put_slice(iavc_softc_t *sc, u_int8_t *dp, int len)
926 {
927     b1io_put_word(sc, len);
928     while (len--) b1io_put_byte(sc, *dp++);
929 }
930
931 u_int32_t b1io_read_reg(iavc_softc_t *sc, int reg)
932 {
933     b1io_put_byte(sc, READ_REGISTER);
934     b1io_put_word(sc, reg);
935     return b1io_get_word(sc);
936 }
937
938 u_int32_t b1io_write_reg(iavc_softc_t *sc, int reg, u_int32_t val)
939 {
940     b1io_put_byte(sc, WRITE_REGISTER);
941     b1io_put_word(sc, reg);
942     b1io_put_word(sc, val);
943     return b1io_get_word(sc);
944 }
945
946 u_int8_t b1io_get_byte(iavc_softc_t *sc)
947 {
948     int spin = 0;
949     while (!b1io_rx_full(sc) && spin < B1IO_WAIT_MAX) {
950         spin++; DELAY(B1IO_WAIT_DLY);
951     }
952     if (b1io_rx_full(sc))
953         return bus_space_read_1(sc->sc_io_bt, sc->sc_io_bh, B1_READ);
954     printf("iavc%d: rx not completed\n", sc->sc_unit);
955     return 0xff;
956 }
957
958 int b1io_put_byte(iavc_softc_t *sc, u_int8_t val)
959 {
960     int spin = 0;
961     while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
962         spin++; DELAY(B1IO_WAIT_DLY);
963     }
964     if (b1io_tx_empty(sc)) {
965         bus_space_write_1(sc->sc_io_bt, sc->sc_io_bh, B1_WRITE, val);
966         return 0;
967     }
968     printf("iavc%d: tx not emptied\n", sc->sc_unit);
969     return -1;
970 }
971
972 int b1io_save_put_byte(iavc_softc_t *sc, u_int8_t val)
973 {
974     int spin = 0;
975     while (!b1io_tx_empty(sc) && spin < B1IO_WAIT_MAX) {
976         spin++; DELAY(B1IO_WAIT_DLY);
977     }
978     if (b1io_tx_empty(sc)) {
979         b1io_outp(sc, B1_WRITE, val);
980         return 0;
981     }
982     printf("iavc%d: tx not emptied\n", sc->sc_unit);
983     return -1;
984 }