No empty .Rs/.Re
[netbsd-mini2440.git] / sys / dev / isa / if_trtcm_isa.c
blob88835ea4a5ceb66fcd7b9305f4f868678d22caef
1 /* $NetBSD: if_trtcm_isa.c,v 1.18 2009/05/12 08:44:19 cegger Exp $ */
3 /* XXXJRT verify doens't change isa_attach_args too early */
5 /*
6 * Copyright (c) 1999 The NetBSD Foundation, Inc.
7 * All rights reserved.
9 * This code is derived from software contributed to The NetBSD Foundation
10 * by Onno van der Linden.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/cdefs.h>
35 __KERNEL_RCSID(0, "$NetBSD: if_trtcm_isa.c,v 1.18 2009/05/12 08:44:19 cegger Exp $");
37 #undef TRTCMISADEBUG
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/socket.h>
42 #include <sys/device.h>
43 #include <sys/malloc.h>
45 #include <net/if.h>
46 #include <net/if_ether.h>
47 #include <net/if_media.h>
49 #include <sys/bus.h>
51 #include <dev/isa/isavar.h>
52 #include <dev/isa/elink.h>
54 #include <dev/ic/tropicreg.h>
55 #include <dev/ic/tropicvar.h>
57 #include <dev/ic/elink3reg.h>
59 u_int16_t tcmreadeeprom(bus_space_tag_t, bus_space_handle_t, int);
60 #ifdef TRTCMISADEBUG
61 void tcmdumpeeprom(bus_space_tag_t, bus_space_handle_t);
62 #endif
64 int trtcm_isa_probe(device_t, cfdata_t, void *);
66 int trtcm_isa_mediachange(struct tr_softc *);
67 void trtcm_isa_mediastatus(struct tr_softc *, struct ifmediareq *);
70 * TODO:
72 * if_media handling in the 3com case
73 * mediachange() and mediastatus() function
74 * certain newer cards can set their speed on the fly via
75 * DIR_SET_DEFAULT_RING_SPEED or set the speed in the eeprom ??
78 static void tcmaddcard(int, int, int, int, u_int, int, int);
81 * This keeps track of which ISAs have been through a 3com probe sequence.
82 * A simple static variable isn't enough, since it's conceivable that
83 * a system might have more than one ISA bus.
85 * The "tcm_bus" member is the unit number of the parent ISA bus, e.g. "0"
86 * for "isa0".
88 struct tcm_isa_done_probe {
89 LIST_ENTRY(tcm_isa_done_probe) tcm_link;
90 int tcm_bus;
92 static LIST_HEAD(, tcm_isa_done_probe) tcm_isa_all_probes;
93 static int tcm_isa_probes_initialized;
95 #define MAXTCMCARDS 20 /* if you have more than 20, you lose */
97 static struct tcmcard {
98 int bus;
99 int iobase;
100 int irq;
101 int maddr;
102 u_int msize;
103 long model;
104 char available;
105 char pnpmode;
106 } tcmcards[MAXTCMCARDS];
108 static int ntcmcards = 0;
110 static void
111 tcmaddcard(int bus, int iobase, int irq, int maddr, u_int msiz, int model, int pnpmode)
114 if (ntcmcards >= MAXTCMCARDS)
115 return;
116 tcmcards[ntcmcards].bus = bus;
117 tcmcards[ntcmcards].iobase = iobase;
118 tcmcards[ntcmcards].irq = irq;
119 tcmcards[ntcmcards].maddr = maddr;
120 tcmcards[ntcmcards].msize = msiz;
121 tcmcards[ntcmcards].model = model;
122 tcmcards[ntcmcards].available = 1;
123 tcmcards[ntcmcards].pnpmode = pnpmode;
124 ntcmcards++;
128 * We get eeprom data from the id_port given an offset into the
129 * eeprom. Basically; after the ID_sequence is sent to all of
130 * the cards; they enter the ID_CMD state where they will accept
131 * command requests. 0x80-0xbf loads the eeprom data. We then
132 * read the port 16 times and with every read; the cards check
133 * for contention (ie: if one card writes a 0 bit and another
134 * writes a 1 bit then the host sees a 0. At the end of the cycle;
135 * each card compares the data on the bus; if there is a difference
136 * then that card goes into ID_WAIT state again). In the meantime;
137 * one bit of data is returned in the AX register which is conveniently
138 * returned to us by bus_space_read_1(). Hence; we read 16 times getting one
139 * bit of data with each read.
141 * NOTE: the caller must provide an i/o handle for ELINK_ID_PORT!
143 u_int16_t
144 tcmreadeeprom(bus_space_tag_t iot, bus_space_handle_t ioh, int offset)
146 u_int16_t data = 0;
147 int i;
149 bus_space_write_1(iot, ioh, 0, 0x80 + offset);
150 delay(1000);
151 for (i = 0; i < 16; i++)
152 data = (data << 1) | (bus_space_read_2(iot, ioh, 0) & 1);
153 return (data);
156 #ifdef TRTCMISADEBUG
158 * Dump the contents of the EEPROM to the console.
160 void
161 tcmdumpeeprom(bus_space_tag_t iot, bus_space_handle_t ioh)
163 unsigned int off, val;
165 printf("EEPROM contents:");
166 for (off=0; off < 32; off++) {
167 val = tcmreadeeprom(iot, ioh, off);
168 if ((off % 8) == 0)
169 printf("\n");
170 printf("%04x ", val);
172 printf("\n");
174 #endif
177 trtcm_isa_mediachange(struct tr_softc *sc)
179 return EINVAL;
182 void
183 trtcm_isa_mediastatus(struct tr_softc *sc, struct ifmediareq *ifmr)
185 struct ifmedia *ifm = &sc->sc_media;
187 ifmr->ifm_active = ifm->ifm_cur->ifm_media;
190 /* XXX hard coded constants in readeeprom elink_idseq */
193 trtcm_isa_probe(device_t parent, cfdata_t match, void *aux)
195 struct isa_attach_args *ia = aux;
196 int bus = device_unit(parent);
197 bus_space_tag_t iot = ia->ia_iot;
198 bus_space_handle_t ioh;
199 u_int msiz;
200 int slot, iobase, irq, i, maddr, rsrccfg, pnpmode;
201 u_int16_t vendor, model;
202 struct tcm_isa_done_probe *tcm;
203 static int irqs[] = { 7, 15, 6, 11, 3, 10, 9, 5 };
205 if (ISA_DIRECT_CONFIG(ia))
206 return (0);
208 if (tcm_isa_probes_initialized == 0) {
209 LIST_INIT(&tcm_isa_all_probes);
210 tcm_isa_probes_initialized = 1;
214 * Probe this bus if we haven't done so already.
216 for (tcm = tcm_isa_all_probes.lh_first; tcm != NULL;
217 tcm = tcm->tcm_link.le_next)
218 if (tcm->tcm_bus == bus)
219 goto bus_probed;
222 * Mark this bus so we don't probe it again.
224 tcm = (struct tcm_isa_done_probe *)
225 malloc(sizeof(struct tcm_isa_done_probe), M_DEVBUF, M_NOWAIT);
226 if (tcm == NULL) {
227 printf("trtcm_isa_probe: can't allocate state storage");
228 return 0;
231 tcm->tcm_bus = bus;
232 LIST_INSERT_HEAD(&tcm_isa_all_probes, tcm, tcm_link);
235 * Map the TokenLink ID port for the probe sequence.
237 if (bus_space_map(iot, ELINK_ID_PORT, 1, 0, &ioh)) {
238 printf("trtcm_isa_probe: can't map TokenLink ID port\n");
239 return 0;
242 for (slot = 0; slot < MAXTCMCARDS; slot++) {
243 pnpmode = 0;
244 elink_reset(iot, ioh, bus);
245 elink_idseq(iot, ioh, TLINK_619_POLY);
247 /* Untag all the adapters so they will talk to us. */
248 if (slot == 0)
249 bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 0);
251 vendor = htons(tcmreadeeprom(iot, ioh, EEPROM_MFG_ID));
252 if (vendor != MFG_ID)
253 continue;
255 model = htons(tcmreadeeprom(iot, ioh, EEPROM_PROD_ID));
256 if (((model & 0xfff0) != 0x6190) &&
257 ((model & 0xfff0) != 0x3190)) { /* XXX hardcoded */
258 #if 0
259 printf("trtcm: unknown model 0x%04x\n", model);
260 #endif
261 continue;
263 #ifdef TRTCMISADEBUG
264 tcmdumpeeprom(iot, ioh);
266 printf("speed: %d\n", (tcmreadeeprom(iot,ioh,8) & 2) ? 4 : 16);
267 #endif
269 rsrccfg = iobase = tcmreadeeprom(iot, ioh, EEPROM_RESOURCE_CFG);
270 if (iobase & 0x20)
271 iobase = tcmreadeeprom(iot, ioh, EEPROM_ADDR_CFG) & 1 ?
272 0xa20 : 0xa24;
273 else
274 iobase = (iobase & 0x1f) * 0x10 + 0x200;
276 maddr = ((tcmreadeeprom(iot, ioh, EEPROM_OEM_ADDR0) & 0xfc00)
277 << 3) + 0x80000;
278 msiz = 65536 >> ((tcmreadeeprom(iot, ioh, 8) & 0x0c) >> 2);
280 irq = tcmreadeeprom(iot, ioh, EEPROM_ADDR_CFG) & 0x180;
281 irq |= (tcmreadeeprom(iot, ioh, EEPROM_RESOURCE_CFG) & 0x40);
282 irq = irqs[irq >> 6];
284 /* Tag card so it will not respond to contention again. */
285 bus_space_write_1(iot, ioh, 0, TAG_ADAPTER + 1);
288 * Don't attach a 3c319 in PnP mode.
290 * XXX Testing for the 13th bit in iobase being 0 might not
291 * be the right thing to do, but the EEPROM of the 3C319 is
292 * undocumented according to 3COM and this is one of the
293 * three bits that changed when I put the card in PnP mode. -chb
295 if (((model & 0xffff0) == 0x3190) &&
296 ((rsrccfg & 0x1000) == 0)) {
297 printf("3COM 3C319 TokenLink Velocity in PnP mode\n");
298 pnpmode = 1;
300 else {
302 * XXX: this should probably not be done here
303 * because it enables the drq/irq lines from
304 * the board. Perhaps it should be done after
305 * we have checked for irq/drq collisions?
307 bus_space_write_1(iot, ioh, 0,
308 ACTIVATE_ADAPTER_TO_CONFIG);
310 tcmaddcard(bus, iobase, irq, maddr, msiz, model, pnpmode);
312 bus_space_unmap(iot, ioh, 1);
314 bus_probed:
316 if (ia->ia_nio < 1)
317 return (0);
318 if (ia->ia_niomem < 1)
319 return (0);
320 if (ia->ia_nirq < 1)
321 return (0);
323 for (i = 0; i < ntcmcards; i++) {
324 if (tcmcards[i].bus != bus)
325 continue;
326 if (tcmcards[i].available == 0)
327 continue;
328 if (ia->ia_io[0].ir_addr != ISA_UNKNOWN_PORT &&
329 ia->ia_io[0].ir_addr != tcmcards[i].iobase)
330 continue;
331 if (ia->ia_irq[0].ir_irq != ISA_UNKNOWN_IRQ &&
332 ia->ia_irq[0].ir_irq != tcmcards[i].irq)
333 continue;
334 goto good;
336 return 0;
338 good:
339 tcmcards[i].available = 0;
340 if (tcmcards[i].pnpmode)
341 return -1; /* XXX Don't actually probe this card. */
343 ia->ia_nio = 1;
344 ia->ia_io[0].ir_addr = tcmcards[i].iobase;
345 /* XXX probably right, but ...... */
346 if (ia->ia_io[0].ir_addr == 0xa20 || ia->ia_io[0].ir_addr == 0xa24)
347 ia->ia_io[0].ir_size = 4;
348 else
349 ia->ia_io[0].ir_size = 16;
351 ia->ia_niomem = 1;
352 ia->ia_iomem[0].ir_addr = tcmcards[i].maddr;
353 ia->ia_iomem[0].ir_size = tcmcards[i].msize;
355 ia->ia_nirq = 1;
356 ia->ia_irq[0].ir_irq = tcmcards[i].irq;
358 ia->ia_ndrq = 0;
360 ia->ia_aux = (void *) tcmcards[i].model;
361 return 1;