if_xe_pccard.c revision 128068
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 128068 2004-04-09 17:27:36Z 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 * Debug logging levels - set with hw.xe.debug sysctl 60 * 0 = None 61 * 1 = More hardware details, probe/attach progress 62 * 2 = Most function calls, ioctls and media selection progress 63 * 3 = Everything - interrupts, packets in/out and multicast address setup 64 */ 65#define XE_DEBUG 66#ifdef XE_DEBUG 67 68extern int xe_debug; 69 70#define DEVPRINTF(level, arg) if (xe_debug >= (level)) device_printf arg 71#define DPRINTF(level, arg) if (xe_debug >= (level)) printf arg 72#else 73#define DEVPRINTF(level, arg) 74#define DPRINTF(level, arg) 75#endif 76 77 78#define XE_CARD_TYPE_FLAGS_NO 0x0 79#define XE_CARD_TYPE_FLAGS_CE2 0x1 80#define XE_CARD_TYPE_FLAGS_MOHAWK 0x2 81#define XE_CARD_TYPE_FLAGS_DINGO 0x4 82#define XE_PROD_ETHER_MASK 0x0100 83#define XE_PROD_MODEM_MASK 0x1000 84 85 86struct xe_pccard_product { 87 struct pccard_product product; 88 u_int16_t prodext; 89 u_int16_t flags; 90}; 91 92static const struct xe_pccard_product xe_pccard_products[] = { 93 { PCMCIA_CARD_D(ACCTON, EN2226, 0), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 94 { PCMCIA_CARD_D(COMPAQ2, CPQ_10_100, 0), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 95 { PCMCIA_CARD_D(INTEL, EEPRO100, 0), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 96 { PCMCIA_CARD_D(XIRCOM, CE, 0), 0x41, XE_CARD_TYPE_FLAGS_NO }, 97 { PCMCIA_CARD_D(XIRCOM, CE2, 0), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, 98 { PCMCIA_CARD_D(XIRCOM, CE2, 0), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 99 { PCMCIA_CARD_D(XIRCOM, CE2_2, 0), 0x41, XE_CARD_TYPE_FLAGS_CE2 }, 100 { PCMCIA_CARD_D(XIRCOM, CE2_2, 0), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 101 { PCMCIA_CARD_D(XIRCOM, CE3, 0), 0x43, XE_CARD_TYPE_FLAGS_MOHAWK }, 102 { PCMCIA_CARD_D(XIRCOM, CEM, 0), 0x41, XE_CARD_TYPE_FLAGS_NO }, 103 { PCMCIA_CARD_D(XIRCOM, CEM2, 0), 0x42, XE_CARD_TYPE_FLAGS_CE2 }, 104 { PCMCIA_CARD_D(XIRCOM, CEM28, 0), 0x43, XE_CARD_TYPE_FLAGS_CE2 }, 105 { PCMCIA_CARD_D(XIRCOM, CEM33, 0), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, 106 { PCMCIA_CARD_D(XIRCOM, CEM33_2, 0), 0x44, XE_CARD_TYPE_FLAGS_CE2 }, 107 { PCMCIA_CARD_D(XIRCOM, CEM56, 0), 0x45, XE_CARD_TYPE_FLAGS_DINGO }, 108 { PCMCIA_CARD_D(XIRCOM, CEM56_2, 0), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, 109 { PCMCIA_CARD_D(XIRCOM, REM56, 0), 0x46, XE_CARD_TYPE_FLAGS_DINGO }, 110 { PCMCIA_CARD_D(XIRCOM, REM10, 0), 0x47, XE_CARD_TYPE_FLAGS_DINGO }, 111 { PCMCIA_CARD_D(XIRCOM, XEM5600, 0), 0x56, XE_CARD_TYPE_FLAGS_DINGO }, 112 { { NULL }, 0, 0 } 113}; 114 115 116/* 117 * Fixing for CEM2, CEM3 and CEM56/REM56 cards. These need some magic to 118 * enable the Ethernet function, which isn't mentioned anywhere in the CIS. 119 * Despite the register names, most of this isn't Dingo-specific. 120 */ 121static int 122xe_cemfix(device_t dev) 123{ 124 struct xe_softc *sc = (struct xe_softc *) device_get_softc(dev); 125 bus_space_tag_t bst; 126 bus_space_handle_t bsh; 127 struct resource *r; 128 int rid; 129 int ioport; 130 131 DEVPRINTF(2, (dev, "cemfix\n")); 132 133 DEVPRINTF(1, (dev, "CEM I/O port 0x%0lx, size 0x%0lx\n", 134 bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid), 135 bus_get_resource_count(dev, SYS_RES_IOPORT, sc->port_rid))); 136 137 rid = 0; 138 r = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, 0, 139 ~0, 4 << 10, RF_ACTIVE); 140 if (!r) { 141 device_printf(dev, "cemfix: Can't map in attribute memory\n"); 142 return (-1); 143 } 144 145 bsh = rman_get_bushandle(r); 146 bst = rman_get_bustag(r); 147 148 CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, rid, 149 PCCARD_A_MEM_ATTR); 150 151 bus_space_write_1(bst, bsh, DINGO_ECOR, DINGO_ECOR_IRQ_LEVEL | 152 DINGO_ECOR_INT_ENABLE | 153 DINGO_ECOR_IOB_ENABLE | 154 DINGO_ECOR_ETH_ENABLE); 155 ioport = bus_get_resource_start(dev, SYS_RES_IOPORT, sc->port_rid); 156 bus_space_write_1(bst, bsh, DINGO_EBAR0, ioport & 0xff); 157 bus_space_write_1(bst, bsh, DINGO_EBAR1, (ioport >> 8) & 0xff); 158 159 if (sc->dingo) { 160 bus_space_write_1(bst, bsh, DINGO_DCOR0, DINGO_DCOR0_SF_INT); 161 bus_space_write_1(bst, bsh, DINGO_DCOR1, DINGO_DCOR1_INT_LEVEL | 162 DINGO_DCOR1_EEDIO); 163 bus_space_write_1(bst, bsh, DINGO_DCOR2, 0x00); 164 bus_space_write_1(bst, bsh, DINGO_DCOR3, 0x00); 165 bus_space_write_1(bst, bsh, DINGO_DCOR4, 0x00); 166 } 167 168 bus_release_resource(dev, SYS_RES_MEMORY, rid, r); 169 170 /* success! */ 171 return (0); 172} 173 174/* 175 * PCMCIA probe routine. 176 * Identify the device. Called from the bus driver when the card is 177 * inserted or otherwise powers up. 178 */ 179static int 180xe_pccard_probe(device_t dev) 181{ 182 struct xe_softc *scp = (struct xe_softc *) device_get_softc(dev); 183 u_int32_t vendor,product; 184 u_int16_t prodext; 185 const char* vendor_str = NULL; 186 const char* product_str = NULL; 187 const char* cis4_str = NULL; 188 const char *cis3_str=NULL; 189 const struct xe_pccard_product *xpp; 190 191 DEVPRINTF(2, (dev, "pccard_probe\n")); 192 193 pccard_get_vendor(dev, &vendor); 194 pccard_get_product(dev, &product); 195 pccard_get_prodext(dev, &prodext); 196 pccard_get_vendor_str(dev, &vendor_str); 197 pccard_get_product_str(dev, &product_str); 198 pccard_get_cis3_str(dev, &cis3_str); 199 pccard_get_cis4_str(dev, &cis4_str); 200 201 DEVPRINTF(1, (dev, "vendor = 0x%04x\n", vendor)); 202 DEVPRINTF(1, (dev, "product = 0x%04x\n", product)); 203 DEVPRINTF(1, (dev, "prodext = 0x%02x\n", prodext)); 204 DEVPRINTF(1, (dev, "vendor_str = %s\n", vendor_str)); 205 DEVPRINTF(1, (dev, "product_str = %s\n", product_str)); 206 DEVPRINTF(1, (dev, "cis3_str = %s\n", cis3_str)); 207 DEVPRINTF(1, (dev, "cis4_str = %s\n", cis4_str)); 208 209 210 /* 211 * Possibly already did this search in xe_pccard_match(), 212 * but we need to do it here anyway to figure out which 213 * card we have. 214 */ 215 for (xpp = xe_pccard_products; xpp->product.pp_vendor != 0; xpp++) { 216 if (vendor == xpp->product.pp_vendor && 217 product == xpp->product.pp_product && 218 prodext == xpp->prodext) 219 break; 220 } 221 222 /* Found a match? */ 223 if (xpp->product.pp_vendor == 0) 224 return (ENODEV); 225 226 227 /* Set card name for logging later */ 228 if (xpp->product.pp_name != NULL) 229 device_set_desc(dev, xpp->product.pp_name); 230 231 /* Reject known but unsupported cards */ 232 if (xpp->flags & XE_CARD_TYPE_FLAGS_NO) { 233 device_printf(dev, "Sorry, your %s %s card is not supported :(\n", 234 vendor_str, product_str); 235 return (ENODEV); 236 } 237 238 /* Set various card ID fields in softc */ 239 scp->vendor = vendor_str; 240 scp->card_type = product_str; 241 if (xpp->flags & XE_CARD_TYPE_FLAGS_CE2) 242 scp->ce2 = 1; 243 if (xpp->flags & XE_CARD_TYPE_FLAGS_MOHAWK) 244 scp->mohawk = 1; 245 if (xpp->flags & XE_CARD_TYPE_FLAGS_DINGO) { 246 scp->dingo = 1; 247 scp->mohawk = 1; 248 } 249 if (xpp->product.pp_product & XE_PROD_MODEM_MASK) 250 scp->modem = 1; 251 252 /* Get MAC address */ 253 pccard_get_ether(dev, scp->arpcom.ac_enaddr); 254 255 /* Success */ 256 return (0); 257} 258 259/* 260 * Attach a device. 261 */ 262static int 263xe_pccard_attach(device_t dev) 264{ 265 struct xe_softc *scp = device_get_softc(dev); 266 int err; 267 268 DEVPRINTF(2, (dev, "pccard_attach\n")); 269 270 if ((err = xe_activate(dev)) != 0) 271 return (err); 272 273 /* Hack RealPorts into submission */ 274 if (scp->modem && xe_cemfix(dev) < 0) { 275 device_printf(dev, "Unable to fix your %s %s combo card\n", 276 scp->vendor, scp->card_type); 277 xe_deactivate(dev); 278 return (ENODEV); 279 } 280 if ((err = xe_attach(dev))) { 281 device_printf(dev, "xe_attach() failed! (%d)\n", err); 282 return (err); 283 } 284 return (0); 285} 286 287/* 288 * The device entry is being removed, probably because someone ejected the 289 * card. The interface should have been brought down manually before calling 290 * this function; if not you may well lose packets. In any case, I shut down 291 * the card and the interface, and hope for the best. 292 */ 293static int 294xe_pccard_detach(device_t dev) 295{ 296 struct xe_softc *sc = device_get_softc(dev); 297 298 DEVPRINTF(2, (dev, "pccard_detach\n")); 299 300 sc->arpcom.ac_if.if_flags &= ~IFF_RUNNING; 301 ether_ifdetach(&sc->arpcom.ac_if); 302 xe_deactivate(dev); 303 return (0); 304} 305 306static int 307xe_pccard_product_match(device_t dev, const struct pccard_product* ent, int vpfmatch) 308{ 309 const struct xe_pccard_product* xpp; 310 u_int16_t prodext; 311 312 DEVPRINTF(2, (dev, "pccard_product_match\n")); 313 314 xpp = (const struct xe_pccard_product*)ent; 315 pccard_get_prodext(dev, &prodext); 316 317 if (xpp->prodext != prodext) 318 vpfmatch--; 319 320 return (vpfmatch); 321} 322 323static int 324xe_pccard_match(device_t dev) 325{ 326 const struct pccard_product *pp; 327 328 DEVPRINTF(2, (dev, "pccard_match\n")); 329 330 pp = (const struct pccard_product*)xe_pccard_products; 331 332 if ((pp = pccard_product_lookup(dev, pp, 333 sizeof(xe_pccard_products[0]), xe_pccard_product_match)) != NULL) 334 return (0); 335 336 return (EIO); 337} 338 339static device_method_t xe_pccard_methods[] = { 340 /* Device interface */ 341 DEVMETHOD(device_probe, pccard_compat_probe), 342 DEVMETHOD(device_attach, pccard_compat_attach), 343 DEVMETHOD(device_detach, xe_pccard_detach), 344 345 /* Card interface */ 346 DEVMETHOD(card_compat_match, xe_pccard_match), 347 DEVMETHOD(card_compat_probe, xe_pccard_probe), 348 DEVMETHOD(card_compat_attach, xe_pccard_attach), 349 350 { 0, 0 } 351}; 352 353static driver_t xe_pccard_driver = { 354 "xe", 355 xe_pccard_methods, 356 sizeof(struct xe_softc), 357}; 358 359devclass_t xe_devclass; 360 361DRIVER_MODULE(xe, pccard, xe_pccard_driver, xe_devclass, 0, 0); 362