]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/sn/if_sn_pccard.c
contrib/tzdata: import tzdata 2022f
[FreeBSD/FreeBSD.git] / sys / dev / sn / if_sn_pccard.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999 M. Warner Losh <imp@village.org> 
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 ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 /*
28  * Modifications for Megahertz X-Jack Ethernet Card (XJ-10BT)
29  * 
30  * Copyright (c) 1996 by Tatsumi Hosokawa <hosokawa@jp.FreeBSD.org>
31  *                       BSD-nomads, Tokyo, Japan.
32  */
33
34 #include <sys/cdefs.h>
35 __FBSDID("$FreeBSD$");
36
37 #include <sys/param.h>
38 #include <sys/bus.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/socket.h>
42 #include <sys/systm.h>
43
44 #include <net/ethernet.h> 
45 #include <net/if.h> 
46 #include <net/if_arp.h>
47
48 #include <machine/bus.h>
49 #include <machine/resource.h>
50 #include <sys/rman.h> 
51
52 #include <dev/pccard/pccardvar.h>
53 #include <dev/pccard/pccard_cis.h>
54 #include <dev/sn/if_snreg.h>
55 #include <dev/sn/if_snvar.h>
56
57 #include "card_if.h"
58 #include "pccarddevs.h"
59
60 typedef int sn_get_enaddr_t(device_t dev, u_char *eaddr);
61 typedef int sn_activate_t(device_t dev);
62
63 struct sn_sw
64 {
65         int type;
66 #define SN_NORMAL 1
67 #define SN_MEGAHERTZ 2
68 #define SN_OSITECH 3
69 #define SN_OSI_SOD 4
70 #define SN_MOTO_MARINER 5
71         char *typestr;
72         sn_get_enaddr_t *get_mac;
73         sn_activate_t *activate;
74 };
75
76 static sn_get_enaddr_t sn_pccard_normal_get_mac;
77 static sn_activate_t sn_pccard_normal_activate;
78 const static struct sn_sw sn_normal_sw = {
79         SN_NORMAL, "plain",
80         sn_pccard_normal_get_mac,
81         sn_pccard_normal_activate
82 };
83
84 static sn_get_enaddr_t sn_pccard_megahertz_get_mac;
85 static sn_activate_t sn_pccard_megahertz_activate;
86 const static struct sn_sw sn_mhz_sw = {
87         SN_MEGAHERTZ, "Megahertz",
88         sn_pccard_megahertz_get_mac,
89         sn_pccard_megahertz_activate
90 };
91
92 static const struct sn_product {
93         struct pccard_product prod;
94         const struct sn_sw *sw;
95 } sn_pccard_products[] = {
96         { PCMCIA_CARD(DSPSI, XJEM1144), &sn_mhz_sw },
97         { PCMCIA_CARD(DSPSI, XJACK), &sn_normal_sw },
98 /*      { PCMCIA_CARD(MOTOROLA, MARINER), SN_MOTO_MARINER }, */
99         { PCMCIA_CARD(NEWMEDIA, BASICS), &sn_normal_sw },
100         { PCMCIA_CARD(MEGAHERTZ, VARIOUS), &sn_mhz_sw},
101         { PCMCIA_CARD(MEGAHERTZ, XJEM3336), &sn_mhz_sw},
102 /*      { PCMCIA_CARD(OSITECH, TRUMP_SOD), SN_OSI_SOD }, */
103 /*      { PCMCIA_CARD(OSITECH, TRUMP_JOH), SN_OSITECH }, */
104 /*      { PCMCIA_CARD(PSION, GOLDCARD), SN_OSITECH }, */
105 /*      { PCMCIA_CARD(PSION, NETGLOBAL), SNI_OSI_SOD }, */
106 /*      { PCMCIA_CARD(PSION, NETGLOBAL2), SN_OSITECH }, */
107         { PCMCIA_CARD(SMC, 8020BT), &sn_normal_sw },
108         { PCMCIA_CARD(SMC, SMC91C96), &sn_normal_sw },
109         { { NULL } }
110         
111 };
112
113 static const struct sn_product *
114 sn_pccard_lookup(device_t dev)
115 {
116
117         return ((const struct sn_product *)
118             pccard_product_lookup(dev,
119                 (const struct pccard_product *)sn_pccard_products,
120                 sizeof(sn_pccard_products[0]), NULL));
121 }
122
123 static int
124 sn_pccard_probe(device_t dev)
125 {
126         const struct sn_product *pp;
127
128         if ((pp = sn_pccard_lookup(dev)) != NULL) {
129                 if (pp->prod.pp_name != NULL)
130                         device_set_desc(dev, pp->prod.pp_name);
131                 return 0;
132         }
133         return EIO;
134 }
135
136 static int
137 sn_pccard_ascii_enaddr(const char *str, u_char *enet)
138 {
139         uint8_t digit;
140         int i;
141
142         memset(enet, 0, ETHER_ADDR_LEN);
143         for (i = 0, digit = 0; i < (ETHER_ADDR_LEN * 2); i++) {
144                 if (str[i] >= '0' && str[i] <= '9')
145                         digit |= str[i] - '0';
146                 else if (str[i] >= 'a' && str[i] <= 'f')
147                         digit |= (str[i] - 'a') + 10;
148                 else if (str[i] >= 'A' && str[i] <= 'F')
149                         digit |= (str[i] - 'A') + 10;
150                 else
151                         return (0);             /* Bogus digit!! */
152
153                 /* Compensate for ordering of digits. */
154                 if (i & 1) {
155                         enet[i >> 1] = digit;
156                         digit = 0;
157                 } else
158                         digit <<= 4;
159         }
160
161         return (1);
162 }
163
164 static int
165 sn_pccard_normal_get_mac(device_t dev, u_char *eaddr)
166 {
167         int i, sum;
168         const char *cisstr;
169
170         pccard_get_ether(dev, eaddr);
171         for (i = 0, sum = 0; i < ETHER_ADDR_LEN; i++)
172                 sum |= eaddr[i];
173         if (sum == 0) {
174                 pccard_get_cis3_str(dev, &cisstr);
175                 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
176                     sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
177         }
178         if (sum == 0) {
179                 pccard_get_cis4_str(dev, &cisstr);
180                 if (cisstr && strlen(cisstr) == ETHER_ADDR_LEN * 2)
181                     sum = sn_pccard_ascii_enaddr(cisstr, eaddr);
182         }
183         return sum;
184 }
185
186 static int
187 sn_pccard_normal_activate(device_t dev)
188 {
189         int err;
190
191         err = sn_activate(dev);
192         if (err)
193                 sn_deactivate(dev);
194         return (err);
195 }
196
197 static int
198 sn_pccard_megahertz_mac(const struct pccard_tuple *tuple, void *argp)
199 {
200         uint8_t *enaddr = argp;
201         int i;
202         uint8_t buffer[ETHER_ADDR_LEN * 2];
203
204         /* Code 0x81 is Megahertz' special cis node contianing the MAC */
205         if (tuple->code != 0x81)
206                 return (0);
207
208         /* Make sure this is a sane node, as ASCII digits */
209         if (tuple->length != ETHER_ADDR_LEN * 2 + 1)
210                 return (0);
211
212         /* Copy the MAC ADDR and return success if decoded */
213         for (i = 0; i < ETHER_ADDR_LEN * 2; i++)
214                 buffer[i] = pccard_tuple_read_1(tuple, i);
215         return (sn_pccard_ascii_enaddr(buffer, enaddr));
216 }
217
218 static int
219 sn_pccard_megahertz_get_mac(device_t dev, u_char *eaddr)
220 {
221
222         if (sn_pccard_normal_get_mac(dev, eaddr))
223                 return 1;
224         /*
225          * If that fails, try the special CIS tuple 0x81 that the
226          * '3288 and '3336 cards have.  That tuple specifies an ASCII
227          * string, ala CIS3 or CIS4 in the 'normal' cards.
228          */
229         return (pccard_cis_scan(dev, sn_pccard_megahertz_mac, eaddr));
230 }
231
232 static int
233 sn_pccard_megahertz_activate(device_t dev)
234 {
235         int err;
236         struct sn_softc *sc = device_get_softc(dev);
237         u_long start;
238
239         err = sn_activate(dev);
240         if (err) {
241                 sn_deactivate(dev);
242                 return (err);
243         }
244         /*
245          * CIS resource is the modem one, so save it away.
246          */
247         sc->modem_rid = sc->port_rid;
248         sc->modem_res = sc->port_res;
249
250         /*
251          * The MHz XJEM/CCEM series of cards just need to have any
252          * old resource allocated for the ethernet side of things,
253          * provided bit 0x80 isn't set in the address.  That bit is
254          * evidentially reserved for modem function and is how the
255          * card steers the addresses internally.
256          */
257         sc->port_res = NULL;
258         start = 0;
259         do
260         {
261                 sc->port_rid = 1;
262                 sc->port_res = bus_alloc_resource(dev, SYS_RES_IOPORT,
263                     &sc->port_rid, start, ~0, SMC_IO_EXTENT, RF_ACTIVE);
264                 if (sc->port_res == NULL)
265                         break;
266                 if (!(rman_get_start(sc->port_res) & 0x80))
267                         break;
268                 start = rman_get_start(sc->port_res) + SMC_IO_EXTENT;
269                 bus_release_resource(dev, SYS_RES_IOPORT, sc->port_rid,
270                     sc->port_res);
271         } while (start < 0xff80);
272         if (sc->port_res == NULL) {
273                 sn_deactivate(dev);
274                 return ENOMEM;
275         }
276         return 0;
277 }
278
279 static int
280 sn_pccard_attach(device_t dev)
281 {
282         struct sn_softc *sc = device_get_softc(dev);
283         u_char eaddr[ETHER_ADDR_LEN];
284         int i, err;
285         uint16_t w;
286         u_char sum;
287         const struct sn_product *pp;
288
289         pp = sn_pccard_lookup(dev);
290         sum = pp->sw->get_mac(dev, eaddr);
291
292         /* Allocate resources so we can program the ether addr */
293         sc->dev = dev;
294         err = pp->sw->activate(dev);
295         if (err != 0)
296                 return (err);
297
298         if (sum) {
299                 printf("Programming sn card's addr\n");
300                 SMC_SELECT_BANK(sc, 1);
301                 for (i = 0; i < 3; i++) {
302                         w = (uint16_t)eaddr[i * 2] | 
303                             (((uint16_t)eaddr[i * 2 + 1]) << 8);
304                         CSR_WRITE_2(sc, IAR_ADDR0_REG_W + i * 2, w);
305                 }
306         }
307         err = sn_attach(dev);
308         if (err)
309                 sn_deactivate(dev);
310         return (err);
311 }
312
313 static device_method_t sn_pccard_methods[] = {
314         /* Device interface */
315         DEVMETHOD(device_probe,         sn_pccard_probe),
316         DEVMETHOD(device_attach,        sn_pccard_attach),
317         DEVMETHOD(device_detach,        sn_detach),
318
319         { 0, 0 }
320 };
321
322 static driver_t sn_pccard_driver = {
323         "sn",
324         sn_pccard_methods,
325         sizeof(struct sn_softc),
326 };
327
328 extern devclass_t sn_devclass;
329
330 DRIVER_MODULE(sn, pccard, sn_pccard_driver, sn_devclass, 0, 0);
331 MODULE_DEPEND(sn, ether, 1, 1, 1);
332 PCCARD_PNP_INFO(sn_pccard_products);