2 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Martin Husemann <martin@NetBSD.org>.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
17 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 * POSSIBILITY OF SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __KERNEL_RCSID(0, "$NetBSD: isic_pcmcia.c,v 1.39 2009/05/12 14:42:18 cegger Exp $");
33 #include <sys/param.h>
34 #include <sys/errno.h>
35 #include <sys/syslog.h>
36 #include <sys/device.h>
37 #include <sys/socket.h>
39 #include <sys/systm.h>
40 #include <sys/malloc.h>
42 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
43 #include <sys/callout.h>
50 #include <dev/pcmcia/pcmciareg.h>
51 #include <dev/pcmcia/pcmciavar.h>
52 #include <dev/pcmcia/pcmciadevs.h>
55 #include <machine/i4b_ioctl.h>
56 #include <machine/i4b_trace.h>
58 #include <netisdn/i4b_ioctl.h>
59 #include <netisdn/i4b_trace.h>
60 #include <netisdn/i4b_debug.h>
61 #include <netisdn/i4b_l2.h>
62 #include <netisdn/i4b_l1l2.h>
65 #include <dev/ic/isic_l1.h>
66 #include <dev/ic/ipac.h>
67 #include <dev/ic/isac.h>
68 #include <dev/ic/hscx.h>
70 #include <netisdn/i4b_l1l2.h>
71 #include <netisdn/i4b_global.h>
73 #include <dev/pcmcia/isic_pcmcia.h>
75 #include "opt_isicpcmcia.h"
77 extern const struct isdn_layer1_isdnif_driver isic_std_driver
;
79 static int isic_pcmcia_match(device_t
, cfdata_t
, void *);
80 static void isic_pcmcia_attach(device_t
, device_t
, void *);
81 static const struct isic_pcmcia_card_entry
* find_matching_card(struct pcmcia_attach_args
*pa
);
82 static int isic_pcmcia_isdn_attach(struct isic_softc
*sc
, const char*);
83 static int isic_pcmcia_detach(device_t self
, int flags
);
84 static int isic_pcmcia_activate(device_t self
, enum devact act
);
86 CFATTACH_DECL(isic_pcmcia
, sizeof(struct pcmcia_isic_softc
),
87 isic_pcmcia_match
, isic_pcmcia_attach
,
88 isic_pcmcia_detach
, isic_pcmcia_activate
);
90 struct isic_pcmcia_card_entry
{
91 int32_t vendor
; /* vendor ID */
92 int32_t product
; /* product ID */
93 const char *cis1_info
[4]; /* CIS info to match */
94 const char *name
; /* name of controller */
95 int function
; /* expected PCMCIA function type */
96 int card_type
; /* card type found */
97 isic_pcmcia_attach_func attach
; /* card initialization */
100 static const struct isic_pcmcia_card_entry card_list
[] = {
102 #ifdef ISICPCMCIA_AVM_A1
103 { PCMCIA_VENDOR_INVALID
, PCMCIA_PRODUCT_INVALID
,
104 { "AVM", "ISDN A", NULL
, NULL
},
105 "AVM Fritz!Card", PCMCIA_FUNCTION_NETWORK
,
106 CARD_TYPEP_PCFRITZ
, isic_attach_fritzpcmcia
},
109 #ifdef ISICPCMCIA_ELSA_ISDNMC
110 { PCMCIA_VENDOR_INVALID
, PCMCIA_PRODUCT_INVALID
,
111 { "ELSA GmbH, Aachen", "MicroLink ISDN/MC ", NULL
, NULL
},
112 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK
,
113 CARD_TYPEP_ELSAMLIMC
, isic_attach_elsaisdnmc
},
114 { PCMCIA_VENDOR_INVALID
, PCMCIA_PRODUCT_INVALID
,
115 { "ELSA AG, Aachen", "MicroLink ISDN/MC ", NULL
, NULL
},
116 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK
,
117 CARD_TYPEP_ELSAMLIMC
, isic_attach_elsaisdnmc
},
118 { PCMCIA_VENDOR_INVALID
, PCMCIA_PRODUCT_INVALID
,
119 { "ELSA AG (Aachen, Germany)", "MicroLink ISDN/MC ", NULL
, NULL
},
120 "ELSA MicroLink ISDN/MC", PCMCIA_FUNCTION_NETWORK
,
121 CARD_TYPEP_ELSAMLIMC
, isic_attach_elsaisdnmc
},
124 #ifdef ISICPCMCIA_ELSA_MCALL
126 { "ELSA", "MicroLink MC all", NULL
, NULL
},
127 "ELSA MicroLink MCall", PCMCIA_FUNCTION_NETWORK
,
128 CARD_TYPEP_ELSAMLMCALL
, isic_attach_elsamcall
},
131 #ifdef ISICPCMCIA_SBSPEEDSTAR2
133 { "SEDLBAUER", "speed star II", NULL
, NULL
},
134 "SEDLBAUER speed star II", PCMCIA_FUNCTION_NETWORK
,
135 CARD_TYPEP_SWS
, isic_attach_sbspeedstar2
},
139 #define NUM_MATCH_ENTRIES (sizeof(card_list)/sizeof(card_list[0]))
141 static const struct isic_pcmcia_card_entry
*
142 find_matching_card(struct pcmcia_attach_args
*pa
)
146 for (i
= 0; i
< NUM_MATCH_ENTRIES
; i
++) {
147 if (card_list
[i
].vendor
!= PCMCIA_VENDOR_INVALID
&& pa
->card
->manufacturer
!= card_list
[i
].vendor
)
149 if (card_list
[i
].product
!= PCMCIA_PRODUCT_INVALID
&& pa
->card
->product
!= card_list
[i
].product
)
151 if (pa
->pf
->function
!= card_list
[i
].function
)
153 for (j
= 0; j
< 4; j
++) {
154 if (card_list
[i
].cis1_info
[j
] == NULL
)
155 continue; /* wildcard */
156 if (pa
->card
->cis1_info
[j
] == NULL
)
157 break; /* not available */
158 if (strcmp(pa
->card
->cis1_info
[j
], card_list
[i
].cis1_info
[j
]) != 0)
159 break; /* mismatch */
164 if (i
>= NUM_MATCH_ENTRIES
)
167 return &card_list
[i
];
174 isic_pcmcia_match(device_t parent
,
175 cfdata_t match
, void *aux
)
177 struct pcmcia_attach_args
*pa
= aux
;
179 if (!find_matching_card(pa
))
189 isic_pcmcia_attach(device_t parent
,
190 device_t self
, void *aux
)
192 struct pcmcia_isic_softc
*psc
= (void*) self
;
193 struct isic_softc
*sc
= &psc
->sc_isic
;
194 struct pcmcia_attach_args
*pa
= aux
;
195 struct pcmcia_config_entry
*cfe
;
196 const struct isic_pcmcia_card_entry
* cde
;
199 cfe
= SIMPLEQ_FIRST(&pa
->pf
->cfe_head
);
202 /* Which card is it? */
203 cde
= find_matching_card(pa
);
205 aprint_error_dev(&psc
->sc_isic
.sc_dev
, "attach failed, couldn't find matching card\n");
208 printf("%s: %s\n", cde
->name
, device_xname(self
));
210 /* Enable the card */
211 pcmcia_function_init(pa
->pf
, cfe
);
212 psc
->sc_ih
= pcmcia_intr_establish(pa
->pf
, IPL_NET
, isicintr
, sc
);
213 pcmcia_function_enable(pa
->pf
);
215 if (!cde
->attach(psc
, cfe
, pa
)) {
216 aprint_error_dev(&psc
->sc_isic
.sc_dev
, "attach failed, card-specific attach unsuccesful\n");
220 /* MI initilization */
221 sc
->sc_cardtyp
= cde
->card_type
;
222 if (isic_pcmcia_isdn_attach(sc
, cde
->name
)) {
223 aprint_error_dev(&psc
->sc_isic
.sc_dev
, "attach failed, generic attach unsuccesful\n");
230 pcmcia_function_disable(psc
->sc_pf
);
231 pcmcia_intr_disestablish(psc
->sc_pf
, psc
->sc_ih
);
235 isic_pcmcia_detach(device_t self
, int flags
)
237 struct pcmcia_isic_softc
*psc
= (struct pcmcia_isic_softc
*)self
;
239 pcmcia_function_disable(psc
->sc_pf
);
240 pcmcia_io_unmap(psc
->sc_pf
, psc
->sc_io_window
);
241 pcmcia_io_free(psc
->sc_pf
, &psc
->sc_pcioh
);
242 if (psc
->sc_ih
!= NULL
)
243 pcmcia_intr_disestablish(psc
->sc_pf
, psc
->sc_ih
);
249 isic_pcmcia_activate(device_t self
, enum devact act
)
251 struct pcmcia_isic_softc
*psc
= device_private(self
);
254 case DVACT_DEACTIVATE
:
255 psc
->sc_isic
.sc_intr_valid
= ISIC_INTR_DYING
;
256 if (psc
->sc_isic
.sc_l3token
!= NULL
)
257 isic_detach_bri(&psc
->sc_isic
);
264 /*---------------------------------------------------------------------------*
265 * card independend attach for pcmicia cards
266 *---------------------------------------------------------------------------*/
268 /* parameter and format for message producing e.g. "isic0: " */
271 #define ISIC_FMT "isic%d: "
272 #define ISIC_PARM dev->id_unit
275 #define ISIC_FMT "%s: "
276 #define ISIC_PARM device_xname(&sc->sc_dev)
281 isic_pcmcia_isdn_attach(struct isic_softc
*sc
, const char *cardname
)
283 static const char *ISACversion
[] = {
284 "2085 Version A1/A2 or 2086/2186 Version 1.1",
287 "2085 Version V2.3 (B3)",
291 static const char *HSCXversion
[] = {
297 "82525 or 21525 Version 2.1",
301 sc
->sc_l3token
= NULL
;
302 sc
->sc_isac_version
= 0;
303 sc
->sc_isac_version
= ((ISAC_READ(I_RBCH
)) >> 5) & 0x03;
305 switch(sc
->sc_isac_version
)
314 printf(ISIC_FMT
"Error, ISAC version %d unknown!\n",
315 ISIC_PARM
, sc
->sc_isac_version
);
319 sc
->sc_hscx_version
= HSCX_READ(0, H_VSTR
) & 0xf;
321 switch(sc
->sc_hscx_version
)
330 printf(ISIC_FMT
"Error, HSCX version %d unknown!\n",
331 ISIC_PARM
, sc
->sc_hscx_version
);
335 sc
->sc_intr_valid
= ISIC_INTR_DISABLED
;
339 isic_bchannel_setup(sc
, HSCX_CH_A
, BPROT_NONE
, 0);
341 isic_bchannel_setup(sc
, HSCX_CH_B
, BPROT_NONE
, 0);
345 isic_init_linktab(sc
);
347 /* set trace level */
349 sc
->sc_trace
= TRACE_OFF
;
351 sc
->sc_state
= ISAC_IDLE
;
363 sc
->sc_freeflag2
= 0;
365 #if defined(__NetBSD__) && __NetBSD_Version__ >= 104230000
366 callout_init(&sc
->sc_T3_callout
, 0);
367 callout_init(&sc
->sc_T4_callout
, 0);
370 /* announce chip versions */
372 if(sc
->sc_isac_version
>= ISAC_UNKN
)
374 printf(ISIC_FMT
"ISAC Version UNKNOWN (VN=0x%x)" TERMFMT
,
376 sc
->sc_isac_version
);
377 sc
->sc_isac_version
= ISAC_UNKN
;
381 printf(ISIC_FMT
"ISAC %s (IOM-%c)" TERMFMT
,
383 ISACversion
[sc
->sc_isac_version
],
384 sc
->sc_bustyp
== BUS_TYPE_IOM1
? '1' : '2');
387 if(sc
->sc_hscx_version
>= HSCX_UNKN
)
389 printf(ISIC_FMT
"HSCX Version UNKNOWN (VN=0x%x)" TERMFMT
,
391 sc
->sc_hscx_version
);
392 sc
->sc_hscx_version
= HSCX_UNKN
;
396 printf(ISIC_FMT
"HSCX %s" TERMFMT
,
398 HSCXversion
[sc
->sc_hscx_version
]);
401 /* init higher protocol layers */
402 isic_attach_bri(sc
, cardname
, &isic_std_driver
);