Sync with FreeBSD dev/xe
[dragonfly.git] / sys / dev / netif / xe / if_xe_pccard.c
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  *
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 $
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
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
65 static 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
82 struct 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
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  
111
112 struct 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
132 static struct xe_vendor         *xe_vendor_lookup       (uint32_t);
133 static struct xe_card_type      *xe_card_type_lookup    (uint32_t);
134
135 static int      xe_cemfix       (device_t);
136 static int      xe_pccard_probe (device_t);
137 static int      xe_pccard_match (device_t);
138 static int      xe_pccard_attach(device_t);
139
140 static 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
154 static driver_t xe_pccard_driver = {
155         "xe",
156         xe_pccard_methods,
157         sizeof(struct xe_softc),
158 };
159
160 devclass_t xe_devclass;
161 DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0);
162
163 /*
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.
167  */
168 static int
169 xe_cemfix(device_t dev)
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
178         device_printf(dev, "CEM I/O port 0x%0lx, size 0x%0lx\n",
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
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         }
212
213         bus_release_resource(dev, SYS_RES_MEMORY, rid, r);
214
215         /* success! */
216         return 0;
217 }
218
219 static struct xe_vendor *
220 xe_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       
231 static struct xe_card_type *
232 xe_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  */
248 static int
249 xe_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
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
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)
336                 if (cis3_str != NULL && strcmp(cis3_str, "PS-CE2-10") == 0)
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
357 static int
358 xe_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 */
367         if (scp->modem && xe_cemfix(dev) < 0) {
368                 device_printf(dev, "Unable to fix your %s combo card\n",
369                               scp->card_type);
370                 xe_deactivate(dev);
371                 return ENODEV;
372         }
373         return xe_attach(dev);
374 }
375
376 static int
377 xe_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 }