]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ex/if_ex_pccard.c
MFV r330102: ntp 4.2.8p11
[FreeBSD/FreeBSD.git] / sys / dev / ex / if_ex_pccard.c
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);