1 /* $NetBSD: altmem.c,v 1.1 2009/03/12 00:15:07 jmcneill 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.1 2009/03/12 00:15:07 jmcneill 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 altmemopen, altmemclose, altmemstrategy, altmemioctl, nodump, 64 altmemsize, D_DISK 65 }; 66 const struct cdevsw altmem_cdevsw = { 67 altmemopen, altmemclose, altmemread, altmemwrite, altmemioctl, 68 nostop, notty, nopoll, nommap, nokqfilter, D_DISK 69 }; 70 static struct dkdriver altmemdkdriver = { altmemstrategy, minphys }; 71 extern struct cfdriver altmem_cd; 72 73 CFATTACH_DECL_NEW(altmem, sizeof(struct altmem_softc), altmem_match, 74 altmem_attach, NULL, NULL); 75 76 static int 77 altmem_match(device_t parent, cfdata_t match, void *opaque) 78 { 79 return 1; 80 } 81 82 static void 83 altmem_attach(device_t parent, device_t self, void *opaque) 84 { 85 struct altmem_softc *sc = device_private(self); 86 struct altmem_attach_args *aaa = opaque; 87 char pbuf[9]; 88 89 sc->sc_dev = self; 90 sc->sc_cookie = aaa->cookie; 91 sc->sc_memops = aaa->memops; 92 sc->sc_size = sc->sc_memops->getsize(sc->sc_cookie); 93 94 format_bytes(pbuf, sizeof(pbuf), sc->sc_size); 95 96 aprint_naive("\n"); 97 aprint_normal(": %s\n", pbuf); 98 99 disk_init(&sc->sc_dkdev, device_xname(self), &altmemdkdriver); 100 disk_attach(&sc->sc_dkdev); 101 } 102 103 static int 104 altmemsize(dev_t dev) 105 { 106 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 107 if (sc == NULL) 108 return 0; 109 return sc->sc_size >> DEV_BSHIFT; 110 } 111 112 static int 113 altmemopen(dev_t dev, int flag, int fmt, struct lwp *l) 114 { 115 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 116 if (sc == NULL) 117 return ENXIO; 118 return 0; 119 } 120 121 static int 122 altmemclose(dev_t dev, int flag, int fmt, struct lwp *l) 123 { 124 return 0; 125 } 126 127 static int 128 altmemread(dev_t dev, struct uio *uio, int flags) 129 { 130 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 131 return ENXIO; 132 return physio(altmemstrategy, NULL, dev, B_READ, minphys, uio); 133 } 134 135 static int 136 altmemwrite(dev_t dev, struct uio *uio, int flags) 137 { 138 if (device_lookup_private(&altmem_cd, DISKUNIT(dev)) == NULL) 139 return ENXIO; 140 return physio(altmemstrategy, NULL, dev, B_WRITE, minphys, uio); 141 } 142 143 static void 144 altmemstrategy(struct buf *bp) 145 { 146 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(bp->b_dev)); 147 148 if (sc == NULL) { 149 bp->b_error = ENXIO; 150 biodone(bp); 151 return; 152 } 153 if (bp->b_bcount == 0) { 154 biodone(bp); 155 return; 156 } 157 158 sc->sc_memops->strategy(sc->sc_cookie, bp); 159 biodone(bp); 160 } 161 162 static int 163 altmemioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) 164 { 165 struct altmem_softc *sc = device_lookup_private(&altmem_cd, DISKUNIT(dev)); 166 struct dkwedge_info *dkw; 167 168 switch (cmd) { 169 case DIOCGWEDGEINFO: 170 dkw = (void *)data; 171 strlcpy(dkw->dkw_devname, device_xname(sc->sc_dev), 172 sizeof(dkw->dkw_devname)); 173 strlcpy(dkw->dkw_wname, "altmem", sizeof(dkw->dkw_wname)); 174 dkw->dkw_parent[0] = '\0'; 175 dkw->dkw_offset = 0; 176 dkw->dkw_size = sc->sc_size >> DEV_BSHIFT; 177 strcpy(dkw->dkw_ptype, DKW_PTYPE_UNUSED); 178 break; 179 default: 180 return ENOTTY; 181 } 182 return 0; 183 } 184