1117035Sgordon/*- 2117035Sgordon * Copyright (c) 1999 M. Warner Losh <imp@village.org> 3117035Sgordon * All rights reserved. 4156813Sru * 5156813Sru * Redistribution and use in source and binary forms, with or without 6156813Sru * modification, are permitted provided that the following conditions 7188895Sru * are met: 8156813Sru * 1. Redistributions of source code must retain the above copyright 9117035Sgordon * notice, this list of conditions and the following disclaimer. 10117692Sobrien * 2. Redistributions in binary form must reproduce the above copyright 11117035Sgordon * notice, this list of conditions and the following disclaimer in the 12117035Sgordon * documentation and/or other materials provided with the distribution. 13117035Sgordon * 14153455Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15117035Sgordon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16117035Sgordon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17117035Sgordon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18117035Sgordon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19147090Sbrooks * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20147090Sbrooks * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21147090Sbrooks * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22147090Sbrooks * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23147090Sbrooks * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24117035Sgordon */ 25215226Sadrian/* 26117035Sgordon * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) 27117035Sgordon * 28117035Sgordon * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 29117035Sgordon * BSD-nomads, Tokyo, Japan. 30117035Sgordon */ 31117035Sgordon 32117449Sgordon#include <sys/cdefs.h> 33117449Sgordon__FBSDID("$FreeBSD$"); 34117035Sgordon 35117035Sgordon#include <sys/param.h> 36117035Sgordon#include <sys/bus.h> 37117035Sgordon#include <sys/kernel.h> 38117035Sgordon#include <sys/module.h> 39117035Sgordon#include <sys/socket.h> 40117035Sgordon#include <sys/systm.h> 41117035Sgordon 42117035Sgordon#include <net/ethernet.h> 43117035Sgordon#include <net/if.h> 44117035Sgordon#include <net/if_arp.h> 45117035Sgordon 46117035Sgordon#include <machine/bus.h> 47117035Sgordon#include <machine/resource.h> 48117035Sgordon#include <sys/rman.h> 49117035Sgordon 50117035Sgordon#include <dev/pccard/pccardvar.h> 51117692Sobrien#include <dev/pccard/pccard_cis.h> 52117791Sobrien#include <dev/sn/if_snreg.h> 53182543Syar#include <dev/sn/if_snvar.h> 54183007Simp 55202755Sed#include "card_if.h" 56215226Sadrian#include "pccarddevs.h" 57117035Sgordon 58117035Sgordontypedef int sn_get_enaddr_t(device_t dev, u_char *eaddr); 59117035Sgordontypedef int sn_activate_t(device_t dev); 60117035Sgordon 61117035Sgordonstruct sn_sw 62117692Sobrien{ 63117035Sgordon int type; 64117035Sgordon#define SN_NORMAL 1 65117035Sgordon#define SN_MEGAHERTZ 2 66173073Syar#define SN_OSITECH 3 67173073Syar#define SN_OSI_SOD 4 68156813Sru#define SN_MOTO_MARINER 5 69117601Sgordon char *typestr; 70117035Sgordon sn_get_enaddr_t *get_mac; 71117035Sgordon sn_activate_t *activate; 72156813Sru}; 73117601Sgordon 74117035Sgordonstatic sn_get_enaddr_t sn_pccard_normal_get_mac; 75215226Sadrianstatic sn_activate_t sn_pccard_normal_activate; 76117692Sobrienconst static struct sn_sw sn_normal_sw = { 77117692Sobrien SN_NORMAL, "plain", 78117035Sgordon sn_pccard_normal_get_mac, 79117035Sgordon sn_pccard_normal_activate 80117035Sgordon}; 81117035Sgordon 82117035Sgordonstatic sn_get_enaddr_t sn_pccard_megahertz_get_mac; 83117035Sgordonstatic sn_activate_t sn_pccard_megahertz_activate; 84117035Sgordonconst static struct sn_sw sn_mhz_sw = { 85117035Sgordon SN_MEGAHERTZ, "Megahertz", 86117791Sobrien sn_pccard_megahertz_get_mac, 87117035Sgordon sn_pccard_megahertz_activate 88117035Sgordon}; 89117692Sobrien 90249083Smavstatic const struct sn_product { 91183007Simp struct pccard_product prod; 92133799Smarius const struct sn_sw *sw; 93173314Smarcel} sn_pccard_products[] = { 94183007Simp { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw }, 95183007Simp { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw }, 96241636Sattilio/* { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */ 97183007Simp { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw }, 98183007Simp { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw}, 99183007Simp { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw}, 100191227Skientzle/* { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */ 101117035Sgordon/* { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */ 102156813Sru/* { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */ 103171453Srwatson/* { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */ 104119664Sphk/* { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */ 105119664Sphk { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw }, 106156813Sru { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw }, 107119664Sphk { { NULL } } 108119664Sphk 109119664Sphk}; 110156813Sru 111145630Sdarrenrstatic const struct sn_product * 112117693Sobriensn_pccard_lookup(device_t dev) 113192617Skmacy{ 114192617Skmacy 115192617Skmacy return ((const struct sn_product *) 116192617Skmacy pccard_product_lookup(dev, 117117693Sobrien (const struct pccard_product *)sn_pccard_products, 118117035Sgordon sizeof(sn_pccard_products[0]), NULL)); 119117035Sgordon} 120117035Sgordon 121157177Scognetstatic int 122156905Srusn_pccard_probe(device_t dev) 123156905Sru{ 124156905Sru const struct sn_product *pp; 125192617Skmacy 126248571Smm if ((pp = sn_pccard_lookup(dev)) != NULL) { 127192617Skmacy if (pp->prod.pp_name != NULL) 128231642Srmh device_set_desc(dev, pp->prod.pp_name); 129117035Sgordon return 0; 130211725Simp } 131173314Smarcel return EIO; 132117057Sgordon} 133252356Sdavide 134252356Sdavidestatic int 135117035Sgordonsn_pccard_ascii_enaddr(const char *str, u_char *enet) 136117035Sgordon{ 137117035Sgordon uint8_t digit; 138173314Smarcel int i; 139117692Sobrien 140117035Sgordon memset(enet, 0, ETHER_ADDR_LEN); 141117035Sgordon for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 142211725Simp if (str[i] >= '0' && str[i] <= '9') 143173314Smarcel digit |= str[i] - '0'; 144117035Sgordon else if (str[i] >= 'a' && str[i] <= 'f') 145117035Sgordon digit |= (str[i] - 'a') + 10; 146211725Simp else if (str[i] >= 'A' && str[i] <= 'F') 147173314Smarcel digit |= (str[i] - 'A') + 10; 148117035Sgordon else 149117035Sgordon return (0); /* Bogus digit!! */ 150211725Simp 151173314Smarcel /* Compensate for ordering of digits. */ 152117057Sgordon if (i & 1) { 153117057Sgordon enet[i >> 1] = digit; 154117057Sgordon digit = 0; 155117692Sobrien } else 156118826Sharti digit <<= 4; 157117692Sobrien } 158117692Sobrien 159117692Sobrien return (1); 160145630Sdarrenr} 161192617Skmacy 162192617Skmacystatic int 163192617Skmacysn_pccard_normal_get_mac(device_t dev, u_char *eaddr) 164192617Skmacy{ 165117035Sgordon int i, sum; 166117692Sobrien const char *cisstr; 167117035Sgordon 168117692Sobrien pccard_get_ether(dev, eaddr); 169177707Sru for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 170117035Sgordon sum |= eaddr[i]; 171117035Sgordon if (sum == 0) { 172147090Sbrooks pccard_get_cis3_str(dev, &cisstr); 173147090Sbrooks if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 174117035Sgordon sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 175117035Sgordon } 176117035Sgordon if (sum == 0) { 177191227Skientzle pccard_get_cis4_str(dev, &cisstr); 178117692Sobrien if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 179117035Sgordon sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 180227531Sdes } 181173073Syar return sum; 182166255Sdelphij} 183117692Sobrien 184117035Sgordonstatic int 185117692Sobriensn_pccard_normal_activate(device_t dev) 186117692Sobrien{ 187117692Sobrien int err; 188117035Sgordon 189250626Sdelphij err = sn_activate(dev); 190250626Sdelphij if (err) 191250626Sdelphij sn_deactivate(dev); 192207849Smm return (err); 193207849Smm} 194207849Smm 195207849Smmstatic int 196138366Sobriensn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp) 197191239Skientzle{ 198191239Skientzle uint8_t *enaddr = argp; 199191239Skientzle int i; 200191239Skientzle uint8_t buffer[ETHER_ADDR_LEN * 2]; 201138366Sobrien 202117692Sobrien /* Code 0x81 is Megahertz' special cis node contianing the MAC */ 203117692Sobrien if (tuple->code != 0x81) 204117035Sgordon return (0); 205126874Sdes 206126874Sdes /* Make sure this is a sane node, as ASCII digits */ 207126874Sdes if (tuple->length != ETHER_ADDR_LEN * 2 + 1) 208117035Sgordon return (0); 209141478Sdes 210191227Skientzle /* Copy the MAC ADDR and return success if decoded */ 211141478Sdes for (i = 0; i < ETHER_ADDR_LEN * 2; i++) 212141478Sdes buffer[i] = pccard_tuple_read_1(tuple, i); 213173073Syar return (sn_pccard_ascii_enaddr(buffer, enaddr)); 214141478Sdes} 215173073Syar 216173073Syarstatic int 217192617Skmacysn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr) 218192617Skmacy{ 219173073Syar 220215226Sadrian if (sn_pccard_normal_get_mac(dev, eaddr)) 221117035Sgordon return 1; 222 /* 223 * If that fails, try the special CIS tuple 0x81 that the 224 * '3288 and '3336 cards have. That tuple specifies an ASCII 225 * string, ala CIS3 or CIS4 in the 'normal' cards. 226 */ 227 return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr)); 228} 229 230static int 231sn_pccard_megahertz_activate(device_t dev) 232{ 233 int err; 234 struct sn_softc *sc = device_get_softc(dev); 235 u_long start; 236 237 err = sn_activate(dev); 238 if (err) { 239 sn_deactivate(dev); 240 return (err); 241 } 242 /* 243 * CIS resource is the modem one, so save it away. 244 */ 245 sc->modem_rid = sc->port_rid; 246 sc->modem_res = sc->port_res; 247 248 /* 249 * The MHz XJEM/CCEM series of cards just need to have any 250 * old resource allocated for the ethernet side of things, 251 * provided bit 0x80 isn't set in the address. That bit is 252 * evidentially reserved for modem function and is how the 253 * card steers the addresses internally. 254 */ 255 sc->port_res = NULL; 256 start = 0; 257 do 258 { 259 sc->port_rid = 1; 260 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 261 &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE); 262 if (sc->port_res == NULL) 263 break; 264 if (!(rman_get_start(sc->port_res) & 0x80)) 265 break; 266 start = rman_get_start(sc->port_res) + SMC_IO_EXTENT; 267 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 268 sc->port_res); 269 } while (start < 0xff80); 270 if (sc->port_res == NULL) { 271 sn_deactivate(dev); 272 return ENOMEM; 273 } 274 return 0; 275} 276 277static int 278sn_pccard_attach(device_t dev) 279{ 280 struct sn_softc *sc = device_get_softc(dev); 281 u_char eaddr[ETHER_ADDR_LEN]; 282 int i, err; 283 uint16_t w; 284 u_char sum; 285 const struct sn_product *pp; 286 287 pp = sn_pccard_lookup(dev); 288 sum = pp->sw->get_mac(dev, eaddr); 289 290 /* Allocate resources so we can program the ether addr */ 291 sc->dev = dev; 292 err = pp->sw->activate(dev); 293 if (err != 0) 294 return (err); 295 296 if (sum) { 297 printf("Programming sn card's addr\n"); 298 SMC_SELECT_BANK(sc, 1); 299 for (i = 0; i < 3; i++) { 300 w = (uint16_t)eaddr[i * 2] | 301 (((uint16_t)eaddr[i * 2 + 1]) << 8); 302 CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w); 303 } 304 } 305 err = sn_attach(dev); 306 if (err) 307 sn_deactivate(dev); 308 return (err); 309} 310 311static device_method_t sn_pccard_methods[] = { 312 /* Device interface */ 313 DEVMETHOD(device_probe, sn_pccard_probe), 314 DEVMETHOD(device_attach, sn_pccard_attach), 315 DEVMETHOD(device_detach, sn_detach), 316 317 { 0, 0 } 318}; 319 320static driver_t sn_pccard_driver = { 321 "sn", 322 sn_pccard_methods, 323 sizeof(struct sn_softc), 324}; 325 326extern devclass_t sn_devclass; 327 328DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0); 329MODULE_DEPEND(sn, ether, 1, 1, 1); 330