xref: /freebsd/sys/dev/io/iodev.c (revision d0b2dbfa0ecf2bbc9709efc5e20baf8e4b44bbbf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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 #include <sys/param.h>
32 #include <sys/conf.h>
33 #include <sys/kernel.h>
34 #include <sys/ioccom.h>
35 #include <sys/module.h>
36 #include <sys/priv.h>
37 #include <sys/proc.h>
38 #include <sys/systm.h>
39 
40 #include <machine/iodev.h>
41 
42 #include <dev/io/iodev.h>
43 
44 static int	 ioopen(struct cdev *dev, int flags, int fmt,
45 		    struct thread *td);
46 static int	 ioclose(struct cdev *dev, int flags, int fmt,
47 		    struct thread *td);
48 static int	 ioioctl(struct cdev *dev, u_long cmd, caddr_t data,
49 		    int fflag, struct thread *td);
50 
51 static int	 iopio_read(struct iodev_pio_req *req);
52 static int	 iopio_write(struct iodev_pio_req *req);
53 
54 static struct cdev *iodev;
55 
56 static struct cdevsw io_cdevsw = {
57 	.d_version =	D_VERSION,
58 	.d_open =	ioopen,
59 	.d_close =	ioclose,
60 	.d_ioctl =	ioioctl,
61 	.d_name =	"io",
62 };
63 
64 /* ARGSUSED */
65 static int
66 ioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused,
67     struct thread *td)
68 {
69 	int error;
70 
71 	error = priv_check(td, PRIV_IO);
72 	if (error != 0)
73 		return (error);
74 	error = securelevel_gt(td->td_ucred, 0);
75 	if (error != 0)
76 		return (error);
77 	error = iodev_open(td);
78 
79         return (error);
80 }
81 
82 /* ARGSUSED */
83 static int
84 ioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused,
85     struct thread *td)
86 {
87 
88 	return (iodev_close(td));
89 }
90 
91 /* ARGSUSED */
92 static int
93 ioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data,
94     int fflag __unused, struct thread *td __unused)
95 {
96 	struct iodev_pio_req *pio_req;
97 	int error;
98 
99 	switch (cmd) {
100 	case IODEV_PIO:
101 		pio_req = (struct iodev_pio_req *)data;
102 		switch (pio_req->access) {
103 		case IODEV_PIO_READ:
104 			error = iopio_read(pio_req);
105 			break;
106 		case IODEV_PIO_WRITE:
107 			error = iopio_write(pio_req);
108 			break;
109 		default:
110 			error = EINVAL;
111 			break;
112 		}
113 		break;
114 	default:
115 		error = iodev_ioctl(cmd, data);
116 	}
117 
118 	return (error);
119 }
120 
121 static int
122 iopio_read(struct iodev_pio_req *req)
123 {
124 
125 	switch (req->width) {
126 	case 1:
127 		req->val = iodev_read_1(req->port);
128 		break;
129 	case 2:
130 		if (req->port & 1) {
131 			req->val = iodev_read_1(req->port);
132 			req->val |= iodev_read_1(req->port + 1) << 8;
133 		} else
134 			req->val = iodev_read_2(req->port);
135 		break;
136 	case 4:
137 		if (req->port & 1) {
138 			req->val = iodev_read_1(req->port);
139 			req->val |= iodev_read_2(req->port + 1) << 8;
140 			req->val |= iodev_read_1(req->port + 3) << 24;
141 		} else if (req->port & 2) {
142 			req->val = iodev_read_2(req->port);
143 			req->val |= iodev_read_2(req->port + 2) << 16;
144 		} else
145 			req->val = iodev_read_4(req->port);
146 		break;
147 	default:
148 		return (EINVAL);
149 	}
150 
151 	return (0);
152 }
153 
154 static int
155 iopio_write(struct iodev_pio_req *req)
156 {
157 
158 	switch (req->width) {
159 	case 1:
160 		iodev_write_1(req->port, req->val);
161 		break;
162 	case 2:
163 		if (req->port & 1) {
164 			iodev_write_1(req->port, req->val);
165 			iodev_write_1(req->port + 1, req->val >> 8);
166 		} else
167 			iodev_write_2(req->port, req->val);
168 		break;
169 	case 4:
170 		if (req->port & 1) {
171 			iodev_write_1(req->port, req->val);
172 			iodev_write_2(req->port + 1, req->val >> 8);
173 			iodev_write_1(req->port + 3, req->val >> 24);
174 		} else if (req->port & 2) {
175 			iodev_write_2(req->port, req->val);
176 			iodev_write_2(req->port + 2, req->val >> 16);
177 		} else
178 			iodev_write_4(req->port, req->val);
179 		break;
180 	default:
181 		return (EINVAL);
182 	}
183 
184 	return (0);
185 }
186 
187 /* ARGSUSED */
188 static int
189 io_modevent(module_t mod __unused, int type, void *data __unused)
190 {
191 	switch(type) {
192 	case MOD_LOAD:
193 		if (bootverbose)
194 			printf("io: <I/O>\n");
195 		iodev = make_dev(&io_cdevsw, 0,
196 			UID_ROOT, GID_WHEEL, 0600, "io");
197 		break;
198 
199 	case MOD_UNLOAD:
200 		destroy_dev(iodev);
201 		break;
202 
203 	case MOD_SHUTDOWN:
204 		break;
205 
206 	default:
207 		return(EOPNOTSUPP);
208 		break;
209 
210 	}
211 
212 	return (0);
213 }
214 
215 DEV_MODULE(io, io_modevent, NULL);
216 MODULE_VERSION(io, 1);
217