Sync with FreeBSD dev/xe
[dragonfly.git] / sys / dev / netif / xe / if_xe_pccard.c
CommitLineData
f572e449
JS
1/*
2 * Copyright (c) 2002 Takeshi Shibagaki
3 * 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 * xe pccard interface driver
27 *
7261a835
SZ
28 * $FreeBSD: src/sys/dev/xe/if_xe_pccard.c,v 1.11 2003/10/14 22:51:35 rsm Exp $
29 * $DragonFly: src/sys/dev/netif/xe/if_xe_pccard.c,v 1.2 2005/11/20 10:16:56 sephe Exp $
f572e449
JS
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/kernel.h>
35#include <sys/socket.h>
36
37#include <sys/module.h>
38#include <sys/bus.h>
39
40#include <machine/bus.h>
41#include <machine/resource.h>
42#include <sys/rman.h>
43
44#include <net/ethernet.h>
45#include <net/if.h>
46#include <net/if_arp.h>
47#include <net/if_media.h>
48#include <net/if_mib.h>
49
50#include <bus/pccard/pccardvar.h>
51#include <bus/pccard/pccarddevs.h>
52#include "card_if.h"
53
54#include "if_xereg.h"
55#include "if_xevar.h"
56
7261a835
SZ
57#define XE_DEBUG
58
59#ifdef XE_DEBUG
60#define DEVPRINTF(level, arg) if (xe_debug >= (level)) device_printf arg
61#else
62#define DEVPRINTF(level, arg)
63#endif
64
f572e449
JS
65static const struct pccard_product xe_pccard_products[] = {
66 PCMCIA_CARD(ACCTON, EN2226, 0),
67 PCMCIA_CARD(COMPAQ2, CPQ_10_100, 0),
68 PCMCIA_CARD(INTEL, EEPRO100, 0),
69 PCMCIA_CARD(XIRCOM, CE, 0),
70 PCMCIA_CARD(XIRCOM, CE2, 0),
71 PCMCIA_CARD(XIRCOM, CE3, 0),
72 PCMCIA_CARD(XIRCOM, CEM, 0),
73 PCMCIA_CARD(XIRCOM, CEM28, 0),
74 PCMCIA_CARD(XIRCOM, CEM33, 0),
75 PCMCIA_CARD(XIRCOM, CEM56, 0),
76 PCMCIA_CARD(XIRCOM, REM56, 0),
77 PCMCIA_CARD(XIRCOM, CNW_801, 0),
78 PCMCIA_CARD(XIRCOM, CNW_802, 0),
79 { NULL }
80};
81
82struct xe_vendor {
83 uint32_t vendor_id;
84 const char *vendor_desc;
85} xe_vendors[] = {
86 { PCMCIA_VENDOR_XIRCOM, "Xircom" },
87 { PCMCIA_VENDOR_COMPAQ, "Compaq" },
88 { PCMCIA_VENDOR_COMPAQ2, "Compaq" },
89 { PCMCIA_VENDOR_INTEL, "Intel" },
90 { 0, "Unknown" }
91};
92
93#define XE_CARD_TYPE_FLAGS_NO 0x0
94#define XE_CARD_TYPE_FLAGS_CE2 0x1
95#define XE_CARD_TYPE_FLAGS_MOHAWK 0x2
96#define XE_CARD_TYPE_FLAGS_DINGO 0x4
97
7261a835
SZ
98#define XE_PROD_UMASK 0x11000f
99#define XE_PROD_ETHER_UMASK 0x010000
100#define XE_PROD_MODEM_UMASK 0x100000
101#define XE_PROD_SINGLE_ID1 0x010001
102#define XE_PROD_SINGLE_ID2 0x010002
103#define XE_PROD_SINGLE_ID3 0x010003
104#define XE_PROD_MULTI_ID1 0x110001
105#define XE_PROD_MULTI_ID2 0x110002
106#define XE_PROD_MULTI_ID3 0x110003
107#define XE_PROD_MULTI_ID4 0x110004
108#define XE_PROD_MULTI_ID5 0x110005
109#define XE_PROD_MULTI_ID6 0x110006
110#define XE_PROD_MULTI_ID7 0x110007
f572e449
JS
111
112struct xe_card_type {
113 uint32_t prod_type;
114 const char *card_type_desc;
115 uint32_t flags;
116} xe_card_types[] = {
117 { XE_PROD_MULTI_ID1, "CEM", XE_CARD_TYPE_FLAGS_NO },
118 { XE_PROD_MULTI_ID2, "CEM2", XE_CARD_TYPE_FLAGS_CE2 },
119 { XE_PROD_MULTI_ID3, "CEM3", XE_CARD_TYPE_FLAGS_CE2 },
120 { XE_PROD_MULTI_ID4, "CEM33", XE_CARD_TYPE_FLAGS_CE2 },
121 { XE_PROD_MULTI_ID5, "CEM56M", XE_CARD_TYPE_FLAGS_MOHAWK },
122 { XE_PROD_MULTI_ID6, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK |
123 XE_CARD_TYPE_FLAGS_DINGO },
124 { XE_PROD_MULTI_ID7, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK |
125 XE_CARD_TYPE_FLAGS_DINGO },
126 { XE_PROD_SINGLE_ID1, "CE", XE_CARD_TYPE_FLAGS_NO },
127 { XE_PROD_SINGLE_ID2, "CE2", XE_CARD_TYPE_FLAGS_CE2 },
128 { XE_PROD_SINGLE_ID3, "CE3", XE_CARD_TYPE_FLAGS_MOHAWK },
129 { 0, NULL, -1 }
130};
131
132static struct xe_vendor *xe_vendor_lookup (uint32_t);
133static struct xe_card_type *xe_card_type_lookup (uint32_t);
134
7261a835 135static int xe_cemfix (device_t);
f572e449
JS
136static int xe_pccard_probe (device_t);
137static int xe_pccard_match (device_t);
138static int xe_pccard_attach(device_t);
139
140static device_method_t xe_pccard_methods[] = {
141 /* Device interface */
142 DEVMETHOD(device_probe, pccard_compat_probe),
143 DEVMETHOD(device_attach, pccard_compat_attach),
144 DEVMETHOD(device_detach, xe_detach),
145
146 /* Card interface */
147 DEVMETHOD(card_compat_match, xe_pccard_match),
148 DEVMETHOD(card_compat_probe, xe_pccard_probe),
149 DEVMETHOD(card_compat_attach, xe_pccard_attach),
150
151 { 0, 0 }
152};
153
154static driver_t xe_pccard_driver = {
155 "xe",
156 xe_pccard_methods,
157 sizeof(struct xe_softc),
158};
159
160devclass_t xe_devclass;
161DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0);
162
163/*
7261a835
SZ
164 * Fixing for CEM2, CEM3 and CEM56/REM56 cards. These need some magic to
165 * enable the Ethernet function, which isn't mentioned anywhere in the CIS.
166 * Despite the register names, most of this isn't Dingo-specific.
f572e449
JS
167 */
168static int
7261a835 169xe_cemfix(device_t dev)
f572e449
JS
170{
171 struct xe_softc *sc = device_get_softc(dev);
172 bus_space_tag_t bst;
173 bus_space_handle_t bsh;
174 struct resource *r;
175 int rid;
176 int ioport;
177
7261a835 178 device_printf(dev, "CEM I/O port 0x%0lx, size 0x%0lx\n",
f572e449
JS
179 bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid),
180 bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid));
181
182 rid = 0;
183 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0,
184 ~0, 4 << 10, RF_ACTIVE);
185 if (r == NULL) {
186 device_printf(dev, "Can't map in attribute memory\n");
187 return -1;
188 }
189
190 bsh = rman_get_bushandle(r);
191 bst = rman_get_bustag(r);
192
193 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, rid,
194 PCCARD_A_MEM_ATTR);
195
196 bus_space_write_1(bst, bsh, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL |
197 DINGO_ECOR_INT_ENABLE |
198 DINGO_ECOR_IOB_ENABLE |
199 DINGO_ECOR_ETH_ENABLE);
200 ioport = bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid);
201 bus_space_write_1(bst, bsh, DINGO_EBAR0, ioport & 0xff);
202 bus_space_write_1(bst, bsh, DINGO_EBAR1, (ioport >> 8) & 0xff);
203
7261a835
SZ
204 if (sc->dingo) {
205 bus_space_write_1(bst, bsh, DINGO_DCOR0, DINGO_DCOR0_SF_INT);
206 bus_space_write_1(bst, bsh, DINGO_DCOR1,
207 DINGO_DCOR1_INT_LEVEL | DINGO_DCOR1_EEDIO);
208 bus_space_write_1(bst, bsh, DINGO_DCOR2, 0x00);
209 bus_space_write_1(bst, bsh, DINGO_DCOR3, 0x00);
210 bus_space_write_1(bst, bsh, DINGO_DCOR4, 0x00);
211 }
f572e449
JS
212
213 bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
214
215 /* success! */
216 return 0;
217}
218
219static struct xe_vendor *
220xe_vendor_lookup(uint32_t vendor_id)
221{
222 struct xe_vendor *v;
223
224 for (v = xe_vendors; v->vendor_id != 0; ++v) {
225 if(v->vendor_id == vendor_id)
226 break;
227 }
228 return v;
229}
230
231static struct xe_card_type *
232xe_card_type_lookup(uint32_t prod)
233{
234 struct xe_card_type *ct;
235
236 for (ct = xe_card_types; ct->card_type_desc != NULL; ++ct) {
237 if(ct->prod_type == (prod & XE_PROD_UMASK))
238 return ct;
239 }
240 return NULL;
241}
242
243/*
244 * PCMCIA probe routine.
245 * Identify the device. Called from the bus driver when the card is
246 * inserted or otherwise powers up.
247 */
248static int
249xe_pccard_probe(device_t dev)
250{
251 struct xe_softc *scp = device_get_softc(dev);
252 uint32_t vendor, product, prod;
253 uint16_t prodext;
254 uint8_t *ether_addr;
255 const char *cis3_str=NULL;
256 struct xe_vendor *vendor_itm;
257 struct xe_card_type *card_itm;
258 int i;
259
7261a835
SZ
260#ifdef XE_DEBUG
261 const char *vendor_str = NULL;
262 const char *product_str = NULL;
263 const char *cis4_str = NULL;
264
265 vendor = pccard_get_vendor(dev);
266 product = pccard_get_product(dev);
267 prodext = pccard_get_prodext(dev);
268 vendor_str = pccard_get_vendor_str(dev);
269 product_str = pccard_get_product_str(dev);
270 cis3_str = pccard_get_cis3_str(dev);
271 cis4_str = pccard_get_cis4_str(dev);
272
273 DEVPRINTF(1, (dev, "pccard_probe\n"));
274 DEVPRINTF(1, (dev, "vendor = 0x%04x\n", vendor));
275 DEVPRINTF(1, (dev, "product = 0x%04x\n", product));
276 DEVPRINTF(1, (dev, "prodext = 0x%02x\n", prodext));
277 DEVPRINTF(1, (dev, "vendor_str = %s\n",
278 vendor_str == NULL ? "NULL" : vendor_str));
279 DEVPRINTF(1, (dev, "product_str = %s\n",
280 product_str == NULL ? "NULL" : product_str));
281 DEVPRINTF(1, (dev, "cis3_str = %s\n",
282 cis3_str == NULL ? "NULL" : cis3_str));
283 DEVPRINTF(1, (dev, "cis4_str = %s\n",
284 cis4_str == NULL ? "NULL" : cis4_str));
285#endif
286
f572e449
JS
287 /*
288 * PCCARD_CISTPL_MANFID = 0x20
289 */
290 vendor = pccard_get_vendor(dev);
291 vendor_itm = xe_vendor_lookup(vendor);
292 /*
293 * We always have some vendor here, although
294 * vendor description may be "Unknown".
295 */
296 scp->vendor = vendor_itm->vendor_desc;
297
298 product = pccard_get_product(dev);
299 prodext = pccard_get_prodext(dev);
300
301 /*
302 * prod(new) = rev, media, prod(old)
303 * prod(new) = (don't care), (care 0x10 bit), (care 0x0f bit)
304 */
305 prod = (product << 8) | prodext;
306 card_itm = xe_card_type_lookup(prod);
307 if (card_itm == NULL)
308 return ENODEV;
309
310 scp->card_type = card_itm->card_type_desc;
311 if (card_itm->prod_type & XE_PROD_MODEM_UMASK)
312 scp->modem = 1;
313
314 for (i = 1; i != XE_CARD_TYPE_FLAGS_DINGO; i = i << 1) {
315 switch(i & card_itm->flags) {
316 case XE_CARD_TYPE_FLAGS_CE2:
317 scp->ce2 = 1;
318 break;
319 case XE_CARD_TYPE_FLAGS_MOHAWK:
320 scp->mohawk = 1;
321 break;
322 case XE_CARD_TYPE_FLAGS_DINGO:
323 scp->dingo = 1;
324 break;
325 }
326 }
327
328 /*
329 * PCCARD_CISTPL_VERS_1 = 0x15
330 *
331 * Check for certain strange CE2's that look like CE's:
332 * match 3rd version string against "CE2"
333 */
334 cis3_str = pccard_get_cis3_str(dev);
335 if (strcmp(scp->card_type, "CE") == 0)
7261a835 336 if (cis3_str != NULL && strcmp(cis3_str, "PS-CE2-10") == 0)
f572e449
JS
337 scp->card_type = "CE2";
338
339 /*
340 * PCCARD_CISTPL_FUNCE = 0x22
341 */
342 ether_addr = pccard_get_ether(dev);
343 bcopy(ether_addr, scp->arpcom.ac_enaddr, ETHER_ADDR_LEN);
344
345 /* Reject unsupported cards */
346 if (strcmp(scp->card_type, "CE") == 0 ||
347 strcmp(scp->card_type, "CEM") == 0) {
348 device_printf(dev, "Sorry, your %s card is not supported :(\n",
349 scp->card_type);
350 return ENODEV;
351 }
352
353 /* Success */
354 return 0;
355}
356
357static int
358xe_pccard_attach(device_t dev)
359{
360 struct xe_softc *scp = device_get_softc(dev);
361 int err;
362
363 if ((err = xe_activate(dev)) != 0)
364 return err;
365
366 /* Hack RealPorts into submission */
7261a835
SZ
367 if (scp->modem && xe_cemfix(dev) < 0) {
368 device_printf(dev, "Unable to fix your %s combo card\n",
369 scp->card_type);
f572e449
JS
370 xe_deactivate(dev);
371 return ENODEV;
372 }
373 return xe_attach(dev);
374}
375
376static int
377xe_pccard_match(device_t dev)
378{
379 const struct pccard_product *pp;
380
381 if ((pp = pccard_product_lookup(dev, xe_pccard_products,
382 sizeof(xe_pccard_products[0]), NULL)) != NULL) {
383 if (pp->pp_name != NULL)
384 device_set_desc(dev, pp->pp_name);
385 return 0;
386 }
387 return EIO;
388}