1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2000 Mitsuru IWASAKI
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/socket.h>
37
38 #include <sys/module.h>
39 #include <sys/bus.h>
40
41 #include <machine/bus.h>
42 #include <machine/resource.h>
43 #include <sys/rman.h>
44
45 #include <net/if.h>
46 #include <net/if_arp.h>
47 #include <net/if_media.h>
48
49 #include <dev/ex/if_exreg.h>
50 #include <dev/ex/if_exvar.h>
51
52 #include <dev/pccard/pccardvar.h>
53 #include <dev/pccard/pccard_cis.h>
54 #include "pccarddevs.h"
55
56 static const struct pccard_product ex_pccard_products[] = {
57 PCMCIA_CARD(OLICOM, OC2220),
58 PCMCIA_CARD(OLICOM, OC2231),
59 PCMCIA_CARD(OLICOM, OC2232),
60 PCMCIA_CARD(INTEL, ETHEREXPPRO),
61 { NULL }
62 };
63
64 /* Bus Front End Functions */
65 static int ex_pccard_probe(device_t);
66 static int ex_pccard_attach(device_t);
67
68 static int
69 ex_pccard_enet_ok(u_char *enaddr)
70 {
71 int i;
72 u_char sum;
73
74 if (enaddr[0] == 0xff)
75 return (0);
76 for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
77 sum |= enaddr[i];
78 return (sum != 0);
79 }
80
81 static int
82 ex_pccard_silicom_cb(const struct pccard_tuple *tuple, void *arg)
83 {
84 u_char *enaddr = arg;
85 int i;
86
87 if (tuple->code != CISTPL_FUNCE)
88 return (0);
89 if (tuple->length != 15)
90 return (0);
91 if (pccard_tuple_read_1(tuple, 6) != 6)
92 return (0);
93 for (i = 0; i < 6; i++)
94 enaddr[i] = pccard_tuple_read_1(tuple, 7 + i);
95 return (1);
96 }
97
98 static void
99 ex_pccard_get_silicom_mac(device_t dev, u_char *ether_addr)
100 {
101 pccard_cis_scan(dev, ex_pccard_silicom_cb, ether_addr);
102 }
103
104 static int
105 ex_pccard_probe(device_t dev)
106 {
107 const struct pccard_product *pp;
108 int error, i, j;
109 uint32_t fcn = PCCARD_FUNCTION_UNSPEC;
110
111 if ((pp = pccard_product_lookup(dev, ex_pccard_products,
112 sizeof(ex_pccard_products[0]), NULL)) == NULL)
113 return (EIO);
114 if (pp->pp_name != NULL)
115 device_set_desc(dev, pp->pp_name);
116 /*
117 * Olicom 22.8k and 33.6k modems need to activate the right
118 * CFE. The odd formula below replicates the sequence of cfes
119 * that have multiple resources:
120 * 9, 11, 13, 15, 0 + 9
121 * 25, 27, 29, 31, 16 + 9
122 * 41, 43, 45, 47, 32 + 9
123 * 57, 59, 61, 63 48 + 9
124 * (entries 8, 24, 40 and 56 are single resoruce cfes)
125 * Fortunately the code that enables and disables the multiple
126 * fuctions of the card won't mess with the lower bit for cards
127 * that aren't stanards conforming MFC cards (which these olicom
128 * cards aren't).
129 *
130 * Note: These cards still don't get interrupts for reasons
131 * unknown, even when the right cfe is selected. There's likely
132 * something in the CCR that needs to be manually tweaked, but
133 * the COR bits seem to all be used. Bit 0 and 3 are always set
134 * and the other bits select the config to use. Maybe one of those
135 * two bits needs to be cleared, or there's something else in the
136 * CCR that needs tweaking. The pattern of resources suggests
137 * bit 0 turns on the ethernet, however...
138 */
139 if (pp->pp_vendor == PCMCIA_VENDOR_OLICOM &&
140 (pp->pp_product == PCMCIA_PRODUCT_OLICOM_OC2231 ||
141 pp->pp_product == PCMCIA_PRODUCT_OLICOM_OC2232)) {
142 if (pccard_select_cfe(dev, 1) == 0)
143 goto good;
144 for (i = 0; i < 4; i++) {
145 for (j = 0; j < 4; j++) {
146 printf("Trying %d %d\n", i, j);
147 if (pccard_select_cfe(dev,
148 (i << 4) + (j << 1) + 9) == 0)
149 goto good;
150 }
151 }
152 /* Can't activate the net entries, punt */
153 return (EIO);
154 }
155 /*
156 * All other cards supported by this driver don't need specail
157 * treatment, so just filter based on the type of card. The
158 * special treatment ones are setup to 'fail safe' to a modem so
159 * this check would effectively filter them out as well.
160 */
161 error = pccard_get_function(dev, &fcn);
162 if (error != 0)
163 return (error);
164 if (fcn != PCCARD_FUNCTION_NETWORK)
165 return (EIO);
166 good:;
167 return (0);
168 }
169
170 static int
171 ex_pccard_attach(device_t dev)
172 {
173 struct ex_softc * sc = device_get_softc(dev);
174 int error = 0;
175 u_char ether_addr[ETHER_ADDR_LEN];
176
177 sc->dev = dev;
178 sc->ioport_rid = 0;
179 sc->irq_rid = 0;
180
181 if ((error = ex_alloc_resources(dev)) != 0) {
182 device_printf(dev, "ex_alloc_resources() failed!\n");
183 goto bad;
184 }
185
186 /*
187 * Fill in several fields of the softc structure:
188 * - Hardware Ethernet address.
189 * - IRQ number.
190 */
191 sc->irq_no = rman_get_start(sc->irq);
192
193 /* Try to get the ethernet address from the chip, then the CIS */
194 ex_get_address(sc, ether_addr);
195 if (!ex_pccard_enet_ok(ether_addr))
196 pccard_get_ether(dev, ether_addr);
197 if (!ex_pccard_enet_ok(ether_addr))
198 ex_pccard_get_silicom_mac(dev, ether_addr);
199 if (!ex_pccard_enet_ok(ether_addr)) {
200 device_printf(dev, "No NIC address found.\n");
201 error = ENXIO;
202 goto bad;
203 }
204 bcopy(ether_addr, sc->enaddr, ETHER_ADDR_LEN);
205
206 if ((error = ex_attach(dev)) != 0) {
207 device_printf(dev, "ex_attach() failed!\n");
208 goto bad;
209 }
210
211 return(0);
212 bad:
213 ex_release_resources(dev);
214 return (error);
215 }
216 static device_method_t ex_pccard_methods[] = {
217 /* Device interface */
218 DEVMETHOD(device_probe, ex_pccard_probe),
219 DEVMETHOD(device_attach, ex_pccard_attach),
220 DEVMETHOD(device_detach, ex_detach),
221
222 { 0, 0 }
223 };
224
225 static driver_t ex_pccard_driver = {
226 "ex",
227 ex_pccard_methods,
228 sizeof(struct ex_softc),
229 };
230
231 DRIVER_MODULE(ex, pccard, ex_pccard_driver, ex_devclass, 0, 0);
232 MODULE_DEPEND(ex, pccard, 1, 1, 1);
233 PCCARD_PNP_INFO(ex_pccard_products);
Cache object: 308080d5e30fa20194f2d63a746c0c5b
|