xref: /freebsd/sys/dev/io/iodev.c (revision 4e462178745853ecc014c13f82f89cfe39b83e9c)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 Mark R V Murray
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  *    in this position and unchanged.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32 
33 #include <sys/param.h>
34 #include <sys/conf.h>
35 #include <sys/kernel.h>
36 #include <sys/ioccom.h>
37 #include <sys/module.h>
38 #include <sys/priv.h>
39 #include <sys/proc.h>
40 #include <sys/systm.h>
41 
42 #include <machine/iodev.h>
43 
44 #include <dev/io/iodev.h>
45 
46 static int	 ioopen(struct cdev *dev, int flags, int fmt,
47 		    struct thread *td);
48 static int	 ioclose(struct cdev *dev, int flags, int fmt,
49 		    struct thread *td);
50 static int	 ioioctl(struct cdev *dev, u_long cmd, caddr_t data,
51 		    int fflag, struct thread *td);
52 
53 static int	 iopio_read(struct iodev_pio_req *req);
54 static int	 iopio_write(struct iodev_pio_req *req);
55 
56 static struct cdev *iodev;
57 
58 static struct cdevsw io_cdevsw = {
59 	.d_version =	D_VERSION,
60 	.d_open =	ioopen,
61 	.d_close =	ioclose,
62 	.d_ioctl =	ioioctl,
63 	.d_name =	"io",
64 };
65 
66 /* ARGSUSED */
67 static int
68 ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused,
69     struct thread *td)
70 {
71 	int error;
72 
73 	error = priv_check(td, PRIV_IO);
74 	if (error != 0)
75 		return (error);
76 	error = securelevel_gt(td->td_ucred, 0);
77 	if (error != 0)
78 		return (error);
79 	error = iodev_open(td);
80 
81         return (error);
82 }
83 
84 /* ARGSUSED */
85 static int
86 ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused,
87     struct thread *td)
88 {
89 
90 	return (iodev_close(td));
91 }
92 
93 /* ARGSUSED */
94 static int
95 ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
96     int fflag __unused, struct thread *td __unused)
97 {
98 	struct iodev_pio_req *pio_req;
99 	int error;
100 
101 	switch (cmd) {
102 	case IODEV_PIO:
103 		pio_req = (struct iodev_pio_req *)data;
104 		switch (pio_req->access) {
105 		case IODEV_PIO_READ:
106 			error = iopio_read(pio_req);
107 			break;
108 		case IODEV_PIO_WRITE:
109 			error = iopio_write(pio_req);
110 			break;
111 		default:
112 			error = EINVAL;
113 			break;
114 		}
115 		break;
116 	default:
117 		error = iodev_ioctl(cmd, data);
118 	}
119 
120 	return (error);
121 }
122 
123 static int
124 iopio_read(struct iodev_pio_req *req)
125 {
126 
127 	switch (req->width) {
128 	case 1:
129 		req->val = iodev_read_1(req->port);
130 		break;
131 	case 2:
132 		if (req->port & 1) {
133 			req->val = iodev_read_1(req->port);
134 			req->val |= iodev_read_1(req->port + 1) << 8;
135 		} else
136 			req->val = iodev_read_2(req->port);
137 		break;
138 	case 4:
139 		if (req->port & 1) {
140 			req->val = iodev_read_1(req->port);
141 			req->val |= iodev_read_2(req->port + 1) << 8;
142 			req->val |= iodev_read_1(req->port + 3) << 24;
143 		} else if (req->port & 2) {
144 			req->val = iodev_read_2(req->port);
145 			req->val |= iodev_read_2(req->port + 2) << 16;
146 		} else
147 			req->val = iodev_read_4(req->port);
148 		break;
149 	default:
150 		return (EINVAL);
151 	}
152 
153 	return (0);
154 }
155 
156 static int
157 iopio_write(struct iodev_pio_req *req)
158 {
159 
160 	switch (req->width) {
161 	case 1:
162 		iodev_write_1(req->port, req->val);
163 		break;
164 	case 2:
165 		if (req->port & 1) {
166 			iodev_write_1(req->port, req->val);
167 			iodev_write_1(req->port + 1, req->val >> 8);
168 		} else
169 			iodev_write_2(req->port, req->val);
170 		break;
171 	case 4:
172 		if (req->port & 1) {
173 			iodev_write_1(req->port, req->val);
174 			iodev_write_2(req->port + 1, req->val >> 8);
175 			iodev_write_1(req->port + 3, req->val >> 24);
176 		} else if (req->port & 2) {
177 			iodev_write_2(req->port, req->val);
178 			iodev_write_2(req->port + 2, req->val >> 16);
179 		} else
180 			iodev_write_4(req->port, req->val);
181 		break;
182 	default:
183 		return (EINVAL);
184 	}
185 
186 	return (0);
187 }
188 
189 /* ARGSUSED */
190 static int
191 io_modevent(module_t mod __unused, int type, void *data __unused)
192 {
193 	switch(type) {
194 	case MOD_LOAD:
195 		if (bootverbose)
196 			printf("io: <I/O>\n");
197 		iodev = make_dev(&io_cdevsw, 0,
198 			UID_ROOT, GID_WHEEL, 0600, "io");
199 		break;
200 
201 	case MOD_UNLOAD:
202 		destroy_dev(iodev);
203 		break;
204 
205 	case MOD_SHUTDOWN:
206 		break;
207 
208 	default:
209 		return(EOPNOTSUPP);
210 		break;
211 
212 	}
213 
214 	return (0);
215 }
216 
217 DEV_MODULE(io, io_modevent, NULL);
218 MODULE_VERSION(io, 1);
219