1 /* $NetBSD: pud_dev.c,v 1.4 2007/11/22 11:26:27 pooka 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.4 2007/11/22 11:26:27 pooka 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 static int 61 doioctl(dev_t dev, u_long cmd, void *data, int flag, int class, int type) 62 { 63 struct pud_req_ioctl *pc_ioctl; 64 size_t dlen, allocsize; 65 int error; 66 67 dlen = IOCPARM_LEN(cmd); 68 allocsize = sizeof(struct pud_req_ioctl) + dlen; 69 pc_ioctl = kmem_zalloc(allocsize, KM_SLEEP); 70 71 pc_ioctl->pm_iocmd = cmd; 72 pc_ioctl->pm_flag = flag; 73 74 if (cmd & IOC_IN) 75 memcpy(pc_ioctl->pm_data, data, dlen); 76 error = pud_request(dev, pc_ioctl, allocsize, class, type); 77 if (error) 78 goto out; 79 if (cmd & IOC_OUT) 80 memcpy(data, pc_ioctl->pm_data, dlen); 81 82 out: 83 kmem_free(pc_ioctl, allocsize); 84 return error; 85 } 86 87 /* 88 * Block de-vices 89 */ 90 91 static dev_type_open(pud_bdev_open); 92 static dev_type_close(pud_bdev_close); 93 static dev_type_strategy(pud_bdev_strategy); 94 static dev_type_ioctl(pud_bdev_ioctl); 95 #if 0 96 static dev_type_dump(pud_bdev_dump); 97 static dev_type_size(pud_bdev_size); 98 #endif 99 100 struct bdevsw pud_bdevsw = { 101 .d_open = pud_bdev_open, 102 .d_close = pud_bdev_close, 103 .d_strategy = pud_bdev_strategy, 104 .d_ioctl = pud_bdev_ioctl, 105 #if 0 106 .d_dump = pud_bdev_dump, 107 .d_psize = pud_bdev_size, 108 #endif 109 }; 110 111 static int 112 pud_bdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 113 { 114 115 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_OPEN); 116 } 117 118 static int 119 pud_bdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 120 { 121 122 return doopenclose(dev, flags, fmt, PUD_REQ_BDEV, PUD_BDEV_CLOSE); 123 } 124 125 static void 126 pud_bdev_strategy(struct buf *bp) 127 { 128 struct pud_req_readwrite *pc_rw; 129 size_t allocsize; 130 int error; 131 132 allocsize = sizeof(struct pud_req_readwrite) + bp->b_bcount; 133 pc_rw = kmem_zalloc(allocsize, KM_SLEEP); 134 135 pc_rw->pm_offset = bp->b_blkno << DEV_BSHIFT; 136 pc_rw->pm_resid = bp->b_bcount; 137 138 if (BUF_ISWRITE(bp)) 139 memcpy(pc_rw->pm_data, bp->b_data, bp->b_bcount); 140 141 error = pud_request(bp->b_dev, pc_rw, allocsize, PUD_REQ_BDEV, 142 BUF_ISREAD(bp) ? PUD_BDEV_STRATREAD : PUD_BDEV_STRATWRITE); 143 if (error) 144 goto out; 145 146 if (pc_rw->pm_resid > bp->b_bcount) { 147 error = EINVAL; 148 goto out; 149 } 150 151 if (BUF_ISREAD(bp)) 152 memcpy(bp->b_data,pc_rw->pm_data,bp->b_bcount-pc_rw->pm_resid); 153 154 bp->b_resid = pc_rw->pm_resid; 155 156 out: 157 kmem_free(pc_rw, allocsize); 158 bp->b_error = error; 159 biodone(bp); 160 } 161 162 int 163 pud_bdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 164 { 165 166 return doioctl(dev, cmd, data, flag, PUD_REQ_BDEV, PUD_BDEV_IOCTL); 167 } 168 169 /* hnmmm */ 170 #if 0 171 int 172 pud_bdev_dump(dev_t dev, daddr_t addr, void *data, size_t sz) 173 { 174 175 return EOPNOTSUPP; 176 } 177 178 int 179 pud_bdev_size(dev_t dev) 180 { 181 182 return 0; 183 } 184 #endif 185 186 /* 187 * Charrr devices 188 */ 189 190 static dev_type_open(pud_cdev_open); 191 static dev_type_close(pud_cdev_close); 192 static dev_type_read(pud_cdev_read); 193 static dev_type_write(pud_cdev_write); 194 static dev_type_ioctl(pud_cdev_ioctl); 195 static dev_type_poll(pud_cdev_poll); 196 static dev_type_mmap(pud_cdev_mmap); 197 static dev_type_kqfilter(pud_cdev_kqfilter); 198 199 struct cdevsw pud_cdevsw = { 200 .d_open = pud_cdev_open, 201 .d_close = pud_cdev_close, 202 .d_read = pud_cdev_read, 203 .d_write = pud_cdev_write, 204 .d_ioctl = pud_cdev_ioctl, 205 #if 0 206 .d_stop = pud_cdev_stop, 207 .d_tty = pud_cdev_tty, 208 #endif 209 .d_poll = pud_cdev_poll, 210 .d_mmap = pud_cdev_mmap, 211 .d_kqfilter = pud_cdev_kqfilter, 212 .d_flag = D_OTHER, 213 }; 214 215 static int 216 pud_cdev_open(dev_t dev, int flags, int fmt, lwp_t *l) 217 { 218 219 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_OPEN); 220 } 221 222 static int 223 pud_cdev_close(dev_t dev, int flags, int fmt, lwp_t *l) 224 { 225 226 return doopenclose(dev, flags, fmt, PUD_REQ_CDEV, PUD_CDEV_OPEN); 227 } 228 229 static int 230 pud_cdev_read(dev_t dev, struct uio *uio, int flag) 231 { 232 struct pud_creq_read *pc_read; 233 size_t allocsize; 234 int error; 235 236 allocsize = sizeof(struct pud_creq_read) + uio->uio_resid; 237 pc_read = kmem_zalloc(allocsize, KM_SLEEP); 238 239 pc_read->pm_offset = uio->uio_offset; 240 pc_read->pm_resid = uio->uio_resid; 241 242 error = pud_request(dev, pc_read, allocsize, 243 PUD_REQ_CDEV, PUD_CDEV_READ); 244 if (error) 245 goto out; 246 247 if (pc_read->pm_resid > uio->uio_resid) { 248 error = EINVAL; 249 goto out; 250 } 251 252 error = uiomove(pc_read->pm_data, 253 uio->uio_resid - pc_read->pm_resid, uio); 254 255 out: 256 kmem_free(pc_read, allocsize); 257 return error; 258 } 259 260 static int 261 pud_cdev_write(dev_t dev, struct uio *uio, int flag) 262 { 263 struct pud_creq_write *pc_write; 264 size_t allocsize; 265 int error; 266 267 allocsize = sizeof(struct pud_creq_write) + uio->uio_resid; 268 pc_write = kmem_zalloc(allocsize, KM_SLEEP); 269 270 pc_write->pm_offset = uio->uio_offset; 271 pc_write->pm_resid = uio->uio_resid; 272 273 error = uiomove(pc_write->pm_data, uio->uio_resid, uio); 274 if (error) 275 goto out; 276 277 error = pud_request(dev, pc_write, allocsize, 278 PUD_REQ_CDEV, PUD_CDEV_WRITE); 279 if (error) 280 goto out; 281 282 if (pc_write->pm_resid) 283 error = EIO; 284 285 out: 286 kmem_free(pc_write, allocsize); 287 return error; 288 } 289 290 static int 291 pud_cdev_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l) 292 { 293 294 return doioctl(dev, cmd, data, flag, PUD_REQ_CDEV, PUD_CDEV_IOCTL); 295 } 296 297 static paddr_t 298 pud_cdev_mmap(dev_t dev, off_t off, int flag) 299 { 300 301 return (paddr_t)-1; 302 } 303 304 static int 305 pud_cdev_poll(dev_t dev, int flag, lwp_t *l) 306 { 307 308 return EOPNOTSUPP; 309 } 310 311 static int 312 pud_cdev_kqfilter(dev_t dev, struct knote *kn) 313 { 314 315 return EOPNOTSUPP; 316 } 317