1132956Smarkm/*- 2132956Smarkm * Copyright (c) 2004 Mark R V Murray 3132956Smarkm * All rights reserved. 4132956Smarkm * 5132956Smarkm * Redistribution and use in source and binary forms, with or without 6132956Smarkm * modification, are permitted provided that the following conditions 7132956Smarkm * are met: 8132956Smarkm * 1. Redistributions of source code must retain the above copyright 9132956Smarkm * notice, this list of conditions and the following disclaimer 10132956Smarkm * in this position and unchanged. 11132956Smarkm * 2. Redistributions in binary form must reproduce the above copyright 12132956Smarkm * notice, this list of conditions and the following disclaimer in the 13132956Smarkm * documentation and/or other materials provided with the distribution. 14132956Smarkm * 15132956Smarkm * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR 16132956Smarkm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17132956Smarkm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18132956Smarkm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19132956Smarkm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20132956Smarkm * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21132956Smarkm * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22132956Smarkm * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23132956Smarkm * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24132956Smarkm * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25132956Smarkm * 26132956Smarkm */ 27132956Smarkm 28132956Smarkm#include <sys/cdefs.h> 29132956Smarkm__FBSDID("$FreeBSD: releng/10.3/sys/dev/io/iodev.c 207329 2010-04-28 15:38:01Z attilio $"); 30132956Smarkm 31132956Smarkm#include <sys/param.h> 32132956Smarkm#include <sys/conf.h> 33132956Smarkm#include <sys/kernel.h> 34207329Sattilio#include <sys/ioccom.h> 35132956Smarkm#include <sys/module.h> 36207329Sattilio#include <sys/priv.h> 37132956Smarkm#include <sys/proc.h> 38132956Smarkm#include <sys/systm.h> 39132956Smarkm 40132956Smarkm#include <machine/iodev.h> 41132956Smarkm 42207329Sattilio#include <dev/io/iodev.h> 43207329Sattilio 44207329Sattiliostatic int ioopen(struct cdev *dev, int flags, int fmt, 45207329Sattilio struct thread *td); 46207329Sattiliostatic int ioclose(struct cdev *dev, int flags, int fmt, 47207329Sattilio struct thread *td); 48207329Sattiliostatic int ioioctl(struct cdev *dev, u_long cmd, caddr_t data, 49207329Sattilio int fflag, struct thread *td); 50207329Sattilio 51207329Sattiliostatic int iopio_read(struct iodev_pio_req *req); 52207329Sattiliostatic int iopio_write(struct iodev_pio_req *req); 53207329Sattilio 54132956Smarkmstatic struct cdev *iodev; 55132956Smarkm 56132956Smarkmstatic struct cdevsw io_cdevsw = { 57132956Smarkm .d_version = D_VERSION, 58132956Smarkm .d_open = ioopen, 59132956Smarkm .d_close = ioclose, 60202097Smarcel .d_ioctl = ioioctl, 61132956Smarkm .d_name = "io", 62132956Smarkm}; 63132956Smarkm 64132956Smarkm/* ARGSUSED */ 65132956Smarkmstatic int 66207329Sattilioioopen(struct cdev *dev __unused, int flags __unused, int fmt __unused, 67207329Sattilio struct thread *td) 68207329Sattilio{ 69207329Sattilio int error; 70207329Sattilio 71207329Sattilio error = priv_check(td, PRIV_IO); 72207329Sattilio if (error != 0) 73207329Sattilio return (error); 74207329Sattilio error = securelevel_gt(td->td_ucred, 0); 75207329Sattilio if (error != 0) 76207329Sattilio return (error); 77207329Sattilio error = iodev_open(td); 78207329Sattilio 79207329Sattilio return (error); 80207329Sattilio} 81207329Sattilio 82207329Sattilio/* ARGSUSED */ 83207329Sattiliostatic int 84207329Sattilioioclose(struct cdev *dev __unused, int flags __unused, int fmt __unused, 85207329Sattilio struct thread *td) 86207329Sattilio{ 87207329Sattilio 88207329Sattilio return (iodev_close(td)); 89207329Sattilio} 90207329Sattilio 91207329Sattilio/* ARGSUSED */ 92207329Sattiliostatic int 93207329Sattilioioioctl(struct cdev *dev __unused, u_long cmd, caddr_t data, 94207329Sattilio int fflag __unused, struct thread *td __unused) 95207329Sattilio{ 96207329Sattilio struct iodev_pio_req *pio_req; 97207329Sattilio int error; 98207329Sattilio 99207329Sattilio switch (cmd) { 100207329Sattilio case IODEV_PIO: 101207329Sattilio pio_req = (struct iodev_pio_req *)data; 102207329Sattilio switch (pio_req->access) { 103207329Sattilio case IODEV_PIO_READ: 104207329Sattilio error = iopio_read(pio_req); 105207329Sattilio break; 106207329Sattilio case IODEV_PIO_WRITE: 107207329Sattilio error = iopio_write(pio_req); 108207329Sattilio break; 109207329Sattilio default: 110207329Sattilio error = EINVAL; 111207329Sattilio break; 112207329Sattilio } 113207329Sattilio break; 114207329Sattilio default: 115207329Sattilio error = iodev_ioctl(cmd, data); 116207329Sattilio } 117207329Sattilio 118207329Sattilio return (error); 119207329Sattilio} 120207329Sattilio 121207329Sattiliostatic int 122207329Sattilioiopio_read(struct iodev_pio_req *req) 123207329Sattilio{ 124207329Sattilio 125207329Sattilio switch (req->width) { 126207329Sattilio case 1: 127207329Sattilio req->val = iodev_read_1(req->port); 128207329Sattilio break; 129207329Sattilio case 2: 130207329Sattilio if (req->port & 1) { 131207329Sattilio req->val = iodev_read_1(req->port); 132207329Sattilio req->val |= iodev_read_1(req->port + 1) << 8; 133207329Sattilio } else 134207329Sattilio req->val = iodev_read_2(req->port); 135207329Sattilio break; 136207329Sattilio case 4: 137207329Sattilio if (req->port & 1) { 138207329Sattilio req->val = iodev_read_1(req->port); 139207329Sattilio req->val |= iodev_read_2(req->port + 1) << 8; 140207329Sattilio req->val |= iodev_read_1(req->port + 3) << 24; 141207329Sattilio } else if (req->port & 2) { 142207329Sattilio req->val = iodev_read_2(req->port); 143207329Sattilio req->val |= iodev_read_2(req->port + 2) << 16; 144207329Sattilio } else 145207329Sattilio req->val = iodev_read_4(req->port); 146207329Sattilio break; 147207329Sattilio default: 148207329Sattilio return (EINVAL); 149207329Sattilio } 150207329Sattilio 151207329Sattilio return (0); 152207329Sattilio} 153207329Sattilio 154207329Sattiliostatic int 155207329Sattilioiopio_write(struct iodev_pio_req *req) 156207329Sattilio{ 157207329Sattilio 158207329Sattilio switch (req->width) { 159207329Sattilio case 1: 160207329Sattilio iodev_write_1(req->port, req->val); 161207329Sattilio break; 162207329Sattilio case 2: 163207329Sattilio if (req->port & 1) { 164207329Sattilio iodev_write_1(req->port, req->val); 165207329Sattilio iodev_write_1(req->port + 1, req->val >> 8); 166207329Sattilio } else 167207329Sattilio iodev_write_2(req->port, req->val); 168207329Sattilio break; 169207329Sattilio case 4: 170207329Sattilio if (req->port & 1) { 171207329Sattilio iodev_write_1(req->port, req->val); 172207329Sattilio iodev_write_2(req->port + 1, req->val >> 8); 173207329Sattilio iodev_write_1(req->port + 3, req->val >> 24); 174207329Sattilio } else if (req->port & 2) { 175207329Sattilio iodev_write_2(req->port, req->val); 176207329Sattilio iodev_write_2(req->port + 2, req->val >> 16); 177207329Sattilio } else 178207329Sattilio iodev_write_4(req->port, req->val); 179207329Sattilio break; 180207329Sattilio default: 181207329Sattilio return (EINVAL); 182207329Sattilio } 183207329Sattilio 184207329Sattilio return (0); 185207329Sattilio} 186207329Sattilio 187207329Sattilio/* ARGSUSED */ 188207329Sattiliostatic int 189132956Smarkmio_modevent(module_t mod __unused, int type, void *data __unused) 190132956Smarkm{ 191132956Smarkm switch(type) { 192132956Smarkm case MOD_LOAD: 193132956Smarkm if (bootverbose) 194132956Smarkm printf("io: <I/O>\n"); 195179990Sed iodev = make_dev(&io_cdevsw, 0, 196132956Smarkm UID_ROOT, GID_WHEEL, 0600, "io"); 197132956Smarkm break; 198132956Smarkm 199132956Smarkm case MOD_UNLOAD: 200132956Smarkm destroy_dev(iodev); 201132956Smarkm break; 202132956Smarkm 203132956Smarkm case MOD_SHUTDOWN: 204132956Smarkm break; 205132956Smarkm 206132956Smarkm default: 207132956Smarkm return(EOPNOTSUPP); 208132956Smarkm break; 209132956Smarkm 210132956Smarkm } 211132956Smarkm 212132956Smarkm return (0); 213132956Smarkm} 214132956Smarkm 215132956SmarkmDEV_MODULE(io, io_modevent, NULL); 216133036SmarkmMODULE_VERSION(io, 1); 217