]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - sys/dev/io/iodev.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / sys / dev / io / iodev.c
1 /*-
2  * Copyright (c) 2004 Mark R V Murray
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
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);