]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/auxio/auxio.c
Upgrade to OpenSSH 7.7p1.
[FreeBSD/FreeBSD.git] / sys / dev / auxio / auxio.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD AND BSD-3-Clause
3  *
4  * Copyright (c) 2004 Pyun YongHyeon
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 /*      $NetBSD: auxio.c,v 1.11 2003/07/15 03:36:04 lukem Exp $ */
31
32 /*-
33  * Copyright (c) 2000, 2001 Matthew R. Green
34  * All rights reserved.
35  *
36  * Redistribution and use in source and binary forms, with or without
37  * modification, are permitted provided that the following conditions
38  * are met:
39  * 1. Redistributions of source code must retain the above copyright
40  *    notice, this list of conditions and the following disclaimer.
41  * 2. Redistributions in binary form must reproduce the above copyright
42  *    notice, this list of conditions and the following disclaimer in the
43  *    documentation and/or other materials provided with the distribution.
44  * 3. The name of the author may not be used to endorse or promote products
45  *    derived from this software without specific prior written permission.
46  *
47  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
48  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
49  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
50  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
51  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
52  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
53  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
54  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
55  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57  * SUCH DAMAGE.
58  */
59
60 /*
61  * AUXIO registers support on the SBus & EBus2, used for the floppy driver
62  * and to control the system LED, for the BLINK option.
63  */
64
65 #include <sys/cdefs.h>
66 __FBSDID("$FreeBSD$");
67
68 #include <sys/param.h>
69 #include <sys/systm.h>
70 #include <sys/bus.h>
71 #include <sys/kernel.h>
72 #include <sys/lock.h>
73 #include <sys/module.h>
74 #include <sys/mutex.h>
75 #include <sys/resource.h>
76 #include <sys/rman.h>
77
78 #include <dev/led/led.h>
79 #include <dev/ofw/ofw_bus.h>
80 #include <dev/ofw/openfirm.h>
81
82 #include <machine/bus.h>
83 #include <machine/ofw_machdep.h>
84 #include <machine/resource.h>
85
86 #include <sparc64/sbus/sbusvar.h>
87 #include <dev/auxio/auxioreg.h>
88
89 /*
90  * On sun4u, auxio exists with one register (LED) on the SBus, and 5
91  * registers on the EBus2 (pci) (LED, PCIMODE, FREQUENCY, SCSI
92  * OSCILLATOR, and TEMP SENSE.
93  */
94
95 #define AUXIO_PCIO_LED  0
96 #define AUXIO_PCIO_PCI  1
97 #define AUXIO_PCIO_FREQ 2
98 #define AUXIO_PCIO_OSC  3
99 #define AUXIO_PCIO_TEMP 4
100 #define AUXIO_PCIO_NREG 5
101
102 struct auxio_softc {
103         device_t                sc_dev;
104
105         int                     sc_nauxio;
106         struct resource         *sc_res[AUXIO_PCIO_NREG];
107         int                     sc_rid[AUXIO_PCIO_NREG];
108         bus_space_tag_t         sc_regt[AUXIO_PCIO_NREG];
109         bus_space_handle_t      sc_regh[AUXIO_PCIO_NREG];
110         struct cdev             *sc_led_dev;
111         u_int32_t               sc_led_stat;
112
113         int                     sc_flags;
114 #define AUXIO_LEDONLY           0x1
115 #define AUXIO_EBUS              0x2
116 #define AUXIO_SBUS              0x4
117
118         struct mtx              sc_lock;
119 };
120
121 static void     auxio_led_func(void *arg, int onoff);
122 static int      auxio_attach_common(struct auxio_softc *);
123 static int      auxio_bus_probe(device_t);
124 static int      auxio_sbus_attach(device_t);
125 static int      auxio_ebus_attach(device_t);
126 static int      auxio_bus_detach(device_t);
127 static void     auxio_free_resource(struct auxio_softc *);
128 static __inline u_int32_t auxio_led_read(struct auxio_softc *);
129 static __inline void auxio_led_write(struct auxio_softc *, u_int32_t);
130
131 /* SBus */
132 static device_method_t auxio_sbus_methods[] = {
133         DEVMETHOD(device_probe,         auxio_bus_probe),
134         DEVMETHOD(device_attach,        auxio_sbus_attach),
135         DEVMETHOD(device_detach,        auxio_bus_detach),
136
137         DEVMETHOD_END
138 };
139
140 static driver_t auxio_sbus_driver = {
141         "auxio",
142         auxio_sbus_methods,
143         sizeof(struct auxio_softc)
144 };
145
146 static devclass_t       auxio_devclass;
147 /* The probe order is handled by sbus(4). */
148 EARLY_DRIVER_MODULE(auxio, sbus, auxio_sbus_driver, auxio_devclass, 0, 0,
149     BUS_PASS_DEFAULT);
150 MODULE_DEPEND(auxio, sbus, 1, 1, 1);
151
152 /* EBus */
153 static device_method_t auxio_ebus_methods[] = {
154         DEVMETHOD(device_probe,         auxio_bus_probe),
155         DEVMETHOD(device_attach,        auxio_ebus_attach),
156         DEVMETHOD(device_detach,        auxio_bus_detach),
157
158         DEVMETHOD_END
159 };
160
161 static driver_t auxio_ebus_driver = {
162         "auxio",
163         auxio_ebus_methods,
164         sizeof(struct auxio_softc)
165 };
166
167 EARLY_DRIVER_MODULE(auxio, ebus, auxio_ebus_driver, auxio_devclass, 0, 0,
168     BUS_PASS_DEFAULT);
169 MODULE_DEPEND(auxio, ebus, 1, 1, 1);
170 MODULE_VERSION(auxio, 1);
171
172 #define AUXIO_LOCK_INIT(sc)     \
173         mtx_init(&sc->sc_lock, "auxio mtx", NULL, MTX_DEF)
174 #define AUXIO_LOCK(sc)          mtx_lock(&sc->sc_lock)
175 #define AUXIO_UNLOCK(sc)        mtx_unlock(&sc->sc_lock)
176 #define AUXIO_LOCK_DESTROY(sc)  mtx_destroy(&sc->sc_lock)
177
178 static __inline void
179 auxio_led_write(struct auxio_softc *sc, u_int32_t v)
180 {
181         if (sc->sc_flags & AUXIO_EBUS)
182                 bus_space_write_4(sc->sc_regt[AUXIO_PCIO_LED],
183                     sc->sc_regh[AUXIO_PCIO_LED], 0, v);
184         else
185                 bus_space_write_1(sc->sc_regt[AUXIO_PCIO_LED],
186                     sc->sc_regh[AUXIO_PCIO_LED], 0, v);
187 }
188
189 static __inline u_int32_t
190 auxio_led_read(struct auxio_softc *sc)
191 {
192         u_int32_t led;
193
194         if (sc->sc_flags & AUXIO_EBUS)
195                 led = bus_space_read_4(sc->sc_regt[AUXIO_PCIO_LED],
196                     sc->sc_regh[AUXIO_PCIO_LED], 0);
197         else
198                 led = bus_space_read_1(sc->sc_regt[AUXIO_PCIO_LED],
199                     sc->sc_regh[AUXIO_PCIO_LED], 0);
200
201         return (led);
202 }
203
204 static void
205 auxio_led_func(void *arg, int onoff)
206 {
207         struct auxio_softc *sc;
208         u_int32_t led;
209
210         sc = (struct auxio_softc *)arg;
211
212         AUXIO_LOCK(sc);
213         /*
214          * NB: We must not touch the other bits of the SBus AUXIO reg.
215          */
216         led = auxio_led_read(sc);
217         if (onoff)
218                 led |= AUXIO_LED_LED;
219         else
220                 led &= ~AUXIO_LED_LED;
221         auxio_led_write(sc, led);
222         AUXIO_UNLOCK(sc);
223 }
224
225 static int
226 auxio_bus_probe(device_t dev)
227 {
228         const char *name;
229
230         name = ofw_bus_get_name(dev);
231         if (strcmp("auxio", name) == 0) {
232                 device_set_desc(dev, "Sun Auxiliary I/O");
233                 return (0);
234         }
235
236         return (ENXIO);
237 }
238
239 static int
240 auxio_ebus_attach(device_t dev)
241 {
242         struct auxio_softc *sc;
243
244         sc = device_get_softc(dev);
245         sc->sc_dev = dev;
246
247         AUXIO_LOCK_INIT(sc);
248         sc->sc_nauxio = AUXIO_PCIO_NREG;
249         sc->sc_flags = AUXIO_LEDONLY | AUXIO_EBUS;
250
251         return(auxio_attach_common(sc));
252 }
253
254 static int
255 auxio_attach_common(struct auxio_softc *sc)
256 {
257         struct resource *res;
258         int i;
259
260         for (i = 0; i < sc->sc_nauxio; i++) {
261                 sc->sc_rid[i] = i;
262                 res = bus_alloc_resource_any(sc->sc_dev, SYS_RES_MEMORY,
263                     &sc->sc_rid[i], RF_ACTIVE);
264                 if (res == NULL) {
265                         device_printf(sc->sc_dev,
266                             "could not allocate resources\n");
267                         goto attach_fail;
268                 }
269                 sc->sc_res[i] = res;
270                 sc->sc_regt[i] = rman_get_bustag(res);
271                 sc->sc_regh[i] = rman_get_bushandle(res);
272         }
273
274         sc->sc_led_stat = auxio_led_read(sc) & AUXIO_LED_LED;
275         sc->sc_led_dev = led_create(auxio_led_func, sc, "auxioled");
276         /* turn on the LED */
277         auxio_led_func(sc, 1);
278
279         return (0);
280
281 attach_fail:
282         auxio_free_resource(sc);
283
284         return (ENXIO);
285 }
286
287 static int
288 auxio_bus_detach(device_t dev)
289 {
290         struct auxio_softc *sc;
291
292         sc = device_get_softc(dev);
293         led_destroy(sc->sc_led_dev);
294         auxio_led_func(sc, sc->sc_led_stat);
295         auxio_free_resource(sc);
296
297         return (0);
298 }
299
300 static void
301 auxio_free_resource(struct auxio_softc *sc)
302 {
303         int i;
304
305         for (i = 0; i < sc->sc_nauxio; i++)
306                 if (sc->sc_res[i])
307                         bus_release_resource(sc->sc_dev, SYS_RES_MEMORY,
308                             sc->sc_rid[i], sc->sc_res[i]);
309         AUXIO_LOCK_DESTROY(sc);
310 }
311
312 static int
313 auxio_sbus_attach(device_t dev)
314 {
315         struct auxio_softc *sc;
316
317         sc = device_get_softc(dev);
318         sc->sc_dev = dev;
319
320         AUXIO_LOCK_INIT(sc);
321         sc->sc_nauxio = 1;
322         sc->sc_flags = AUXIO_LEDONLY | AUXIO_SBUS;
323
324         return (auxio_attach_common(sc));
325 }