if_xe_pccard.c revision 121916
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 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/dev/xe/if_xe_pccard.c 121916 2003-11-02 23:29:33Z rsm $"); 29 30/* xe pccard interface driver */ 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 51#include <dev/xe/if_xereg.h> 52#include <dev/xe/if_xevar.h> 53 54#include <dev/pccard/pccardvar.h> 55#include <dev/pccard/pccarddevs.h> 56#include "card_if.h" 57 58/* 59 * Set XE_DEBUG to enable debug messages 60 * Larger values increase verbosity 61 */ 62#define XE_DEBUG 0 63 64struct xe_vendor_table { 65 u_int32_t vendor_id; 66 char *vendor_desc; 67} xe_vendor_devs[] = { 68 { PCMCIA_VENDOR_XIRCOM, "Xircom" }, 69 { PCMCIA_VENDOR_COMPAQ, "Compaq" }, 70 { PCMCIA_VENDOR_COMPAQ2, "Compaq" }, /* Maybe Paralon Techologies, Inc */ 71 { PCMCIA_VENDOR_INTEL, "Intel" }, 72 { 0, "Unknown" } 73}; 74 75#define XE_CARD_TYPE_FLAGS_NO 0x0 76#define XE_CARD_TYPE_FLAGS_CE2 0x1 77#define XE_CARD_TYPE_FLAGS_MOHAWK 0x2 78#define XE_CARD_TYPE_FLAGS_DINGO 0x4 79#define XE_PROD_UMASK 0x11000f 80#define XE_PROD_ETHER_UMASK 0x010000 81#define XE_PROD_MODEM_UMASK 0x100000 82#define XE_PROD_SINGLE_ID1 0x010001 83#define XE_PROD_SINGLE_ID2 0x010002 84#define XE_PROD_SINGLE_ID3 0x010003 85#define XE_PROD_MULTI_ID1 0x110001 86#define XE_PROD_MULTI_ID2 0x110002 87#define XE_PROD_MULTI_ID3 0x110003 88#define XE_PROD_MULTI_ID4 0x110004 89#define XE_PROD_MULTI_ID5 0x110005 90#define XE_PROD_MULTI_ID6 0x110006 91#define XE_PROD_MULTI_ID7 0x110007 92 93struct xe_card_type_table { 94 u_int32_t prod_type; 95 char *card_type_desc; 96 u_int32_t flags; 97} xe_card_type_devs[] = { 98 { XE_PROD_MULTI_ID1, "CEM", XE_CARD_TYPE_FLAGS_NO }, 99 { XE_PROD_MULTI_ID2, "CEM2", XE_CARD_TYPE_FLAGS_CE2 }, 100 { XE_PROD_MULTI_ID3, "CEM3", XE_CARD_TYPE_FLAGS_CE2 }, 101 { XE_PROD_MULTI_ID4, "CEM33", XE_CARD_TYPE_FLAGS_CE2 }, 102 { XE_PROD_MULTI_ID5, "CEM56M", XE_CARD_TYPE_FLAGS_MOHAWK }, 103 { XE_PROD_MULTI_ID6, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK | 104 XE_CARD_TYPE_FLAGS_DINGO }, 105 { XE_PROD_MULTI_ID7, "CEM56", XE_CARD_TYPE_FLAGS_MOHAWK | 106 XE_CARD_TYPE_FLAGS_DINGO }, 107 { XE_PROD_SINGLE_ID1, "CE", XE_CARD_TYPE_FLAGS_NO }, 108 { XE_PROD_SINGLE_ID2, "CE2", XE_CARD_TYPE_FLAGS_CE2 }, 109 { XE_PROD_SINGLE_ID3, "CE3", XE_CARD_TYPE_FLAGS_MOHAWK }, 110 { 0, NULL, -1 } 111}; 112 113/* 114 * Prototypes 115 */ 116static int xe_cemfix(device_t dev); 117static struct xe_vendor_table *xe_vendor_lookup(u_int32_t devid, 118 struct xe_vendor_table *tbl); 119static struct xe_card_type_table *xe_card_type_lookup(u_int32_t devid, 120 struct xe_card_type_table *tbl); 121 122/* 123 * Fixing for CEM2, CEM3 and CEM56/REM56 cards. These need some magic to 124 * enable the Ethernet function, which isn't mentioned anywhere in the CIS. 125 * Despite the register names, most of this isn't Dingo-specific. 126 */ 127static int 128xe_cemfix(device_t dev) 129{ 130 struct xe_softc *sc = (struct xe_softc *) device_get_softc(dev); 131 bus_space_tag_t bst; 132 bus_space_handle_t bsh; 133 struct resource *r; 134 int rid; 135 int ioport; 136 137#if XE_DEBUG > 1 138 device_printf(dev, "cemfix\n"); 139#endif 140 141 device_printf(dev, "CEM I/O port 0x%0lx, size 0x%0lx\n", 142 bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), 143 bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid)); 144 145 rid = 0; 146 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 147 ~0, 4 << 10, RF_ACTIVE); 148 if (!r) { 149 device_printf(dev, "Can't map in attribute memory\n"); 150 return (-1); 151 } 152 153 bsh = rman_get_bushandle(r); 154 bst = rman_get_bustag(r); 155 156 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, rid, 157 PCCARD_A_MEM_ATTR); 158 159 bus_space_write_1(bst, bsh, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL | 160 DINGO_ECOR_INT_ENABLE | 161 DINGO_ECOR_IOB_ENABLE | 162 DINGO_ECOR_ETH_ENABLE); 163 ioport = bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid); 164 bus_space_write_1(bst, bsh, DINGO_EBAR0, ioport & 0xff); 165 bus_space_write_1(bst, bsh, DINGO_EBAR1, (ioport >> 8) & 0xff); 166 167 if (sc->dingo) { 168 bus_space_write_1(bst, bsh, DINGO_DCOR0, DINGO_DCOR0_SF_INT); 169 bus_space_write_1(bst, bsh, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL | 170 DINGO_DCOR1_EEDIO); 171 bus_space_write_1(bst, bsh, DINGO_DCOR2, 0x00); 172 bus_space_write_1(bst, bsh, DINGO_DCOR3, 0x00); 173 bus_space_write_1(bst, bsh, DINGO_DCOR4, 0x00); 174 } 175 176 bus_release_resource(dev, SYS_RES_MEMORY, rid, r); 177 178 /* success! */ 179 return (0); 180} 181 182static struct xe_vendor_table * 183xe_vendor_lookup(u_int32_t devid, struct xe_vendor_table *tbl) 184{ 185 while(tbl->vendor_id) { 186 if(tbl->vendor_id == devid) 187 return (tbl); 188 tbl++; 189 } 190 return (tbl); /* return Unknown */ 191} 192 193static struct xe_card_type_table * 194xe_card_type_lookup(u_int32_t devid, struct xe_card_type_table *tbl) 195{ 196 while(tbl->prod_type) { 197 if(tbl->prod_type == (devid & XE_PROD_UMASK)) 198 return (tbl); 199 tbl++; 200 } 201 return (NULL); 202} 203 204/* 205 * PCMCIA probe routine. 206 * Identify the device. Called from the bus driver when the card is 207 * inserted or otherwise powers up. 208 */ 209static int 210xe_pccard_probe(device_t dev) 211{ 212 struct xe_softc *scp = (struct xe_softc *) device_get_softc(dev); 213 u_int32_t vendor,prodid,prod; 214 u_int16_t prodext; 215 const char *cis3_str=NULL; 216 struct xe_vendor_table *vendor_itm; 217 struct xe_card_type_table *card_itm; 218 int i; 219 220#if XE_DEBUG > 1 221 const char* vendor_str = NULL; 222 const char* product_str = NULL; 223 const char* cis4_str = NULL; 224 device_printf(dev, "pccard_probe\n"); 225 pccard_get_vendor(dev, &vendor); 226 pccard_get_product(dev, &prodid); 227 pccard_get_prodext(dev, &prodext); 228 pccard_get_vendor_str(dev, &vendor_str); 229 pccard_get_product_str(dev, &product_str); 230 pccard_get_cis3_str(dev, &cis3_str); 231 pccard_get_cis4_str(dev, &cis4_str); 232 device_printf(dev, "vendor = 0x%04x\n", vendor); 233 device_printf(dev, "product = 0x%04x\n", prodid); 234 device_printf(dev, "prodext = 0x%02x\n", prodext); 235 device_printf(dev, "vendor_str = %s\n", vendor_str); 236 device_printf(dev, "product_str = %s\n", product_str); 237 device_printf(dev, "cis3_str = %s\n", cis3_str); 238 device_printf(dev, "cis4_str = %s\n", cis4_str); 239#endif 240 241 /* 242 * PCCARD_CISTPL_MANFID = 0x20 243 */ 244 pccard_get_vendor(dev, &vendor); 245 vendor_itm = xe_vendor_lookup(vendor, &xe_vendor_devs[0]); 246 if (vendor_itm == NULL) 247 return (ENODEV); 248 scp->vendor = vendor_itm->vendor_desc; 249 pccard_get_product(dev, &prodid); 250 pccard_get_prodext(dev, &prodext); 251 /* 252 * prod(new) = rev, media, prod(old) 253 * prod(new) = (don't care), (care 0x10 bit), (care 0x0f bit) 254 */ 255 prod = (prodid << 8) | prodext; 256 card_itm = xe_card_type_lookup(prod, &xe_card_type_devs[0]); 257 if (card_itm == NULL) 258 return (ENODEV); 259 scp->card_type = card_itm->card_type_desc; 260 if (card_itm->prod_type & XE_PROD_MODEM_UMASK) 261 scp->modem = 1; 262 for(i=1; i!=XE_CARD_TYPE_FLAGS_DINGO; i=i<<1) { 263 switch(i & card_itm->flags) { 264 case XE_CARD_TYPE_FLAGS_CE2: 265 scp->ce2 = 1; break; 266 case XE_CARD_TYPE_FLAGS_MOHAWK: 267 scp->mohawk = 1; break; 268 case XE_CARD_TYPE_FLAGS_DINGO: 269 scp->dingo = 1; break; 270 } 271 } 272 /* 273 * PCCARD_CISTPL_VERS_1 = 0x15 274 */ 275 pccard_get_cis3_str(dev, &cis3_str); 276 if (strcmp(scp->card_type, "CE") == 0) 277 if (cis3_str != NULL && strcmp(cis3_str, "PS-CE2-10") == 0) 278 scp->card_type = "CE2"; /* Look for "CE2" string */ 279 280 /* 281 * PCCARD_CISTPL_FUNCE = 0x22 282 */ 283 pccard_get_ether(dev, scp->arpcom.ac_enaddr); 284 285 /* Reject unsupported cards */ 286 if(strcmp(scp->card_type, "CE") == 0 287 || strcmp(scp->card_type, "CEM") == 0) { 288 device_printf(dev, "Sorry, your %s card is not supported :(\n", 289 scp->card_type); 290 return (ENODEV); 291 } 292 293 /* Success */ 294 return (0); 295} 296 297/* 298 * Attach a device. 299 */ 300static int 301xe_pccard_attach(device_t dev) 302{ 303 struct xe_softc *scp = device_get_softc(dev); 304 int err; 305 306#if XE_DEBUG > 1 307 device_printf(dev, "pccard_attach\n"); 308#endif 309 310 if ((err = xe_activate(dev)) != 0) 311 return (err); 312 313 /* Hack RealPorts into submission */ 314 if (scp->modem && xe_cemfix(dev) < 0) { 315 device_printf(dev, "Unable to fix your %s combo card\n", 316 scp->card_type); 317 xe_deactivate(dev); 318 return (ENODEV); 319 } 320 if ((err = xe_attach(dev))) { 321 device_printf(dev, "xe_attach() failed! (%d)\n", err); 322 return (err); 323 } 324 return (0); 325} 326 327/* 328 * The device entry is being removed, probably because someone ejected the 329 * card. The interface should have been brought down manually before calling 330 * this function; if not you may well lose packets. In any case, I shut down 331 * the card and the interface, and hope for the best. 332 */ 333static int 334xe_pccard_detach(device_t dev) 335{ 336 struct xe_softc *sc = device_get_softc(dev); 337 338#if XE_DEBUG > 1 339 device_printf(dev, "pccard_detach\n"); 340#endif 341 342 sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; 343 ether_ifdetach(&sc->arpcom.ac_if); 344 xe_deactivate(dev); 345 return (0); 346} 347 348static const struct pccard_product xe_pccard_products[] = { 349 PCMCIA_CARD(ACCTON, EN2226, 0), 350 PCMCIA_CARD(COMPAQ2, CPQ_10_100, 0), 351 PCMCIA_CARD(INTEL, EEPRO100, 0), 352 PCMCIA_CARD(XIRCOM, CE, 0), 353 PCMCIA_CARD(XIRCOM, CE2, 0), 354 PCMCIA_CARD(XIRCOM, CE3, 0), 355 PCMCIA_CARD(XIRCOM, CEM, 0), 356 PCMCIA_CARD(XIRCOM, CEM28, 0), 357 PCMCIA_CARD(XIRCOM, CEM33, 0), 358 PCMCIA_CARD(XIRCOM, CEM56, 0), 359 PCMCIA_CARD(XIRCOM, REM56, 0), 360 { NULL } 361}; 362 363static int 364xe_pccard_match(device_t dev) 365{ 366 const struct pccard_product *pp; 367 368#if XE_DEBUG > 1 369 device_printf(dev, "pccard_match\n"); 370#endif 371 372 if ((pp = pccard_product_lookup(dev, xe_pccard_products, 373 sizeof(xe_pccard_products[0]), NULL)) != NULL) { 374 if (pp->pp_name != NULL) 375 device_set_desc(dev, pp->pp_name); 376 return (0); 377 } 378 return (EIO); 379} 380 381static device_method_t xe_pccard_methods[] = { 382 /* Device interface */ 383 DEVMETHOD(device_probe, pccard_compat_probe), 384 DEVMETHOD(device_attach, pccard_compat_attach), 385 DEVMETHOD(device_detach, xe_pccard_detach), 386 387 /* Card interface */ 388 DEVMETHOD(card_compat_match, xe_pccard_match), 389 DEVMETHOD(card_compat_probe, xe_pccard_probe), 390 DEVMETHOD(card_compat_attach, xe_pccard_attach), 391 392 { 0, 0 } 393}; 394 395static driver_t xe_pccard_driver = { 396 "xe", 397 xe_pccard_methods, 398 sizeof(struct xe_softc), 399}; 400 401devclass_t xe_devclass; 402 403DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0); 404