1 /* $NetBSD: iwic_dchan.c,v 1.5 2007/10/19 12:00:50 ad Exp $ */
4 * Copyright (c) 1999, 2000 Dave Boyce. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 *---------------------------------------------------------------------------
29 * i4b_iwic - isdn4bsd Winbond W6692 driver
30 * ----------------------------------------
34 * last edit-date: [Tue Jan 16 13:20:14 2001]
36 *---------------------------------------------------------------------------*/
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: iwic_dchan.c,v 1.5 2007/10/19 12:00:50 ad Exp $");
41 #include <sys/param.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
45 #include <sys/callout.h>
50 #include <dev/pci/pcivar.h>
52 #include <dev/pci/iwicreg.h>
53 #include <dev/pci/iwicvar.h>
55 #include <netisdn/i4b_global.h>
56 #include <netisdn/i4b_mbuf.h>
58 #define MAX_DFRAME_LEN 264
60 static void dchan_receive(struct iwic_softc
*sc
, int ista
);
62 /*---------------------------------------------------------------------------*
63 * initialize D-channel variables and registers
64 *---------------------------------------------------------------------------*/
66 iwic_dchan_init(struct iwic_softc
*sc
)
68 sc
->sc_dchan
.ibuf
= NULL
;
69 sc
->sc_dchan
.rx_count
= 0;
71 sc
->sc_dchan
.obuf
= NULL
;
72 sc
->sc_dchan
.obuf2
= NULL
;
73 sc
->sc_dchan
.tx_count
= 0;
74 sc
->sc_dchan
.tx_ready
= 0;
76 IWIC_WRITE(sc
, D_CTL
, D_CTL_SRST
);
80 IWIC_WRITE(sc
, D_CTL
, 0);
82 IWIC_WRITE(sc
, SQX
, SQX_SCIE
);
84 IWIC_WRITE(sc
, PCTL
, 0x00);
85 IWIC_WRITE(sc
, MOCR
, 0x00);
86 IWIC_WRITE(sc
, GCR
, 0x00);
88 IWIC_WRITE(sc
, D_CMDR
, D_CMDR_RRST
| D_CMDR_XRST
);
89 IWIC_WRITE(sc
, D_MODE
, D_MODE_RACT
);
91 IWIC_WRITE(sc
, D_SAM
, 0xff);
92 IWIC_WRITE(sc
, D_TAM
, 0xff);
94 IWIC_WRITE(sc
, D_EXIM
, 0x00);
97 /*---------------------------------------------------------------------------*
98 * Extended IRQ handler for the D-channel
99 *---------------------------------------------------------------------------*/
101 iwic_dchan_xirq(struct iwic_softc
*sc
)
106 irq_stat
= IWIC_READ(sc
, D_EXIR
);
108 if (irq_stat
& D_EXIR_RDOV
)
110 NDBGL1(L1_I_ERR
, "RDOV in state %s", iwic_printstate(sc
));
111 IWIC_WRITE(sc
, D_CMDR
, D_CMDR_RRST
);
113 if (irq_stat
& D_EXIR_XDUN
)
115 NDBGL1(L1_I_ERR
, "XDUN in state %s", iwic_printstate(sc
));
116 sc
->sc_dchan
.tx_ready
= 0;
118 if (irq_stat
& D_EXIR_XCOL
)
120 NDBGL1(L1_I_ERR
, "XCOL in state %s", iwic_printstate(sc
));
121 IWIC_WRITE(sc
, D_CMDR
, D_CMDR_XRST
);
122 sc
->sc_dchan
.tx_ready
= 0;
124 if (irq_stat
& D_EXIR_TIN2
)
126 NDBGL1(L1_I_ERR
, "TIN2 in state %s", iwic_printstate(sc
));
128 if (irq_stat
& D_EXIR_MOC
)
130 stat
= IWIC_READ(sc
, MOR
);
131 NDBGL1(L1_I_ERR
, "MOC in state %s, byte = 0x%x", iwic_printstate(sc
), stat
);
134 if (irq_stat
& D_EXIR_ISC
)
136 stat
= (IWIC_READ(sc
, CIR
)) & 0x0f;
141 NDBGL1(L1_I_CICO
, "rx CE in state %s", iwic_printstate(sc
));
142 iwic_next_state(sc
, EV_CE
);
145 NDBGL1(L1_I_CICO
, "rx DRD in state %s", iwic_printstate(sc
));
146 iwic_next_state(sc
, EV_INFO0
);
147 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_IDLE
);
150 NDBGL1(L1_I_CICO
, "rx LD in state %s", iwic_printstate(sc
));
151 iwic_next_state(sc
, EV_RSY
);
154 NDBGL1(L1_I_CICO
, "rx ARD in state %s", iwic_printstate(sc
));
155 iwic_next_state(sc
, EV_INFO2
);
158 NDBGL1(L1_I_CICO
, "rx TI in state %s", iwic_printstate(sc
));
159 iwic_next_state(sc
, EV_INFO0
);
162 NDBGL1(L1_I_CICO
, "rx ATI in state %s", iwic_printstate(sc
));
163 iwic_next_state(sc
, EV_INFO0
);
166 NDBGL1(L1_I_CICO
, "rx AI8 in state %s", iwic_printstate(sc
));
167 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_ACTIVE
);
168 iwic_next_state(sc
, EV_INFO48
);
171 NDBGL1(L1_I_CICO
, "rx AI10 in state %s", iwic_printstate(sc
));
172 isdn_layer2_status_ind(&sc
->sc_l2
, sc
->sc_l3token
, STI_L1STAT
, LAYER_ACTIVE
);
173 iwic_next_state(sc
, EV_INFO410
);
176 NDBGL1(L1_I_CICO
, "rx DIS in state %s", iwic_printstate(sc
));
177 iwic_next_state(sc
, EV_DIS
);
180 NDBGL1(L1_I_ERR
, "ERROR, unknown indication 0x%x in state %s", stat
, iwic_printstate(sc
));
181 iwic_next_state(sc
, EV_INFO0
);
186 if (irq_stat
& D_EXIR_TEXP
)
188 NDBGL1(L1_I_ERR
, "TEXP in state %s", iwic_printstate(sc
));
191 if (irq_stat
& D_EXIR_WEXP
)
193 NDBGL1(L1_I_ERR
, "WEXP in state %s", iwic_printstate(sc
));
197 /*---------------------------------------------------------------------------*
198 * All receiving and transmitting takes place here.
199 *---------------------------------------------------------------------------*/
201 iwic_dchan_xfer_irq(struct iwic_softc
*sc
, int ista
)
203 NDBGL1(L1_I_MSG
, "ISTA = 0x%x", ista
);
205 if (ista
& (ISTA_D_RMR
| ISTA_D_RME
))
207 /* Receive message ready */
208 dchan_receive(sc
, ista
);
210 if (ista
& ISTA_D_XFR
)
212 /* Transmitter ready */
213 sc
->sc_dchan
.tx_ready
= 1;
215 iwic_dchan_transmit(sc
);
219 /*---------------------------------------------------------------------------*
221 *---------------------------------------------------------------------------*/
223 iwic_dchan_disable(struct iwic_softc
*sc
)
229 if (sc
->sc_dchan
.obuf
)
231 if (sc
->sc_dchan
.free_obuf
)
232 i4b_Dfreembuf(sc
->sc_dchan
.obuf
);
233 sc
->sc_dchan
.obuf
= NULL
;
236 if (sc
->sc_dchan
.obuf2
)
238 if (sc
->sc_dchan
.free_obuf2
)
239 i4b_Dfreembuf(sc
->sc_dchan
.obuf2
);
240 sc
->sc_dchan
.obuf2
= NULL
;
245 IWIC_WRITE(sc
, CIX
, CIX_DRC
);
248 /*---------------------------------------------------------------------------*
249 * queue D-channel message for transmission
250 *---------------------------------------------------------------------------*/
252 iwic_dchan_data_req(struct iwic_softc
*sc
, struct mbuf
*m
, int freeflag
)
263 if (sc
->sc_dchan
.obuf
)
265 if (sc
->sc_dchan
.obuf2
)
267 NDBGL1(L1_I_ERR
, "no buffer space!");
271 sc
->sc_dchan
.obuf2
= m
;
272 sc
->sc_dchan
.free_obuf2
= freeflag
;
277 sc
->sc_dchan
.obuf
= m
;
278 sc
->sc_dchan
.obuf_ptr
= m
->m_data
;
279 sc
->sc_dchan
.obuf_len
= m
->m_len
;
280 sc
->sc_dchan
.free_obuf
= freeflag
;
283 iwic_dchan_transmit(sc
);
290 /*---------------------------------------------------------------------------*
292 *---------------------------------------------------------------------------*/
294 dchan_get_mbuf(struct iwic_softc
*sc
, int len
)
296 sc
->sc_dchan
.ibuf
= i4b_Dgetmbuf(len
);
298 if (!sc
->sc_dchan
.ibuf
)
299 panic("dchan_get_mbuf: unable to allocate %d bytes for mbuf!", len
);
301 sc
->sc_dchan
.ibuf_ptr
= sc
->sc_dchan
.ibuf
->m_data
;
302 sc
->sc_dchan
.ibuf_max_len
= sc
->sc_dchan
.ibuf
->m_len
;
303 sc
->sc_dchan
.ibuf_len
= 0;
306 /*---------------------------------------------------------------------------*
307 * D-channel receive data interrupt
308 *---------------------------------------------------------------------------*/
310 dchan_receive(struct iwic_softc
*sc
, int ista
)
312 int command
= D_CMDR_RACK
;
314 if (ista
& ISTA_D_RMR
)
316 /* Got 64 bytes in FIFO */
318 if (!sc
->sc_dchan
.ibuf
)
320 dchan_get_mbuf(sc
, MAX_DFRAME_LEN
);
323 else if ((sc
->sc_dchan
.ibuf_len
+ MAX_DFRAME_LEN
) >
324 sc
->sc_dchan
.ibuf_max_len
)
326 panic("dchan_receive: not enough space in buffer!");
329 IWIC_RDDFIFO(sc
, sc
->sc_dchan
.ibuf_ptr
, 64);
331 sc
->sc_dchan
.ibuf_ptr
+= 64;
332 sc
->sc_dchan
.ibuf_len
+= 64;
333 sc
->sc_dchan
.rx_count
+= 64;
335 if (ista
& ISTA_D_RME
)
337 /* Got end of frame */
340 status
= IWIC_READ(sc
, D_RSTA
);
342 if (status
& (D_RSTA_RDOV
| D_RSTA_CRCE
| D_RSTA_RMB
))
344 if (status
& D_RSTA_RDOV
)
345 NDBGL1(L1_I_ERR
, "%s: D-channel Receive Data Overflow", device_xname(&sc
->sc_dev
));
346 if (status
& D_RSTA_CRCE
)
347 NDBGL1(L1_I_ERR
, "%s: D-channel CRC Error", device_xname(&sc
->sc_dev
));
348 if (status
& D_RSTA_RMB
)
349 NDBGL1(L1_I_ERR
, "%s: D-channel Receive Message Aborted", device_xname(&sc
->sc_dev
));
350 command
|= D_CMDR_RRST
;
357 lo
= IWIC_READ(sc
, D_RBCL
);
358 hi
= IWIC_READ(sc
, D_RBCH
);
359 total_frame_len
= D_RBC(hi
, lo
);
363 lo
= IWIC_DCHAN_FIFO_LEN
;
365 if (!sc
->sc_dchan
.ibuf
)
367 dchan_get_mbuf(sc
, lo
);
369 else if ((sc
->sc_dchan
.ibuf_len
+ lo
) >
370 sc
->sc_dchan
.ibuf_max_len
)
372 panic("dchan_receive: buffer not long enough");
375 IWIC_RDDFIFO(sc
, sc
->sc_dchan
.ibuf_ptr
, lo
);
376 sc
->sc_dchan
.ibuf_len
+= lo
;
377 sc
->sc_dchan
.rx_count
+= lo
;
379 sc
->sc_dchan
.ibuf
->m_len
= sc
->sc_dchan
.ibuf_len
;
381 if(sc
->sc_trace
& TRACE_D_RX
)
386 hdr
.count
= ++sc
->sc_dchan
.trace_count
;
387 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, sc
->sc_dchan
.ibuf
->m_len
, sc
->sc_dchan
.ibuf
->m_data
);
389 isdn_layer2_data_ind(&sc
->sc_l2
,sc
->sc_l3token
,sc
->sc_dchan
.ibuf
);
391 sc
->sc_dchan
.ibuf
= NULL
;
394 IWIC_WRITE(sc
, D_CMDR
, command
);
397 /*---------------------------------------------------------------------------*
398 * transmit D-channel frame
399 *---------------------------------------------------------------------------*/
401 iwic_dchan_transmit(struct iwic_softc
*sc
)
407 if (!sc
->sc_dchan
.tx_ready
)
410 if (!sc
->sc_dchan
.obuf
)
413 if (sc
->sc_I430state
!= ST_F7
)
416 ptr
= sc
->sc_dchan
.obuf_ptr
;
417 len
= min(sc
->sc_dchan
.obuf_len
, IWIC_DCHAN_FIFO_LEN
);
419 if(sc
->sc_trace
& TRACE_D_TX
)
424 hdr
.count
= ++sc
->sc_dchan
.trace_count
;
425 isdn_layer2_trace_ind(&sc
->sc_l2
, sc
->sc_l3token
, &hdr
, len
, ptr
);
428 IWIC_WRDFIFO(sc
, ptr
, len
);
430 sc
->sc_dchan
.tx_count
+= len
;
432 if (len
< sc
->sc_dchan
.obuf_len
)
434 sc
->sc_dchan
.obuf_ptr
+= len
;
435 sc
->sc_dchan
.obuf_len
-= len
;
442 if (sc
->sc_dchan
.free_obuf
)
443 i4b_Dfreembuf(sc
->sc_dchan
.obuf
);
445 sc
->sc_dchan
.obuf
= NULL
;
446 sc
->sc_dchan
.obuf_ptr
= NULL
;
447 sc
->sc_dchan
.obuf_len
= 0;
449 if (sc
->sc_dchan
.obuf2
)
451 sc
->sc_dchan
.obuf
= sc
->sc_dchan
.obuf2
;
452 sc
->sc_dchan
.obuf_ptr
= sc
->sc_dchan
.obuf
->m_data
;
453 sc
->sc_dchan
.obuf_len
= sc
->sc_dchan
.obuf
->m_len
;
454 sc
->sc_dchan
.free_obuf
= sc
->sc_dchan
.free_obuf2
;
456 sc
->sc_dchan
.obuf2
= NULL
;
458 cmd
= D_CMDR_XMS
| D_CMDR_XME
;
460 sc
->sc_dchan
.tx_ready
= 0;
461 IWIC_WRITE(sc
, D_CMDR
, cmd
);