1 /* $NetBSD: pud_dev.c,v 1.7 2015/12/08 20:36:15 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Antti Kantee. All Rights Reserved. 5 * 6 * Development of this software was supported by the 7 * Research Foundation of Helsinki University of Technology 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31 #include <sys/cdefs.h> 32 __KERNEL_RCSID(0, "$NetBSD: pud_dev.c,v 1.7 2015/12/08 20:36:15 christos Exp $"); 33 34 #include <sys/param.h> 35 #include <sys/buf.h> 36 #include <sys/conf.h> 37 #include <sys/event.h> 38 #include <sys/ioccom.h> 39 #include <sys/kmem.h> 40 #include <sys/poll.h> 41 #include <sys/socketvar.h> 42 43 #include <dev/pud/pud_sys.h> 44 45 /* 46 * b/c independent helpers 47 */ 48 49 static int 50 doopenclose(dev_t dev, int flags, int fmt, int class, int type) 51 { 52 struct pud_req_openclose pc_oc; /* XXX: stack = stupid */ 53 54 pc_oc.pm_flags = flags; 55 pc_oc.pm_fmt = fmt; 56 57 return pud_request(dev, &pc_oc, sizeof(pc_oc), class, type); 58 } 59 60 #include <sys/disklabel.h> 61 static int 62 doioctl(dev_t dev, u_long cmd, void *data, int flag, int class, int type) 63 { 64 struct pud_req_ioctl *pc_ioctl; 65 size_t dlen, allocsize; 66 int error; 67 68 dlen = IOCPARM_LEN(cmd); 69 allocsize = sizeof(struct pud_req_ioctl) + dlen; 70 pc_ioctl = kmem_zalloc(allocsize, KM_SLEEP); 71 72 pc_ioctl->pm_iocmd = cmd; 73 pc_ioctl->pm_flag = flag; 74 75 if (cmd & IOC_IN) 76 memcpy(pc_ioctl->pm_data, data, dlen); 77 error = pud_request(dev, pc_ioctl, allocsize, class, type); 78 if (error) 79 goto out; 80 if (cmd & IOC_OUT) 81 memcpy(data, pc_ioctl->pm_data, dlen); 82 83 out: 84 kmem_free(pc_ioctl, allocsize); 85 return error; 86 } 87 88 /* 89 * Block de-vices 90 */ 91 92 static dev_type_open(pud_bdev_open); 93 static dev_type_close(pud_bdev_close); 94 static dev_type_strategy(pud_bdev_strategy); 95 static dev_type_ioctl(pud_bdev_ioctl); 96 #if 0 97 static dev_type_dump(pud_bdev_dump); 98 static dev_type_size(pud_bdev_size); 99 #endif 100 101 struct bdevsw pud_bdevsw = { 102 .d_open = pud_bdev_open, 103 .d_close = pud_bdev_close, 104 .d_strategy = pud_bdev_strategy, 105 .d_ioctl = pud_bdev_ioctl, 106 #if 0 107 .d_dump = pud_bdev_dump, 108 .d_psize = pud_bdev_size, 109 #endif 110 }; 111 112 static int 113 pud_bdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 114 { 115 116 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_OPEN); 117 } 118 119 static int 120 pud_bdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 121 { 122 123 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_CLOSE); 124 } 125 126 static void 127 pud_bdev_strategy(struct buf *bp) 128 { 129 struct pud_req_readwrite *pc_rw; 130 size_t allocsize; 131 int error; 132 133 allocsize = sizeof(struct pud_req_readwrite) + bp->b_bcount; 134 pc_rw = kmem_zalloc(allocsize, KM_SLEEP); 135 136 pc_rw->pm_offset = bp->b_blkno << DEV_BSHIFT; 137 pc_rw->pm_resid = bp->b_bcount; 138 139 if (BUF_ISWRITE(bp)) 140 memcpy(pc_rw->pm_data, bp->b_data, bp->b_bcount); 141 142 error = pud_request(bp->b_dev, pc_rw, allocsize, PUD_REQ_BDEV, 143 BUF_ISREAD(bp) ? PUD_BDEV_STRATREAD : PUD_BDEV_STRATWRITE); 144 if (error) 145 goto out; 146 147 if (pc_rw->pm_resid > bp->b_bcount) { 148 error = EINVAL; 149 goto out; 150 } 151 152 if (BUF_ISREAD(bp)) 153 memcpy(bp->b_data,pc_rw->pm_data,bp->b_bcount-pc_rw->pm_resid); 154 155 bp->b_resid = pc_rw->pm_resid; 156 157 out: 158 kmem_free(pc_rw, allocsize); 159 bp->b_error = error; 160 biodone(bp); 161 } 162 163 int 164 pud_bdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 165 { 166 167 return doioctl(dev, cmd, data, flag, PUD_REQ_BDEV, PUD_BDEV_IOCTL); 168 } 169 170 /* hnmmm */ 171 #if 0 172 int 173 pud_bdev_dump(dev_t dev, daddr_t addr, void *data, size_t sz) 174 { 175 176 return EOPNOTSUPP; 177 } 178 179 int 180 pud_bdev_size(dev_t dev) 181 { 182 183 return 0; 184 } 185 #endif 186 187 /* 188 * Charrr devices 189 */ 190 191 static dev_type_open(pud_cdev_open); 192 static dev_type_close(pud_cdev_close); 193 static dev_type_read(pud_cdev_read); 194 static dev_type_write(pud_cdev_write); 195 static dev_type_ioctl(pud_cdev_ioctl); 196 static dev_type_poll(pud_cdev_poll); 197 static dev_type_mmap(pud_cdev_mmap); 198 static dev_type_kqfilter(pud_cdev_kqfilter); 199 200 struct cdevsw pud_cdevsw = { 201 .d_open = pud_cdev_open, 202 .d_close = pud_cdev_close, 203 .d_read = pud_cdev_read, 204 .d_write = pud_cdev_write, 205 .d_ioctl = pud_cdev_ioctl, 206 #if 0 207 .d_stop = pud_cdev_stop, 208 .d_tty = pud_cdev_tty, 209 #endif 210 .d_poll = pud_cdev_poll, 211 .d_mmap = pud_cdev_mmap, 212 .d_kqfilter = pud_cdev_kqfilter, 213 .d_flag = D_OTHER, 214 }; 215 216 static int 217 pud_cdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 218 { 219 220 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_OPEN); 221 } 222 223 static int 224 pud_cdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 225 { 226 227 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_CLOSE); 228 } 229 230 static int 231 pud_cdev_read(dev_t dev, struct uio *uio, int flag) 232 { 233 struct pud_creq_read *pc_read; 234 size_t allocsize; 235 int error; 236 237 allocsize = sizeof(struct pud_creq_read) + uio->uio_resid; 238 pc_read = kmem_zalloc(allocsize, KM_SLEEP); 239 240 pc_read->pm_offset = uio->uio_offset; 241 pc_read->pm_resid = uio->uio_resid; 242 243 error = pud_request(dev, pc_read, allocsize, 244 PUD_REQ_CDEV, PUD_CDEV_READ); 245 if (error) 246 goto out; 247 248 if (pc_read->pm_resid > uio->uio_resid) { 249 error = EINVAL; 250 goto out; 251 } 252 253 error = uiomove(pc_read->pm_data, 254 uio->uio_resid - pc_read->pm_resid, uio); 255 256 out: 257 kmem_free(pc_read, allocsize); 258 return error; 259 } 260 261 static int 262 pud_cdev_write(dev_t dev, struct uio *uio, int flag) 263 { 264 struct pud_creq_write *pc_write; 265 size_t allocsize; 266 int error; 267 268 allocsize = sizeof(struct pud_creq_write) + uio->uio_resid; 269 pc_write = kmem_zalloc(allocsize, KM_SLEEP); 270 271 pc_write->pm_offset = uio->uio_offset; 272 pc_write->pm_resid = uio->uio_resid; 273 274 error = uiomove(pc_write->pm_data, uio->uio_resid, uio); 275 if (error) 276 goto out; 277 278 error = pud_request(dev, pc_write, allocsize, 279 PUD_REQ_CDEV, PUD_CDEV_WRITE); 280 if (error) 281 goto out; 282 283 if (pc_write->pm_resid) 284 error = EIO; 285 286 out: 287 kmem_free(pc_write, allocsize); 288 return error; 289 } 290 291 static int 292 pud_cdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 293 { 294 295 return doioctl(dev, cmd, data, flag, PUD_REQ_CDEV, PUD_CDEV_IOCTL); 296 } 297 298 static paddr_t 299 pud_cdev_mmap(dev_t dev, off_t off, int flag) 300 { 301 302 return (paddr_t)-1; 303 } 304 305 static int 306 pud_cdev_poll(dev_t dev, int flag, lwp_t *l) 307 { 308 309 return EOPNOTSUPP; 310 } 311 312 static int 313 pud_cdev_kqfilter(dev_t dev, struct knote *kn) 314 { 315 316 return EOPNOTSUPP; 317 } 318