1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 1999 M. Warner Losh <imp@village.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27/* 28 * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) 29 * 30 * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 31 * BSD-nomads, Tokyo, Japan. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37#include <sys/param.h> 38#include <sys/bus.h> 39#include <sys/kernel.h> 40#include <sys/module.h> 41#include <sys/socket.h> 42#include <sys/systm.h> 43 44#include <net/ethernet.h> 45#include <net/if.h> 46#include <net/if_arp.h> 47 48#include <machine/bus.h> 49#include <machine/resource.h> 50#include <sys/rman.h> 51 52#include <dev/pccard/pccardvar.h> 53#include <dev/pccard/pccard_cis.h> 54#include <dev/sn/if_snreg.h> 55#include <dev/sn/if_snvar.h> 56 57#include "card_if.h" 58#include "pccarddevs.h" 59 60typedef int sn_get_enaddr_t(device_t dev, u_char *eaddr); 61typedef int sn_activate_t(device_t dev); 62 63struct sn_sw 64{ 65 int type; 66#define SN_NORMAL 1 67#define SN_MEGAHERTZ 2 68#define SN_OSITECH 3 69#define SN_OSI_SOD 4 70#define SN_MOTO_MARINER 5 71 char *typestr; 72 sn_get_enaddr_t *get_mac; 73 sn_activate_t *activate; 74}; 75 76static sn_get_enaddr_t sn_pccard_normal_get_mac; 77static sn_activate_t sn_pccard_normal_activate; 78const static struct sn_sw sn_normal_sw = { 79 SN_NORMAL, "plain", 80 sn_pccard_normal_get_mac, 81 sn_pccard_normal_activate 82}; 83 84static sn_get_enaddr_t sn_pccard_megahertz_get_mac; 85static sn_activate_t sn_pccard_megahertz_activate; 86const static struct sn_sw sn_mhz_sw = { 87 SN_MEGAHERTZ, "Megahertz", 88 sn_pccard_megahertz_get_mac, 89 sn_pccard_megahertz_activate 90}; 91 92static const struct sn_product { 93 struct pccard_product prod; 94 const struct sn_sw *sw; 95} sn_pccard_products[] = { 96 { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw }, 97 { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw }, 98/* { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */ 99 { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw }, 100 { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw}, 101 { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw}, 102/* { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */ 103/* { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */ 104/* { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */ 105/* { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */ 106/* { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */ 107 { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw }, 108 { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw }, 109 { { NULL } } 110 111}; 112 113static const struct sn_product * 114sn_pccard_lookup(device_t dev) 115{ 116 117 return ((const struct sn_product *) 118 pccard_product_lookup(dev, 119 (const struct pccard_product *)sn_pccard_products, 120 sizeof(sn_pccard_products[0]), NULL)); 121} 122 123static int 124sn_pccard_probe(device_t dev) 125{ 126 const struct sn_product *pp; 127 128 if ((pp = sn_pccard_lookup(dev)) != NULL) { 129 if (pp->prod.pp_name != NULL) 130 device_set_desc(dev, pp->prod.pp_name); 131 return 0; 132 } 133 return EIO; 134} 135 136static int 137sn_pccard_ascii_enaddr(const char *str, u_char *enet) 138{ 139 uint8_t digit; 140 int i; 141 142 memset(enet, 0, ETHER_ADDR_LEN); 143 for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 144 if (str[i] >= '0' && str[i] <= '9') 145 digit |= str[i] - '0'; 146 else if (str[i] >= 'a' && str[i] <= 'f') 147 digit |= (str[i] - 'a') + 10; 148 else if (str[i] >= 'A' && str[i] <= 'F') 149 digit |= (str[i] - 'A') + 10; 150 else 151 return (0); /* Bogus digit!! */ 152 153 /* Compensate for ordering of digits. */ 154 if (i & 1) { 155 enet[i >> 1] = digit; 156 digit = 0; 157 } else 158 digit <<= 4; 159 } 160 161 return (1); 162} 163 164static int 165sn_pccard_normal_get_mac(device_t dev, u_char *eaddr) 166{ 167 int i, sum; 168 const char *cisstr; 169 170 pccard_get_ether(dev, eaddr); 171 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 172 sum |= eaddr[i]; 173 if (sum == 0) { 174 pccard_get_cis3_str(dev, &cisstr); 175 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 176 sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 177 } 178 if (sum == 0) { 179 pccard_get_cis4_str(dev, &cisstr); 180 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 181 sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 182 } 183 return sum; 184} 185 186static int 187sn_pccard_normal_activate(device_t dev) 188{ 189 int err; 190 191 err = sn_activate(dev); 192 if (err) 193 sn_deactivate(dev); 194 return (err); 195} 196 197static int 198sn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp) 199{ 200 uint8_t *enaddr = argp; 201 int i; 202 uint8_t buffer[ETHER_ADDR_LEN * 2]; 203 204 /* Code 0x81 is Megahertz' special cis node contianing the MAC */ 205 if (tuple->code != 0x81) 206 return (0); 207 208 /* Make sure this is a sane node, as ASCII digits */ 209 if (tuple->length != ETHER_ADDR_LEN * 2 + 1) 210 return (0); 211 212 /* Copy the MAC ADDR and return success if decoded */ 213 for (i = 0; i < ETHER_ADDR_LEN * 2; i++) 214 buffer[i] = pccard_tuple_read_1(tuple, i); 215 return (sn_pccard_ascii_enaddr(buffer, enaddr)); 216} 217 218static int 219sn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr) 220{ 221 222 if (sn_pccard_normal_get_mac(dev, eaddr)) 223 return 1; 224 /* 225 * If that fails, try the special CIS tuple 0x81 that the 226 * '3288 and '3336 cards have. That tuple specifies an ASCII 227 * string, ala CIS3 or CIS4 in the 'normal' cards. 228 */ 229 return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr)); 230} 231 232static int 233sn_pccard_megahertz_activate(device_t dev) 234{ 235 int err; 236 struct sn_softc *sc = device_get_softc(dev); 237 u_long start; 238 239 err = sn_activate(dev); 240 if (err) { 241 sn_deactivate(dev); 242 return (err); 243 } 244 /* 245 * CIS resource is the modem one, so save it away. 246 */ 247 sc->modem_rid = sc->port_rid; 248 sc->modem_res = sc->port_res; 249 250 /* 251 * The MHz XJEM/CCEM series of cards just need to have any 252 * old resource allocated for the ethernet side of things, 253 * provided bit 0x80 isn't set in the address. That bit is 254 * evidentially reserved for modem function and is how the 255 * card steers the addresses internally. 256 */ 257 sc->port_res = NULL; 258 start = 0; 259 do 260 { 261 sc->port_rid = 1; 262 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT, 263 &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE); 264 if (sc->port_res == NULL) 265 break; 266 if (!(rman_get_start(sc->port_res) & 0x80)) 267 break; 268 start = rman_get_start(sc->port_res) + SMC_IO_EXTENT; 269 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid, 270 sc->port_res); 271 } while (start < 0xff80); 272 if (sc->port_res == NULL) { 273 sn_deactivate(dev); 274 return ENOMEM; 275 } 276 return 0; 277} 278 279static int 280sn_pccard_attach(device_t dev) 281{ 282 struct sn_softc *sc = device_get_softc(dev); 283 u_char eaddr[ETHER_ADDR_LEN]; 284 int i, err; 285 uint16_t w; 286 u_char sum; 287 const struct sn_product *pp; 288 289 pp = sn_pccard_lookup(dev); 290 sum = pp->sw->get_mac(dev, eaddr); 291 292 /* Allocate resources so we can program the ether addr */ 293 sc->dev = dev; 294 err = pp->sw->activate(dev); 295 if (err != 0) 296 return (err); 297 298 if (sum) { 299 printf("Programming sn card's addr\n"); 300 SMC_SELECT_BANK(sc, 1); 301 for (i = 0; i < 3; i++) { 302 w = (uint16_t)eaddr[i * 2] | 303 (((uint16_t)eaddr[i * 2 + 1]) << 8); 304 CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w); 305 } 306 } 307 err = sn_attach(dev); 308 if (err) 309 sn_deactivate(dev); 310 return (err); 311} 312 313static device_method_t sn_pccard_methods[] = { 314 /* Device interface */ 315 DEVMETHOD(device_probe, sn_pccard_probe), 316 DEVMETHOD(device_attach, sn_pccard_attach), 317 DEVMETHOD(device_detach, sn_detach), 318 319 { 0, 0 } 320}; 321 322static driver_t sn_pccard_driver = { 323 "sn", 324 sn_pccard_methods, 325 sizeof(struct sn_softc), 326}; 327 328extern devclass_t sn_devclass; 329 330DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0); 331MODULE_DEPEND(sn, ether, 1, 1, 1); 332PCCARD_PNP_INFO(sn_pccard_products); 333