xref: /freebsd/sys/dev/io/iodev.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
18ab2f5ecSMark Murray /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
48ab2f5ecSMark Murray  * Copyright (c) 2004 Mark R V Murray
58ab2f5ecSMark Murray  * All rights reserved.
68ab2f5ecSMark Murray  *
78ab2f5ecSMark Murray  * Redistribution and use in source and binary forms, with or without
88ab2f5ecSMark Murray  * modification, are permitted provided that the following conditions
98ab2f5ecSMark Murray  * are met:
108ab2f5ecSMark Murray  * 1. Redistributions of source code must retain the above copyright
118ab2f5ecSMark Murray  *    notice, this list of conditions and the following disclaimer
128ab2f5ecSMark Murray  *    in this position and unchanged.
138ab2f5ecSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
148ab2f5ecSMark Murray  *    notice, this list of conditions and the following disclaimer in the
158ab2f5ecSMark Murray  *    documentation and/or other materials provided with the distribution.
168ab2f5ecSMark Murray  *
178ab2f5ecSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
188ab2f5ecSMark Murray  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
198ab2f5ecSMark Murray  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
208ab2f5ecSMark Murray  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
218ab2f5ecSMark Murray  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
228ab2f5ecSMark Murray  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
238ab2f5ecSMark Murray  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
248ab2f5ecSMark Murray  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
258ab2f5ecSMark Murray  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
268ab2f5ecSMark Murray  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
278ab2f5ecSMark Murray  *
288ab2f5ecSMark Murray  */
298ab2f5ecSMark Murray 
308ab2f5ecSMark Murray #include <sys/param.h>
318ab2f5ecSMark Murray #include <sys/conf.h>
328ab2f5ecSMark Murray #include <sys/kernel.h>
33d8b87887SAttilio Rao #include <sys/ioccom.h>
348ab2f5ecSMark Murray #include <sys/module.h>
35d8b87887SAttilio Rao #include <sys/priv.h>
368ab2f5ecSMark Murray #include <sys/proc.h>
378ab2f5ecSMark Murray #include <sys/systm.h>
388ab2f5ecSMark Murray 
398ab2f5ecSMark Murray #include <machine/iodev.h>
408ab2f5ecSMark Murray 
41d8b87887SAttilio Rao #include <dev/io/iodev.h>
42d8b87887SAttilio Rao 
43d8b87887SAttilio Rao static int	 ioopen(struct cdev *dev, int flags, int fmt,
44d8b87887SAttilio Rao 		    struct thread *td);
45d8b87887SAttilio Rao static int	 ioclose(struct cdev *dev, int flags, int fmt,
46d8b87887SAttilio Rao 		    struct thread *td);
47d8b87887SAttilio Rao static int	 ioioctl(struct cdev *dev, u_long cmd, caddr_t data,
48d8b87887SAttilio Rao 		    int fflag, struct thread *td);
49d8b87887SAttilio Rao 
50d8b87887SAttilio Rao static int	 iopio_read(struct iodev_pio_req *req);
51d8b87887SAttilio Rao static int	 iopio_write(struct iodev_pio_req *req);
52d8b87887SAttilio Rao 
538ab2f5ecSMark Murray static struct cdev *iodev;
548ab2f5ecSMark Murray 
558ab2f5ecSMark Murray static struct cdevsw io_cdevsw = {
568ab2f5ecSMark Murray 	.d_version =	D_VERSION,
578ab2f5ecSMark Murray 	.d_open =	ioopen,
588ab2f5ecSMark Murray 	.d_close =	ioclose,
59409a390cSMarcel Moolenaar 	.d_ioctl =	ioioctl,
608ab2f5ecSMark Murray 	.d_name =	"io",
618ab2f5ecSMark Murray };
628ab2f5ecSMark Murray 
638ab2f5ecSMark Murray /* ARGSUSED */
648ab2f5ecSMark Murray static int
ioopen(struct cdev * dev __unused,int flags __unused,int fmt __unused,struct thread * td)65d8b87887SAttilio Rao ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused,
66d8b87887SAttilio Rao     struct thread *td)
67d8b87887SAttilio Rao {
68d8b87887SAttilio Rao 	int error;
69d8b87887SAttilio Rao 
70d8b87887SAttilio Rao 	error = priv_check(td, PRIV_IO);
71d8b87887SAttilio Rao 	if (error != 0)
72d8b87887SAttilio Rao 		return (error);
73d8b87887SAttilio Rao 	error = securelevel_gt(td->td_ucred, 0);
74d8b87887SAttilio Rao 	if (error != 0)
75d8b87887SAttilio Rao 		return (error);
76d8b87887SAttilio Rao 	error = iodev_open(td);
77d8b87887SAttilio Rao 
78d8b87887SAttilio Rao         return (error);
79d8b87887SAttilio Rao }
80d8b87887SAttilio Rao 
81d8b87887SAttilio Rao /* ARGSUSED */
82d8b87887SAttilio Rao static int
ioclose(struct cdev * dev __unused,int flags __unused,int fmt __unused,struct thread * td)83d8b87887SAttilio Rao ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused,
84d8b87887SAttilio Rao     struct thread *td)
85d8b87887SAttilio Rao {
86d8b87887SAttilio Rao 
87d8b87887SAttilio Rao 	return (iodev_close(td));
88d8b87887SAttilio Rao }
89d8b87887SAttilio Rao 
90d8b87887SAttilio Rao /* ARGSUSED */
91d8b87887SAttilio Rao static int
ioioctl(struct cdev * dev __unused,u_long cmd,caddr_t data,int fflag __unused,struct thread * td __unused)92d8b87887SAttilio Rao ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
93d8b87887SAttilio Rao     int fflag __unused, struct thread *td __unused)
94d8b87887SAttilio Rao {
95d8b87887SAttilio Rao 	struct iodev_pio_req *pio_req;
96d8b87887SAttilio Rao 	int error;
97d8b87887SAttilio Rao 
98d8b87887SAttilio Rao 	switch (cmd) {
99d8b87887SAttilio Rao 	case IODEV_PIO:
100d8b87887SAttilio Rao 		pio_req = (struct iodev_pio_req *)data;
101d8b87887SAttilio Rao 		switch (pio_req->access) {
102d8b87887SAttilio Rao 		case IODEV_PIO_READ:
103d8b87887SAttilio Rao 			error = iopio_read(pio_req);
104d8b87887SAttilio Rao 			break;
105d8b87887SAttilio Rao 		case IODEV_PIO_WRITE:
106d8b87887SAttilio Rao 			error = iopio_write(pio_req);
107d8b87887SAttilio Rao 			break;
108d8b87887SAttilio Rao 		default:
109d8b87887SAttilio Rao 			error = EINVAL;
110d8b87887SAttilio Rao 			break;
111d8b87887SAttilio Rao 		}
112d8b87887SAttilio Rao 		break;
113d8b87887SAttilio Rao 	default:
114d8b87887SAttilio Rao 		error = iodev_ioctl(cmd, data);
115d8b87887SAttilio Rao 	}
116d8b87887SAttilio Rao 
117d8b87887SAttilio Rao 	return (error);
118d8b87887SAttilio Rao }
119d8b87887SAttilio Rao 
120d8b87887SAttilio Rao static int
iopio_read(struct iodev_pio_req * req)121d8b87887SAttilio Rao iopio_read(struct iodev_pio_req *req)
122d8b87887SAttilio Rao {
123d8b87887SAttilio Rao 
124d8b87887SAttilio Rao 	switch (req->width) {
125d8b87887SAttilio Rao 	case 1:
126d8b87887SAttilio Rao 		req->val = iodev_read_1(req->port);
127d8b87887SAttilio Rao 		break;
128d8b87887SAttilio Rao 	case 2:
129d8b87887SAttilio Rao 		if (req->port & 1) {
130d8b87887SAttilio Rao 			req->val = iodev_read_1(req->port);
131d8b87887SAttilio Rao 			req->val |= iodev_read_1(req->port + 1) << 8;
132d8b87887SAttilio Rao 		} else
133d8b87887SAttilio Rao 			req->val = iodev_read_2(req->port);
134d8b87887SAttilio Rao 		break;
135d8b87887SAttilio Rao 	case 4:
136d8b87887SAttilio Rao 		if (req->port & 1) {
137d8b87887SAttilio Rao 			req->val = iodev_read_1(req->port);
138d8b87887SAttilio Rao 			req->val |= iodev_read_2(req->port + 1) << 8;
139d8b87887SAttilio Rao 			req->val |= iodev_read_1(req->port + 3) << 24;
140d8b87887SAttilio Rao 		} else if (req->port & 2) {
141d8b87887SAttilio Rao 			req->val = iodev_read_2(req->port);
142d8b87887SAttilio Rao 			req->val |= iodev_read_2(req->port + 2) << 16;
143d8b87887SAttilio Rao 		} else
144d8b87887SAttilio Rao 			req->val = iodev_read_4(req->port);
145d8b87887SAttilio Rao 		break;
146d8b87887SAttilio Rao 	default:
147d8b87887SAttilio Rao 		return (EINVAL);
148d8b87887SAttilio Rao 	}
149d8b87887SAttilio Rao 
150d8b87887SAttilio Rao 	return (0);
151d8b87887SAttilio Rao }
152d8b87887SAttilio Rao 
153d8b87887SAttilio Rao static int
iopio_write(struct iodev_pio_req * req)154d8b87887SAttilio Rao iopio_write(struct iodev_pio_req *req)
155d8b87887SAttilio Rao {
156d8b87887SAttilio Rao 
157d8b87887SAttilio Rao 	switch (req->width) {
158d8b87887SAttilio Rao 	case 1:
159d8b87887SAttilio Rao 		iodev_write_1(req->port, req->val);
160d8b87887SAttilio Rao 		break;
161d8b87887SAttilio Rao 	case 2:
162d8b87887SAttilio Rao 		if (req->port & 1) {
163d8b87887SAttilio Rao 			iodev_write_1(req->port, req->val);
164d8b87887SAttilio Rao 			iodev_write_1(req->port + 1, req->val >> 8);
165d8b87887SAttilio Rao 		} else
166d8b87887SAttilio Rao 			iodev_write_2(req->port, req->val);
167d8b87887SAttilio Rao 		break;
168d8b87887SAttilio Rao 	case 4:
169d8b87887SAttilio Rao 		if (req->port & 1) {
170d8b87887SAttilio Rao 			iodev_write_1(req->port, req->val);
171d8b87887SAttilio Rao 			iodev_write_2(req->port + 1, req->val >> 8);
172d8b87887SAttilio Rao 			iodev_write_1(req->port + 3, req->val >> 24);
173d8b87887SAttilio Rao 		} else if (req->port & 2) {
174d8b87887SAttilio Rao 			iodev_write_2(req->port, req->val);
175d8b87887SAttilio Rao 			iodev_write_2(req->port + 2, req->val >> 16);
176d8b87887SAttilio Rao 		} else
177d8b87887SAttilio Rao 			iodev_write_4(req->port, req->val);
178d8b87887SAttilio Rao 		break;
179d8b87887SAttilio Rao 	default:
180d8b87887SAttilio Rao 		return (EINVAL);
181d8b87887SAttilio Rao 	}
182d8b87887SAttilio Rao 
183d8b87887SAttilio Rao 	return (0);
184d8b87887SAttilio Rao }
185d8b87887SAttilio Rao 
186d8b87887SAttilio Rao /* ARGSUSED */
187d8b87887SAttilio Rao static int
io_modevent(module_t mod __unused,int type,void * data __unused)1888ab2f5ecSMark Murray io_modevent(module_t mod __unused, int type, void *data __unused)
1898ab2f5ecSMark Murray {
1908ab2f5ecSMark Murray 	switch(type) {
1918ab2f5ecSMark Murray 	case MOD_LOAD:
1928ab2f5ecSMark Murray 		if (bootverbose)
1938ab2f5ecSMark Murray 			printf("io: <I/O>\n");
19472135187SEd Schouten 		iodev = make_dev(&io_cdevsw, 0,
1958ab2f5ecSMark Murray 			UID_ROOT, GID_WHEEL, 0600, "io");
1968ab2f5ecSMark Murray 		break;
1978ab2f5ecSMark Murray 
1988ab2f5ecSMark Murray 	case MOD_UNLOAD:
1998ab2f5ecSMark Murray 		destroy_dev(iodev);
2008ab2f5ecSMark Murray 		break;
2018ab2f5ecSMark Murray 
2028ab2f5ecSMark Murray 	case MOD_SHUTDOWN:
2038ab2f5ecSMark Murray 		break;
2048ab2f5ecSMark Murray 
2058ab2f5ecSMark Murray 	default:
2068ab2f5ecSMark Murray 		return(EOPNOTSUPP);
2078ab2f5ecSMark Murray 		break;
2088ab2f5ecSMark Murray 
2098ab2f5ecSMark Murray 	}
2108ab2f5ecSMark Murray 
2118ab2f5ecSMark Murray 	return (0);
2128ab2f5ecSMark Murray }
2138ab2f5ecSMark Murray 
2148ab2f5ecSMark Murray DEV_MODULE(io, io_modevent, NULL);
215ce46e205SMark Murray MODULE_VERSION(io, 1);
216