1 /*-
2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the NetBSD
19 * Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 * contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: isic_pcmcia.c,v 1.23 2004/01/04 12:41:46 martin Exp $");
39
40 #include <sys/param.h>
41 #include <sys/errno.h>
42 #include <sys/syslog.h>
43 #include <sys/device.h>
44 #include <sys/socket.h>
45 #include <net/if.h>
46 #include <sys/systm.h>
47 #include <sys/malloc.h>
48
49 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
50 #include <sys/callout.h>
51 #endif
52
53 #include <machine/cpu.h>
54 #include <machine/intr.h>
55 #include <machine/bus.h>
56
57 #include <dev/pcmcia/pcmciareg.h>
58 #include <dev/pcmcia/pcmciavar.h>
59 #include <dev/pcmcia/pcmciadevs.h>
60
61 #ifdef __FreeBSD__
62 #include <machine/i4b_ioctl.h>
63 #include <machine/i4b_trace.h>
64 #else
65 #include <netisdn/i4b_ioctl.h>
66 #include <netisdn/i4b_trace.h>
67 #include <netisdn/i4b_debug.h>
68 #include <netisdn/i4b_l2.h>
69 #include <netisdn/i4b_l1l2.h>
70 #endif
71
72 #include <dev/ic/isic_l1.h>
73 #include <dev/ic/ipac.h>
74 #include <dev/ic/isac.h>
75 #include <dev/ic/hscx.h>
76
77 #include <netisdn/i4b_l1l2.h>
78 #include <netisdn/i4b_global.h>
79
80 #include <dev/pcmcia/isic_pcmcia.h>
81
82 #include "opt_isicpcmcia.h"
83
84 extern const struct isdn_layer1_isdnif_driver isic_std_driver;
85
86 static int isic_pcmcia_match __P((struct device *, struct cfdata *, void *));
87 static void isic_pcmcia_attach __P((struct device *, struct device *, void *));
88 static const struct isic_pcmcia_card_entry * find_matching_card __P((struct pcmcia_attach_args *pa));
89 static int isic_pcmcia_isdn_attach __P((struct isic_softc *sc, const char*));
90 static int isic_pcmcia_detach(struct device *self, int flags);
91 static int isic_pcmcia_activate(struct device *self, enum devact act);
92
93 CFATTACH_DECL(isic_pcmcia, sizeof(struct pcmcia_isic_softc),
94 isic_pcmcia_match, isic_pcmcia_attach,
95 isic_pcmcia_detach, isic_pcmcia_activate);
96
97 struct isic_pcmcia_card_entry {
98 int32_t vendor; /* vendor ID */
99 int32_t product; /* product ID */
100 char *cis1_info[4]; /* CIS info to match */
101 char *name; /* name of controller */
102 int function; /* expected PCMCIA function type */
103 int card_type; /* card type found */
104 isic_pcmcia_attach_func attach; /* card initialization */
105 };
106
107 static const struct isic_pcmcia_card_entry card_list[] = {
108
109 #ifdef ISICPCMCIA_AVM_A1
110 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
111 { "AVM", "ISDN A", NULL, NULL },
112 "AVM Fritz!Card", PCMCIA_FUNCTION_NETWORK,
113 CARD_TYPEP_PCFRITZ, isic_attach_fritzpcmcia },
114 #endif
115
116 #ifdef ISICPCMCIA_ELSA_ISDNMC
117 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
118 { "ELSA GmbH, Aachen", "MicroLink ISDN/MC ", NULL, NULL },
119 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK,
120 CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc },
121 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
122 { "ELSA AG, Aachen", "MicroLink ISDN/MC ", NULL, NULL },
123 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK,
124 CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc },
125 { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID,
126 { "ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", NULL, NULL },
127 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK,
128 CARD_TYPEP_ELSAMLIMC, isic_attach_elsaisdnmc },
129 #endif
130
131 #ifdef ISICPCMCIA_ELSA_MCALL
132 { 0x105, 0x410a,
133 { "ELSA", "MicroLink MC all", NULL, NULL },
134 "ELSA MicroLink MCall", PCMCIA_FUNCTION_NETWORK,
135 CARD_TYPEP_ELSAMLMCALL, isic_attach_elsamcall },
136 #endif
137
138 #ifdef ISICPCMCIA_SBSPEEDSTAR2
139 { 0x020e, 0x0002,
140 { "SEDLBAUER", "speed star II", NULL, NULL },
141 "SEDLBAUER speed star II", PCMCIA_FUNCTION_NETWORK,
142 CARD_TYPEP_SWS, isic_attach_sbspeedstar2 },
143 #endif
144
145 };
146 #define NUM_MATCH_ENTRIES (sizeof(card_list)/sizeof(card_list[0]))
147
148 static const struct isic_pcmcia_card_entry *
149 find_matching_card(pa)
150 struct pcmcia_attach_args *pa;
151 {
152 int i, j;
153
154 for (i = 0; i < NUM_MATCH_ENTRIES; i++) {
155 if (card_list[i].vendor != PCMCIA_VENDOR_INVALID && pa->card->manufacturer != card_list[i].vendor)
156 continue;
157 if (card_list[i].product != PCMCIA_PRODUCT_INVALID && pa->card->product != card_list[i].product)
158 continue;
159 if (pa->pf->function != card_list[i].function)
160 continue;
161 for (j = 0; j < 4; j++) {
162 if (card_list[i].cis1_info[j] == NULL)
163 continue; /* wildcard */
164 if (pa->card->cis1_info[j] == NULL)
165 break; /* not available */
166 if (strcmp(pa->card->cis1_info[j], card_list[i].cis1_info[j]) != 0)
167 break; /* mismatch */
168 }
169 if (j >= 4)
170 break;
171 }
172 if (i >= NUM_MATCH_ENTRIES)
173 return NULL;
174
175 return &card_list[i];
176 }
177
178 /*
179 * Match card
180 */
181 static int
182 isic_pcmcia_match(parent, match, aux)
183 struct device *parent;
184 struct cfdata *match;
185 void *aux;
186 {
187 struct pcmcia_attach_args *pa = aux;
188
189 if (!find_matching_card(pa))
190 return 0;
191
192 return 1;
193 }
194
195 /*
196 * Attach the card
197 */
198 static void
199 isic_pcmcia_attach(parent, self, aux)
200 struct device *parent, *self;
201 void *aux;
202 {
203 struct pcmcia_isic_softc *psc = (void*) self;
204 struct isic_softc *sc = &psc->sc_isic;
205 struct pcmcia_attach_args *pa = aux;
206 struct pcmcia_config_entry *cfe;
207 const struct isic_pcmcia_card_entry * cde;
208 int s;
209
210 psc->sc_pf = pa->pf;
211 cfe = SIMPLEQ_FIRST(&pa->pf->cfe_head);
212 psc->sc_ih = NULL;
213
214 /* Which card is it? */
215 cde = find_matching_card(pa);
216 if (cde == NULL) {
217 printf("%s: attach failed, couldn't find matching card\n",
218 psc->sc_isic.sc_dev.dv_xname);
219 return;
220 }
221 printf(": %s\n", cde->name);
222
223 /* Enable the card */
224 pcmcia_function_init(pa->pf, cfe);
225 pcmcia_function_enable(pa->pf);
226
227 if (!cde->attach(psc, cfe, pa)) {
228 pcmcia_function_disable(psc->sc_pf);
229 printf("%s: attach failed, card-specific attach unsuccesful\n",
230 psc->sc_isic.sc_dev.dv_xname);
231 return;
232 }
233
234 /* XXX - we generate interrupts during card initialization.
235 Block them for now, until the handler is established. */
236 s = splhigh();
237
238 /* MI initilization */
239 sc->sc_cardtyp = cde->card_type;
240 if (isic_pcmcia_isdn_attach(sc, cde->name) == 0) {
241 /* setup interrupt */
242 psc->sc_ih = pcmcia_intr_establish(pa->pf, IPL_NET, isicintr, sc);
243 } else {
244 pcmcia_function_disable(psc->sc_pf);
245 splx(s);
246 printf("%s: attach failed, couldn't establish interrupt\n",
247 psc->sc_isic.sc_dev.dv_xname);
248 return;
249 }
250
251 splx(s);
252 return;
253 }
254
255 static int
256 isic_pcmcia_detach(self, flags)
257 struct device *self;
258 int flags;
259 {
260 struct pcmcia_isic_softc *psc = (struct pcmcia_isic_softc *)self;
261
262 pcmcia_function_disable(psc->sc_pf);
263 pcmcia_io_unmap(psc->sc_pf, psc->sc_io_window);
264 pcmcia_io_free(psc->sc_pf, &psc->sc_pcioh);
265 if (psc->sc_ih != NULL)
266 pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih);
267
268 return (0);
269 }
270
271 int
272 isic_pcmcia_activate(self, act)
273 struct device *self;
274 enum devact act;
275 {
276 struct pcmcia_isic_softc *psc = (struct pcmcia_isic_softc *)self;
277 int error = 0, s;
278
279 s = splnet();
280 switch (act) {
281 case DVACT_ACTIVATE:
282 error = EOPNOTSUPP;
283 break;
284
285 case DVACT_DEACTIVATE:
286 psc->sc_isic.sc_intr_valid = ISIC_INTR_DYING;
287 if (psc->sc_isic.sc_l3token != NULL)
288 isic_detach_bri(&psc->sc_isic);
289 break;
290 }
291 splx(s);
292 return (error);
293 }
294
295 /*---------------------------------------------------------------------------*
296 * card independend attach for pcmicia cards
297 *---------------------------------------------------------------------------*/
298
299 /* parameter and format for message producing e.g. "isic0: " */
300
301 #ifdef __FreeBSD__
302 #define ISIC_FMT "isic%d: "
303 #define ISIC_PARM dev->id_unit
304 #define TERMFMT " "
305 #else
306 #define ISIC_FMT "%s: "
307 #define ISIC_PARM sc->sc_dev.dv_xname
308 #define TERMFMT "\n"
309 #endif
310
311 int
312 isic_pcmcia_isdn_attach(struct isic_softc *sc, const char *cardname)
313 {
314 static char *ISACversion[] = {
315 "2085 Version A1/A2 or 2086/2186 Version 1.1",
316 "2085 Version B1",
317 "2085 Version B2",
318 "2085 Version V2.3 (B3)",
319 "Unknown Version"
320 };
321
322 static char *HSCXversion[] = {
323 "82525 Version A1",
324 "Unknown (0x01)",
325 "82525 Version A2",
326 "Unknown (0x03)",
327 "82525 Version A3",
328 "82525 or 21525 Version 2.1",
329 "Unknown Version"
330 };
331
332 sc->sc_l3token = NULL;
333 sc->sc_isac_version = 0;
334 sc->sc_isac_version = ((ISAC_READ(I_RBCH)) >> 5) & 0x03;
335
336 switch(sc->sc_isac_version)
337 {
338 case ISAC_VA:
339 case ISAC_VB1:
340 case ISAC_VB2:
341 case ISAC_VB3:
342 break;
343
344 default:
345 printf(ISIC_FMT "Error, ISAC version %d unknown!\n",
346 ISIC_PARM, sc->sc_isac_version);
347 return(EIO);
348 }
349
350 sc->sc_hscx_version = HSCX_READ(0, H_VSTR) & 0xf;
351
352 switch(sc->sc_hscx_version)
353 {
354 case HSCX_VA1:
355 case HSCX_VA2:
356 case HSCX_VA3:
357 case HSCX_V21:
358 break;
359
360 default:
361 printf(ISIC_FMT "Error, HSCX version %d unknown!\n",
362 ISIC_PARM, sc->sc_hscx_version);
363 return(EIO);
364 };
365
366 sc->sc_intr_valid = ISIC_INTR_DISABLED;
367
368 /* HSCX setup */
369
370 isic_bchannel_setup(sc, HSCX_CH_A, BPROT_NONE, 0);
371
372 isic_bchannel_setup(sc, HSCX_CH_B, BPROT_NONE, 0);
373
374 /* setup linktab */
375
376 isic_init_linktab(sc);
377
378 /* set trace level */
379
380 sc->sc_trace = TRACE_OFF;
381
382 sc->sc_state = ISAC_IDLE;
383
384 sc->sc_ibuf = NULL;
385 sc->sc_ib = NULL;
386 sc->sc_ilen = 0;
387
388 sc->sc_obuf = NULL;
389 sc->sc_op = NULL;
390 sc->sc_ol = 0;
391 sc->sc_freeflag = 0;
392
393 sc->sc_obuf2 = NULL;
394 sc->sc_freeflag2 = 0;
395
396 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
397 callout_init(&sc->sc_T3_callout);
398 callout_init(&sc->sc_T4_callout);
399 #endif
400
401 /* announce chip versions */
402
403 if(sc->sc_isac_version >= ISAC_UNKN)
404 {
405 printf(ISIC_FMT "ISAC Version UNKNOWN (VN=0x%x)" TERMFMT,
406 ISIC_PARM,
407 sc->sc_isac_version);
408 sc->sc_isac_version = ISAC_UNKN;
409 }
410 else
411 {
412 printf(ISIC_FMT "ISAC %s (IOM-%c)" TERMFMT,
413 ISIC_PARM,
414 ISACversion[sc->sc_isac_version],
415 sc->sc_bustyp == BUS_TYPE_IOM1 ? '1' : '2');
416 }
417
418 if(sc->sc_hscx_version >= HSCX_UNKN)
419 {
420 printf(ISIC_FMT "HSCX Version UNKNOWN (VN=0x%x)" TERMFMT,
421 ISIC_PARM,
422 sc->sc_hscx_version);
423 sc->sc_hscx_version = HSCX_UNKN;
424 }
425 else
426 {
427 printf(ISIC_FMT "HSCX %s" TERMFMT,
428 ISIC_PARM,
429 HSCXversion[sc->sc_hscx_version]);
430 }
431
432 /* init higher protocol layers */
433 isic_attach_bri(sc, cardname, &isic_std_driver);
434
435 return(0);
436 }
437
Cache object: 0ca4edc62fed98b7db18033b78de5b34
|