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