1117035Sgordon/*-
2117035Sgordon * Copyright (c) 1999 M. Warner Losh <imp@village.org>
3117035Sgordon * All rights reserved.
4156813Sru *
5156813Sru * Redistribution and use in source and binary forms, with or without
6156813Sru * modification, are permitted provided that the following conditions
7188895Sru * are met:
8156813Sru * 1. Redistributions of source code must retain the above copyright
9117035Sgordon *    notice, this list of conditions and the following disclaimer.
10117692Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11117035Sgordon *    notice, this list of conditions and the following disclaimer in the
12117035Sgordon *    documentation and/or other materials provided with the distribution.
13117035Sgordon *
14153455Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15117035Sgordon * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16117035Sgordon * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17117035Sgordon * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18117035Sgordon * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19147090Sbrooks * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20147090Sbrooks * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21147090Sbrooks * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22147090Sbrooks * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23147090Sbrooks * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24117035Sgordon */
25215226Sadrian/*
26117035Sgordon * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT)
27117035Sgordon *
28117035Sgordon * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
29117035Sgordon *                       BSD-nomads, Tokyo, Japan.
30117035Sgordon */
31117035Sgordon
32117449Sgordon#include <sys/cdefs.h>
33117449Sgordon__FBSDID("$FreeBSD$");
34117035Sgordon
35117035Sgordon#include <sys/param.h>
36117035Sgordon#include <sys/bus.h>
37117035Sgordon#include <sys/kernel.h>
38117035Sgordon#include <sys/module.h>
39117035Sgordon#include <sys/socket.h>
40117035Sgordon#include <sys/systm.h>
41117035Sgordon
42117035Sgordon#include <net/ethernet.h>
43117035Sgordon#include <net/if.h>
44117035Sgordon#include <net/if_arp.h>
45117035Sgordon
46117035Sgordon#include <machine/bus.h>
47117035Sgordon#include <machine/resource.h>
48117035Sgordon#include <sys/rman.h>
49117035Sgordon
50117035Sgordon#include <dev/pccard/pccardvar.h>
51117692Sobrien#include <dev/pccard/pccard_cis.h>
52117791Sobrien#include <dev/sn/if_snreg.h>
53182543Syar#include <dev/sn/if_snvar.h>
54183007Simp
55202755Sed#include "card_if.h"
56215226Sadrian#include "pccarddevs.h"
57117035Sgordon
58117035Sgordontypedef int sn_get_enaddr_t(device_t dev, u_char *eaddr);
59117035Sgordontypedef int sn_activate_t(device_t dev);
60117035Sgordon
61117035Sgordonstruct sn_sw
62117692Sobrien{
63117035Sgordon	int type;
64117035Sgordon#define SN_NORMAL 1
65117035Sgordon#define SN_MEGAHERTZ 2
66173073Syar#define SN_OSITECH 3
67173073Syar#define SN_OSI_SOD 4
68156813Sru#define SN_MOTO_MARINER 5
69117601Sgordon	char *typestr;
70117035Sgordon	sn_get_enaddr_t *get_mac;
71117035Sgordon	sn_activate_t *activate;
72156813Sru};
73117601Sgordon
74117035Sgordonstatic sn_get_enaddr_t sn_pccard_normal_get_mac;
75215226Sadrianstatic sn_activate_t sn_pccard_normal_activate;
76117692Sobrienconst static struct sn_sw sn_normal_sw = {
77117692Sobrien	SN_NORMAL, "plain",
78117035Sgordon	sn_pccard_normal_get_mac,
79117035Sgordon	sn_pccard_normal_activate
80117035Sgordon};
81117035Sgordon
82117035Sgordonstatic sn_get_enaddr_t sn_pccard_megahertz_get_mac;
83117035Sgordonstatic sn_activate_t sn_pccard_megahertz_activate;
84117035Sgordonconst static struct sn_sw sn_mhz_sw = {
85117035Sgordon	SN_MEGAHERTZ, "Megahertz",
86117791Sobrien	sn_pccard_megahertz_get_mac,
87117035Sgordon	sn_pccard_megahertz_activate
88117035Sgordon};
89117692Sobrien
90249083Smavstatic const struct sn_product {
91183007Simp	struct pccard_product prod;
92133799Smarius	const struct sn_sw *sw;
93173314Smarcel} sn_pccard_products[] = {
94183007Simp	{ PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw },
95183007Simp	{ PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw },
96241636Sattilio/*	{ PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */
97183007Simp	{ PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw },
98183007Simp	{ PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw},
99183007Simp	{ PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw},
100191227Skientzle/*	{ PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */
101117035Sgordon/*	{ PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */
102156813Sru/*	{ PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */
103171453Srwatson/*	{ PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */
104119664Sphk/*	{ PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */
105119664Sphk	{ PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw },
106156813Sru	{ PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw },
107119664Sphk	{ { NULL } }
108119664Sphk
109119664Sphk};
110156813Sru
111145630Sdarrenrstatic const struct sn_product *
112117693Sobriensn_pccard_lookup(device_t dev)
113192617Skmacy{
114192617Skmacy
115192617Skmacy	return ((const struct sn_product *)
116192617Skmacy	    pccard_product_lookup(dev,
117117693Sobrien		(const struct pccard_product *)sn_pccard_products,
118117035Sgordon		sizeof(sn_pccard_products[0]), NULL));
119117035Sgordon}
120117035Sgordon
121157177Scognetstatic int
122156905Srusn_pccard_probe(device_t dev)
123156905Sru{
124156905Sru	const struct sn_product *pp;
125192617Skmacy
126248571Smm	if ((pp = sn_pccard_lookup(dev)) != NULL) {
127192617Skmacy		if (pp->prod.pp_name != NULL)
128231642Srmh			device_set_desc(dev, pp->prod.pp_name);
129117035Sgordon		return 0;
130211725Simp	}
131173314Smarcel	return EIO;
132117057Sgordon}
133252356Sdavide
134252356Sdavidestatic int
135117035Sgordonsn_pccard_ascii_enaddr(const char *str, u_char *enet)
136117035Sgordon{
137117035Sgordon        uint8_t digit;
138173314Smarcel	int i;
139117692Sobrien
140117035Sgordon	memset(enet, 0, ETHER_ADDR_LEN);
141117035Sgordon	for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) {
142211725Simp		if (str[i] >= '0' && str[i] <= '9')
143173314Smarcel			digit |= str[i] - '0';
144117035Sgordon		else if (str[i] >= 'a' && str[i] <= 'f')
145117035Sgordon			digit |= (str[i] - 'a') + 10;
146211725Simp		else if (str[i] >= 'A' && str[i] <= 'F')
147173314Smarcel			digit |= (str[i] - 'A') + 10;
148117035Sgordon		else
149117035Sgordon			return (0);		/* Bogus digit!! */
150211725Simp
151173314Smarcel		/* Compensate for ordering of digits. */
152117057Sgordon		if (i & 1) {
153117057Sgordon			enet[i >> 1] = digit;
154117057Sgordon			digit = 0;
155117692Sobrien		} else
156118826Sharti			digit <<= 4;
157117692Sobrien	}
158117692Sobrien
159117692Sobrien	return (1);
160145630Sdarrenr}
161192617Skmacy
162192617Skmacystatic int
163192617Skmacysn_pccard_normal_get_mac(device_t dev, u_char *eaddr)
164192617Skmacy{
165117035Sgordon	int i, sum;
166117692Sobrien	const char *cisstr;
167117035Sgordon
168117692Sobrien	pccard_get_ether(dev, eaddr);
169177707Sru	for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
170117035Sgordon		sum |= eaddr[i];
171117035Sgordon	if (sum == 0) {
172147090Sbrooks		pccard_get_cis3_str(dev, &cisstr);
173147090Sbrooks		if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
174117035Sgordon		    sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
175117035Sgordon	}
176117035Sgordon	if (sum == 0) {
177191227Skientzle		pccard_get_cis4_str(dev, &cisstr);
178117692Sobrien		if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
179117035Sgordon		    sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
180227531Sdes	}
181173073Syar	return sum;
182166255Sdelphij}
183117692Sobrien
184117035Sgordonstatic int
185117692Sobriensn_pccard_normal_activate(device_t dev)
186117692Sobrien{
187117692Sobrien	int err;
188117035Sgordon
189250626Sdelphij	err = sn_activate(dev);
190250626Sdelphij	if (err)
191250626Sdelphij		sn_deactivate(dev);
192207849Smm	return (err);
193207849Smm}
194207849Smm
195207849Smmstatic int
196138366Sobriensn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp)
197191239Skientzle{
198191239Skientzle	uint8_t *enaddr = argp;
199191239Skientzle	int i;
200191239Skientzle	uint8_t buffer[ETHER_ADDR_LEN * 2];
201138366Sobrien
202117692Sobrien	/* Code 0x81 is Megahertz' special cis node contianing the MAC */
203117692Sobrien	if (tuple->code != 0x81)
204117035Sgordon		return (0);
205126874Sdes
206126874Sdes	/* Make sure this is a sane node, as ASCII digits */
207126874Sdes	if (tuple->length != ETHER_ADDR_LEN * 2 + 1)
208117035Sgordon		return (0);
209141478Sdes
210191227Skientzle	/* Copy the MAC ADDR and return success if decoded */
211141478Sdes	for (i = 0; i < ETHER_ADDR_LEN * 2; i++)
212141478Sdes		buffer[i] = pccard_tuple_read_1(tuple, i);
213173073Syar	return (sn_pccard_ascii_enaddr(buffer, enaddr));
214141478Sdes}
215173073Syar
216173073Syarstatic int
217192617Skmacysn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr)
218192617Skmacy{
219173073Syar
220215226Sadrian	if (sn_pccard_normal_get_mac(dev, eaddr))
221117035Sgordon		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
230static int
231sn_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
277static int
278sn_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
311static 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
320static driver_t sn_pccard_driver = {
321	"sn",
322	sn_pccard_methods,
323	sizeof(struct sn_softc),
324};
325
326extern devclass_t sn_devclass;
327
328DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0);
329MODULE_DEPEND(sn, ether, 1, 1, 1);
330