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