]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/io/iodev.c
MFV r357783:
[FreeBSD/FreeBSD.git] / sys / dev / io / iodev.c
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);