smapi.c revision 115679
1207151Smarius/*-
2207151Smarius * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
3207151Smarius * All rights reserved.
4207151Smarius *
5207151Smarius * Redistribution and use in source and binary forms, with or without
6207151Smarius * modification, are permitted provided that the following conditions
7207151Smarius * are met:
8207151Smarius * 1. Redistributions of source code must retain the above copyright
9207151Smarius *    notice, this list of conditions and the following disclaimer.
10207151Smarius * 2. Redistributions in binary form must reproduce the above copyright
11207151Smarius *    notice, this list of conditions and the following disclaimer in the
12207151Smarius *    documentation and/or other materials provided with the distribution.
13207151Smarius *
14207151Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15207151Smarius * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16207151Smarius * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17207151Smarius * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18207151Smarius * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19207151Smarius * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20207151Smarius * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21207151Smarius * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22207151Smarius * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23207151Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24207151Smarius * SUCH DAMAGE.
25207151Smarius */
26207151Smarius
27207151Smarius#include <sys/cdefs.h>
28207151Smarius__FBSDID("$FreeBSD: head/sys/i386/bios/smapi.c 115679 2003-06-02 06:02:49Z obrien $");
29207151Smarius
30207151Smarius#include <sys/param.h>
31207151Smarius#include <sys/systm.h>
32207151Smarius#include <sys/kernel.h>
33207151Smarius
34207151Smarius#include <sys/module.h>
35207151Smarius#include <sys/bus.h>
36207151Smarius#include <sys/conf.h>
37207151Smarius
38207151Smarius#include <machine/bus.h>
39207151Smarius#include <machine/resource.h>
40207151Smarius#include <sys/rman.h>
41207151Smarius
42207151Smarius/* And all this for BIOS_PADDRTOVADDR() */
43207151Smarius#include <vm/vm.h>
44207151Smarius#include <vm/pmap.h>
45207151Smarius#include <machine/md_var.h>
46207151Smarius#include <machine/pc/bios.h>
47207151Smarius
48207151Smarius#include <machine/smapi.h>
49207151Smarius
50207151Smarius#define	SMAPI_START	0xf0000
51207151Smarius#define	SMAPI_STEP	0x10
52207151Smarius#define	SMAPI_OFF	0
53207151Smarius#define	SMAPI_LEN	4
54207151Smarius#define	SMAPI_SIG	"$SMB"
55207151Smarius
56207151Smarius#define	RES2HDR(res)	((struct smapi_bios_header *)rman_get_virtual(res))
57207151Smarius#define	ADDR2HDR(addr)	((struct smapi_bios_header *)BIOS_PADDRTOVADDR(addr))
58207151Smarius
59207151Smariusstruct smapi_softc {
60207151Smarius	dev_t			cdev;
61207151Smarius	device_t		dev;
62207151Smarius	struct resource *	res;
63207151Smarius	int			rid;
64207151Smarius
65207151Smarius	u_int32_t		smapi32_entry;
66207151Smarius
67207151Smarius	struct smapi_bios_header *header;
68207151Smarius};
69207151Smarius
70207151Smariusu_long smapi32_offset;
71207151Smariusu_short smapi32_segment;
72207151Smarius#define	SMAPI32_SEGMENT	0x18
73207151Smarius
74207151Smariusdevclass_t smapi_devclass;
75207151Smarius
76207151Smariusstatic d_ioctl_t smapi_ioctl;
77207151Smarius
78207151Smariusstatic struct cdevsw smapi_cdevsw = {
79207151Smarius	.d_open =	nullopen,
80207151Smarius	.d_close =	nullclose,
81207151Smarius	.d_ioctl =	smapi_ioctl,
82207151Smarius	.d_name =	"smapi",
83207151Smarius	.d_maj =	MAJOR_AUTO,
84207151Smarius	.d_flags =	D_MEM,
85207151Smarius};
86207151Smarius
87207151Smariusstatic void	smapi_identify		(driver_t *, device_t);
88207151Smariusstatic int	smapi_probe		(device_t);
89207151Smariusstatic int	smapi_attach		(device_t);
90207151Smariusstatic int	smapi_detach            (device_t);
91207151Smariusstatic int	smapi_modevent		(module_t, int, void *);
92207151Smarius
93207151Smariusstatic int	smapi_header_cksum	(struct smapi_bios_header *);
94207151Smarius
95207151Smariusextern int	smapi32			(struct smapi_bios_parameter *,
96207151Smarius					 struct smapi_bios_parameter *);
97207151Smariusextern int	smapi32_new		(u_long, u_short,
98207151Smarius					 struct smapi_bios_parameter *,
99207151Smarius					 struct smapi_bios_parameter *);
100207151Smarius
101207151Smariusstatic int
102207151Smariussmapi_ioctl (dev, cmd, data, fflag, td)
103207151Smarius	dev_t		dev;
104207151Smarius	u_long		cmd;
105207151Smarius	caddr_t		data;
106207151Smarius	int		fflag;
107207151Smarius	d_thread_t *	td;
108207151Smarius{
109207151Smarius	struct smapi_softc *sc;
110207151Smarius	int error;
111207151Smarius
112207151Smarius	error = 0;
113207151Smarius	sc = devclass_get_softc(smapi_devclass, minor(dev));
114207151Smarius        if (sc == NULL) {
115207151Smarius                error = ENXIO;
116207151Smarius                goto fail;
117207151Smarius        }
118207151Smarius
119207151Smarius	switch (cmd) {
120207151Smarius	case SMAPIOGHEADER:
121207151Smarius		bcopy((caddr_t)sc->header, data,
122207151Smarius				sizeof(struct smapi_bios_header));
123207151Smarius		error = 0;
124207151Smarius		break;
125207151Smarius	case SMAPIOCGFUNCTION:
126207151Smarius#if 1
127207151Smarius		smapi32_segment = SMAPI32_SEGMENT;
128207151Smarius		smapi32_offset = sc->smapi32_entry;
129207151Smarius		error = smapi32(
130207151Smarius#else
131207151Smarius		error = smapi32_new(sc->smapi32_entry, SMAPI32_SEGMENT,
132207151Smarius#endif
133207151Smarius				(struct smapi_bios_parameter *)data,
134207151Smarius				(struct smapi_bios_parameter *)data);
135207151Smarius		break;
136207151Smarius	default:
137207151Smarius		error = ENOTTY;
138207151Smarius	}
139207151Smarius
140207151Smariusfail:
141207151Smarius	return (error);
142207151Smarius}
143207151Smarius
144207151Smariusstatic int
145207151Smariussmapi_header_cksum (struct smapi_bios_header *header)
146207151Smarius{
147207151Smarius	u_int8_t *ptr;
148207151Smarius	u_int8_t cksum;
149207151Smarius	int i;
150207151Smarius
151207151Smarius	ptr = (u_int8_t *)header;
152207151Smarius	cksum = 0;
153207151Smarius	for (i = 0; i < header->length; i++) {
154207151Smarius		cksum += ptr[i];
155207151Smarius	}
156207151Smarius
157207151Smarius	return (cksum);
158207151Smarius}
159207151Smarius
160207151Smariusstatic void
161207151Smariussmapi_identify (driver_t *driver, device_t parent)
162207151Smarius{
163207151Smarius	device_t child;
164207151Smarius	u_int32_t addr;
165207151Smarius	int length;
166207151Smarius	int rid;
167207151Smarius
168207151Smarius	if (!device_is_alive(parent))
169207151Smarius		return;
170207151Smarius
171207151Smarius	addr = bios_sigsearch(SMAPI_START, SMAPI_SIG, SMAPI_LEN,
172207151Smarius                              SMAPI_STEP, SMAPI_OFF);
173207151Smarius	if (addr != 0) {
174207151Smarius		rid = 0;
175207151Smarius		length = ADDR2HDR(addr)->length;
176207151Smarius
177207151Smarius		child = BUS_ADD_CHILD(parent, 0, "smapi", -1);
178207151Smarius		device_set_driver(child, driver);
179207151Smarius		bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length);
180207151Smarius		device_set_desc(child, "SMAPI BIOS");
181207151Smarius	}
182207151Smarius
183207151Smarius	return;
184207151Smarius}
185207151Smarius
186207151Smariusstatic int
187smapi_probe (device_t dev)
188{
189	struct resource *res;
190	int rid;
191	int error;
192
193	error = 0;
194	rid = 0;
195	res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
196		0ul, ~0ul, 1, RF_ACTIVE);
197	if (res == NULL) {
198		device_printf(dev, "Unable to allocate memory resource.\n");
199		error = ENOMEM;
200		goto bad;
201	}
202
203	if (smapi_header_cksum(RES2HDR(res))) {
204		device_printf(dev, "SMAPI header checksum failed.\n");
205		error = ENXIO;
206		goto bad;
207	}
208
209bad:
210	if (res)
211		bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
212	return (error);
213}
214
215static int
216smapi_attach (device_t dev)
217{
218	struct smapi_softc *sc;
219	int error;
220
221	sc = device_get_softc(dev);
222	error = 0;
223
224	sc->dev = dev;
225	sc->rid = 0;
226	sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid,
227		0ul, ~0ul, 1, RF_ACTIVE);
228	if (sc->res == NULL) {
229		device_printf(dev, "Unable to allocate memory resource.\n");
230		error = ENOMEM;
231		goto bad;
232	}
233	sc->header = (struct smapi_bios_header *)rman_get_virtual(sc->res);
234	sc->smapi32_entry = (u_int32_t)BIOS_PADDRTOVADDR(
235					sc->header->prot32_segment +
236					sc->header->prot32_offset);
237
238        sc->cdev = make_dev(&smapi_cdevsw,
239			device_get_unit(sc->dev),
240			UID_ROOT, GID_WHEEL, 0600,
241			"%s%d",
242			smapi_cdevsw.d_name,
243			device_get_unit(sc->dev));
244
245	device_printf(dev, "Version: %d.%02d, Length: %d, Checksum: 0x%02x\n",
246		bcd2bin(sc->header->version_major),
247		bcd2bin(sc->header->version_minor),
248		sc->header->length,
249		sc->header->checksum);
250	device_printf(dev, "Information=0x%b\n",
251		sc->header->information,
252		"\020"
253		"\001REAL_VM86"
254		"\002PROTECTED_16"
255		"\003PROTECTED_32");
256
257	if (bootverbose) {
258		if (sc->header->information & SMAPI_REAL_VM86)
259			device_printf(dev, "Real/VM86 mode: Segment 0x%04x, Offset 0x%04x\n",
260				sc->header->real16_segment,
261				sc->header->real16_offset);
262		if (sc->header->information & SMAPI_PROT_16BIT)
263			device_printf(dev, "16-bit Protected mode: Segment 0x%08x, Offset 0x%04x\n",
264				sc->header->prot16_segment,
265				sc->header->prot16_offset);
266		if (sc->header->information & SMAPI_PROT_32BIT)
267			device_printf(dev, "32-bit Protected mode: Segment 0x%08x, Offset 0x%08x\n",
268				sc->header->prot32_segment,
269				sc->header->prot32_offset);
270	}
271
272	return (0);
273bad:
274	if (sc->res)
275		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
276	return (error);
277}
278
279static int
280smapi_detach (device_t dev)
281{
282	struct smapi_softc *sc;
283
284	sc = device_get_softc(dev);
285
286	destroy_dev(sc->cdev);
287
288	if (sc->res)
289		bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
290
291	return (0);
292}
293
294static int
295smapi_modevent (mod, what, arg)
296        module_t        mod;
297        int             what;
298        void *          arg;
299{
300	device_t *	devs;
301	int		count;
302	int		i;
303
304	switch (what) {
305	case MOD_LOAD:
306		break;
307	case MOD_UNLOAD:
308		devclass_get_devices(smapi_devclass, &devs, &count);
309		for (i = 0; i < count; i++) {
310			device_delete_child(device_get_parent(devs[i]), devs[i]);
311		}
312		break;
313	default:
314		break;
315	}
316
317	return (0);
318}
319
320static device_method_t smapi_methods[] = {
321	/* Device interface */
322	DEVMETHOD(device_identify,      smapi_identify),
323	DEVMETHOD(device_probe,         smapi_probe),
324	DEVMETHOD(device_attach,        smapi_attach),
325	DEVMETHOD(device_detach,        smapi_detach),
326	{ 0, 0 }
327};
328
329static driver_t smapi_driver = {
330	"smapi",
331	smapi_methods,
332	sizeof(struct smapi_softc),
333};
334
335DRIVER_MODULE(smapi, nexus, smapi_driver, smapi_devclass, smapi_modevent, 0);
336MODULE_VERSION(smapi, 1);
337