if_sn_pccard.c revision 147797
1/*- 2 * Copyright (c) 1999 M. Warner Losh <imp@village.org> 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 ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25/* 26 * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT) 27 * 28 * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org> 29 * BSD-nomads, Tokyo, Japan. 30 */ 31 32#include <sys/cdefs.h> 33__FBSDID("$FreeBSD: head/sys/dev/sn/if_sn_pccard.c 147797 2005-07-06 15:59:47Z imp $"); 34 35#include <sys/param.h> 36#include <sys/bus.h> 37#include <sys/kernel.h> 38#include <sys/module.h> 39#include <sys/socket.h> 40#include <sys/systm.h> 41 42#include <net/ethernet.h> 43#include <net/if.h> 44#include <net/if_arp.h> 45 46#include <machine/bus.h> 47 48#include <dev/pccard/pccardvar.h> 49#include <dev/pccard/pccard_cis.h> 50#include <dev/sn/if_snreg.h> 51#include <dev/sn/if_snvar.h> 52 53#include "card_if.h" 54#include "pccarddevs.h" 55 56static const struct pccard_product sn_pccard_products[] = { 57 PCMCIA_CARD(DSPSI, XJACK), 58 PCMCIA_CARD(NEWMEDIA, BASICS), 59 PCMCIA_CARD(SMC, SMC91C96), 60#if 0 61 PCMCIA_CARD(SMC, 8020BT), 62#endif 63 { NULL } 64}; 65 66static int 67sn_pccard_probe(device_t dev) 68{ 69 const struct pccard_product *pp; 70 int error; 71 uint32_t fcn = PCCARD_FUNCTION_UNSPEC; 72 73 /* Make sure we're a network function */ 74 error = pccard_get_function(dev, &fcn); 75 if (error != 0) 76 return (error); 77 if (fcn != PCCARD_FUNCTION_NETWORK) 78 return (ENXIO); 79 80 if ((pp = pccard_product_lookup(dev, sn_pccard_products, 81 sizeof(sn_pccard_products[0]), NULL)) != NULL) { 82 if (pp->pp_name != NULL) 83 device_set_desc(dev, pp->pp_name); 84 return 0; 85 } 86 return EIO; 87} 88 89static int 90sn_pccard_ascii_enaddr(const char *str, u_char *enet) 91{ 92 uint8_t digit; 93 int i; 94 95 memset(enet, 0, ETHER_ADDR_LEN); 96 97 for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) { 98 if (str[i] >= '0' && str[i] <= '9') 99 digit |= str[i] - '0'; 100 else if (str[i] >= 'a' && str[i] <= 'f') 101 digit |= (str[i] - 'a') + 10; 102 else if (str[i] >= 'A' && str[i] <= 'F') 103 digit |= (str[i] - 'A') + 10; 104 else { 105 /* Bogus digit!! */ 106 return (0); 107 } 108 109 /* Compensate for ordering of digits. */ 110 if (i & 1) { 111 enet[i >> 1] = digit; 112 digit = 0; 113 } else 114 digit <<= 4; 115 } 116 117 return (1); 118} 119 120static int 121sn_pccard_attach(device_t dev) 122{ 123 struct sn_softc *sc = device_get_softc(dev); 124 const char *cisstr; 125 u_char eaddr[ETHER_ADDR_LEN]; 126 int i, err; 127 uint16_t w; 128 u_char sum; 129 130 pccard_get_ether(dev, eaddr); 131 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++) 132 sum |= eaddr[i]; 133 if (sum == 0) { 134 pccard_get_cis3_str(dev, &cisstr); 135 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 136 sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 137 } 138 if (sum == 0) { 139 pccard_get_cis4_str(dev, &cisstr); 140 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2) 141 sum = sn_pccard_ascii_enaddr(cisstr, eaddr); 142 } 143 144 /* Allocate resources so we can program the ether addr */ 145 sc->dev = dev; 146 err = sn_activate(dev); 147 if (err) { 148 sn_deactivate(dev); 149 return (err); 150 } 151 152 if (sum) { 153 SMC_SELECT_BANK(sc, 1); 154 for (i = 0; i < 3; i++) { 155 w = (uint16_t)eaddr[i * 2] | 156 (((uint16_t)eaddr[i * 2 + 1]) << 8); 157 CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w); 158 } 159 } 160 err = sn_attach(dev); 161 if (err) 162 sn_deactivate(dev); 163 return (err); 164} 165 166static device_method_t sn_pccard_methods[] = { 167 /* Device interface */ 168 DEVMETHOD(device_probe, sn_pccard_probe), 169 DEVMETHOD(device_attach, sn_pccard_attach), 170 DEVMETHOD(device_detach, sn_detach), 171 172 { 0, 0 } 173}; 174 175static driver_t sn_pccard_driver = { 176 "sn", 177 sn_pccard_methods, 178 sizeof(struct sn_softc), 179}; 180 181extern devclass_t sn_devclass; 182 183DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0); 184MODULE_DEPEND(sn, ether, 1, 1, 1); 185