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); 217