150476Speter/*-
23455Sache * Copyright (c) 2004 Mark R V Murray
3166130Srafan * All rights reserved.
4156837Sru *
5245887Sbrooks * Redistribution and use in source and binary forms, with or without
6245887Sbrooks * modification, are permitted provided that the following conditions
7245887Sbrooks * are met:
8245887Sbrooks * 1. Redistributions of source code must retain the above copyright
9156813Sru *    notice, this list of conditions and the following disclaimer
10156813Sru *    in this position and unchanged.
11167358Srafan * 2. Redistributions in binary form must reproduce the above copyright
123410Sache *    notice, this list of conditions and the following disclaimer in the
13167359Srafan *    documentation and/or other materials provided with the distribution.
14195767Skensmith *
153410Sache * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16166130Srafan * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
173523Sache * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18166130Srafan * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19166130Srafan * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20166130Srafan * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
213410Sache * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2250624Speter * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23167359Srafan * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24167359Srafan * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25174999Srafan *
26167359Srafan */
27167359Srafan
28166130Srafan#include <sys/cdefs.h>
29174999Srafan__FBSDID("$FreeBSD$");
30166130Srafan
31167359Srafan#include <sys/param.h>
3297053Speter#include <sys/conf.h>
33166130Srafan#include <sys/kernel.h>
3497053Speter#include <sys/ioccom.h>
35166130Srafan#include <sys/module.h>
3697053Speter#include <sys/priv.h>
3797053Speter#include <sys/proc.h>
38166130Srafan#include <sys/systm.h>
39174999Srafan
40166130Srafan#include <machine/iodev.h>
41166130Srafan
42174999Srafan#include <dev/io/iodev.h>
43166130Srafan
44166130Srafanstatic int	 ioopen(struct cdev *dev, int flags, int fmt,
45166130Srafan		    struct thread *td);
46166130Srafanstatic int	 ioclose(struct cdev *dev, int flags, int fmt,
4797053Speter		    struct thread *td);
4897053Speterstatic int	 ioioctl(struct cdev *dev, u_long cmd, caddr_t data,
49166130Srafan		    int fflag, struct thread *td);
50174999Srafan
51174999Srafanstatic int	 iopio_read(struct iodev_pio_req *req);
52166130Srafanstatic int	 iopio_write(struct iodev_pio_req *req);
53166130Srafan
54166130Srafanstatic struct cdev *iodev;
5597053Speter
5697053Speterstatic struct cdevsw io_cdevsw = {
57166130Srafan	.d_version =	D_VERSION,
58166130Srafan	.d_open =	ioopen,
59166130Srafan	.d_close =	ioclose,
60166130Srafan	.d_ioctl =	ioioctl,
6197053Speter	.d_name =	"io",
62174999Srafan};
63166130Srafan
643410Sache/* ARGSUSED */
65167358Srafanstatic int
66167358Srafanioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused,
67167358Srafan    struct thread *td)
68167358Srafan{
69167358Srafan	int error;
70167358Srafan
71167358Srafan	error = priv_check(td, PRIV_IO);
72167358Srafan	if (error != 0)
733410Sache		return (error);
74167358Srafan	error = securelevel_gt(td->td_ucred, 0);
75167358Srafan	if (error != 0)
76167358Srafan		return (error);
77167358Srafan	error = iodev_open(td);
78167358Srafan
79167358Srafan        return (error);
80167358Srafan}
81167358Srafan
82167358Srafan/* ARGSUSED */
83167358Srafanstatic int
843410Sacheioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused,
85167358Srafan    struct thread *td)
863410Sache{
87167358Srafan
88167358Srafan	return (iodev_close(td));
89167358Srafan}
90167358Srafan
91167358Srafan/* ARGSUSED */
92167358Srafanstatic int
93167358Srafanioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
94167358Srafan    int fflag __unused, struct thread *td __unused)
95167358Srafan{
96167358Srafan	struct iodev_pio_req *pio_req;
97167358Srafan	int error;
98167358Srafan
99167358Srafan	switch (cmd) {
100167358Srafan	case IODEV_PIO:
101167358Srafan		pio_req = (struct iodev_pio_req *)data;
102167358Srafan		switch (pio_req->access) {
103167358Srafan		case IODEV_PIO_READ:
104167358Srafan			error = iopio_read(pio_req);
105167358Srafan			break;
106167358Srafan		case IODEV_PIO_WRITE:
107167358Srafan			error = iopio_write(pio_req);
108167358Srafan			break;
109167358Srafan		default:
110167358Srafan			error = EINVAL;
111167358Srafan			break;
112167358Srafan		}
113167358Srafan		break;
114167358Srafan	default:
115167358Srafan		error = iodev_ioctl(cmd, data);
116167358Srafan	}
117167358Srafan
118167358Srafan	return (error);
119167358Srafan}
120167358Srafan
121167358Srafanstatic int
122167358Srafaniopio_read(struct iodev_pio_req *req)
123167358Srafan{
124167358Srafan
125167358Srafan	switch (req->width) {
126167358Srafan	case 1:
127167358Srafan		req->val = iodev_read_1(req->port);
128167358Srafan		break;
129167358Srafan	case 2:
130167358Srafan		if (req->port & 1) {
131167358Srafan			req->val = iodev_read_1(req->port);
132167358Srafan			req->val |= iodev_read_1(req->port + 1) << 8;
133167358Srafan		} else
134167358Srafan			req->val = iodev_read_2(req->port);
135167358Srafan		break;
136167358Srafan	case 4:
137167358Srafan		if (req->port & 1) {
138167358Srafan			req->val = iodev_read_1(req->port);
139167358Srafan			req->val |= iodev_read_2(req->port + 1) << 8;
140167358Srafan			req->val |= iodev_read_1(req->port + 3) << 24;
141167358Srafan		} else if (req->port & 2) {
142167358Srafan			req->val = iodev_read_2(req->port);
143167358Srafan			req->val |= iodev_read_2(req->port + 2) << 16;
144167358Srafan		} else
145167358Srafan			req->val = iodev_read_4(req->port);
146167358Srafan		break;
147167358Srafan	default:
148167358Srafan		return (EINVAL);
149167358Srafan	}
150167358Srafan
151167358Srafan	return (0);
152167358Srafan}
153167358Srafan
154167358Srafanstatic int
155167358Srafaniopio_write(struct iodev_pio_req *req)
156167358Srafan{
157167358Srafan
158167358Srafan	switch (req->width) {
159167358Srafan	case 1:
160167358Srafan		iodev_write_1(req->port, req->val);
161167358Srafan		break;
162167358Srafan	case 2:
163167358Srafan		if (req->port & 1) {
164167358Srafan			iodev_write_1(req->port, req->val);
165167358Srafan			iodev_write_1(req->port + 1, req->val >> 8);
166167358Srafan		} else
167167358Srafan			iodev_write_2(req->port, req->val);
168167358Srafan		break;
169167358Srafan	case 4:
170167358Srafan		if (req->port & 1) {
171167358Srafan			iodev_write_1(req->port, req->val);
17250624Speter			iodev_write_2(req->port + 1, req->val >> 8);
173167358Srafan			iodev_write_1(req->port + 3, req->val >> 24);
174167358Srafan		} else if (req->port & 2) {
175167358Srafan			iodev_write_2(req->port, req->val);
176167358Srafan			iodev_write_2(req->port + 2, req->val >> 16);
177167358Srafan		} else
178167358Srafan			iodev_write_4(req->port, req->val);
179167358Srafan		break;
180167358Srafan	default:
181167358Srafan		return (EINVAL);
182167358Srafan	}
183167358Srafan
184167358Srafan	return (0);
185167358Srafan}
186167358Srafan
187167358Srafan/* ARGSUSED */
188174999Srafanstatic int
189167358Srafanio_modevent(module_t mod __unused, int type, void *data __unused)
190167358Srafan{
191167358Srafan	switch(type) {
192167358Srafan	case MOD_LOAD:
193167358Srafan		if (bootverbose)
194167358Srafan			printf("io: <I/O>\n");
195167358Srafan		iodev = make_dev(&io_cdevsw, 0,
196167358Srafan			UID_ROOT, GID_WHEEL, 0600, "io");
197167358Srafan		break;
198167358Srafan
199167358Srafan	case MOD_UNLOAD:
200167358Srafan		destroy_dev(iodev);
201167358Srafan		break;
202167358Srafan
203167358Srafan	case MOD_SHUTDOWN:
204167358Srafan		break;
205167358Srafan
206167358Srafan	default:
207167358Srafan		return(EOPNOTSUPP);
208167358Srafan		break;
209167358Srafan
210167358Srafan	}
211167358Srafan
212167358Srafan	return (0);
213167358Srafan}
214167358Srafan
215167358SrafanDEV_MODULE(io, io_modevent, NULL);
216167358SrafanMODULE_VERSION(io, 1);
217167358Srafan