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