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