1119419Sobrien/*- 254994Simp * Copyright (c) 1999 M. Warner Losh <imp@village.org> 354994Simp * All rights reserved. 454994Simp * 554994Simp * Redistribution and use in source and binary forms, with or without 654994Simp * modification, are permitted provided that the following conditions 754994Simp * are met: 854994Simp * 1. Redistributions of source code must retain the above copyright 954994Simp * notice, this list of conditions and the following disclaimer. 1054994Simp * 2. Redistributions in binary form must reproduce the above copyright 1154994Simp * notice, this list of conditions and the following disclaimer in the 1254994Simp * documentation and/or other materials provided with the distribution. 1354994Simp * 1454994Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1554994Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1654994Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1754994Simp * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1854994Simp * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1954994Simp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2054994Simp * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2154994Simp * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2254994Simp * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2354994Simp * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2454994Simp */ 2554994Simp/* 2654994Simp * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) 2754994Simp * 2854994Simp * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 2954994Simp * BSD-nomads, Tokyo, Japan. 3054994Simp */ 3154994Simp 32119419Sobrien#include <sys/cdefs.h> 33119419Sobrien__FBSDID("$FreeBSD$"); 34119419Sobrien 3554994Simp#include <sys/param.h> 36129764Simp#include <sys/bus.h> 3754994Simp#include <sys/kernel.h> 38129879Sphk#include <sys/module.h> 3954994Simp#include <sys/socket.h> 40129764Simp#include <sys/systm.h> 4154994Simp 4256366Shosokawa#include <net/ethernet.h> 4354994Simp#include <net/if.h> 4454994Simp#include <net/if_arp.h> 4554994Simp 46129798Simp#include <machine/bus.h> 47149101Simp#include <machine/resource.h> 48149101Simp#include <sys/rman.h> 49129798Simp 50129764Simp#include <dev/pccard/pccardvar.h> 51140525Simp#include <dev/pccard/pccard_cis.h> 52147797Simp#include <dev/sn/if_snreg.h> 5354994Simp#include <dev/sn/if_snvar.h> 5466058Simp 5566058Simp#include "card_if.h" 56129764Simp#include "pccarddevs.h" 5766058Simp 58149101Simptypedef int sn_get_enaddr_t(device_t dev, u_char *eaddr); 59149101Simptypedef int sn_activate_t(device_t dev); 60149101Simp 61149101Simpstruct sn_sw 62149101Simp{ 63149101Simp int type; 64149101Simp#define SN_NORMAL 1 65149101Simp#define SN_MEGAHERTZ 2 66149101Simp#define SN_OSITECH 3 67149101Simp#define SN_OSI_SOD 4 68149101Simp#define SN_MOTO_MARINER 5 69149101Simp char *typestr; 70149101Simp sn_get_enaddr_t *get_mac; 71149101Simp sn_activate_t *activate; 72149101Simp}; 73149101Simp 74149101Simpstatic sn_get_enaddr_t sn_pccard_normal_get_mac; 75149101Simpstatic sn_activate_t sn_pccard_normal_activate; 76149101Simpconst static struct sn_sw sn_normal_sw = { 77149101Simp SN_NORMAL, "plain", 78149101Simp sn_pccard_normal_get_mac, 79149101Simp sn_pccard_normal_activate 80149101Simp}; 81149101Simp 82149101Simpstatic sn_get_enaddr_t sn_pccard_megahertz_get_mac; 83149101Simpstatic sn_activate_t sn_pccard_megahertz_activate; 84149101Simpconst static struct sn_sw sn_mhz_sw = { 85149101Simp SN_MEGAHERTZ, "Megahertz", 86149101Simp sn_pccard_megahertz_get_mac, 87149101Simp sn_pccard_megahertz_activate 88149101Simp}; 89149101Simp 90147957Simpstatic const struct sn_product { 91147957Simp struct pccard_product prod; 92149101Simp const struct sn_sw *sw; 93147957Simp} sn_pccard_products[] = { 94149101Simp { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw }, 95149101Simp { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw }, 96147957Simp/* { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */ 97149101Simp { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw }, 98149101Simp { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw}, 99149101Simp { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw}, 100147957Simp/* { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */ 101147957Simp/* { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */ 102147957Simp/* { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */ 103147957Simp/* { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */ 104147957Simp/* { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */ 105149101Simp { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw }, 106149101Simp { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw }, 107147957Simp { { NULL } } 108147957Simp 10966425Simp}; 110100426Simp 111147957Simpstatic const struct sn_product * 112147957Simpsn_pccard_lookup(device_t dev) 113147957Simp{ 114147957Simp 115147957Simp return ((const struct sn_product *) 116147957Simp pccard_product_lookup(dev, 117147957Simp (const struct pccard_product *)sn_pccard_products, 118147957Simp sizeof(sn_pccard_products[0]), NULL)); 119147957Simp} 120147957Simp 12154994Simpstatic int 122147797Simpsn_pccard_probe(device_t dev) 12366425Simp{ 124147957Simp const struct sn_product *pp; 12566425Simp 126147957Simp if ((pp = sn_pccard_lookup(dev)) != NULL) { 127147957Simp if (pp->prod.pp_name != NULL) 128147957Simp device_set_desc(dev, pp->prod.pp_name); 12966425Simp return 0; 13066425Simp } 13166425Simp return EIO; 13266425Simp} 13366425Simp 13466425Simpstatic int 135121514Simpsn_pccard_ascii_enaddr(const char *str, u_char *enet) 136121514Simp{ 137121514Simp uint8_t digit; 138121514Simp int i; 139149101Simp 140121514Simp memset(enet, 0, ETHER_ADDR_LEN); 141121514Simp for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 142121514Simp if (str[i] >= '0' && str[i] <= '9') 143121514Simp digit |= str[i] - '0'; 144121514Simp else if (str[i] >= 'a' && str[i] <= 'f') 145121514Simp digit |= (str[i] - 'a') + 10; 146121514Simp else if (str[i] >= 'A' && str[i] <= 'F') 147121514Simp digit |= (str[i] - 'A') + 10; 148149101Simp else 149149101Simp return (0); /* Bogus digit!! */ 150121514Simp 151121514Simp /* Compensate for ordering of digits. */ 152121514Simp if (i & 1) { 153121514Simp enet[i >> 1] = digit; 154121514Simp digit = 0; 155121514Simp } else 156121514Simp digit <<= 4; 157121514Simp } 158121514Simp 159121514Simp return (1); 160121514Simp} 161121514Simp 162121514Simpstatic int 163149101Simpsn_pccard_normal_get_mac(device_t dev, u_char *eaddr) 16454994Simp{ 165149101Simp int i, sum; 166147797Simp const char *cisstr; 16756366Shosokawa 168147797Simp pccard_get_ether(dev, eaddr); 16956366Shosokawa for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 170147797Simp sum |= eaddr[i]; 171121514Simp if (sum == 0) { 172121514Simp pccard_get_cis3_str(dev, &cisstr); 173147797Simp if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 174147797Simp sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 175121514Simp } 176121514Simp if (sum == 0) { 177121514Simp pccard_get_cis4_str(dev, &cisstr); 178147797Simp if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 179147797Simp sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 180121514Simp } 181149101Simp return sum; 182149101Simp} 183147797Simp 184149101Simpstatic int 185149101Simpsn_pccard_normal_activate(device_t dev) 186149101Simp{ 187149101Simp int err; 188149101Simp 189147797Simp err = sn_activate(dev); 190149101Simp if (err) 191149101Simp sn_deactivate(dev); 192149101Simp return (err); 193149101Simp} 194149101Simp 195149101Simpstatic int 196149101Simpsn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp) 197149101Simp{ 198149101Simp uint8_t *enaddr = argp; 199149101Simp int i; 200149101Simp uint8_t buffer[ETHER_ADDR_LEN * 2]; 201149101Simp 202149101Simp /* Code 0x81 is Megahertz' special cis node contianing the MAC */ 203149101Simp if (tuple->code != 0x81) 204149101Simp return (0); 205149101Simp 206149101Simp /* Make sure this is a sane node, as ASCII digits */ 207149101Simp if (tuple->length != ETHER_ADDR_LEN * 2 + 1) 208149101Simp return (0); 209149101Simp 210149101Simp /* Copy the MAC ADDR and return success if decoded */ 211149101Simp for (i = 0; i < ETHER_ADDR_LEN * 2; i++) 212149101Simp buffer[i] = pccard_tuple_read_1(tuple, i); 213149101Simp return (sn_pccard_ascii_enaddr(buffer, enaddr)); 214149101Simp} 215149101Simp 216149101Simpstatic int 217149101Simpsn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr) 218149101Simp{ 219149101Simp 220149101Simp if (sn_pccard_normal_get_mac(dev, eaddr)) 221149101Simp return 1; 222149101Simp /* 223149101Simp * If that fails, try the special CIS tuple 0x81 that the 224149101Simp * '3288 and '3336 cards have. That tuple specifies an ASCII 225149101Simp * string, ala CIS3 or CIS4 in the 'normal' cards. 226149101Simp */ 227150106Simp return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr)); 228149101Simp} 229149101Simp 230149101Simpstatic int 231149101Simpsn_pccard_megahertz_activate(device_t dev) 232149101Simp{ 233149101Simp int err; 234149101Simp struct sn_softc *sc = device_get_softc(dev); 235149101Simp u_long start; 236149101Simp 237149101Simp err = sn_activate(dev); 238147797Simp if (err) { 239147797Simp sn_deactivate(dev); 240147797Simp return (err); 241147797Simp } 242149101Simp /* 243149101Simp * CIS resource is the modem one, so save it away. 244149101Simp */ 245149101Simp sc->modem_rid = sc->port_rid; 246149101Simp sc->modem_res = sc->port_res; 247147797Simp 248149101Simp /* 249149101Simp * The MHz XJEM/CCEM series of cards just need to have any 250149101Simp * old resource allocated for the ethernet side of things, 251149101Simp * provided bit 0x80 isn't set in the address. That bit is 252149101Simp * evidentially reserved for modem function and is how the 253149101Simp * card steers the addresses internally. 254149101Simp */ 255149101Simp sc->port_res = NULL; 256149101Simp start = 0; 257149101Simp do 258149101Simp { 259149101Simp sc->port_rid = 1; 260149101Simp sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 261149101Simp &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE); 262149101Simp if (sc->port_res == NULL) 263149101Simp break; 264149101Simp if (!(rman_get_start(sc->port_res) & 0x80)) 265149101Simp break; 266149101Simp start = rman_get_start(sc->port_res) + SMC_IO_EXTENT; 267149101Simp bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 268149101Simp sc->port_res); 269149101Simp } while (start < 0xff80); 270149101Simp if (sc->port_res == NULL) { 271149101Simp sn_deactivate(dev); 272149101Simp return ENOMEM; 273149101Simp } 274149101Simp return 0; 275149101Simp} 276149101Simp 277149101Simpstatic int 278149101Simpsn_pccard_attach(device_t dev) 279149101Simp{ 280149101Simp struct sn_softc *sc = device_get_softc(dev); 281149101Simp u_char eaddr[ETHER_ADDR_LEN]; 282149101Simp int i, err; 283149101Simp uint16_t w; 284149101Simp u_char sum; 285149101Simp const struct sn_product *pp; 286149101Simp 287149101Simp pp = sn_pccard_lookup(dev); 288149101Simp sum = pp->sw->get_mac(dev, eaddr); 289149101Simp 290149101Simp /* Allocate resources so we can program the ether addr */ 291149101Simp sc->dev = dev; 292149101Simp err = pp->sw->activate(dev); 293149101Simp if (err != 0) 294149101Simp return (err); 295149101Simp 29656397Shosokawa if (sum) { 297149101Simp printf("Programming sn card's addr\n"); 298147797Simp SMC_SELECT_BANK(sc, 1); 299147797Simp for (i = 0; i < 3; i++) { 300147797Simp w = (uint16_t)eaddr[i * 2] | 301147797Simp (((uint16_t)eaddr[i * 2 + 1]) << 8); 302147797Simp CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w); 303147797Simp } 30456397Shosokawa } 305147797Simp err = sn_attach(dev); 306147797Simp if (err) 307147797Simp sn_deactivate(dev); 308147797Simp return (err); 30954994Simp} 31054994Simp 31154994Simpstatic device_method_t sn_pccard_methods[] = { 31254994Simp /* Device interface */ 313147797Simp DEVMETHOD(device_probe, sn_pccard_probe), 314147797Simp DEVMETHOD(device_attach, sn_pccard_attach), 31569955Simp DEVMETHOD(device_detach, sn_detach), 31654994Simp 31754994Simp { 0, 0 } 31854994Simp}; 31954994Simp 32054994Simpstatic driver_t sn_pccard_driver = { 32154994Simp "sn", 32254994Simp sn_pccard_methods, 32354994Simp sizeof(struct sn_softc), 32454994Simp}; 32554994Simp 32654994Simpextern devclass_t sn_devclass; 32754994Simp 328113506SmdoddDRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0); 329113506SmdoddMODULE_DEPEND(sn, ether, 1, 1, 1); 330