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: stable/10/sys/dev/sn/if_sn_pccard.c 199414 2009-11-17 18:22:14Z jhb $");
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 #include <machine/resource.h>
48 #include <sys/rman.h>
49 
50 #include <dev/pccard/pccardvar.h>
51 #include <dev/pccard/pccard_cis.h>
52 #include <dev/sn/if_snreg.h>
53 #include <dev/sn/if_snvar.h>
54 
55 #include "card_if.h"
56 #include "pccarddevs.h"
57 
58 typedef int sn_get_enaddr_t(device_t dev, u_char *eaddr);
59 typedef int sn_activate_t(device_t dev);
60 
61 struct sn_sw
62 {
63 	int type;
64 #define SN_NORMAL 1
65 #define SN_MEGAHERTZ 2
66 #define SN_OSITECH 3
67 #define SN_OSI_SOD 4
68 #define SN_MOTO_MARINER 5
69 	char *typestr;
70 	sn_get_enaddr_t *get_mac;
71 	sn_activate_t *activate;
72 };
73 
74 static sn_get_enaddr_t sn_pccard_normal_get_mac;
75 static sn_activate_t sn_pccard_normal_activate;
76 const static struct sn_sw sn_normal_sw = {
77 	SN_NORMAL, "plain",
78 	sn_pccard_normal_get_mac,
79 	sn_pccard_normal_activate
80 };
81 
82 static sn_get_enaddr_t sn_pccard_megahertz_get_mac;
83 static sn_activate_t sn_pccard_megahertz_activate;
84 const static struct sn_sw sn_mhz_sw = {
85 	SN_MEGAHERTZ, "Megahertz",
86 	sn_pccard_megahertz_get_mac,
87 	sn_pccard_megahertz_activate
88 };
89 
90 static const struct sn_product {
91 	struct pccard_product prod;
92 	const struct sn_sw *sw;
93 } sn_pccard_products[] = {
94 	{ PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw },
95 	{ PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw },
96 /*	{ PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */
97 	{ PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw },
98 	{ PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw},
99 	{ PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw},
100 /*	{ PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */
101 /*	{ PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */
102 /*	{ PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */
103 /*	{ PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */
104 /*	{ PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */
105 	{ PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw },
106 	{ PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw },
107 	{ { NULL } }
108 
109 };
110 
111 static const struct sn_product *
sn_pccard_lookup(device_t dev)112 sn_pccard_lookup(device_t dev)
113 {
114 
115 	return ((const struct sn_product *)
116 	    pccard_product_lookup(dev,
117 		(const struct pccard_product *)sn_pccard_products,
118 		sizeof(sn_pccard_products[0]), NULL));
119 }
120 
121 static int
sn_pccard_probe(device_t dev)122 sn_pccard_probe(device_t dev)
123 {
124 	const struct sn_product *pp;
125 
126 	if ((pp = sn_pccard_lookup(dev)) != NULL) {
127 		if (pp->prod.pp_name != NULL)
128 			device_set_desc(dev, pp->prod.pp_name);
129 		return 0;
130 	}
131 	return EIO;
132 }
133 
134 static int
sn_pccard_ascii_enaddr(const char * str,u_char * enet)135 sn_pccard_ascii_enaddr(const char *str, u_char *enet)
136 {
137         uint8_t digit;
138 	int i;
139 
140 	memset(enet, 0, ETHER_ADDR_LEN);
141 	for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) {
142 		if (str[i] >= '0' && str[i] <= '9')
143 			digit |= str[i] - '0';
144 		else if (str[i] >= 'a' && str[i] <= 'f')
145 			digit |= (str[i] - 'a') + 10;
146 		else if (str[i] >= 'A' && str[i] <= 'F')
147 			digit |= (str[i] - 'A') + 10;
148 		else
149 			return (0);		/* Bogus digit!! */
150 
151 		/* Compensate for ordering of digits. */
152 		if (i & 1) {
153 			enet[i >> 1] = digit;
154 			digit = 0;
155 		} else
156 			digit <<= 4;
157 	}
158 
159 	return (1);
160 }
161 
162 static int
sn_pccard_normal_get_mac(device_t dev,u_char * eaddr)163 sn_pccard_normal_get_mac(device_t dev, u_char *eaddr)
164 {
165 	int i, sum;
166 	const char *cisstr;
167 
168 	pccard_get_ether(dev, eaddr);
169 	for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
170 		sum |= eaddr[i];
171 	if (sum == 0) {
172 		pccard_get_cis3_str(dev, &cisstr);
173 		if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
174 		    sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
175 	}
176 	if (sum == 0) {
177 		pccard_get_cis4_str(dev, &cisstr);
178 		if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
179 		    sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
180 	}
181 	return sum;
182 }
183 
184 static int
sn_pccard_normal_activate(device_t dev)185 sn_pccard_normal_activate(device_t dev)
186 {
187 	int err;
188 
189 	err = sn_activate(dev);
190 	if (err)
191 		sn_deactivate(dev);
192 	return (err);
193 }
194 
195 static int
sn_pccard_megahertz_mac(const struct pccard_tuple * tuple,void * argp)196 sn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp)
197 {
198 	uint8_t *enaddr = argp;
199 	int i;
200 	uint8_t buffer[ETHER_ADDR_LEN * 2];
201 
202 	/* Code 0x81 is Megahertz' special cis node contianing the MAC */
203 	if (tuple->code != 0x81)
204 		return (0);
205 
206 	/* Make sure this is a sane node, as ASCII digits */
207 	if (tuple->length != ETHER_ADDR_LEN * 2 + 1)
208 		return (0);
209 
210 	/* Copy the MAC ADDR and return success if decoded */
211 	for (i = 0; i < ETHER_ADDR_LEN * 2; i++)
212 		buffer[i] = pccard_tuple_read_1(tuple, i);
213 	return (sn_pccard_ascii_enaddr(buffer, enaddr));
214 }
215 
216 static int
sn_pccard_megahertz_get_mac(device_t dev,u_char * eaddr)217 sn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr)
218 {
219 
220 	if (sn_pccard_normal_get_mac(dev, eaddr))
221 		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 
230 static int
sn_pccard_megahertz_activate(device_t dev)231 sn_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 
277 static int
sn_pccard_attach(device_t dev)278 sn_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 
311 static 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 
320 static driver_t sn_pccard_driver = {
321 	"sn",
322 	sn_pccard_methods,
323 	sizeof(struct sn_softc),
324 };
325 
326 extern devclass_t sn_devclass;
327 
328 DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0);
329 MODULE_DEPEND(sn, ether, 1, 1, 1);
330