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 __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