1112790Smdodd/*-
2112790Smdodd * Copyright (c) 2003 Matthew N. Dodd
3112790Smdodd * All rights reserved.
4112790Smdodd *
5112790Smdodd * Redistribution and use in source and binary forms, with or without
6112790Smdodd * modification, are permitted provided that the following conditions
7112790Smdodd * are met:
8112790Smdodd * 1. Redistributions of source code must retain the above copyright
9112790Smdodd *    notice, this list of conditions and the following disclaimer.
10112790Smdodd * 2. Redistributions in binary form must reproduce the above copyright
11112790Smdodd *    notice, this list of conditions and the following disclaimer in the
12112790Smdodd *    documentation and/or other materials provided with the distribution.
13112790Smdodd *
14112790Smdodd * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15112790Smdodd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16112790Smdodd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17112790Smdodd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18112790Smdodd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19112790Smdodd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20112790Smdodd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21112790Smdodd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22112790Smdodd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23112790Smdodd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24112790Smdodd * SUCH DAMAGE.
25112790Smdodd *
26112790Smdodd * Portions:
27112790Smdodd * Copyright (c) 1992, 1993, University of Vermont and State
28112790Smdodd *  Agricultural College.
29112790Smdodd * Copyright (c) 1992, 1993, Garrett A. Wollman.
30112790Smdodd * Copyright (c) 1990, 1991, William F. Jolitz
31112790Smdodd * Copyright (c) 1990, The Regents of the University of California
32112790Smdodd * Copyright (c) 1993, 1994, Charles M. Hannum
33112790Smdodd * Copyright (c) 1993, 1994, 1995, Rodney W. Grimes
34112790Smdodd * Copyright (c) 1997, Aaron C. Smith
35112790Smdodd *
36112790Smdodd * See if_ie.c for applicable license.
37112790Smdodd */
38112790Smdodd
39119418Sobrien#include <sys/cdefs.h>
40119418Sobrien__FBSDID("$FreeBSD$");
41119418Sobrien
42112790Smdodd#include <sys/param.h>
43112790Smdodd#include <sys/systm.h>
44112790Smdodd#include <sys/kernel.h>
45112790Smdodd#include <sys/socket.h>
46112790Smdodd
47112790Smdodd#include <sys/module.h>
48112790Smdodd#include <sys/bus.h>
49112790Smdodd
50112790Smdodd#include <machine/bus.h>
51112790Smdodd#include <machine/resource.h>
52112790Smdodd#include <sys/rman.h>
53112790Smdodd
54112790Smdodd#include <machine/md_var.h>
55112790Smdodd
56112790Smdodd#include <net/if.h>
57112790Smdodd#include <net/if_arp.h>
58112790Smdodd#include <net/if_media.h>
59112790Smdodd
60112790Smdodd#include <isa/isavar.h>
61112790Smdodd#include <isa/pnpvar.h>
62112790Smdodd
63112790Smdodd#include <i386/isa/elink.h>
64112790Smdodd
65112790Smdodd#include <dev/ic/i82586.h>
66112790Smdodd#include <dev/ie/if_ie507.h>
67112790Smdodd#include <dev/ie/if_iee16.h>
68112790Smdodd#include <dev/ie/if_iereg.h>
69112790Smdodd#include <dev/ie/if_ievar.h>
70112790Smdodd
71112790Smdoddstatic int		ie_modevent		(module_t, int, void *);
72112790Smdodd
73112790Smdoddstatic void		ie_isa_3C507_identify	(driver_t *, device_t);
74112790Smdoddstatic int		ie_isa_3C507_probe	(device_t);
75112790Smdoddstatic int		ie_isa_3C507_attach	(device_t);
76112790Smdoddstatic int		ie_3C507_port_check	(u_int32_t);
77112790Smdodd
78112790Smdoddstatic void		ie_isa_ee16_identify	(driver_t *, device_t);
79112790Smdoddstatic int		ie_isa_ee16_probe	(device_t);
80112790Smdoddstatic int		ie_isa_ee16_attach	(device_t);
81181134Sjhbstatic int		ie_isa_ee16_shutdown	(device_t);
82112790Smdoddstatic int		ie_ee16_port_check	(u_int32_t port);
83112790Smdoddstatic u_int16_t	ie_ee16_hw_read_eeprom	(u_int32_t port, int loc);
84112790Smdodd
85112790Smdoddstatic int		ie_isa_sl_probe		(device_t);
86112790Smdoddstatic int		ie_isa_sl_attach	(device_t);
87112790Smdoddstatic enum ie_hardware	ie_isa_sl_get_hard_type	(u_int32_t);
88112790Smdodd
89112790Smdodd/*
90112790Smdodd * 3Com 3C507 Etherlink 16
91112790Smdodd */
92112790Smdodd#define IE_3C507_IOBASE_LOW	0x200
93112790Smdodd#define IE_3C507_IOBASE_HIGH	0x3e0
94112790Smdodd#define IE_3C507_IOSIZE		16
95112790Smdodd
96112790Smdodd#define IE_3C507_IRQ_MASK	0x0f
97112790Smdodd
98112790Smdodd#define IE_3C507_MADDR_HIGH	0x20
99112790Smdodd#define IE_3C507_MADDR_MASK	0x1c
100112790Smdodd#define IE_3C507_MADDR_BASE	0xc0000
101112790Smdodd#define IE_3C507_MADDR_SHIFT	12
102112790Smdodd
103112790Smdodd#define IE_3C507_MSIZE_MASK	3
104112790Smdodd#define IE_3C507_MSIZE_SHIFT	14
105112790Smdodd
106112790Smdoddstatic void
107112790Smdoddie_isa_3C507_identify (driver_t *driver, device_t parent)
108112790Smdodd{
109112790Smdodd	char *		desc = "3Com 3C507 Etherlink 16";
110112790Smdodd	device_t	child;
111112790Smdodd	u_int32_t	port, maddr, msize;
112112790Smdodd	u_int8_t	irq, data;
113112790Smdodd	int		error;
114112790Smdodd
115112790Smdodd	/* Reset and put card in CONFIG state without changing address. */
116112790Smdodd	elink_reset();
117112790Smdodd	elink_idseq(ELINK_507_POLY);
118112790Smdodd	elink_idseq(ELINK_507_POLY);
119112790Smdodd	outb(ELINK_ID_PORT, 0xff);
120112790Smdodd
121112790Smdodd	for (port = IE_3C507_IOBASE_LOW;
122112790Smdodd	     port <= IE_3C507_IOBASE_HIGH;
123112790Smdodd	     port += IE_3C507_IOSIZE) {
124112790Smdodd
125112790Smdodd		if (ie_3C507_port_check(port)) {
126153110Sru#ifdef DEBUG
127112790Smdodd			if (bootverbose) {
128112790Smdodd				device_printf(parent,
129112790Smdodd					"(if_ie) (3C507) not found at port %#x\n",
130112790Smdodd					port);
131112790Smdodd			}
132112790Smdodd#endif
133112790Smdodd			continue;
134112790Smdodd		}
135112790Smdodd
136112790Smdodd		outb(port + IE507_CTRL, EL_CTRL_NRST);
137112790Smdodd
138112790Smdodd		data = inb(port + IE507_IRQ);
139112790Smdodd		irq = data & IE_3C507_IRQ_MASK;
140112790Smdodd
141112790Smdodd		data = inb(port + IE507_MADDR);
142112790Smdodd
143112790Smdodd		if (data & IE_3C507_MADDR_HIGH) {
144112790Smdodd			if (bootverbose) {
145112790Smdodd				device_printf(parent,
146112790Smdodd					"(if_ie) can't map 3C507 RAM in high memory\n");
147112790Smdodd			}
148112790Smdodd			continue;
149112790Smdodd		}
150112790Smdodd
151112790Smdodd		maddr = IE_3C507_MADDR_BASE +
152112790Smdodd			((data & IE_3C507_MADDR_MASK)
153112790Smdodd			<< IE_3C507_MADDR_SHIFT);
154112790Smdodd		msize = ((data & IE_3C507_MSIZE_MASK) + 1)
155112790Smdodd			<< IE_3C507_MSIZE_SHIFT;
156112790Smdodd
157112790Smdodd		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
158112790Smdodd		device_set_desc_copy(child, desc);
159112790Smdodd		device_set_driver(child, driver);
160112790Smdodd
161112790Smdodd		error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
162112790Smdodd		if (error) {
163112790Smdodd			device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
164112790Smdodd					irq);
165112790Smdodd			error = device_delete_child(parent, child);
166112790Smdodd			continue;
167112790Smdodd		}
168112790Smdodd
169112790Smdodd		error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_3C507_IOSIZE);
170112790Smdodd		if (error) {
171112790Smdodd			device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
172112790Smdodd					port, port+IE_3C507_IOSIZE);
173112790Smdodd			error = device_delete_child(parent, child);
174112790Smdodd			continue;
175112790Smdodd		}
176112790Smdodd
177112790Smdodd		error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
178112790Smdodd		if (error) {
179112790Smdodd			device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
180112790Smdodd					maddr, maddr+msize);
181112790Smdodd			error = device_delete_child(parent, child);
182112790Smdodd			continue;
183112790Smdodd		}
184112790Smdodd
185112790Smdodd		if (bootverbose) {
186112790Smdodd			device_printf(parent,
187112790Smdodd				"(if_ie) <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
188112790Smdodd				desc,
189112790Smdodd				port, (port + IE_3C507_IOSIZE) - 1,
190112790Smdodd				irq,
191112790Smdodd				(u_long)maddr, (u_long)(maddr + msize) - 1,
192112790Smdodd				(msize / 1024));
193112790Smdodd		}
194112790Smdodd	}
195112790Smdodd
196112790Smdodd	/* go to RUN state */
197112790Smdodd	outb(ELINK_ID_PORT, 0x00);
198112790Smdodd	elink_idseq(ELINK_507_POLY);
199112790Smdodd	outb(ELINK_ID_PORT, 0x00);
200112790Smdodd
201112790Smdodd	return;
202112790Smdodd}
203112790Smdodd
204112790Smdoddstatic int
205112790Smdoddie_isa_3C507_probe (device_t dev)
206112790Smdodd{
207112790Smdodd	u_int32_t	iobase;
208112790Smdodd
209112790Smdodd	/* No ISA-PnP support */
210112790Smdodd	if (isa_get_vendorid(dev)) {
211112790Smdodd		return (ENXIO);
212112790Smdodd	}
213112790Smdodd
214112790Smdodd	/* No ISA-HINT support */
215112790Smdodd	if (!device_get_desc(dev)) {
216112790Smdodd		return (EBUSY);
217112790Smdodd	}
218112790Smdodd
219112790Smdodd	/* Have we at least an ioport? */
220112790Smdodd	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0) {
221112790Smdodd		return (ENXIO);
222112790Smdodd	}
223112790Smdodd
224112790Smdodd	/* Is this thing really a 3c507? */
225112790Smdodd	if (ie_3C507_port_check(iobase)) {
226112790Smdodd		return (ENXIO);
227112790Smdodd	}
228112790Smdodd
229112790Smdodd	return (0);
230112790Smdodd}
231112790Smdodd
232112790Smdoddstatic int
233112790Smdoddie_isa_3C507_attach (device_t dev)
234112790Smdodd{
235112790Smdodd	struct ie_softc *	sc;
236112790Smdodd	int			error;
237112790Smdodd
238112790Smdodd	sc = device_get_softc(dev);
239112790Smdodd
240112790Smdodd	sc->io_rid = 0;
241112790Smdodd	sc->irq_rid = 0;
242112790Smdodd	sc->mem_rid = 0;
243112790Smdodd
244112790Smdodd	error = ie_alloc_resources(dev);
245112790Smdodd	if (error) {
246112790Smdodd		goto bad;
247112790Smdodd	}
248112790Smdodd
249112790Smdodd	sc->bus_use = 0;
250112790Smdodd	sc->ie_reset_586 = el_reset_586;
251112790Smdodd	sc->ie_chan_attn = el_chan_attn;
252112790Smdodd	sc->hard_type = IE_3C507;
253112790Smdodd	sc->hard_vers = 0;
254112790Smdodd
255112790Smdodd	outb(PORT(sc) + IE507_CTRL, EL_CTRL_NORMAL);
256112790Smdodd
257112790Smdodd	if (!check_ie_present(sc)) {
258112790Smdodd		error = ENXIO;
259112790Smdodd		goto bad;
260112790Smdodd	}
261112790Smdodd
262147256Sbrooks	sl_read_ether(sc, sc->enaddr);
263112790Smdodd
264112790Smdodd	/* Clear the interrupt latch just in case. */
265112790Smdodd	outb(PORT(sc) + IE507_ICTRL, 1);
266112790Smdodd
267112790Smdodd	error = ie_attach(dev);
268112790Smdodd	if (error) {
269112790Smdodd		device_printf(dev, "ie_attach() failed.\n");
270112790Smdodd		goto bad;
271112790Smdodd	}
272112790Smdodd
273112790Smdodd	return (0);
274112790Smdoddbad:
275112790Smdodd	ie_release_resources(dev);
276112790Smdodd
277112790Smdodd	return (error);
278112790Smdodd}
279112790Smdodd
280112790Smdodd/*
281112790Smdodd * If a 3c507 is present, return 0
282112790Smdodd * else, return 1.
283112790Smdodd */
284112790Smdoddstatic int
285112790Smdoddie_3C507_port_check (u_int32_t port)
286112790Smdodd{
287112790Smdodd	u_char *	signature = "*3COM*";
288112790Smdodd	int		i;
289112790Smdodd
290112790Smdodd	for (i = 0; i < 6; i++)
291112790Smdodd		if (inb(port + i) != signature[i])
292112790Smdodd			return (ENXIO);
293112790Smdodd
294112790Smdodd	return (0);
295112790Smdodd}
296112790Smdodd
297112790Smdodd/*
298112790Smdodd * Intel EtherExpress 16
299112790Smdodd */
300112790Smdodd#define IE_EE16_ID_PORT			0x0f
301112790Smdodd#define IE_EE16_ID			0xbaba
302112790Smdodd#define IE_EE16_EEPROM_CONFIG1		0x00
303112790Smdodd#define IE_EE16_EEPROM_IRQ_MASK		0xe000
304112790Smdodd#define IE_EE16_EEPROM_IRQ_SHIFT	13
305112790Smdodd#define IE_EE16_EEPROM_MEMCFG		0x06
306112790Smdodd#define IE_EE16_IOSIZE			16
307112790Smdodd
308112790Smdodd/*
309112790Smdodd * TODO:
310112790Smdodd *		Test for 8/16 bit mode.
311112790Smdodd *		Test for invalid mem sizes.
312112790Smdodd */
313112790Smdoddstatic void
314112790Smdoddie_isa_ee16_identify (driver_t *driver, device_t parent)
315112790Smdodd{
316112790Smdodd	char *		desc = "Intel EtherExpress 16";
317112790Smdodd	device_t	child;
318112790Smdodd	u_int16_t	ports[] = {
319112790Smdodd				0x300, 0x310, 0x320, 0x330,
320112790Smdodd				0x340, 0x350, 0x360, 0x370,
321112790Smdodd				0x200, 0x210, 0x220, 0x230,
322112790Smdodd				0x240, 0x250, 0x260, 0x270,
323112790Smdodd				0
324112790Smdodd			};
325112790Smdodd	u_int16_t	irqs[] = { 0, 0x09, 0x03, 0x04, 0x05, 0x0a, 0x0b, 0 };
326112790Smdodd	u_int32_t	port, maddr, msize;
327112790Smdodd	u_int8_t	irq;
328112790Smdodd	u_int16_t	data;
329112790Smdodd	int		i, error;
330112790Smdodd
331112790Smdodd	for (i = 0; ports[i]; i++) {
332112790Smdodd		port = ports[i];
333112790Smdodd
334112790Smdodd		if (ie_ee16_port_check(port)) {
335153110Sru#ifdef DEBUG
336112790Smdodd			if (bootverbose) {
337112790Smdodd				device_printf(parent,
338112790Smdodd					"if_ie: (EE16) not found at port %#x\n",
339112790Smdodd					port);
340112790Smdodd			}
341112790Smdodd#endif
342112790Smdodd			continue;
343112790Smdodd		}
344112790Smdodd
345112790Smdodd		/* reset any ee16 at the current iobase */
346112790Smdodd		outb(port + IEE16_ECTRL, IEE16_RESET_ASIC);
347112790Smdodd		outb(port + IEE16_ECTRL, 0);
348112790Smdodd		DELAY(240);
349112790Smdodd
350112790Smdodd		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_CONFIG1);
351112790Smdodd		irq = irqs[((data & IE_EE16_EEPROM_IRQ_MASK)
352112790Smdodd			   >> IE_EE16_EEPROM_IRQ_SHIFT)];
353112790Smdodd
354112790Smdodd		data = ie_ee16_hw_read_eeprom(port, IE_EE16_EEPROM_MEMCFG);
355112790Smdodd		maddr = 0xc0000 + ((ffs(data & 0x00ff) - 1) * 0x4000);
356112790Smdodd		msize = (fls((data & 0x00ff) >> (ffs(data & 0x00ff) - 1)))
357112790Smdodd			* 0x4000;
358112790Smdodd
359112790Smdodd		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "ie", -1);
360112790Smdodd		device_set_desc_copy(child, desc);
361112790Smdodd		device_set_driver(child, driver);
362112790Smdodd
363112790Smdodd		error = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
364112790Smdodd		if (error) {
365112790Smdodd			device_printf(parent, "(if_ie) Unable to set IRQ resource %d.\n",
366112790Smdodd					irq);
367112790Smdodd			error = device_delete_child(parent, child);
368112790Smdodd			continue;
369112790Smdodd		}
370112790Smdodd
371112790Smdodd		error = bus_set_resource(child, SYS_RES_IOPORT, 0, port, IE_EE16_IOSIZE);
372112790Smdodd		if (error) {
373112790Smdodd			device_printf(parent, "(if_ie) Unable to set IOPORT resource %#x-%#x.\n",
374112790Smdodd					port, port+IE_EE16_IOSIZE);
375112790Smdodd			error = device_delete_child(parent, child);
376112790Smdodd			continue;
377112790Smdodd		}
378112790Smdodd
379112790Smdodd		error = bus_set_resource(child, SYS_RES_MEMORY, 0, maddr, msize);
380112790Smdodd		if (error) {
381112790Smdodd			device_printf(parent, "(if_ie) Unable to set MEMORY resource %#x-%#x.\n",
382112790Smdodd					maddr, maddr+msize);
383112790Smdodd			error = device_delete_child(parent, child);
384112790Smdodd			continue;
385112790Smdodd		}
386112790Smdodd
387112790Smdodd		if (bootverbose) {
388112790Smdodd			device_printf(parent,
389112790Smdodd				"if_ie: <%s> at port %#x-%#x irq %d iomem %#lx-%#lx (%dKB)\n",
390112790Smdodd				desc,
391112790Smdodd				port, (port + IE_EE16_IOSIZE) - 1,
392112790Smdodd				irq,
393112790Smdodd				(u_long)maddr, (u_long)(maddr + msize) - 1,
394112790Smdodd				(msize / 1024));
395112790Smdodd		}
396112790Smdodd	}
397112790Smdodd
398112790Smdodd	return;
399112790Smdodd}
400112790Smdodd
401112790Smdoddstatic int
402112790Smdoddie_isa_ee16_probe (device_t dev)
403112790Smdodd{
404112790Smdodd	u_int32_t	iobase;
405112790Smdodd
406112790Smdodd	/* No ISA-PnP support */
407112790Smdodd	if (isa_get_vendorid(dev))
408112790Smdodd		return (ENXIO);
409112790Smdodd
410112790Smdodd	/* No ISA-HINT support */
411112790Smdodd	if (!device_get_desc(dev))
412112790Smdodd		return (EBUSY);
413112790Smdodd
414112790Smdodd	/* Have we at least an ioport? */
415112790Smdodd	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
416112790Smdodd		return (ENXIO);
417112790Smdodd
418112790Smdodd	/* Is this really an EE16? */
419112790Smdodd	if (ie_ee16_port_check(iobase))
420112790Smdodd		return (ENXIO);
421112790Smdodd
422112790Smdodd	return (0);
423112790Smdodd}
424112790Smdodd
425112790Smdoddstatic int
426112790Smdoddie_isa_ee16_attach (device_t dev)
427112790Smdodd{
428112790Smdodd	struct ie_softc *	sc;
429112790Smdodd	int			i, error;
430112790Smdodd	u_int16_t		checksum;
431112790Smdodd	u_short			eaddrtemp, pg, adjust, decode, edecode;
432112790Smdodd	u_char			bart_config;
433112790Smdodd
434112790Smdodd	sc = device_get_softc(dev);
435112790Smdodd
436112790Smdodd	sc->io_rid = 0;
437112790Smdodd	sc->irq_rid = 0;
438112790Smdodd	sc->mem_rid = 0;
439112790Smdodd
440112790Smdodd	error = ie_alloc_resources(dev);
441112790Smdodd	if (error) {
442112790Smdodd		goto bad;
443112790Smdodd	}
444112790Smdodd
445112790Smdodd	sc->bus_use = 0;
446112790Smdodd	sc->ie_reset_586 = ee16_reset_586;
447112790Smdodd	sc->ie_chan_attn = ee16_chan_attn;
448112790Smdodd	sc->hard_type = IE_EE16;
449112790Smdodd	sc->hard_vers = 0;
450112790Smdodd	sc->iomem = 0;
451112790Smdodd
452112790Smdodd	/* reset any ee16 at the current iobase */
453112790Smdodd	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_ASIC);
454112790Smdodd	outb(PORT(sc) + IEE16_ECTRL, 0);
455112790Smdodd	DELAY(240);
456112790Smdodd
457112790Smdodd	/* Is this really an EE16? */
458112790Smdodd	if (ie_ee16_port_check(PORT(sc))) {
459112790Smdodd		device_printf(dev, "ie_ee16_port_check() failed\n");
460112790Smdodd		error = ENXIO;
461112790Smdodd		goto bad;
462112790Smdodd	}
463112790Smdodd
464112790Smdodd	/* need to put the 586 in RESET while we access the eeprom. */
465112790Smdodd	outb(PORT(sc) + IEE16_ECTRL, IEE16_RESET_586);
466112790Smdodd
467112790Smdodd	/* read the eeprom and checksum it, should == IE_E16_ID */
468112790Smdodd	checksum = 0;
469112790Smdodd	for (i = 0; i < 0x40; i++)
470112790Smdodd		checksum += ie_ee16_hw_read_eeprom(PORT(sc), i);
471112790Smdodd
472112790Smdodd	if (checksum != IE_EE16_ID) {
473112790Smdodd		device_printf(dev, "invalid eeprom checksum: %x\n", checksum);
474112790Smdodd		error = ENXIO;
475112790Smdodd		goto bad;
476112790Smdodd	}
477112790Smdodd
478112790Smdodd	if ((kvtop(sc->iomembot) < 0xC0000) ||
479112790Smdodd	     (kvtop(sc->iomembot) + sc->iosize > 0xF0000)) {
480112790Smdodd		device_printf(sc->dev, "mapped memory location %p out of range\n",
481112790Smdodd			(void *)sc->iomembot);
482112790Smdodd		error = ENXIO;
483112790Smdodd		goto bad;
484112790Smdodd	}
485112790Smdodd
486112790Smdodd	pg = ((kvtop(sc->iomembot)) & 0x3C000) >> 14;
487112790Smdodd	adjust = IEE16_MCTRL_FMCS16 | (pg & 0x3) << 2;
488112790Smdodd	decode = ((1 << (sc->iosize / 16384)) - 1) << pg;
489112790Smdodd	edecode = ((~decode >> 4) & 0xF0) | (decode >> 8);
490112790Smdodd
491112790Smdodd	/* ZZZ This should be checked against eeprom location 6, low byte */
492112790Smdodd	outb(PORT(sc) + IEE16_MEMDEC, decode & 0xFF);
493112790Smdodd	/* ZZZ This should be checked against eeprom location 1, low byte */
494112790Smdodd	outb(PORT(sc) + IEE16_MCTRL, adjust);
495112790Smdodd	/* ZZZ Now if I could find this one I would have it made */
496112790Smdodd	outb(PORT(sc) + IEE16_MPCTRL, (~decode & 0xFF));
497112790Smdodd	/* ZZZ I think this is location 6, high byte */
498112790Smdodd	outb(PORT(sc) + IEE16_MECTRL, edecode); /* XXX disable Exxx */
499112790Smdodd
500112790Smdodd#if 0
501112790Smdodd	(void) kvtop(sc->iomembot);
502112790Smdodd#endif
503112790Smdodd
504112790Smdodd	/*
505112790Smdodd	 * first prime the stupid bart DRAM controller so that it works,
506112790Smdodd	 * then zero out all of memory.
507112790Smdodd	 */
508112790Smdodd	bzero(sc->iomembot, 32);
509112790Smdodd	bzero(sc->iomembot, sc->iosize);
510112790Smdodd
511112790Smdodd	/* Get the encoded interrupt number from the EEPROM */
512112790Smdodd	sc->irq_encoded = ie_ee16_hw_read_eeprom(PORT(sc),
513112790Smdodd						 IE_EE16_EEPROM_CONFIG1);
514112790Smdodd	sc->irq_encoded = (sc->irq_encoded & IE_EE16_EEPROM_IRQ_MASK) >>
515112790Smdodd			   IE_EE16_EEPROM_IRQ_SHIFT;
516112790Smdodd
517112790Smdodd	/*
518112790Smdodd	 * Get the hardware ethernet address from the EEPROM and save it in
519112790Smdodd	 * the softc for use by the 586 setup code.
520112790Smdodd	 */
521112790Smdodd	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_HIGH);
522147256Sbrooks	sc->enaddr[1] = eaddrtemp & 0xFF;
523147256Sbrooks	sc->enaddr[0] = eaddrtemp >> 8;
524112790Smdodd	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_MID);
525147256Sbrooks	sc->enaddr[3] = eaddrtemp & 0xFF;
526147256Sbrooks	sc->enaddr[2] = eaddrtemp >> 8;
527112790Smdodd	eaddrtemp = ie_ee16_hw_read_eeprom(PORT(sc), IEE16_EEPROM_ENET_LOW);
528147256Sbrooks	sc->enaddr[5] = eaddrtemp & 0xFF;
529147256Sbrooks	sc->enaddr[4] = eaddrtemp >> 8;
530112790Smdodd
531112790Smdodd	/* disable the board interrupts */
532112790Smdodd	outb(PORT(sc) + IEE16_IRQ, sc->irq_encoded);
533112790Smdodd
534112790Smdodd	/* enable loopback to keep bad packets off the wire */
535112790Smdodd	bart_config = inb(PORT(sc) + IEE16_CONFIG);
536112790Smdodd	bart_config |= IEE16_BART_LOOPBACK;
537112790Smdodd	bart_config |= IEE16_BART_MCS16_TEST;/* inb doesn't get bit! */
538112790Smdodd	outb(PORT(sc) + IEE16_CONFIG, bart_config);
539112790Smdodd	bart_config = inb(PORT(sc) + IEE16_CONFIG);
540112790Smdodd
541112790Smdodd	/* take the board out of reset state */
542112790Smdodd	outb(PORT(sc) + IEE16_ECTRL, 0);
543112790Smdodd	DELAY(100);
544112790Smdodd
545112790Smdodd	if (!check_ie_present(sc)) {
546112790Smdodd		device_printf(dev, "check_ie_present() returned false.\n");
547112790Smdodd		error = ENXIO;
548112790Smdodd		goto bad;
549112790Smdodd	}
550112790Smdodd
551112790Smdodd	error = ie_attach(dev);
552112790Smdodd	if (error) {
553112790Smdodd		device_printf(dev, "ie_attach() failed.\n");
554112790Smdodd		goto bad;
555112790Smdodd	}
556112790Smdodd
557112790Smdodd	return (0);
558112790Smdoddbad:
559112790Smdodd	ie_release_resources(dev);
560112790Smdodd
561112790Smdodd	return (error);
562112790Smdodd}
563112790Smdodd
564181134Sjhbstatic int
565181134Sjhbie_isa_ee16_shutdown(device_t dev)
566181134Sjhb{
567181134Sjhb	struct ie_softc *	sc;
568181134Sjhb
569181134Sjhb	sc = device_get_softc(dev);
570181134Sjhb	IE_LOCK(sc);
571181134Sjhb	ee16_shutdown(sc);
572181134Sjhb	IE_UNLOCK(sc);
573181134Sjhb
574181134Sjhb	return (0);
575181134Sjhb}
576181134Sjhb
577112790Smdodd/*
578112790Smdodd * If an EE16 is present, return 0
579112790Smdodd * else, return 1.
580112790Smdodd */
581112790Smdoddstatic int
582112790Smdoddie_ee16_port_check (u_int32_t port)
583112790Smdodd{
584112790Smdodd	int		i;
585112790Smdodd	u_int16_t	board_id;
586112790Smdodd	u_int8_t	data;
587112790Smdodd
588112790Smdodd	board_id = 0;
589112790Smdodd	for (i = 0; i < 4; i++) {
590112790Smdodd		data = inb(port + IE_EE16_ID_PORT);
591112790Smdodd		board_id |= ((data >> 4) << ((data & 0x03) << 2));
592112790Smdodd	}
593112790Smdodd
594112790Smdodd	if (board_id != IE_EE16_ID)
595112790Smdodd		return (1);
596112790Smdodd
597112790Smdodd	return (0);
598112790Smdodd}
599112790Smdodd
600112790Smdoddstatic void
601112790Smdoddie_ee16_hw_eeprom_clock (u_int32_t port, int state)
602112790Smdodd{
603112790Smdodd	u_int8_t	ectrl;
604112790Smdodd
605112790Smdodd	ectrl = inb(port + IEE16_ECTRL);
606112790Smdodd	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EESK);
607112790Smdodd
608112790Smdodd	if (state) {
609112790Smdodd		ectrl |= IEE16_ECTRL_EESK;
610112790Smdodd	}
611112790Smdodd	outb(port + IEE16_ECTRL, ectrl);
612112790Smdodd	DELAY(9);		/* EESK must be stable for 8.38 uSec */
613112790Smdodd}
614112790Smdodd
615112790Smdoddstatic void
616112790Smdoddie_ee16_hw_eeprom_out (u_int32_t port, u_int16_t edata, int count)
617112790Smdodd{
618112790Smdodd	u_int8_t	ectrl;
619112790Smdodd	int		i;
620112790Smdodd
621112790Smdodd	ectrl = inb(port + IEE16_ECTRL);
622112790Smdodd	ectrl &= ~IEE16_RESET_ASIC;
623112790Smdodd
624112790Smdodd	for (i = count - 1; i >= 0; i--) {
625112790Smdodd		ectrl &= ~IEE16_ECTRL_EEDI;
626112790Smdodd		if (edata & (1 << i)) {
627112790Smdodd			ectrl |= IEE16_ECTRL_EEDI;
628112790Smdodd		}
629112790Smdodd		outb(port + IEE16_ECTRL, ectrl);
630112790Smdodd		DELAY(1);       /* eeprom data must be setup for 0.4 uSec */
631112790Smdodd		ie_ee16_hw_eeprom_clock(port, 1);
632112790Smdodd		ie_ee16_hw_eeprom_clock(port, 0);
633112790Smdodd	}
634112790Smdodd	ectrl &= ~IEE16_ECTRL_EEDI;
635112790Smdodd	outb(port + IEE16_ECTRL, ectrl);
636112790Smdodd	DELAY(1);               /* eeprom data must be held for 0.4 uSec */
637112790Smdodd
638112790Smdodd	return;
639112790Smdodd}
640112790Smdodd
641112790Smdoddstatic u_int16_t
642112790Smdoddie_ee16_hw_eeprom_in (u_int32_t port)
643112790Smdodd{
644112790Smdodd	u_int8_t	ectrl;
645112790Smdodd	u_int16_t	edata;
646112790Smdodd	int		i;
647112790Smdodd
648112790Smdodd	ectrl = inb(port + IEE16_ECTRL);
649112790Smdodd	ectrl &= ~IEE16_RESET_ASIC;
650112790Smdodd
651112790Smdodd	for (edata = 0, i = 0; i < 16; i++) {
652112790Smdodd		edata = edata << 1;
653112790Smdodd		ie_ee16_hw_eeprom_clock(port, 1);
654112790Smdodd		ectrl = inb(port + IEE16_ECTRL);
655112790Smdodd		if (ectrl & IEE16_ECTRL_EEDO) {
656112790Smdodd			edata |= 1;
657112790Smdodd		}
658112790Smdodd		ie_ee16_hw_eeprom_clock(port, 0);
659112790Smdodd	}
660112790Smdodd	return (edata);
661112790Smdodd}
662112790Smdodd
663112790Smdoddstatic u_int16_t
664112790Smdoddie_ee16_hw_read_eeprom (u_int32_t port, int loc)
665112790Smdodd{
666112790Smdodd	u_int8_t	ectrl;
667112790Smdodd	u_int16_t	edata;
668112790Smdodd
669112790Smdodd	ectrl = inb(port + IEE16_ECTRL);
670112790Smdodd	ectrl &= IEE16_ECTRL_MASK;
671112790Smdodd	ectrl |= IEE16_ECTRL_EECS;
672112790Smdodd	outb(port + IEE16_ECTRL, ectrl);
673112790Smdodd
674112790Smdodd	ie_ee16_hw_eeprom_out(port, IEE16_EEPROM_READ, IEE16_EEPROM_OPSIZE1);
675112790Smdodd	ie_ee16_hw_eeprom_out(port, loc, IEE16_EEPROM_ADDR_SIZE);
676112790Smdodd	edata = ie_ee16_hw_eeprom_in(port);
677112790Smdodd
678112790Smdodd	ectrl = inb(port + IEE16_ECTRL);
679112790Smdodd	ectrl &= ~(IEE16_RESET_ASIC | IEE16_ECTRL_EEDI | IEE16_ECTRL_EECS);
680112790Smdodd	outb(port + IEE16_ECTRL, ectrl);
681112790Smdodd
682112790Smdodd	ie_ee16_hw_eeprom_clock(port, 1);
683112790Smdodd	ie_ee16_hw_eeprom_clock(port, 0);
684112790Smdodd
685112790Smdodd	return (edata);
686112790Smdodd}
687112790Smdodd
688112790Smdodd/*
689112790Smdodd * AT&T StarLan/
690112790Smdodd */
691112790Smdodd
692112790Smdoddstatic int
693112790Smdoddie_isa_sl_probe (device_t dev)
694112790Smdodd{
695112790Smdodd	u_int32_t	iobase;
696112790Smdodd
697112790Smdodd	/* No ISA-PnP support */
698112790Smdodd	if (isa_get_vendorid(dev))
699112790Smdodd		return (ENXIO);
700112790Smdodd
701112790Smdodd	/* ISA-HINT support only! */
702112790Smdodd	if (device_get_desc(dev))
703112790Smdodd		return (EBUSY);
704112790Smdodd
705112790Smdodd	/* Have we at least an ioport? */
706112790Smdodd	if ((iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0)) == 0)
707112790Smdodd		return (ENXIO);
708112790Smdodd
709112790Smdodd	/* Is this really an SL board? */
710112790Smdodd	if (ie_isa_sl_get_hard_type(iobase) == IE_NONE)
711112790Smdodd		return (ENXIO);
712112790Smdodd
713112790Smdodd	return (ENXIO);
714112790Smdodd}
715112790Smdodd
716112790Smdoddstatic int
717112790Smdoddie_isa_sl_attach (device_t dev)
718112790Smdodd{
719112790Smdodd	struct ie_softc *	sc;
720112790Smdodd	int			error;
721112790Smdodd
722112790Smdodd	sc = device_get_softc(dev);
723112790Smdodd
724112790Smdodd	sc->io_rid = 0;
725112790Smdodd	sc->irq_rid = 0;
726112790Smdodd	sc->mem_rid = 0;
727112790Smdodd
728112790Smdodd	error = ie_alloc_resources(dev);
729112790Smdodd	if (error) {
730112790Smdodd		goto bad;
731112790Smdodd	}
732112790Smdodd
733112790Smdodd	/* Is this really an SL board? */
734112790Smdodd	if ((sc->hard_type = ie_isa_sl_get_hard_type(PORT(sc))) == IE_NONE) {
735112790Smdodd		error = ENXIO;
736112790Smdodd		goto bad;
737112790Smdodd	}
738112790Smdodd
739112790Smdodd	sc->hard_vers = SL_REV(inb(PORT(sc) + IEATT_REVISION));
740112790Smdodd	if (sc->hard_type == IE_NI5210) {
741112790Smdodd		sc->bus_use = 1;
742112790Smdodd	} else {
743112790Smdodd		sc->bus_use = 0;
744112790Smdodd	}
745112790Smdodd
746112790Smdodd	sc->ie_reset_586 = sl_reset_586;
747112790Smdodd	sc->ie_chan_attn = sl_chan_attn;
748112790Smdodd
749112790Smdodd	if (!check_ie_present(sc)) {
750112790Smdodd		error = ENXIO;
751112790Smdodd		goto bad;
752112790Smdodd	}
753112790Smdodd
754112790Smdodd	switch (sc->hard_type) {
755112790Smdodd		case IE_EN100:
756112790Smdodd		case IE_STARLAN10:
757112790Smdodd		case IE_SLFIBER:
758112790Smdodd		case IE_NI5210:
759147256Sbrooks			sl_read_ether(sc, sc->enaddr);
760112790Smdodd			break;
761112790Smdodd		default:
762112790Smdodd			if (bootverbose)
763112790Smdodd				device_printf(sc->dev, "unknown AT&T board type code %d\n", sc->hard_type);
764112790Smdodd			error = ENXIO;
765112790Smdodd			goto bad;
766112790Smdodd			break;
767112790Smdodd	}
768112790Smdodd
769112790Smdodd	error = ie_attach(dev);
770112790Smdodd	if (error) {
771112790Smdodd		device_printf(dev, "ie_attach() failed.\n");
772112790Smdodd		goto bad;
773112790Smdodd	}
774112790Smdodd
775112790Smdodd	return (0);
776112790Smdoddbad:
777112790Smdodd	ie_release_resources(dev);
778112790Smdodd
779112790Smdodd	return (error);
780112790Smdodd}
781112790Smdodd
782112790Smdoddstatic enum ie_hardware
783112790Smdoddie_isa_sl_get_hard_type (u_int32_t port)
784112790Smdodd{
785112790Smdodd	u_char			c;
786112790Smdodd	enum ie_hardware	retval;
787112790Smdodd
788112790Smdodd	c = inb(port + IEATT_REVISION);
789112790Smdodd	switch (SL_BOARD(c)) {
790112790Smdodd		case SL1_BOARD:
791112790Smdodd			if (inb(port + IEATT_ATTRIB) != NI5210_BOARD)
792112790Smdodd				retval = IE_NONE;
793112790Smdodd			retval = IE_NI5210;
794112790Smdodd			break;
795112790Smdodd		case SL10_BOARD:
796112790Smdodd			retval = IE_STARLAN10;
797112790Smdodd			break;
798112790Smdodd		case EN100_BOARD:
799112790Smdodd			retval = IE_EN100;
800112790Smdodd			break;
801112790Smdodd		case SLFIBER_BOARD:
802112790Smdodd			retval = IE_SLFIBER;
803112790Smdodd			break;
804112790Smdodd		default:
805112790Smdodd			retval = IE_NONE;
806112790Smdodd	}
807112790Smdodd	return (retval);
808112790Smdodd}
809112790Smdodd
810112790Smdoddstatic devclass_t ie_devclass;
811112790Smdodd
812112790Smdoddstatic device_method_t ie_isa_3C507_methods[] = {
813112790Smdodd	DEVMETHOD(device_identify,	ie_isa_3C507_identify),
814112790Smdodd	DEVMETHOD(device_probe,		ie_isa_3C507_probe),
815112790Smdodd	DEVMETHOD(device_attach,	ie_isa_3C507_attach),
816112790Smdodd	DEVMETHOD(device_detach,	ie_detach),
817112790Smdodd	{ 0, 0 }
818112790Smdodd};
819179559Sjhb
820112790Smdoddstatic driver_t ie_isa_3C507_driver = {
821112790Smdodd	"ie",
822112790Smdodd	ie_isa_3C507_methods,
823112790Smdodd	sizeof(struct ie_softc),
824112790Smdodd};
825179559Sjhb
826112790SmdoddDRIVER_MODULE(ie_3C507, isa, ie_isa_3C507_driver, ie_devclass, ie_modevent, 0);
827112790SmdoddMODULE_DEPEND(ie_3C507, elink, 1, 1, 1);
828112790Smdodd
829112790Smdoddstatic device_method_t ie_isa_ee16_methods[] = {
830112790Smdodd	DEVMETHOD(device_identify,	ie_isa_ee16_identify),
831112790Smdodd	DEVMETHOD(device_probe,		ie_isa_ee16_probe),
832112790Smdodd	DEVMETHOD(device_attach,	ie_isa_ee16_attach),
833181134Sjhb	DEVMETHOD(device_shutdown,	ie_isa_ee16_shutdown),
834112790Smdodd	DEVMETHOD(device_detach,	ie_detach),
835112790Smdodd	{ 0, 0 }
836112790Smdodd};
837179559Sjhb
838112790Smdoddstatic driver_t ie_isa_ee16_driver = {
839112790Smdodd	"ie",
840112790Smdodd	ie_isa_ee16_methods,
841112790Smdodd	sizeof(struct ie_softc),
842112790Smdodd};
843112790Smdodd
844179559SjhbDRIVER_MODULE(ie, isa, ie_isa_ee16_driver, ie_devclass, ie_modevent, 0);
845179559Sjhb
846112790Smdoddstatic device_method_t ie_isa_sl_methods[] = {
847112790Smdodd	DEVMETHOD(device_probe,		ie_isa_sl_probe),
848112790Smdodd	DEVMETHOD(device_attach,	ie_isa_sl_attach),
849112790Smdodd	DEVMETHOD(device_detach,	ie_detach),
850112790Smdodd	{ 0, 0 }
851112790Smdodd};
852179559Sjhb
853112790Smdoddstatic driver_t ie_isa_sl_driver = {
854112790Smdodd	"ie",
855112790Smdodd	ie_isa_sl_methods,
856112790Smdodd	sizeof(struct ie_softc),
857112790Smdodd};
858179559Sjhb
859112790SmdoddDRIVER_MODULE(ie_SL, isa, ie_isa_sl_driver, ie_devclass, ie_modevent, 0);
860112790Smdodd
861112790Smdoddstatic int
862112790Smdoddie_modevent (mod, what, arg)
863112790Smdodd	module_t	mod;
864112790Smdodd	int		what;
865112790Smdodd	void *		arg;
866112790Smdodd{
867112790Smdodd	device_t *	devs;
868112790Smdodd	int		count;
869112790Smdodd	int		i;
870112790Smdodd
871112790Smdodd	switch (what) {
872112790Smdodd	case MOD_LOAD:
873112790Smdodd		break;
874112790Smdodd	case MOD_UNLOAD:
875112790Smdodd		devclass_get_devices(ie_devclass, &devs, &count);
876112790Smdodd		for (i = 0; i < count; i++)
877112790Smdodd			device_delete_child(device_get_parent(devs[i]), devs[i]);
878241066Skevlo		free(devs, M_TEMP);
879112790Smdodd		break;
880112790Smdodd	default:
881112790Smdodd		break;
882112790Smdodd	};
883112790Smdodd
884112790Smdodd	return (0);
885112790Smdodd}
886