1 /* $NetBSD: altmem.c,v 1.2 2014/03/16 05:20:26 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 2009 Jared D. McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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, 20 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 22 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __KERNEL_RCSID(0, "$NetBSD: altmem.c,v 1.2 2014/03/16 05:20:26 dholland Exp $"); 30 #include <sys/param.h> 31 #include <sys/types.h> 32 #include <sys/device.h> 33 #include <sys/conf.h> 34 #include <sys/buf.h> 35 #include <sys/disklabel.h> 36 #include <sys/disk.h> 37 38 #include <dev/altmem/altmemvar.h> 39 40 struct altmem_softc { 41 device_t sc_dev; 42 43 struct disk sc_dkdev; 44 45 void *sc_cookie; 46 const struct altmem_memops *sc_memops; 47 48 size_t sc_size; 49 }; 50 51 static dev_type_open(altmemopen); 52 static dev_type_close(altmemclose); 53 static dev_type_read(altmemread); 54 static dev_type_write(altmemwrite); 55 static dev_type_ioctl(altmemioctl); 56 static dev_type_strategy(altmemstrategy); 57 static dev_type_size(altmemsize); 58 59 static int altmem_match(device_t, cfdata_t, void *); 60 static void altmem_attach(device_t, device_t, void *); 61 62 const struct bdevsw altmem_bdevsw = { 63 .d_open = altmemopen, 64 .d_close = altmemclose, 65 .d_strategy = altmemstrategy, 66 .d_ioctl = altmemioctl, 67 .d_dump = nodump, 68 .d_psize = altmemsize, 69 .d_flag = D_DISK 70 }; 71 const struct cdevsw altmem_cdevsw = { 72 .d_open = altmemopen, 73 .d_close = altmemclose, 74 .d_read = altmemread, 75 .d_write = altmemwrite, 76 .d_ioctl = altmemioctl, 77 .d_stop = nostop, 78 .d_tty = notty, 79 .d_poll = nopoll, 80 .d_mmap = nommap, 81 .d_kqfilter = nokqfilter, 82 .d_flag = D_DISK 83 }; 84 static struct dkdriver altmemdkdriver = { altmemstrategy, minphys }; 85 extern struct cfdriver altmem_cd; 86 87 CFATTACH_DECL_NEW(altmem, sizeof(struct altmem_softc), altmem_match, 88 altmem_attach, NULL, NULL); 89 90 static int 91 altmem_match(device_t parent, cfdata_t match, void *opaque) 92 { 93 return 1; 94 } 95 96 static void 97 altmem_attach(device_t parent, device_t self, void *opaque) 98 { 99 struct altmem_softc *sc = device_private(self); 100 struct altmem_attach_args *aaa = opaque; 101 char pbuf[9]; 102 103 sc->sc_dev = self; 104 sc->sc_cookie = aaa->cookie; 105 sc->sc_memops = aaa->memops; 106 sc->sc_size = sc->sc_memops->getsize(sc->sc_cookie); 107 108 format_bytes(pbuf, sizeof(pbuf), sc->sc_size); 109 110 aprint_naive("\n"); 111 aprint_normal(": %s\n", pbuf); 112 113 disk_init(&sc->sc_dkdev, device_xname(self), &altmemdkdriver); 114 disk_attach(&sc->sc_dkdev); 115 } 116 117 static int 118 altmemsize(dev_t dev) 119 { 120 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 121 if (sc == NULL) 122 return 0; 123 return sc->sc_size >> DEV_BSHIFT; 124 } 125 126 static int 127 altmemopen(dev_t dev, int flag, int fmt, struct lwp *l) 128 { 129 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 130 if (sc == NULL) 131 return ENXIO; 132 return 0; 133 } 134 135 static int 136 altmemclose(dev_t dev, int flag, int fmt, struct lwp *l) 137 { 138 return 0; 139 } 140 141 static int 142 altmemread(dev_t dev, struct uio *uio, int flags) 143 { 144 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 145 return ENXIO; 146 return physio(altmemstrategy, NULL, dev, B_READ, minphys, uio); 147 } 148 149 static int 150 altmemwrite(dev_t dev, struct uio *uio, int flags) 151 { 152 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 153 return ENXIO; 154 return physio(altmemstrategy, NULL, dev, B_WRITE, minphys, uio); 155 } 156 157 static void 158 altmemstrategy(struct buf *bp) 159 { 160 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(bp->b_dev)); 161 162 if (sc == NULL) { 163 bp->b_error = ENXIO; 164 biodone(bp); 165 return; 166 } 167 if (bp->b_bcount == 0) { 168 biodone(bp); 169 return; 170 } 171 172 sc->sc_memops->strategy(sc->sc_cookie, bp); 173 biodone(bp); 174 } 175 176 static int 177 altmemioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 178 { 179 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 180 struct dkwedge_info *dkw; 181 182 switch (cmd) { 183 case DIOCGWEDGEINFO: 184 dkw = (void *)data; 185 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 186 sizeof(dkw->dkw_devname)); 187 strlcpy(dkw->dkw_wname, "altmem", sizeof(dkw->dkw_wname)); 188 dkw->dkw_parent[0] = '\0'; 189 dkw->dkw_offset = 0; 190 dkw->dkw_size = sc->sc_size >> DEV_BSHIFT; 191 strcpy(dkw->dkw_ptype, DKW_PTYPE_UNUSED); 192 break; 193 default: 194 return ENOTTY; 195 } 196 return 0; 197 } 198