1 /* ISDN4BSD code */
2 /* $NetBSD: isic_l1.c,v 1.14 2003/10/03 16:38:44 pooka Exp $ */
3 
4 /*
5  * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: isic_l1.c,v 1.13 2002/10/25 21:03:48 leo Exp $");
32 
33 #include <sys/param.h>
34 #include <sys/ioctl.h>
35 #include <sys/kernel.h>
36 #include <sys/systm.h>
37 #include <sys/mbuf.h>
38 
39 #include <machine/bus.h>
40 #include <sys/device.h>
41 
42 #include <sys/socket.h>
43 #include <net/if.h>
44 #include <sys/timeout.h>
45 #include <netisdn/i4b_debug.h>
46 #include <netisdn/i4b_ioctl.h>
47 #include <netisdn/i4b_trace.h>
48 
49 #include <netisdn/i4b_l2.h>
50 #include <netisdn/i4b_l1l2.h>
51 #include <netisdn/i4b_mbuf.h>
52 #include <netisdn/i4b_global.h>
53 
54 #include <dev/ic/isic_l1.h>
55 #include <dev/ic/isac.h>
56 #include <dev/ic/ipac.h>
57 #include <dev/ic/hscx.h>
58 
59 #include "nisac.h"
60 #include "nisacsx.h"
61 
62 unsigned int i4b_l1_debug = L1_DEBUG_DEFAULT;
63 
64 static int isic_std_ph_data_req(isdn_layer1token, struct mbuf *, int);
65 static int isic_std_ph_activate_req(isdn_layer1token);
66 static int isic_std_mph_command_req(isdn_layer1token, int, void*);
67 static void isic_enable_intr(struct isic_softc *sc, int enable);
68 
69 const struct isdn_layer1_isdnif_driver isic_std_driver = {
70 	isic_std_ph_data_req,
71 	isic_std_ph_activate_req,
72 	isic_std_mph_command_req
73 };
74 
75 /* from i4btrc driver i4b_trace.c */
76 extern int get_trace_data_from_l1(int unit, int what, int len, char *buf);
77 
78 /*---------------------------------------------------------------------------*
79  *
80  *	L2 -> L1: PH-DATA-REQUEST
81  *	=========================
82  *
83  *	parms:
84  *		token		softc of physical driver
85  *		m		mbuf containing L2 frame to be sent out
86  *		freeflag	MBUF_FREE: free mbuf here after having sent
87  *						it out
88  *				MBUF_DONTFREE: mbuf is freed by Layer 2
89  *	returns:
90  *		==0	fail, nothing sent out
91  *		!=0	ok, frame sent out
92  *
93  *---------------------------------------------------------------------------*/
94 static int
isic_std_ph_data_req(isdn_layer1token token,struct mbuf * m,int freeflag)95 isic_std_ph_data_req(isdn_layer1token token, struct mbuf *m, int freeflag)
96 {
97 	struct isic_softc *sc = (struct isic_softc*)token;
98 	u_char cmd;
99 	int s;
100 
101 	if (m == NULL)			/* failsafe */
102 		return (0);
103 
104 	s = splnet();
105 
106 	if(sc->sc_I430state == ST_F3)	/* layer 1 not running ? */
107 	{
108 		NDBGL1(L1_I_ERR, "still in state F3!");
109 		isic_std_ph_activate_req(token);
110 	}
111 
112 	if(sc->sc_state & ISAC_TX_ACTIVE)
113 	{
114 		if(sc->sc_obuf2 == NULL)
115 		{
116 			sc->sc_obuf2 = m;		/* save mbuf ptr */
117 
118 			if(freeflag)
119 				sc->sc_freeflag2 = 1;	/* IRQ must mfree */
120 			else
121 				sc->sc_freeflag2 = 0;	/* IRQ must not mfree */
122 
123 			NDBGL1(L1_I_MSG, "using 2nd ISAC TX buffer, state = %s", isic_printstate(sc));
124 
125 			if(sc->sc_trace & TRACE_D_TX)
126 			{
127 				i4b_trace_hdr hdr;
128 				hdr.type = TRC_CH_D;
129 				hdr.dir = FROM_TE;
130 				hdr.count = ++sc->sc_trace_dcount;
131 				isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, m->m_len, m->m_data);
132 			}
133 			splx(s);
134 			return(1);
135 		}
136 
137 		NDBGL1(L1_I_ERR, "No Space in TX FIFO, state = %s", isic_printstate(sc));
138 
139 		if(freeflag == MBUF_FREE)
140 			i4b_Dfreembuf(m);
141 
142 		splx(s);
143 		return (0);
144 	}
145 
146 	if(sc->sc_trace & TRACE_D_TX)
147 	{
148 		i4b_trace_hdr hdr;
149 		hdr.type = TRC_CH_D;
150 		hdr.dir = FROM_TE;
151 		hdr.count = ++sc->sc_trace_dcount;
152 		isdn_layer2_trace_ind(&sc->sc_l2, sc->sc_l3token, &hdr, m->m_len, m->m_data);
153 	}
154 
155 	sc->sc_state |= ISAC_TX_ACTIVE;	/* set transmitter busy flag */
156 
157 	NDBGL1(L1_I_MSG, "ISAC_TX_ACTIVE set");
158 
159 	sc->sc_freeflag = 0;		/* IRQ must NOT mfree */
160 
161 	ISAC_WRFIFO(m->m_data, min(m->m_len, ISAC_FIFO_LEN)); /* output to TX fifo */
162 
163 	if(m->m_len > ISAC_FIFO_LEN)	/* message > 32 bytes ? */
164 	{
165 		sc->sc_obuf = m;	/* save mbuf ptr */
166 		sc->sc_op = m->m_data + ISAC_FIFO_LEN; 	/* ptr for irq hdl */
167 		sc->sc_ol = m->m_len - ISAC_FIFO_LEN;	/* length for irq hdl */
168 
169 		if(freeflag)
170 			sc->sc_freeflag = 1;	/* IRQ must mfree */
171 
172 		cmd = ISAC_CMDR_XTF;
173 	}
174 	else
175 	{
176 		sc->sc_obuf = NULL;
177 		sc->sc_op = NULL;
178 		sc->sc_ol = 0;
179 
180 		if(freeflag)
181 			i4b_Dfreembuf(m);
182 
183 		cmd = ISAC_CMDR_XTF | ISAC_CMDR_XME;
184   	}
185 
186 	ISAC_WRITE(I_CMDR, cmd);
187 	ISACCMDRWRDELAY();
188 
189 	splx(s);
190 
191 	return(1);
192 }
193 
194 /*---------------------------------------------------------------------------*
195  *
196  *	L2 -> L1: PH-ACTIVATE-REQUEST
197  *	=============================
198  *
199  *	parms:
200  *		token		softc of physical interface
201  *
202  *	returns:
203  *		==0
204  *		!=0
205  *
206  *---------------------------------------------------------------------------*/
207 static int
isic_std_ph_activate_req(isdn_layer1token token)208 isic_std_ph_activate_req(isdn_layer1token token)
209 {
210 	struct isic_softc *sc = (struct isic_softc*)token;
211 
212 	NDBGL1(L1_PRIM, " %s ", sc->sc_dev.dv_xname);
213 	isic_next_state(sc, EV_PHAR);
214 	return(0);
215 }
216 
217 /*---------------------------------------------------------------------------*
218  *	command from the upper layers
219  *---------------------------------------------------------------------------*/
220 static int
isic_std_mph_command_req(isdn_layer1token token,int command,void * parm)221 isic_std_mph_command_req(isdn_layer1token token, int command, void *parm)
222 {
223 	struct isic_softc *sc = (struct isic_softc*)token;
224 	int s, pass_down = 0;
225 
226 	s = splnet();
227 	switch(command)
228 	{
229 		case CMR_DOPEN:		/* daemon running */
230 			NDBGL1(L1_PRIM, "%s, command = CMR_DOPEN", sc->sc_dev.dv_xname);
231 			sc->sc_intr_valid = ISIC_INTR_VALID;
232 			pass_down = 1;
233 			break;
234 
235 		case CMR_DCLOSE:	/* daemon not running */
236 			NDBGL1(L1_PRIM, "%s, command = CMR_DCLOSE", sc->sc_dev.dv_xname);
237 			sc->sc_intr_valid = ISIC_INTR_DISABLED;
238 			isic_enable_intr(sc, 0);
239 			pass_down = 1;
240 			break;
241 
242 		case CMR_SETLEDS:
243 			pass_down = 1;
244 			break;
245 
246 		case CMR_SETTRACE:
247 			NDBGL1(L1_PRIM, "%s, command = CMR_SETTRACE, parm = %p", sc->sc_dev.dv_xname, parm);
248 			sc->sc_trace = (int)(unsigned long)parm;
249 			break;
250 
251 		default:
252 			NDBGL1(L1_ERROR, "ERROR, unknown command = %d, %s, parm = %p", command, sc->sc_dev.dv_xname, parm);
253 			break;
254 	}
255 
256 	if (pass_down && sc->drv_command != NULL)
257 		sc->drv_command(sc, command, parm);
258 
259 	if (command == CMR_DOPEN)
260 		isic_enable_intr(sc, 1);
261 
262 	splx(s);
263 
264 	return(0);
265 }
266 
267 static void
isic_enable_intr(struct isic_softc * sc,int enable)268 isic_enable_intr(struct isic_softc *sc, int enable)
269 {
270 #if NNISACSX > 0
271 	if (sc->sc_cardtyp == CARD_TYPEP_AVMA1PCIV2) {
272 		if (enable)
273 			isic_isacsx_init(sc);
274 		else isic_isacsx_disable_intr(sc);
275 		return;
276 	}
277 #endif /* NNISACSX > 0 */
278 
279 #if NNISAC > 0
280 	if (enable) {
281 			isic_isac_init(sc);
282 	} else {
283 		/* disable receiver */
284 		ISAC_WRITE(I_MODE, ISAC_MODE_MDS2|ISAC_MODE_MDS1|ISAC_MODE_DIM0);
285 		/* mask interrupts */
286 		if (sc->sc_ipac) {
287 			IPAC_WRITE(IPAC_MASK, 0xff);
288 		} else {
289 			ISAC_WRITE(I_MASK, 0xff);
290 		}
291 	}
292 #endif /* NNISAC > 0 */
293 }
294