/*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2000 Mark R. V. Murray & Jeroen C. van Gelderen * Copyright (c) 2001-2004 Mark R. V. Murray * Copyright (c) 2014 Eitan Adler * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer * in this position and unchanged. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include /* For use with destroy_dev(9). */ static struct cdev *zeroo_dev; static d_write_t zeroo_write; static d_ioctl_t zeroo_ioctl; static d_read_t zeroo_read; static d_kqfilter_t zeroo_kqfilter; static int zeroo_kqread(struct knote *kn, long hint); static const struct filterops zeroo_filterops_read = { .f_isfd = 1, .f_event = zeroo_kqread, }; static struct cdevsw zeroo_cdevsw = { .d_version = D_VERSION, .d_read = zeroo_read, .d_write = zeroo_write, .d_ioctl = zeroo_ioctl, .d_kqfilter = zeroo_kqfilter, .d_name = "zeroo", .d_flags = D_MMAP_ANON, }; /* ARGSUSED */ static int zeroo_write(struct cdev *dev __unused, struct uio *uio, int flags __unused) { uio->uio_resid = 0; return (0); } /* ARGSUSED */ static int zeroo_ioctl(struct cdev *dev __unused, u_long cmd, caddr_t data __unused, int flags __unused, struct thread *td) { int error; error = 0; switch (cmd) { case FIONBIO: break; case FIOASYNC: if (*(int *)data != 0) error = EINVAL; break; default: error = ENOIOCTL; } return (error); } /* ARGSUSED */ static int zeroo_read(struct cdev *dev __unused, struct uio *uio, int flags __unused) { void *zbuf; ssize_t len; int error = 0; KASSERT(uio->uio_rw == UIO_READ, ("Can't be in %s for write", __func__)); zbuf = __DECONST(void *, zero_region); while (uio->uio_resid > 0 && error == 0) { len = uio->uio_resid; if (len > ZERO_REGION_SIZE) len = ZERO_REGION_SIZE; error = uiomove(zbuf, len, uio); } return (error); } /* ARGSUSED */ static int zeroo_modevent(module_t mod __unused, int type, void *data __unused) { switch(type) { case MOD_LOAD: zeroo_dev = make_dev(&zeroo_cdevsw, 0, UID_ROOT, GID_WHEEL, 0666, "zeroo"); break; case MOD_UNLOAD: destroy_dev(zeroo_dev); break; case MOD_SHUTDOWN: break; default: return (EOPNOTSUPP); } return (0); } static int zeroo_kqread(struct knote *kn, long hint) { return 1; } static int zeroo_kqfilter(struct cdev *dev, struct knote *kn) { if (kn->kn_filter != EVFILT_READ) return(EOPNOTSUPP); struct knlist lst; knlist_init(&lst, NULL, NULL, NULL, NULL); kn->kn_fop = &zeroo_filterops_read; knlist_add(&lst, kn, 0); KNOTE_LOCKED(&lst, 0); knlist_remove(&lst, kn, 0); return (0); } DEV_MODULE(zeroo, zeroo_modevent, NULL);