1 | /* $NetBSD: if_ne_pcmcia.c,v 1.160 2013/10/17 21:06:47 christos Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (c) 1997 Marc Horowitz. All rights reserved. |
5 | * |
6 | * Redistribution and use in source and binary forms, with or without |
7 | * modification, are permitted provided that the following conditions |
8 | * are met: |
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. |
14 | * 3. All advertising materials mentioning features or use of this software |
15 | * must display the following acknowledgement: |
16 | * This product includes software developed by Marc Horowitz. |
17 | * 4. The name of the author may not be used to endorse or promote products |
18 | * derived from this software without specific prior written permission. |
19 | * |
20 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
21 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
22 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
23 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
24 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
25 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
26 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
27 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
28 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
29 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | #include <sys/cdefs.h> |
33 | __KERNEL_RCSID(0, "$NetBSD: if_ne_pcmcia.c,v 1.160 2013/10/17 21:06:47 christos Exp $" ); |
34 | |
35 | #include <sys/param.h> |
36 | #include <sys/systm.h> |
37 | #include <sys/select.h> |
38 | #include <sys/device.h> |
39 | #include <sys/socket.h> |
40 | |
41 | #include <net/if_types.h> |
42 | #include <net/if.h> |
43 | #include <net/if_media.h> |
44 | #include <net/if_ether.h> |
45 | |
46 | #include <sys/bus.h> |
47 | #include <sys/intr.h> |
48 | |
49 | #include <dev/pcmcia/pcmciareg.h> |
50 | #include <dev/pcmcia/pcmciavar.h> |
51 | #include <dev/pcmcia/pcmciadevs.h> |
52 | |
53 | #include <dev/ic/dp8390reg.h> |
54 | #include <dev/ic/dp8390var.h> |
55 | |
56 | #include <dev/ic/ne2000reg.h> |
57 | #include <dev/ic/ne2000var.h> |
58 | |
59 | #include <dev/ic/rtl80x9reg.h> |
60 | #include <dev/ic/rtl80x9var.h> |
61 | |
62 | #include <dev/ic/dl10019var.h> |
63 | |
64 | #include <dev/ic/ax88190reg.h> |
65 | #include <dev/ic/ax88190var.h> |
66 | |
67 | int ne_pcmcia_match(device_t, cfdata_t , void *); |
68 | int ne_pcmcia_validate_config(struct pcmcia_config_entry *); |
69 | void ne_pcmcia_attach(device_t, device_t, void *); |
70 | int ne_pcmcia_detach(device_t, int); |
71 | |
72 | int ne_pcmcia_enable(struct dp8390_softc *); |
73 | void ne_pcmcia_disable(struct dp8390_softc *); |
74 | |
75 | struct ne_pcmcia_softc { |
76 | struct ne2000_softc sc_ne2000; /* real "ne2000" softc */ |
77 | |
78 | void *sc_ih; /* interrupt handle */ |
79 | |
80 | struct pcmcia_function *sc_pf; /* our PCMCIA function */ |
81 | int sc_state; |
82 | #define NE_PCMCIA_ATTACHED 3 |
83 | }; |
84 | |
85 | u_int8_t *ne_pcmcia_get_enaddr(struct ne_pcmcia_softc *, int, |
86 | u_int8_t [ETHER_ADDR_LEN]); |
87 | u_int8_t *ne_pcmcia_dl10019_get_enaddr(struct ne_pcmcia_softc *, |
88 | u_int8_t [ETHER_ADDR_LEN]); |
89 | |
90 | CFATTACH_DECL_NEW(ne_pcmcia, sizeof(struct ne_pcmcia_softc), |
91 | ne_pcmcia_match, ne_pcmcia_attach, ne_pcmcia_detach, dp8390_activate); |
92 | |
93 | static const struct ne2000dev { |
94 | int32_t manufacturer; |
95 | int32_t product; |
96 | const char *cis_info[4]; |
97 | int function; |
98 | int enet_maddr; |
99 | unsigned char enet_vendor[3]; |
100 | int flags; |
101 | #define NE2000DVF_DL10019 0x0001 /* chip is D-Link DL10019 */ |
102 | #define NE2000DVF_AX88190 0x0002 /* chip is ASIX AX88190 */ |
103 | } ne2000devs[] = { |
104 | { PCMCIA_VENDOR_EDIMAX, PCMCIA_PRODUCT_EDIMAX_EP4000A, |
105 | PCMCIA_CIS_INVALID, |
106 | 0, -1, { 0x00, 0xa0, 0x0c }, 0 }, |
107 | |
108 | { PCMCIA_VENDOR_EDIMAX, PCMCIA_PRODUCT_EDIMAX_EP4101, |
109 | PCMCIA_CIS_INVALID, |
110 | 0, -1, { 0x00, 0x90, 0xcc }, NE2000DVF_AX88190 }, |
111 | |
112 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
113 | PCMCIA_CIS_SYNERGY21_S21810, |
114 | 0, -1, { 0x00, 0x48, 0x54 }, 0 }, |
115 | |
116 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
117 | PCMCIA_CIS_AMBICOM_AMB8002T, |
118 | 0, -1, { 0x00, 0x10, 0x7a }, 0 }, |
119 | |
120 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
121 | PCMCIA_CIS_AMBICOM_AMB8110, |
122 | 0, -1, { 0x00, 0x10, 0x7a }, NE2000DVF_AX88190 }, |
123 | |
124 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
125 | PCMCIA_CIS_PREMAX_PE200, |
126 | 0, 0x07f0, { 0x00, 0x20, 0xe0 }, 0 }, |
127 | |
128 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
129 | PCMCIA_CIS_PREMAX_PE200, |
130 | 0, -1, { 0x00, 0x20, 0xe0 }, 0 }, |
131 | |
132 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
133 | PCMCIA_CIS_PLANET_SMARTCOM2000, |
134 | 0, 0xff0, { 0x00, 0x00, 0xe8 }, 0 }, |
135 | |
136 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
137 | PCMCIA_CIS_DLINK_DE660, |
138 | 0, -1, { 0x00, 0x80, 0xc8 }, 0 }, |
139 | |
140 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
141 | PCMCIA_CIS_DLINK_DE660PLUS, |
142 | 0, -1, { 0x00, 0x80, 0xc8 }, 0 }, |
143 | |
144 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
145 | PCMCIA_CIS_RPTI_EP400, |
146 | 0, 0x110, { 0x00, 0x40, 0x95 }, 0 }, |
147 | |
148 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
149 | PCMCIA_CIS_RPTI_EP401, |
150 | 0, -1, { 0x00, 0x40, 0x95 }, 0 }, |
151 | |
152 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
153 | PCMCIA_CIS_ACCTON_EN2212, |
154 | 0, 0x0ff0, { 0x00, 0x00, 0xe8 }, 0 }, |
155 | |
156 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
157 | PCMCIA_CIS_ACCTON_EN2216, |
158 | 0, -1, { 0x00, 0x00, 0xe8 }, 0 }, |
159 | |
160 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
161 | PCMCIA_CIS_SVEC_COMBOCARD, |
162 | 0, -1, { 0x00, 0xe0, 0x98 }, 0 }, |
163 | |
164 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
165 | PCMCIA_CIS_SVEC_LANCARD, |
166 | 0, 0x7f0, { 0x00, 0xc0, 0x6c }, 0 }, |
167 | |
168 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_EPSON_EEN10B, |
169 | PCMCIA_CIS_EPSON_EEN10B, |
170 | 0, 0xff0, { 0x00, 0x00, 0x48 }, 0 }, |
171 | |
172 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
173 | PCMCIA_CIS_TAMARACK_ETHERNET, |
174 | 0, -1, { 0x00, 0x00, 0x00 }, 0 }, |
175 | |
176 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
177 | PCMCIA_CIS_CNET_NE2000, |
178 | 0, -1, { 0x00, 0x80, 0xad }, 0 }, |
179 | |
180 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
181 | PCMCIA_CIS_GENIUS_ME3000II, |
182 | 0, -1, { 0x00, 0x40, 0x95 }, 0 }, |
183 | |
184 | |
185 | /* |
186 | * You have to add new entries which contains |
187 | * PCMCIA_VENDOR_INVALID and/or PCMCIA_PRODUCT_INVALID |
188 | * in front of this comment. |
189 | * |
190 | * There are cards which use a generic vendor and product id but needs |
191 | * a different handling depending on the cis_info, so ne2000_match |
192 | * needs a table where the exceptions comes first and then the normal |
193 | * product and vendor entries. |
194 | */ |
195 | |
196 | { PCMCIA_VENDOR_IBM, PCMCIA_PRODUCT_IBM_INFOMOVER, |
197 | PCMCIA_CIS_INVALID, |
198 | 0, 0x0ff0, { 0xff, 0xff, 0xff }, 0 }, |
199 | |
200 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ECARD_1, |
201 | PCMCIA_CIS_INVALID, |
202 | 0, -1, { 0x00, 0x80, 0xc8 }, 0 }, |
203 | |
204 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD, |
205 | PCMCIA_CIS_INVALID, |
206 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_DL10019 }, |
207 | |
208 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD, |
209 | PCMCIA_CIS_INVALID, |
210 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_AX88190 }, |
211 | |
212 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
213 | PCMCIA_CIS_LANTECH_FASTNETTX, |
214 | 0, -1, { 0x00, 0x04, 0x1c }, NE2000DVF_AX88190 }, |
215 | |
216 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_ETHERFAST, |
217 | PCMCIA_CIS_INVALID, |
218 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_DL10019 }, |
219 | |
220 | { PCMCIA_VENDOR_NETGEAR, PCMCIA_PRODUCT_NETGEAR_FA410TXC, |
221 | PCMCIA_CIS_INVALID, |
222 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_DL10019 }, |
223 | |
224 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
225 | PCMCIA_CIS_DLINK_DFE670TXD, |
226 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_DL10019 }, |
227 | |
228 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
229 | PCMCIA_CIS_MELCO_LPC2_TX, |
230 | 0, -1, { 0x00, 0x40, 0x26 }, NE2000DVF_DL10019 }, |
231 | |
232 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_COMBO_ECARD, |
233 | PCMCIA_CIS_INVALID, |
234 | 0, -1, { 0x00, 0x80, 0xc8 }, 0 }, |
235 | |
236 | { PCMCIA_VENDOR_LINKSYS, PCMCIA_PRODUCT_LINKSYS_TRUST_COMBO_ECARD, |
237 | PCMCIA_CIS_INVALID, |
238 | 0, 0x0120, { 0x20, 0x04, 0x49 }, 0 }, |
239 | |
240 | /* Although the comments above say to put VENDOR/PRODUCT INVALID IDs |
241 | above this list, we need to keep this one below the ECARD_1, or else |
242 | both will match the same more-generic entry rather than the more |
243 | specific one above with proper vendor and product IDs. */ |
244 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
245 | PCMCIA_CIS_LINKSYS_ECARD_2, |
246 | 0, -1, { 0x00, 0x80, 0xc8 }, 0 }, |
247 | |
248 | /* |
249 | * D-Link DE-650 has many minor versions: |
250 | * |
251 | * CIS information Manufacturer Product Note |
252 | * 1 "D-Link, DE-650" INVALID INVALID white card |
253 | * 2 "D-Link, DE-650, Ver 01.00" INVALID INVALID became bare metal |
254 | * 3 "D-Link, DE-650, Ver 01.00" 0x149 0x265 minor change in look |
255 | * 4 "D-Link, DE-650, Ver 01.00" 0x149 0x265 collision LED added |
256 | * |
257 | * While the 1st and the 2nd types should use the "D-Link DE-650" entry, |
258 | * the 3rd and the 4th types should use the "Linksys EtherCard" entry. |
259 | * Therefore, this enty must be below the LINKSYS_ECARD_1. --itohy |
260 | */ |
261 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
262 | PCMCIA_CIS_DLINK_DE650, |
263 | 0, 0x0040, { 0x00, 0x80, 0xc8 }, 0 }, |
264 | |
265 | /* |
266 | * IO-DATA PCLA/TE and later version of PCLA/T has valid |
267 | * vendor/product ID and it is possible to read MAC address |
268 | * using standard I/O ports. It also read from CIS offset 0x01c0. |
269 | * On the other hand, earlier version of PCLA/T doesn't have valid |
270 | * vendor/product ID and MAC address must be read from CIS offset |
271 | * 0x0ff0 (i.e., usual ne2000 way to read it doesn't work). |
272 | * And CIS information of earlier and later version of PCLA/T are |
273 | * same except fourth element. So, for now, we place the entry for |
274 | * PCLA/TE (and later version of PCLA/T) followed by entry |
275 | * for the earlier version of PCLA/T (or, modify to match all CIS |
276 | * information and have three or more individual entries). |
277 | */ |
278 | { PCMCIA_VENDOR_IODATA, PCMCIA_PRODUCT_IODATA_PCLATE, |
279 | PCMCIA_CIS_INVALID, |
280 | 0, -1, { 0xff, 0xff, 0xff }, 0 }, |
281 | |
282 | { PCMCIA_VENDOR_IODATA3, PCMCIA_PRODUCT_IODATA3_PCETTXR, |
283 | PCMCIA_CIS_IODATA3_PCETTXR, |
284 | 0, -1, { 0x00, 0xa0, 0xb0 }, NE2000DVF_DL10019 }, |
285 | |
286 | /* |
287 | * This entry should be placed after above PCLA-TE entry. |
288 | * See above comments for detail. |
289 | */ |
290 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
291 | PCMCIA_CIS_IODATA_PCLAT, |
292 | 0, 0x0ff0, { 0x00, 0xa0, 0xb0 }, 0 }, |
293 | |
294 | { PCMCIA_VENDOR_DAYNA, PCMCIA_PRODUCT_DAYNA_COMMUNICARD_E_1, |
295 | PCMCIA_CIS_INVALID, |
296 | 0, 0x0110, { 0x00, 0x80, 0x19 }, 0 }, |
297 | |
298 | { PCMCIA_VENDOR_DAYNA, PCMCIA_PRODUCT_DAYNA_COMMUNICARD_E_2, |
299 | PCMCIA_CIS_INVALID, |
300 | 0, -1, { 0x00, 0x80, 0x19 }, 0 }, |
301 | |
302 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
303 | PCMCIA_CIS_COREGA_ETHER_CF_TD, |
304 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
305 | |
306 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
307 | PCMCIA_CIS_COREGA_ETHER_PCC_T, |
308 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
309 | |
310 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
311 | PCMCIA_CIS_COREGA_ETHER_PCC_TD, |
312 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
313 | |
314 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
315 | PCMCIA_CIS_COREGA_ETHER_PCC_TL, |
316 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
317 | |
318 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
319 | PCMCIA_CIS_COREGA_ETHER_II_PCC_T, |
320 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
321 | |
322 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
323 | PCMCIA_CIS_COREGA_ETHER_II_PCC_TD, |
324 | 0, -1, { 0x00, 0x00, 0xf4 }, 0 }, |
325 | |
326 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
327 | PCMCIA_CIS_COREGA_FAST_ETHER_PCC_TX, |
328 | 0, -1, { 0x00, 0x00, 0xf4 }, NE2000DVF_DL10019 }, |
329 | |
330 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
331 | PCMCIA_CIS_COREGA_FETHER_PCC_TXF, |
332 | 0, -1, { 0x00, 0x90, 0x99 }, NE2000DVF_DL10019 }, |
333 | |
334 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
335 | PCMCIA_CIS_COREGA_FETHER_PCC_TXD, |
336 | 0, -1, { 0x00, 0x90, 0x99 }, 0 }, |
337 | |
338 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
339 | PCMCIA_CIS_COREGA_FETHER_II_PCC_TXD, |
340 | 0, -1, { 0x00, 0x90, 0x99 }, NE2000DVF_AX88190 }, |
341 | |
342 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
343 | PCMCIA_CIS_COREGA_LAPCCTXD, |
344 | 0, -1, { 0x00, 0x90, 0x99 }, 0 }, |
345 | |
346 | { PCMCIA_VENDOR_COMPEX, PCMCIA_PRODUCT_COMPEX_LINKPORT_ENET_B, |
347 | PCMCIA_CIS_INVALID, |
348 | 0, 0x01c0, { 0xff, 0xff, 0xff }, 0 }, |
349 | |
350 | { PCMCIA_VENDOR_SMC, PCMCIA_PRODUCT_SMC_EZCARD, |
351 | PCMCIA_CIS_INVALID, |
352 | 0, 0x01c0, { 0x00, 0xe0, 0x29 }, 0 }, |
353 | |
354 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
355 | PCMCIA_CIS_SMC_8041, |
356 | 0, -1, { 0x00, 0x04, 0xe2 }, 0 }, |
357 | |
358 | { PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_EA_ETHER, |
359 | PCMCIA_CIS_INVALID, |
360 | 0, -1, { 0x00, 0xc0, 0x1b }, 0 }, |
361 | |
362 | { PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_LP_ETHER_CF, |
363 | PCMCIA_CIS_INVALID, |
364 | 0, -1, { 0x00, 0xc0, 0x1b }, 0 }, |
365 | |
366 | { PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_LP_ETH_10_100_CF, |
367 | PCMCIA_CIS_INVALID, |
368 | 0, -1, { 0x00, 0xe0, 0x98 }, NE2000DVF_DL10019 }, |
369 | |
370 | { PCMCIA_VENDOR_SOCKET, PCMCIA_PRODUCT_SOCKET_LP_ETHER, |
371 | PCMCIA_CIS_INVALID, |
372 | 0, -1, { 0x00, 0xc0, 0x1b }, 0 }, |
373 | |
374 | { PCMCIA_VENDOR_KINGSTON, PCMCIA_PRODUCT_KINGSTON_KNE2, |
375 | PCMCIA_CIS_INVALID, |
376 | 0, -1, { 0x00, 0xc0, 0xf0 }, 0 }, |
377 | |
378 | { PCMCIA_VENDOR_XIRCOM, PCMCIA_PRODUCT_XIRCOM_CFE_10, |
379 | PCMCIA_CIS_INVALID, |
380 | 0, -1, { 0x00, 0x10, 0xa4 }, 0 }, |
381 | |
382 | { PCMCIA_VENDOR_MELCO, PCMCIA_PRODUCT_MELCO_LPC3_TX, |
383 | PCMCIA_CIS_INVALID, |
384 | 0, -1, { 0xff, 0xff, 0xff }, NE2000DVF_AX88190 }, |
385 | |
386 | { PCMCIA_VENDOR_BUFFALO, PCMCIA_PRODUCT_BUFFALO_LPC_CF_CLT, |
387 | PCMCIA_CIS_INVALID, |
388 | 0, -1, { 0x00, 0x07, 0x40 }, 0 }, |
389 | |
390 | { PCMCIA_VENDOR_BUFFALO, PCMCIA_PRODUCT_BUFFALO_LPC3_CLT, |
391 | PCMCIA_CIS_INVALID, |
392 | 0, -1, { 0x00, 0x07, 0x40 }, 0 }, |
393 | |
394 | { PCMCIA_VENDOR_BUFFALO, PCMCIA_PRODUCT_BUFFALO_LPC4_CLX, |
395 | PCMCIA_CIS_INVALID, |
396 | 0, -1, { 0x00, 0x40, 0xfa }, NE2000DVF_AX88190 }, |
397 | |
398 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
399 | PCMCIA_CIS_BILLIONTON_LNT10TN, |
400 | 0, -1, { 0x00, 0x00, 0x00 }, 0 }, |
401 | |
402 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
403 | PCMCIA_CIS_BILLIONTON_CFLT10N, |
404 | 0, -1, { 0x00, 0x00, 0x00 }, 0 }, |
405 | |
406 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
407 | PCMCIA_CIS_NDC_ND5100_E, |
408 | 0, -1, { 0x00, 0x80, 0xc6 }, 0 }, |
409 | |
410 | { PCMCIA_VENDOR_TELECOMDEVICE, PCMCIA_PRODUCT_TELECOMDEVICE_TCD_HPC100, |
411 | PCMCIA_CIS_INVALID, |
412 | 0, -1, { 0x00, 0x40, 0x26 }, NE2000DVF_AX88190 }, |
413 | |
414 | { PCMCIA_VENDOR_MACNICA, PCMCIA_PRODUCT_MACNICA_ME1_JEIDA, |
415 | PCMCIA_CIS_INVALID, |
416 | 0, 0x00b8, { 0x08, 0x00, 0x42 }, 0 }, |
417 | |
418 | { PCMCIA_VENDOR_NETGEAR, PCMCIA_PRODUCT_NETGEAR_FA411, |
419 | PCMCIA_CIS_INVALID, |
420 | 0, -1, { 0x00, 0x40, 0xf4 }, 0 }, |
421 | |
422 | { PCMCIA_VENDOR_INVALID, PCMCIA_PRODUCT_INVALID, |
423 | PCMCIA_CIS_DYNALINK_L10C, |
424 | 0, -1, { 0x00, 0x00, 0x00 }, 0 }, |
425 | |
426 | { PCMCIA_VENDOR_ALLIEDTELESIS, PCMCIA_PRODUCT_ALLIEDTELESIS_LA_PCM, |
427 | PCMCIA_CIS_INVALID, |
428 | 0, 0x0ff0, { 0x00, 0x00, 0xf4 }, 0 }, |
429 | |
430 | { PCMCIA_VENDOR_NEXTCOM, PCMCIA_PRODUCT_NEXTCOM_NEXTHAWK, |
431 | PCMCIA_CIS_INVALID, |
432 | 0, -1, { 0x00, 0x40, 0xb4 }, 0 }, |
433 | |
434 | { PCMCIA_VENDOR_BELKIN, PCMCIA_PRODUCT_BELKIN_F5D5020, |
435 | PCMCIA_CIS_BELKIN_F5D5020, |
436 | 0, -1, { 0x00, 0x30, 0xbd } , NE2000DVF_AX88190 }, |
437 | |
438 | #if 0 |
439 | /* the rest of these are stolen from the linux pcnet pcmcia device |
440 | driver. Since I don't know the manfid or cis info strings for |
441 | any of them, they're not compiled in until I do. */ |
442 | { "APEX MultiCard" , |
443 | 0x0000, 0x0000, NULL, NULL, 0, |
444 | 0x03f4, { 0x00, 0x20, 0xe5 }, 0 }, |
445 | { "ASANTE FriendlyNet" , |
446 | 0x0000, 0x0000, NULL, NULL, 0, |
447 | 0x4910, { 0x00, 0x00, 0x94 }, 0 }, |
448 | { "Danpex EN-6200P2" , |
449 | 0x0000, 0x0000, NULL, NULL, 0, |
450 | 0x0110, { 0x00, 0x40, 0xc7 }, 0 }, |
451 | { "DataTrek NetCard" , |
452 | 0x0000, 0x0000, NULL, NULL, 0, |
453 | 0x0ff0, { 0x00, 0x20, 0xe8 }, 0 }, |
454 | { "EP-210 Ethernet" , |
455 | 0x0000, 0x0000, NULL, NULL, 0, |
456 | 0x0110, { 0x00, 0x40, 0x33 }, 0 }, |
457 | { "ELECOM Laneed LD-CDWA" , |
458 | 0x0000, 0x0000, NULL, NULL, 0, |
459 | 0x00b8, { 0x08, 0x00, 0x42 }, 0 }, |
460 | { "Grey Cell GCS2220" , |
461 | 0x0000, 0x0000, NULL, NULL, 0, |
462 | 0x0000, { 0x00, 0x47, 0x43 }, 0 }, |
463 | { "Hypertec Ethernet" , |
464 | 0x0000, 0x0000, NULL, NULL, 0, |
465 | 0x01c0, { 0x00, 0x40, 0x4c }, 0 }, |
466 | { "IBM CCAE" , |
467 | 0x0000, 0x0000, NULL, NULL, 0, |
468 | 0x0ff0, { 0x08, 0x00, 0x5a }, 0 }, |
469 | { "IBM CCAE" , |
470 | 0x0000, 0x0000, NULL, NULL, 0, |
471 | 0x0ff0, { 0x00, 0x04, 0xac }, 0 }, |
472 | { "IBM CCAE" , |
473 | 0x0000, 0x0000, NULL, NULL, 0, |
474 | 0x0ff0, { 0x00, 0x06, 0x29 }, 0 }, |
475 | { "IBM FME" , |
476 | 0x0000, 0x0000, NULL, NULL, 0, |
477 | 0x0374, { 0x00, 0x04, 0xac }, 0 }, |
478 | { "IBM FME" , |
479 | 0x0000, 0x0000, NULL, NULL, 0, |
480 | 0x0374, { 0x08, 0x00, 0x5a }, 0 }, |
481 | { "Katron PE-520" , |
482 | 0x0000, 0x0000, NULL, NULL, 0, |
483 | 0x0110, { 0x00, 0x40, 0xf6 }, 0 }, |
484 | { "Kingston KNE-PCM/x" , |
485 | 0x0000, 0x0000, NULL, NULL, 0, |
486 | 0x0ff0, { 0x00, 0xc0, 0xf0 }, 0 }, |
487 | { "Kingston KNE-PCM/x" , |
488 | 0x0000, 0x0000, NULL, NULL, 0, |
489 | 0x0ff0, { 0xe2, 0x0c, 0x0f }, 0 }, |
490 | { "Longshine LCS-8534" , |
491 | 0x0000, 0x0000, NULL, NULL, 0, |
492 | 0x0000, { 0x08, 0x00, 0x00 }, 0 }, |
493 | { "Maxtech PCN2000" , |
494 | 0x0000, 0x0000, NULL, NULL, 0, |
495 | 0x5000, { 0x00, 0x00, 0xe8 }, 0 }, |
496 | { "NDC Instant-Link" , |
497 | 0x0000, 0x0000, NULL, NULL, 0, |
498 | 0x003a, { 0x00, 0x80, 0xc6 }, 0 }, |
499 | { "NE2000 Compatible" , |
500 | 0x0000, 0x0000, NULL, NULL, 0, |
501 | 0x0ff0, { 0x00, 0xa0, 0x0c }, 0 }, |
502 | { "Network General Sniffer" , |
503 | 0x0000, 0x0000, NULL, NULL, 0, |
504 | 0x0ff0, { 0x00, 0x00, 0x65 }, 0 }, |
505 | { "Panasonic VEL211" , |
506 | 0x0000, 0x0000, NULL, NULL, 0, |
507 | 0x0ff0, { 0x00, 0x80, 0x45 }, 0 }, |
508 | { "SCM Ethernet" , |
509 | 0x0000, 0x0000, NULL, NULL, 0, |
510 | 0x0ff0, { 0x00, 0x20, 0xcb }, 0 }, |
511 | { "Volktek NPL-402CT" , |
512 | 0x0000, 0x0000, NULL, NULL, 0, |
513 | 0x0060, { 0x00, 0x40, 0x05 }, 0 }, |
514 | #endif |
515 | }; |
516 | |
517 | #define NE2000_NDEVS (sizeof(ne2000devs) / sizeof(ne2000devs[0])) |
518 | |
519 | static const struct ne2000dev * |
520 | ne2000_match(struct pcmcia_card *card, int fct, int n) |
521 | { |
522 | size_t i; |
523 | |
524 | /* |
525 | * See if it matches by manufacturer & product. |
526 | */ |
527 | if (card->manufacturer == ne2000devs[n].manufacturer && |
528 | card->manufacturer != PCMCIA_VENDOR_INVALID && |
529 | card->product == ne2000devs[n].product && |
530 | card->product != PCMCIA_PRODUCT_INVALID) |
531 | goto match; |
532 | |
533 | /* |
534 | * Otherwise, try to match by CIS strings. |
535 | */ |
536 | for (i = 0; i < 2; i++) |
537 | if (card->cis1_info[i] == NULL || |
538 | ne2000devs[n].cis_info[i] == NULL || |
539 | strcmp(card->cis1_info[i], ne2000devs[n].cis_info[i]) != 0) |
540 | return (NULL); |
541 | |
542 | match: |
543 | /* |
544 | * Finally, see if function number matches. |
545 | */ |
546 | return (fct == ne2000devs[n].function ? &ne2000devs[n] : NULL); |
547 | } |
548 | |
549 | |
550 | int |
551 | ne_pcmcia_match(device_t parent, cfdata_t match, void *aux) |
552 | { |
553 | struct pcmcia_attach_args *pa = aux; |
554 | int i; |
555 | |
556 | for (i = 0; i < NE2000_NDEVS; i++) { |
557 | if (ne2000_match(pa->card, pa->pf->number, i)) |
558 | return (1); |
559 | } |
560 | |
561 | return (0); |
562 | } |
563 | |
564 | int |
565 | ne_pcmcia_validate_config(struct pcmcia_config_entry *cfe) |
566 | { |
567 | if (cfe->iftype != PCMCIA_IFTYPE_IO || |
568 | cfe->num_iospace < 1 || cfe->num_iospace > 2) |
569 | return (EINVAL); |
570 | /* Some cards have a memory space, but we don't use it. */ |
571 | cfe->num_memspace = 0; |
572 | return (0); |
573 | } |
574 | |
575 | void |
576 | ne_pcmcia_attach(device_t parent, device_t self, void *aux) |
577 | { |
578 | struct ne_pcmcia_softc *psc = device_private(self); |
579 | struct ne2000_softc *nsc = &psc->sc_ne2000; |
580 | struct dp8390_softc *dsc = &nsc->sc_dp8390; |
581 | struct pcmcia_attach_args *pa = aux; |
582 | struct pcmcia_config_entry *cfe; |
583 | const struct ne2000dev *ne_dev; |
584 | int i; |
585 | u_int8_t myea[6], *enaddr; |
586 | int error; |
587 | |
588 | aprint_naive("\n" ); |
589 | |
590 | dsc->sc_dev = self; |
591 | psc->sc_pf = pa->pf; |
592 | |
593 | error = pcmcia_function_configure(pa->pf, ne_pcmcia_validate_config); |
594 | if (error) { |
595 | aprint_error_dev(self, "configure failed, error=%d\n" , error); |
596 | return; |
597 | } |
598 | |
599 | cfe = pa->pf->cfe; |
600 | dsc->sc_regt = cfe->iospace[0].handle.iot; |
601 | dsc->sc_regh = cfe->iospace[0].handle.ioh; |
602 | |
603 | if (cfe->num_iospace == 1) { |
604 | nsc->sc_asict = dsc->sc_regt; |
605 | if (bus_space_subregion(dsc->sc_regt, dsc->sc_regh, |
606 | NE2000_ASIC_OFFSET, NE2000_ASIC_NPORTS, &nsc->sc_asich)) { |
607 | aprint_error_dev(self, |
608 | "can't get subregion for asic\n" ); |
609 | goto fail; |
610 | } |
611 | } else { |
612 | nsc->sc_asict = cfe->iospace[1].handle.iot; |
613 | nsc->sc_asich = cfe->iospace[1].handle.ioh; |
614 | } |
615 | |
616 | error = ne_pcmcia_enable(dsc); |
617 | if (error) |
618 | goto fail; |
619 | |
620 | /* Set up power management hooks. */ |
621 | dsc->sc_enable = ne_pcmcia_enable; |
622 | dsc->sc_disable = ne_pcmcia_disable; |
623 | |
624 | /* |
625 | * Read the station address from the board. |
626 | */ |
627 | i = 0; |
628 | again: |
629 | enaddr = NULL; /* Ask ASIC by default */ |
630 | for (; i < NE2000_NDEVS; i++) { |
631 | ne_dev = ne2000_match(pa->card, pa->pf->number, i); |
632 | if (ne_dev != NULL) { |
633 | if (ne_dev->enet_maddr >= 0) { |
634 | enaddr = ne_pcmcia_get_enaddr(psc, |
635 | ne_dev->enet_maddr, myea); |
636 | if (enaddr == NULL) |
637 | continue; |
638 | } |
639 | goto found; |
640 | } |
641 | } |
642 | aprint_error_dev(self, "can't match ethernet vendor code\n" ); |
643 | if (enaddr != NULL) |
644 | aprint_error_dev(self, |
645 | "ethernet vendor code %02x:%02x:%02x\n" , |
646 | enaddr[0], enaddr[1], enaddr[2]); |
647 | goto fail2; |
648 | |
649 | found: |
650 | if ((ne_dev->flags & NE2000DVF_DL10019) != 0) { |
651 | u_int8_t type; |
652 | |
653 | enaddr = ne_pcmcia_dl10019_get_enaddr(psc, myea); |
654 | if (enaddr == NULL) { |
655 | ++i; |
656 | goto again; |
657 | } |
658 | |
659 | dsc->sc_mediachange = dl10019_mediachange; |
660 | dsc->sc_mediastatus = dl10019_mediastatus; |
661 | dsc->init_card = dl10019_init_card; |
662 | dsc->stop_card = dl10019_stop_card; |
663 | dsc->sc_media_init = dl10019_media_init; |
664 | dsc->sc_media_fini = dl10019_media_fini; |
665 | |
666 | /* Determine if this is a DL10019 or a DL10022. */ |
667 | type = bus_space_read_1(nsc->sc_asict, nsc->sc_asich, 0x0f); |
668 | if (type == 0x91 || type == 0x99) { |
669 | nsc->sc_type = NE2000_TYPE_DL10022; |
670 | } else { |
671 | nsc->sc_type = NE2000_TYPE_DL10019; |
672 | } |
673 | } |
674 | |
675 | if ((ne_dev->flags & NE2000DVF_AX88190) != 0) { |
676 | u_int8_t test; |
677 | |
678 | /* XXX This is highly bogus. */ |
679 | if ((pa->pf->ccr_mask & (1 << PCMCIA_CCR_IOBASE0)) == 0) { |
680 | ++i; |
681 | goto again; |
682 | } |
683 | |
684 | dsc->sc_mediachange = ax88190_mediachange; |
685 | dsc->sc_mediastatus = ax88190_mediastatus; |
686 | dsc->init_card = ax88190_init_card; |
687 | dsc->stop_card = ax88190_stop_card; |
688 | dsc->sc_media_init = ax88190_media_init; |
689 | dsc->sc_media_fini = ax88190_media_fini; |
690 | |
691 | test = bus_space_read_1(nsc->sc_asict, nsc->sc_asich, 0x05); |
692 | if (test != 0) { |
693 | nsc->sc_type = NE2000_TYPE_AX88790; |
694 | } else { |
695 | nsc->sc_type = NE2000_TYPE_AX88190; |
696 | } |
697 | } |
698 | |
699 | if (enaddr != NULL && |
700 | ne_dev->enet_vendor[0] != 0xff) { |
701 | /* |
702 | * Make sure this is what we expect. |
703 | */ |
704 | if (enaddr[0] != ne_dev->enet_vendor[0] || |
705 | enaddr[1] != ne_dev->enet_vendor[1] || |
706 | enaddr[2] != ne_dev->enet_vendor[2]) { |
707 | ++i; |
708 | goto again; |
709 | } |
710 | } |
711 | |
712 | /* |
713 | * Check for a Realtek 8019. |
714 | */ |
715 | if (nsc->sc_type == NE2000_TYPE_UNKNOWN) { |
716 | bus_space_write_1(dsc->sc_regt, dsc->sc_regh, ED_P0_CR, |
717 | ED_CR_PAGE_0 | ED_CR_STP); |
718 | if (bus_space_read_1(dsc->sc_regt, dsc->sc_regh, |
719 | NERTL_RTL0_8019ID0) == RTL0_8019ID0 && |
720 | bus_space_read_1(dsc->sc_regt, dsc->sc_regh, |
721 | NERTL_RTL0_8019ID1) == RTL0_8019ID1) { |
722 | dsc->sc_mediachange = rtl80x9_mediachange; |
723 | dsc->sc_mediastatus = rtl80x9_mediastatus; |
724 | dsc->init_card = rtl80x9_init_card; |
725 | dsc->sc_media_init = rtl80x9_media_init; |
726 | } |
727 | } |
728 | |
729 | if (ne2000_attach(nsc, enaddr)) |
730 | goto fail2; |
731 | |
732 | if (!pmf_device_register(self, ne2000_suspend, ne2000_resume)) { |
733 | aprint_error_dev(self, "cannot set power mgmt handler\n" ); |
734 | } |
735 | /* pmf(9) power hooks */ |
736 | if (pmf_device_register(self, ne2000_suspend, ne2000_resume)) { |
737 | #if 0 /* XXX: notyet: if_stop is NULL! */ |
738 | pmf_class_network_register(self, &dsc->sc_ec.ec_if); |
739 | #endif |
740 | } else |
741 | aprint_error_dev(self, "unable to establish power handler\n" ); |
742 | |
743 | psc->sc_state = NE_PCMCIA_ATTACHED; |
744 | ne_pcmcia_disable(dsc); |
745 | return; |
746 | |
747 | fail2: |
748 | ne_pcmcia_disable(dsc); |
749 | fail: |
750 | pcmcia_function_unconfigure(pa->pf); |
751 | } |
752 | |
753 | int |
754 | ne_pcmcia_detach(device_t self, int flags) |
755 | { |
756 | struct ne_pcmcia_softc *psc = device_private(self); |
757 | struct pcmcia_function *pf = psc->sc_pf; |
758 | int error; |
759 | |
760 | if (psc->sc_state != NE_PCMCIA_ATTACHED) |
761 | return (0); |
762 | |
763 | pmf_device_deregister(self); |
764 | error = ne2000_detach(&psc->sc_ne2000, flags); |
765 | if (error) |
766 | return (error); |
767 | |
768 | pcmcia_function_unconfigure(pf); |
769 | |
770 | return (0); |
771 | } |
772 | |
773 | int |
774 | ne_pcmcia_enable(struct dp8390_softc *dsc) |
775 | { |
776 | struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc; |
777 | int error; |
778 | |
779 | /* set up the interrupt */ |
780 | psc->sc_ih = pcmcia_intr_establish(psc->sc_pf, IPL_NET, dp8390_intr, |
781 | dsc); |
782 | if (!psc->sc_ih) |
783 | return (EIO); |
784 | |
785 | error = pcmcia_function_enable(psc->sc_pf); |
786 | if (error) { |
787 | pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); |
788 | psc->sc_ih = 0; |
789 | } |
790 | |
791 | return (error); |
792 | } |
793 | |
794 | void |
795 | ne_pcmcia_disable(struct dp8390_softc *dsc) |
796 | { |
797 | struct ne_pcmcia_softc *psc = (struct ne_pcmcia_softc *)dsc; |
798 | |
799 | pcmcia_function_disable(psc->sc_pf); |
800 | pcmcia_intr_disestablish(psc->sc_pf, psc->sc_ih); |
801 | psc->sc_ih = 0; |
802 | } |
803 | |
804 | u_int8_t * |
805 | ne_pcmcia_get_enaddr(struct ne_pcmcia_softc *psc, int maddr, |
806 | u_int8_t myea[ETHER_ADDR_LEN]) |
807 | { |
808 | struct ne2000_softc *nsc = &psc->sc_ne2000; |
809 | struct dp8390_softc *dsc = &nsc->sc_dp8390; |
810 | struct pcmcia_mem_handle pcmh; |
811 | bus_size_t offset; |
812 | u_int8_t *enaddr = NULL; |
813 | int j, mwindow; |
814 | |
815 | if (maddr < 0) |
816 | return (NULL); |
817 | |
818 | if (pcmcia_mem_alloc(psc->sc_pf, ETHER_ADDR_LEN * 2, &pcmh)) { |
819 | aprint_error_dev(dsc->sc_dev, |
820 | "can't alloc mem for enet addr\n" ); |
821 | goto fail_1; |
822 | } |
823 | if (pcmcia_mem_map(psc->sc_pf, PCMCIA_MEM_ATTR, maddr, |
824 | ETHER_ADDR_LEN * 2, &pcmh, &offset, &mwindow)) { |
825 | aprint_error_dev(dsc->sc_dev, "can't map mem for enet addr\n" ); |
826 | goto fail_2; |
827 | } |
828 | for (j = 0; j < ETHER_ADDR_LEN; j++) |
829 | myea[j] = bus_space_read_1(pcmh.memt, pcmh.memh, |
830 | offset + (j * 2)); |
831 | enaddr = myea; |
832 | |
833 | pcmcia_mem_unmap(psc->sc_pf, mwindow); |
834 | fail_2: |
835 | pcmcia_mem_free(psc->sc_pf, &pcmh); |
836 | fail_1: |
837 | return (enaddr); |
838 | } |
839 | |
840 | u_int8_t * |
841 | ne_pcmcia_dl10019_get_enaddr(struct ne_pcmcia_softc *psc, |
842 | u_int8_t myea[ETHER_ADDR_LEN]) |
843 | { |
844 | struct ne2000_softc *nsc = &psc->sc_ne2000; |
845 | u_int8_t sum; |
846 | int j; |
847 | |
848 | #define PAR0 0x04 |
849 | for (j = 0, sum = 0; j < 8; j++) |
850 | sum += bus_space_read_1(nsc->sc_asict, nsc->sc_asich, |
851 | PAR0 + j); |
852 | if (sum != 0xff) |
853 | return (NULL); |
854 | for (j = 0; j < ETHER_ADDR_LEN; j++) |
855 | myea[j] = bus_space_read_1(nsc->sc_asict, |
856 | nsc->sc_asich, PAR0 + j); |
857 | #undef PAR0 |
858 | return (myea); |
859 | } |
860 | |