]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ed/if_ed_pccard.c
This commit was generated by cvs2svn to compensate for changes in r64593,
[FreeBSD/FreeBSD.git] / sys / dev / ed / if_ed_pccard.c
1 /*
2  * Copyright (c) 1995, David Greenman
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 unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * 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$
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 #include <machine/clock.h>
38
39 #include <sys/module.h>
40 #include <sys/bus.h>
41 #include <machine/bus.h>
42
43 #include <net/ethernet.h>
44 #include <net/if.h>
45 #include <net/if_arp.h>
46 #include <net/if_mib.h>
47
48 #include <dev/ed/if_edreg.h>
49 #include <dev/ed/if_edvar.h>
50 #include <dev/pccard/pccardvar.h>
51 #include <pccard/cardinfo.h>
52 #include <pccard/slot.h>
53
54 #define CARD_MAJOR      50
55
56 /*
57  *      PC-Card (PCMCIA) specific code.
58  */
59 static int      ed_pccard_probe(device_t);
60 static int      ed_pccard_attach(device_t);
61 static int      ed_pccard_detach(device_t);
62
63 static void     ax88190_geteprom(device_t);
64 static int      ed_pccard_memwrite(device_t dev, off_t offset, u_char byte);
65 static int      ed_pccard_memread(device_t dev, off_t offset, u_char *buf, int size);
66
67 static device_method_t ed_pccard_methods[] = {
68         /* Device interface */
69         DEVMETHOD(device_probe,         ed_pccard_probe),
70         DEVMETHOD(device_attach,        ed_pccard_attach),
71         DEVMETHOD(device_detach,        ed_pccard_detach),
72
73         { 0, 0 }
74 };
75
76 static driver_t ed_pccard_driver = {
77         "ed",
78         ed_pccard_methods,
79         sizeof(struct ed_softc)
80 };
81
82 static devclass_t ed_pccard_devclass;
83
84 DRIVER_MODULE(ed, pccard, ed_pccard_driver, ed_pccard_devclass, 0, 0);
85
86 /*
87  *      ed_pccard_detach - unload the driver and clear the table.
88  *      XXX TODO:
89  *      This is usually called when the card is ejected, but
90  *      can be caused by a modunload of a controller driver.
91  *      The idea is to reset the driver's view of the device
92  *      and ensure that any driver entry points such as
93  *      read and write do not hang.
94  */
95 static int
96 ed_pccard_detach(device_t dev)
97 {
98         struct ed_softc *sc = device_get_softc(dev);
99         struct ifnet *ifp = &sc->arpcom.ac_if;
100
101         if (sc->gone) {
102                 device_printf(dev, "already unloaded\n");
103                 return (0);
104         }
105         ed_stop(sc);
106         ifp->if_flags &= ~IFF_RUNNING;
107         ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
108         sc->gone = 1;
109         bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
110         ed_release_resources(dev);
111         return (0);
112 }
113
114 /* 
115  * Probe framework for pccards.  Replicates the standard framework,
116  * minus the pccard driver registration and ignores the ether address
117  * supplied (from the CIS), relying on the probe to find it instead.
118  */
119 static int
120 ed_pccard_probe(device_t dev)
121 {
122         int     error;
123         int     flags;
124         struct ed_softc *sc = device_get_softc(dev);
125
126         flags = device_get_flags(dev);
127
128         if (ED_FLAGS_GETTYPE(flags) == ED_FLAGS_AX88190) {
129                 /* Special setup for AX88190 */
130                 u_char rdbuf[4];
131                 int iobase;
132                 int attr_ioport;
133                 sc->chip_type = ED_CHIP_TYPE_AX88190;
134                 /*
135                  * Check & Set Attribute Memory IOBASE Register
136                  */
137                 ed_pccard_memread(dev,ED_AX88190_IOBASE0,rdbuf,4);
138                 attr_ioport = rdbuf[2] << 8 | rdbuf[0];
139                 iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
140                 if (attr_ioport != iobase) {
141 #if notdef
142                         printf("AX88190 IOBASE MISMATCH %04x -> %04x Setting\n",attr_ioport,iobase);
143 #endif /* notdef */
144                         ed_pccard_memwrite(dev,ED_AX88190_IOBASE0,iobase & 0xff);
145                         ed_pccard_memwrite(dev,ED_AX88190_IOBASE1,(iobase >> 8) & 0xff);
146                 }
147                 ax88190_geteprom(dev);
148         }
149
150         error = ed_probe_Novell(dev);
151         if (error == 0)
152                 goto end;
153         ed_release_resources(dev);
154
155         error = ed_probe_WD80x3(dev);
156         if (error == 0)
157                 goto end;
158         ed_release_resources(dev);
159
160 end:
161         if (error == 0)
162                 error = ed_alloc_irq(dev, 0, 0);
163
164         ed_release_resources(dev);
165         return (error);
166 }
167
168 static int
169 ed_pccard_attach(device_t dev)
170 {
171         struct ed_softc *sc = device_get_softc(dev);
172         int flags = device_get_flags(dev);
173         int error;
174         int i;
175         u_char sum;
176         u_char ether_addr[ETHER_ADDR_LEN];
177         
178         if (sc->port_used > 0)
179                 ed_alloc_port(dev, sc->port_rid, sc->port_used);
180         if (sc->mem_used)
181                 ed_alloc_memory(dev, sc->mem_rid, sc->mem_used);
182         ed_alloc_irq(dev, sc->irq_rid, 0);
183                 
184         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET,
185                                edintr, sc, &sc->irq_handle);
186         if (error) {
187                 printf("setup intr failed %d \n", error);
188                 ed_release_resources(dev);
189                 return (error);
190         }             
191
192         if (ed_get_Linksys(sc) == 0) {
193                 pccard_get_ether(dev, ether_addr);
194                 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
195                         sum |= ether_addr[i];
196                 if (sum)
197                         bcopy(ether_addr, sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
198         }
199
200         error = ed_attach(sc, device_get_unit(dev), flags);
201         return (error);
202
203
204 static void
205 ax88190_geteprom(device_t dev)
206 {
207         int prom[16],i;
208         u_char tmp;
209         struct ed_softc *sc;
210         struct pccard_devinfo *devi;
211         int iobase;
212         struct {
213                 unsigned char offset,value;
214         } pg_seq[]={
215                 {ED_P0_CR ,ED_CR_RD2|ED_CR_STP}, /* Select Page0 */
216                 {ED_P0_DCR,0x01},
217                 {ED_P0_RBCR0, 0x00}, /* Clear the count regs. */
218                 {ED_P0_RBCR1, 0x00},
219                 {ED_P0_IMR, 0x00},   /* Mask completion irq. */
220                 {ED_P0_ISR, 0xff},
221                 {ED_P0_RCR, ED_RCR_MON|ED_RCR_INTT}, /* Set To Monitor */
222                 {ED_P0_TCR, ED_TCR_LB0},             /* loopback mode. */
223                 {ED_P0_RBCR0,32},
224                 {ED_P0_RBCR1,0x00},
225                 {ED_P0_RSAR0,0x00},
226                 {ED_P0_RSAR1,0x04},
227                 {ED_P0_CR ,ED_CR_RD0|ED_CR_STA},
228         };
229
230         sc = device_get_softc(dev);
231         devi = device_get_ivars(dev);
232         iobase = bus_get_resource_start(dev, SYS_RES_IOPORT, 0);
233
234         /* XXX: no bus_space_*()? */
235
236         /* Default Set */
237         sc->asic_addr = iobase + ED_NOVELL_ASIC_OFFSET;
238         sc->nic_addr = iobase + ED_NOVELL_NIC_OFFSET;
239         /* Reset Card */
240         tmp = inb(sc->asic_addr + ED_NOVELL_RESET);
241         outb(sc->asic_addr + ED_NOVELL_RESET, tmp);
242         DELAY(5000);
243         outb(sc->nic_addr + ED_P0_CR, ED_CR_RD2 | ED_CR_STP);
244         DELAY(5000);
245
246         /* Card Settings */
247         for(i=0;i<sizeof(pg_seq)/sizeof(pg_seq[0]);i++) {
248                 outb(sc->nic_addr + pg_seq[i].offset , pg_seq[i].value);
249         }
250
251         /* Get Data */
252         for(i=0;i<16;i++) {
253                 prom[i] = inw(sc->asic_addr);
254         }
255 /*
256         for(i=0;i<16;i++) {
257                 printf("ax88190 eprom [%02d] %02x %02x\n",
258                         i,prom[i] & 0xff,prom[i] >> 8);
259         }
260 */
261         sc->arpcom.ac_enaddr[0] = prom[0] & 0xff;
262         sc->arpcom.ac_enaddr[1] = prom[0] >> 8;
263         sc->arpcom.ac_enaddr[2] = prom[1] & 0xff;
264         sc->arpcom.ac_enaddr[3] = prom[1] >> 8;
265         sc->arpcom.ac_enaddr[4] = prom[2] & 0xff;
266         sc->arpcom.ac_enaddr[5] = prom[2] >> 8;
267
268         return;
269 }
270
271 /* XXX: Warner-san, any plan to provide access to the attribute memory? */
272 static int
273 ed_pccard_memwrite(device_t dev, off_t offset, u_char byte)
274 {
275         struct pccard_devinfo *devi;
276         dev_t d;
277         struct iovec iov;
278         struct uio uios;
279
280         devi = device_get_ivars(dev);
281
282         iov.iov_base = &byte;
283         iov.iov_len = sizeof(byte);
284
285         uios.uio_iov = &iov;
286         uios.uio_iovcnt = 1;
287         uios.uio_offset = offset;
288         uios.uio_resid = sizeof(byte);
289         uios.uio_segflg = UIO_SYSSPACE;
290         uios.uio_rw = UIO_WRITE;
291         uios.uio_procp = 0;
292
293         d = makedev(CARD_MAJOR, devi->slt->slotnum);
294         return devsw(d)->d_write(d, &uios, 0);
295 }
296
297 static int
298 ed_pccard_memread(device_t dev, off_t offset, u_char *buf, int size)
299 {
300         struct pccard_devinfo *devi;
301         dev_t d;
302         struct iovec iov;
303         struct uio uios;
304
305         devi = device_get_ivars(dev);
306
307         iov.iov_base = buf;
308         iov.iov_len = size;
309
310         uios.uio_iov = &iov;
311         uios.uio_iovcnt = 1;
312         uios.uio_offset = offset;
313         uios.uio_resid = size;
314         uios.uio_segflg = UIO_SYSSPACE;
315         uios.uio_rw = UIO_READ;
316         uios.uio_procp = 0;
317
318         d = makedev(CARD_MAJOR, devi->slt->slotnum);
319         return devsw(d)->d_read(d, &uios, 0);
320 }