View | Details | Raw Unified | Return to bug 189772
Collapse All | Expand All

(-)sys/modules/Makefile (+2 lines)
Lines 41-46 Link Here
41
	${_an} \
41
	${_an} \
42
	${_aout} \
42
	${_aout} \
43
	${_apm} \
43
	${_apm} \
44
	${_apuled} \
44
	${_arcmsr} \
45
	${_arcmsr} \
45
	${_arcnet} \
46
	${_arcnet} \
46
	${_asmc} \
47
	${_asmc} \
Lines 481-486 Link Here
481
_agp=		agp
482
_agp=		agp
482
_an=		an
483
_an=		an
483
_aout=		aout
484
_aout=		aout
485
_apuled=	apuled
484
_bktr=		bktr
486
_bktr=		bktr
485
_bxe=		bxe
487
_bxe=		bxe
486
_cardbus=	cardbus
488
_cardbus=	cardbus
(-)sys/modules/apuled/Makefile (+4 lines)
Line 0 Link Here
1
KMOD=	apuled
2
SRCS=	apuled.c device_if.h bus_if.h isa_if.h pci_if.h
3
4
.include <bsd.kmod.mk>
(-)sys/modules/apuled/apuled.c (+360 lines)
Line 0 Link Here
1
/*-
2
 * Copyright (c) 2014 Larry Baird
3
 * All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24
 * SUCH DAMAGE.
25
 */
26
27
#include <sys/param.h>
28
#include <sys/conf.h>
29
#include <sys/bus.h>
30
#include <sys/priv.h>
31
#include <sys/types.h>
32
#include <sys/uio.h>
33
#include <sys/proc.h>
34
#include <dev/pci/pcireg.h>
35
#include <dev/pci/pcivar.h>
36
#include <sys/kernel.h>
37
#include <sys/systm.h>
38
#include <sys/module.h>
39
#include <sys/rman.h>
40
#include <x86/bus.h>
41
#include <isa/isavar.h>
42
#include <dev/led/led.h>
43
44
/* SB7xx RRG 2.3.3.1.1. */
45
#define AMDSB_PMIO_INDEX                0xcd6
46
#define AMDSB_PMIO_DATA                 (PMIO_INDEX + 1)
47
#define AMDSB_PMIO_WIDTH                2
48
49
#define AMDSB_SMBUS_DEVID               0x43851002
50
51
/* SB8xx RRG 2.3.3. */
52
#define AMDSB8_PM_WDT_EN                0x24
53
54
/* Here are some magic numbers from APU BIOS. */
55
#define GPIO_OFFSET			0x100
56
#define GPIO_187      			187       // MODESW
57
#define GPIO_188      			188       // Unknown ??
58
#define GPIO_189      			189       // LED1#
59
#define GPIO_190      			190       // LED2#
60
#define GPIO_191      			191       // LED3#
61
62
#define LED_ON           		0x08
63
#define LED_OFF          		0xC8
64
65
struct apuled {
66
	struct resource *res;
67
	bus_size_t 	offset;
68
	struct cdev    	*led;
69
};
70
71
struct apuled_softc {
72
        int             sc_rid;
73
        int             sc_type;
74
	struct resource *sc_res;
75
	struct apuled   sc_led[3];
76
	struct cdev	*sc_sw;
77
};
78
79
/*
80
 * Mode switch methods.
81
 */
82
static int      modesw_open(struct cdev *dev, int flags, int fmt,
83
                        struct thread *td);
84
static int      modesw_close(struct cdev *dev, int flags, int fmt,
85
                        struct thread *td);
86
static int      modesw_read(struct cdev *dev, struct uio *uio, int ioflag);
87
88
static struct cdevsw modesw_cdev = {
89
	.d_version =    D_VERSION,
90
	.d_open =       modesw_open,
91
	.d_read	=	modesw_read,
92
	.d_close =      modesw_close,
93
	.d_name =       "modesw",
94
};
95
96
/*
97
 * Device methods.
98
 */
99
static int	apuled_probe(device_t dev);
100
static int	apuled_attach(device_t dev);
101
static int	apuled_detach(device_t dev);
102
static void	apuled_identify(driver_t *driver, device_t parent);
103
104
static device_method_t apuled_methods[] = {
105
	/* Device interface */
106
	DEVMETHOD(device_probe,		apuled_probe),
107
	DEVMETHOD(device_attach,	apuled_attach),
108
	DEVMETHOD(device_detach,	apuled_detach),
109
	DEVMETHOD(device_identify,	apuled_identify),
110
111
	DEVMETHOD_END
112
};
113
114
static driver_t apuled_driver = {
115
	"apuled",
116
	apuled_methods,
117
	sizeof(struct apuled_softc),
118
};
119
120
static devclass_t apuled_devclass;
121
DRIVER_MODULE(apuled, isa, apuled_driver, apuled_devclass, NULL, NULL);
122
123
static int
124
hw_is_apu( void )
125
{
126
	int apu = 0;
127
	char *maker;
128
	char *product;
129
130
	maker = kern_getenv("smbios.system.maker");
131
	if (maker != NULL) {
132
		if ( 0 == strcmp( "PC Engines", maker ) ) {
133
			product = kern_getenv("smbios.system.product");
134
			if (product != NULL) {
135
				if ( 0 == strcmp( "APU", product ) )
136
					apu = 1;
137
138
				freeenv(product);
139
			}
140
		}
141
142
		freeenv(maker);
143
	}
144
145
	return (apu);
146
}
147
148
static void
149
apu_led_callback(void *ptr, int onoff)
150
{
151
	struct apuled *led = (struct apuled *)ptr;
152
	u_int8_t value;
153
154
	value = bus_read_1(led->res, led->offset);
155
156
	if ( onoff )
157
		value = LED_ON;
158
	else
159
		value = LED_OFF;
160
161
	bus_write_1(led->res, led->offset, value);
162
}
163
164
static void
165
apuled_identify(driver_t *driver, device_t parent)
166
{
167
	device_t	child;
168
	device_t	smb;
169
170
	if (resource_disabled("apuled", 0))
171
		return;
172
173
	if (device_find_child(parent, "apuled", -1) != NULL)
174
		return;
175
176
	/* Do was have expected south bridge? */
177
	smb = pci_find_bsf(0, 20, 0);
178
	if (smb == NULL)
179
		return;
180
181
	if (pci_get_devid(smb) != AMDSB_SMBUS_DEVID)
182
		return;
183
184
	if ( hw_is_apu() ) {
185
		child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "apuled", -1);
186
		if ( child == NULL )
187
			device_printf(parent, "apuled: bus add child failed\n");
188
	}
189
}
190
191
static int
192
apuled_probe(device_t dev)
193
{
194
	struct resource         *res;
195
	int			rc;
196
	uint32_t		gpio_mmio_base;
197
	int			i;
198
	int			rid;
199
200
	/* Make sure we do not claim some ISA PNP device. */
201
	if (isa_get_logicalid(dev) != 0)
202
		return (ENXIO);
203
204
	if ( ! hw_is_apu() )
205
		return (ENXIO);
206
207
	/* Find the ACPImmioAddr base address */
208
	rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
209
	    AMDSB_PMIO_WIDTH);
210
	if (rc != 0) {
211
		device_printf(dev, "bus_set_resource for find address failed\n");
212
		return (ENXIO);
213
	}
214
215
	rid = 0;
216
	res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, 0ul, ~0ul,
217
	    AMDSB_PMIO_WIDTH, RF_ACTIVE | RF_SHAREABLE);
218
	if (res == NULL) {
219
		device_printf(dev, "bus_alloc_resource for finding base address failed.\n");
220
		return (ENXIO);
221
	}
222
223
	/* Find base address of memory mapped WDT registers. */
224
	for (gpio_mmio_base = 0, i = 0; i < 4; i++) {
225
		gpio_mmio_base <<= 8;
226
		bus_write_1(res, 0, AMDSB8_PM_WDT_EN + 3 - i);
227
		gpio_mmio_base |= bus_read_1(res, 1);
228
	}
229
	gpio_mmio_base &= 0xFFFFF000;
230
231
	if ( bootverbose )
232
		device_printf(dev, "MMIO base adddress is 0x%x\n", gpio_mmio_base);
233
234
	bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
235
	bus_delete_resource(dev, SYS_RES_IOPORT, rid);
236
237
	rc = bus_set_resource(dev, SYS_RES_MEMORY, 0,
238
	    gpio_mmio_base + GPIO_OFFSET + GPIO_187, GPIO_191 - GPIO_187);
239
	if (rc != 0) {
240
		device_printf(dev, "bus_set_resource for memory region failed\n");
241
		return (ENXIO);
242
	}
243
244
	return (0);
245
}
246
247
248
static int
249
apuled_attach(device_t dev)
250
{
251
	struct apuled_softc *sc = device_get_softc(dev);
252
	int i;
253
254
	sc->sc_rid = 0;
255
	sc->sc_type = SYS_RES_MEMORY;
256
257
	sc->sc_res = bus_alloc_resource_any( dev, sc->sc_type, &sc->sc_rid,
258
	    RF_ACTIVE | RF_SHAREABLE);
259
260
	if ( sc->sc_res == NULL ) {
261
		device_printf( dev, "Unable to allocate bus resource\n" );
262
		return (ENXIO);
263
	}
264
265
	sc->sc_sw = make_dev(&modesw_cdev, 0, UID_ROOT, GID_WHEEL, 0440, "modesw");
266
	sc->sc_sw->si_drv1 = sc;
267
268
	for ( i = 0; i < 3; i++ ) {
269
		char name[30];
270
271
		snprintf( name, sizeof(name), "led%d", i + 1 );
272
273
		sc->sc_led[ i ].res = sc->sc_res;
274
		sc->sc_led[ i ].offset = GPIO_189 - GPIO_187 + i;
275
276
		sc->sc_led[ i ].led = led_create(apu_led_callback,
277
		    &sc->sc_led[ i ], name);
278
279
		if ( sc->sc_led[ i ].led == NULL ) {
280
			device_printf( dev, "%s creation failed\n", name );
281
282
		/* Make sure power LED stays on by default */
283
		} else if ( i == 0 ) {
284
			apu_led_callback(&sc->sc_led[ i ], TRUE);
285
		}
286
	}
287
288
	device_printf( dev, "created\n" );
289
290
	return (0);
291
}
292
293
int
294
apuled_detach(device_t dev)
295
{
296
	struct apuled_softc *sc = device_get_softc(dev);
297
	int i;
298
299
	for ( i = 0; i < 3; i++ )
300
		if ( sc->sc_led[ i ].led != NULL ) {
301
			if ( i == 0 )
302
				apu_led_callback(&sc->sc_led[ i ], TRUE);
303
			else
304
				apu_led_callback(&sc->sc_led[ i ], FALSE);
305
306
			led_destroy(sc->sc_led[ i ].led);
307
		}
308
309
	if ( sc->sc_res != NULL ) {
310
		bus_release_resource(dev, sc->sc_type, sc->sc_rid, sc->sc_res);
311
		bus_delete_resource(dev, sc->sc_type, sc->sc_rid );
312
	}
313
314
	if ( sc->sc_sw != NULL )
315
	    destroy_dev(sc->sc_sw);
316
317
	return (0);
318
}
319
320
static int
321
modesw_open(struct cdev *dev __unused, int flags __unused, int fmt __unused,
322
    struct thread *td)
323
{
324
	int error;
325
326
	error = priv_check(td, PRIV_IO);
327
	if (error != 0)
328
		return (error);
329
	error = securelevel_gt(td->td_ucred, 0);
330
	if (error != 0)
331
		return (error);
332
333
	return (error);
334
}
335
336
static int
337
modesw_read(struct cdev *dev, struct uio *uio, int ioflag) {
338
	struct apuled_softc *sc = dev->si_drv1;
339
	uint8_t value;
340
        char ch;
341
        int error;
342
343
	/* Is mode switch pressed? */
344
	value = bus_read_1(sc->sc_res, GPIO_187 - GPIO_187 );
345
	if (value == 0x28 )
346
		ch = '1';
347
	else
348
		ch = '0';
349
350
	error = uiomove(&ch, sizeof(ch), uio);
351
352
	return (error);
353
}
354
355
static int
356
modesw_close(struct cdev *dev __unused, int flags __unused, int fmt __unused,
357
    struct thread *td __unused)
358
{
359
	return (0);
360
}

Return to bug 189772