1 /* ISDN4BSD code */
2 /*
3  * Copyright (c) 1997, 2000 Hellmuth Michaelis. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *---------------------------------------------------------------------------
27  *
28  *	i4b_isic.c - global isic stuff
29  *	==============================
30  *
31  *	$Id: isic.c,v 1.3 2003/10/03 17:24:11 tg Stab $
32  *
33  *      last edit-date: [Fri Jan  5 11:36:10 2001]
34  *
35  *---------------------------------------------------------------------------*/
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: isic.c,v 1.19 2003/01/06 13:05:10 wiz Exp $");
39 
40 #include <sys/param.h>
41 #include <sys/ioccom.h>
42 #include <sys/kernel.h>
43 #include <sys/systm.h>
44 #include <sys/mbuf.h>
45 #include <sys/socket.h>
46 #include <net/if.h>
47 #include <sys/timeout.h>
48 #include <sys/device.h>
49 #include <machine/bus.h>
50 
51 #include <netisdn/i4b_debug.h>
52 #include <netisdn/i4b_ioctl.h>
53 #include <netisdn/i4b_trace.h>
54 
55 #include <netisdn/i4b_l2.h>
56 #include <netisdn/i4b_l1l2.h>
57 #include <netisdn/i4b_mbuf.h>
58 #include <netisdn/i4b_global.h>
59 
60 #include <dev/ic/isic_l1.h>
61 #include <dev/ic/ipac.h>
62 #include <dev/ic/isac.h>
63 #include <dev/ic/hscx.h>
64 
65 isdn_link_t *isic_ret_linktab(void*, int channel);
66 void isic_set_link(void*, int channel, const struct isdn_l4_driver_functions *l4_driver, void *l4_driver_softc);
67 void n_connect_request(struct call_desc *cd);
68 void n_connect_response(struct call_desc *cd, int response, int cause);
69 void n_disconnect_request(struct call_desc *cd, int cause);
70 void n_alert_request(struct call_desc *cd);
71 void n_mgmt_command(struct isdn_l3_driver *drv, int cmd, void *parm);
72 
73 const struct isdn_l3_driver_functions
74 isic_l3_driver = {
75 	isic_ret_linktab,
76 	isic_set_link,
77 	n_connect_request,
78 	n_connect_response,
79 	n_disconnect_request,
80 	n_alert_request,
81 	NULL,
82 	NULL,
83 	n_mgmt_command
84 };
85 
86 /*---------------------------------------------------------------------------*
87  *	isic - device driver interrupt routine
88  *---------------------------------------------------------------------------*/
89 int
isicintr(void * arg)90 isicintr(void *arg)
91 {
92 	struct isic_softc *sc = arg;
93 
94 	/* could this be an interrupt for us? */
95 	if (sc->sc_intr_valid == ISIC_INTR_DYING)
96 		return 0;	/* do not touch removed hardware */
97 
98 	if(sc->sc_ipac == 0)	/* HSCX/ISAC interrupt routine */
99 	{
100 		u_char was_hscx_irq = 0;
101 		u_char was_isac_irq = 0;
102 
103 		register u_char hscx_irq_stat;
104 		register u_char isac_irq_stat;
105 
106 		for(;;)
107 		{
108 			/* get hscx irq status from hscx b ista */
109 			hscx_irq_stat =
110 	 	    	    HSCX_READ(HSCX_CH_B, H_ISTA) & ~HSCX_B_IMASK;
111 
112 			/* get isac irq status */
113 			isac_irq_stat = ISAC_READ(I_ISTA);
114 
115 			/* do as long as there are pending irqs in the chips */
116 			if(!hscx_irq_stat && !isac_irq_stat)
117 				break;
118 
119 			if(hscx_irq_stat & (HSCX_ISTA_RME | HSCX_ISTA_RPF |
120 					    HSCX_ISTA_RSC | HSCX_ISTA_XPR |
121 					    HSCX_ISTA_TIN | HSCX_ISTA_EXB))
122 			{
123 				isic_hscx_irq(sc, hscx_irq_stat,
124 						HSCX_CH_B,
125 						hscx_irq_stat & HSCX_ISTA_EXB);
126 				was_hscx_irq = 1;
127 			}
128 
129 			if(hscx_irq_stat & (HSCX_ISTA_ICA | HSCX_ISTA_EXA))
130 			{
131 				isic_hscx_irq(sc,
132 				    HSCX_READ(HSCX_CH_A, H_ISTA) & ~HSCX_A_IMASK,
133 				    HSCX_CH_A,
134 				    hscx_irq_stat & HSCX_ISTA_EXA);
135 				was_hscx_irq = 1;
136 			}
137 
138 			if(isac_irq_stat)
139 			{
140 				/* isac handler */
141 				isic_isac_irq(sc, isac_irq_stat);
142 				was_isac_irq = 1;
143 			}
144 		}
145 
146 		HSCX_WRITE(0, H_MASK, 0xff);
147 		ISAC_WRITE(I_MASK, 0xff);
148 		HSCX_WRITE(1, H_MASK, 0xff);
149 
150 		if (sc->clearirq)
151 		{
152 			DELAY(80);
153 			sc->clearirq(sc);
154 		} else
155 			DELAY(100);
156 
157 		HSCX_WRITE(0, H_MASK, HSCX_A_IMASK);
158 		ISAC_WRITE(I_MASK, ISAC_IMASK);
159 		HSCX_WRITE(1, H_MASK, HSCX_B_IMASK);
160 
161 		return(was_hscx_irq || was_isac_irq);
162 	}
163 	else	/* IPAC interrupt routine */
164 	{
165 		register u_char ipac_irq_stat;
166 		register u_char was_ipac_irq = 0;
167 
168 		for(;;)
169 		{
170 			/* get global irq status */
171 
172 			ipac_irq_stat = (IPAC_READ(IPAC_ISTA)) & 0x3f;
173 
174 			/* check hscx a */
175 
176 			if(ipac_irq_stat & (IPAC_ISTA_ICA | IPAC_ISTA_EXA))
177 			{
178 				/* HSCX A interrupt */
179 				isic_hscx_irq(sc, HSCX_READ(HSCX_CH_A, H_ISTA),
180 						HSCX_CH_A,
181 						ipac_irq_stat & IPAC_ISTA_EXA);
182 				was_ipac_irq = 1;
183 			}
184 			if(ipac_irq_stat & (IPAC_ISTA_ICB | IPAC_ISTA_EXB))
185 			{
186 				/* HSCX B interrupt */
187 				isic_hscx_irq(sc, HSCX_READ(HSCX_CH_B, H_ISTA),
188 						HSCX_CH_B,
189 						ipac_irq_stat & IPAC_ISTA_EXB);
190 				was_ipac_irq = 1;
191 			}
192 			if(ipac_irq_stat & IPAC_ISTA_ICD)
193 			{
194 				/* ISAC interrupt, Obey ISAC-IPAC differences */
195 				u_int8_t isac_ista = ISAC_READ(I_ISTA);
196 				if (isac_ista & 0xfe)
197 					isic_isac_irq(sc, isac_ista & 0xfe);
198 				if (isac_ista & 0x01) /* unexpected */
199 					printf("%s: unexpected ipac timer2 irq\n",
200 					    sc->sc_dev.dv_xname);
201 				was_ipac_irq = 1;
202 			}
203 			if(ipac_irq_stat & IPAC_ISTA_EXD)
204 			{
205 				/* ISAC EXI interrupt */
206 				isic_isac_irq(sc, ISAC_ISTA_EXI);
207 				was_ipac_irq = 1;
208 			}
209 
210 			/* do as long as there are pending irqs in the chip */
211 			if(!ipac_irq_stat)
212 				break;
213 		}
214 
215 #if 0
216 		/*
217 		 * This seems not to be necessary on IPACs - no idea why
218 		 * it is here - but due to limit range of test cards, leave
219 		 * it in for now, in case we have to resurrect it.
220 		 */
221 		IPAC_WRITE(IPAC_MASK, 0xff);
222 		DELAY(50);
223 		IPAC_WRITE(IPAC_MASK, 0xc0);
224 #endif
225 
226 		return(was_ipac_irq);
227 	}
228 }
229 
230 int
isic_attach_bri(struct isic_softc * sc,const char * cardname,const struct isdn_layer1_isdnif_driver * dchan_driver)231 isic_attach_bri(struct isic_softc *sc, const char *cardname, const struct isdn_layer1_isdnif_driver *dchan_driver)
232 {
233 	struct isdn_l3_driver * drv;
234 
235 	drv = isdn_attach_isdnif(sc->sc_dev.dv_xname, cardname,
236 	    &sc->sc_l2, &isic_l3_driver, NBCH_BRI);
237 	sc->sc_l3token = drv;
238 	sc->sc_l2.driver = dchan_driver;
239 	sc->sc_l2.l1_token = sc;
240 	sc->sc_l2.drv = drv;
241 	isdn_layer2_status_ind(&sc->sc_l2, drv, STI_ATTACH, 1);
242 	isdn_isdnif_ready(drv->isdnif);
243 	return 1;
244 }
245 
246 int
isic_detach_bri(struct isic_softc * sc)247 isic_detach_bri(struct isic_softc *sc)
248 {
249 	isdn_layer2_status_ind(&sc->sc_l2, sc->sc_l3token, STI_ATTACH, 0);
250 	isdn_detach_isdnif(sc->sc_l3token);
251 	sc->sc_l3token = NULL;
252 	return 1;
253 }
254