if_ed_pccard.c revision 67164
1255570Strasz/*
2255570Strasz * Copyright (c) 1995, David Greenman
3255570Strasz * All rights reserved.
4255570Strasz *
5255570Strasz * Redistribution and use in source and binary forms, with or without
6255570Strasz * modification, are permitted provided that the following conditions
7255570Strasz * are met:
8255570Strasz * 1. Redistributions of source code must retain the above copyright
9255570Strasz *    notice unmodified, this list of conditions, and the following
10270907Sngie *    disclaimer.
11255570Strasz * 2. Redistributions in binary form must reproduce the above copyright
12255570Strasz *    notice, this list of conditions and the following disclaimer in the
13255570Strasz *    documentation and/or other materials provided with the distribution.
14255570Strasz *
15255570Strasz * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16255570Strasz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17255570Strasz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18255570Strasz * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19255570Strasz * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 * $FreeBSD: head/sys/dev/ed/if_ed_pccard.c 67164 2000-10-15 14:19:01Z phk $
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/socket.h>
33#include <sys/kernel.h>
34#include <sys/conf.h>
35#include <sys/uio.h>
36#include <sys/select.h>
37
38#include <sys/module.h>
39#include <sys/bus.h>
40#include <machine/bus.h>
41#include <sys/rman.h>
42#include <machine/resource.h>
43
44#include <net/ethernet.h>
45#include <net/if.h>
46#include <net/if_arp.h>
47#include <net/if_mib.h>
48
49#include <dev/ed/if_edreg.h>
50#include <dev/ed/if_edvar.h>
51#include <dev/pccard/pccardvar.h>
52#include "card_if.h"
53
54/*
55 *      PC-Card (PCMCIA) specific code.
56 */
57static int	ed_pccard_probe(device_t);
58static int	ed_pccard_attach(device_t);
59static int	ed_pccard_detach(device_t);
60
61static void	ax88190_geteprom(struct ed_softc *);
62static int	ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
63static int	linksys;
64
65static device_method_t ed_pccard_methods[] = {
66	/* Device interface */
67	DEVMETHOD(device_probe,		ed_pccard_probe),
68	DEVMETHOD(device_attach,	ed_pccard_attach),
69	DEVMETHOD(device_detach,	ed_pccard_detach),
70
71	{ 0, 0 }
72};
73
74static driver_t ed_pccard_driver = {
75	"ed",
76	ed_pccard_methods,
77	sizeof(struct ed_softc)
78};
79
80static devclass_t ed_pccard_devclass;
81
82DRIVER_MODULE(ed, pccard, ed_pccard_driver, ed_pccard_devclass, 0, 0);
83
84/*
85 *      ed_pccard_detach - unload the driver and clear the table.
86 *      XXX TODO:
87 *      This is usually called when the card is ejected, but
88 *      can be caused by a modunload of a controller driver.
89 *      The idea is to reset the driver's view of the device
90 *      and ensure that any driver entry points such as
91 *      read and write do not hang.
92 */
93static int
94ed_pccard_detach(device_t dev)
95{
96	struct ed_softc *sc = device_get_softc(dev);
97	struct ifnet *ifp = &sc->arpcom.ac_if;
98
99	if (sc->gone) {
100		device_printf(dev, "already unloaded\n");
101		return (0);
102	}
103	ed_stop(sc);
104	ifp->if_flags &= ~IFF_RUNNING;
105	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
106	sc->gone = 1;
107	bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
108	ed_release_resources(dev);
109	return (0);
110}
111
112/*
113 * Probe framework for pccards.  Replicates the standard framework,
114 * minus the pccard driver registration and ignores the ether address
115 * supplied (from the CIS), relying on the probe to find it instead.
116 */
117static int
118ed_pccard_probe(device_t dev)
119{
120	struct	ed_softc *sc = device_get_softc(dev);
121	int	flags = device_get_flags(dev);
122	int	error;
123
124	if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_AX88190) {
125		/* Special setup for AX88190 */
126		int iobase;
127
128		/* Allocate the port resource during setup. */
129		error = ed_alloc_port(dev, 0, ED_NOVELL_IO_PORTS);
130		if (error)
131			return (error);
132
133		sc->asic_offset = ED_NOVELL_ASIC_OFFSET;
134		sc->nic_offset  = ED_NOVELL_NIC_OFFSET;
135
136		sc->chip_type = ED_CHIP_TYPE_AX88190;
137
138		/*
139		 * Set Attribute Memory IOBASE Register
140		 */
141		iobase = rman_get_start(sc->port_res);
142		ed_pccard_memwrite(dev, ED_AX88190_IOBASE0,
143				   iobase & 0xff);
144		ed_pccard_memwrite(dev, ED_AX88190_IOBASE1,
145				   (iobase >> 8) & 0xff);
146		ax88190_geteprom(sc);
147
148		ed_release_resources(dev);
149	}
150
151	error = ed_probe_Novell(dev, 0, flags);
152	if (error == 0)
153		goto end;
154	ed_release_resources(dev);
155
156	error = ed_probe_WD80x3(dev, 0, flags);
157	if (error == 0)
158		goto end;
159	ed_release_resources(dev);
160	goto end2;
161
162end:
163	linksys = ed_get_Linksys(dev);
164end2:
165	if (error == 0)
166		error = ed_alloc_irq(dev, 0, 0);
167
168	ed_release_resources(dev);
169	return (error);
170}
171
172static int
173ed_pccard_attach(device_t dev)
174{
175	struct ed_softc *sc = device_get_softc(dev);
176	int flags = device_get_flags(dev);
177	int error;
178	int i;
179	u_char sum;
180	u_char ether_addr[ETHER_ADDR_LEN];
181
182	if (sc->port_used > 0)
183		ed_alloc_port(dev, sc->port_rid, sc->port_used);
184	if (sc->mem_used)
185		ed_alloc_memory(dev, sc->mem_rid, sc->mem_used);
186	ed_alloc_irq(dev, sc->irq_rid, 0);
187
188	error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
189			       edintr, sc, &sc->irq_handle);
190	if (error) {
191		printf("setup intr failed %d \n", error);
192		ed_release_resources(dev);
193		return (error);
194	}
195
196	if (linksys == 0) {
197		pccard_get_ether(dev, ether_addr);
198		for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
199			sum |= ether_addr[i];
200		if (sum)
201			bcopy(ether_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
202	}
203
204	error = ed_attach(sc, device_get_unit(dev), flags);
205	return (error);
206}
207
208static void
209ax88190_geteprom(struct ed_softc *sc)
210{
211	int prom[16],i;
212	u_char tmp;
213	struct {
214		unsigned char offset, value;
215	} pg_seq[] = {
216		{ED_P0_CR, ED_CR_RD2|ED_CR_STP},	/* Select Page0 */
217		{ED_P0_DCR, 0x01},
218		{ED_P0_RBCR0, 0x00},	/* Clear the count regs. */
219		{ED_P0_RBCR1, 0x00},
220		{ED_P0_IMR, 0x00},	/* Mask completion irq. */
221		{ED_P0_ISR, 0xff},
222		{ED_P0_RCR, ED_RCR_MON | ED_RCR_INTT},	/* Set To Monitor */
223		{ED_P0_TCR, ED_TCR_LB0},	/* loopback mode. */
224		{ED_P0_RBCR0, 32},
225		{ED_P0_RBCR1, 0x00},
226		{ED_P0_RSAR0, 0x00},
227		{ED_P0_RSAR1, 0x04},
228		{ED_P0_CR ,ED_CR_RD0 | ED_CR_STA},
229	};
230
231	/* Reset Card */
232	tmp = ed_asic_inb(sc, ED_NOVELL_RESET);
233	ed_asic_outb(sc, ED_NOVELL_RESET, tmp);
234	DELAY(5000);
235	ed_asic_outb(sc, ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
236	DELAY(5000);
237
238	/* Card Settings */
239	for (i = 0; i < sizeof(pg_seq) / sizeof(pg_seq[0]); i++)
240		ed_nic_outb(sc, pg_seq[i].offset, pg_seq[i].value);
241
242	/* Get Data */
243	for (i = 0; i < 16; i++)
244		prom[i] = ed_asic_inb(sc, 0);
245/*
246	for (i = 0; i < 16; i++)
247		printf("ax88190 eprom [%02d] %02x %02x\n",
248			i,prom[i] & 0xff,prom[i] >> 8);
249*/
250	sc->arpcom.ac_enaddr[0] = prom[0] & 0xff;
251	sc->arpcom.ac_enaddr[1] = prom[0] >> 8;
252	sc->arpcom.ac_enaddr[2] = prom[1] & 0xff;
253	sc->arpcom.ac_enaddr[3] = prom[1] >> 8;
254	sc->arpcom.ac_enaddr[4] = prom[2] & 0xff;
255	sc->arpcom.ac_enaddr[5] = prom[2] >> 8;
256}
257
258static int
259ed_pccard_memwrite(device_t dev, off_t offset, u_char byte)
260{
261	int cis_rid;
262	struct resource *cis;
263
264	cis_rid = 0;
265	cis = bus_alloc_resource(dev, SYS_RES_MEMORY, &cis_rid, 0, ~0, 4 << 10, RF_ACTIVE | RF_SHAREABLE);
266	if (cis == NULL)
267		return (ENXIO);
268	CARD_SET_RES_FLAGS(device_get_parent(dev), dev, SYS_RES_MEMORY, cis_rid, PCCARD_A_MEM_ATTR);
269
270	bus_space_write_1(rman_get_bustag(cis), rman_get_bushandle(cis), offset, byte);
271
272	bus_release_resource(dev, SYS_RES_MEMORY, cis_rid, cis);
273
274	return (0);
275}
276