1 /* 2 * Copyright (c) 2007 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 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 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* 36 * Virtual CDROM driver 37 */ 38 #include <sys/types.h> 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> 43 #include <sys/conf.h> 44 #include <sys/buf.h> 45 #include <sys/devicestat.h> 46 #include <sys/disk.h> 47 #include <machine/md_var.h> 48 49 #include <sys/buf2.h> 50 51 #include <sys/stat.h> 52 #include <unistd.h> 53 54 struct vcd_softc { 55 struct bio_queue_head bio_queue; 56 struct devstat stats; 57 struct disk disk; 58 cdev_t dev; 59 int unit; 60 int fd; 61 }; 62 63 static d_strategy_t vcdstrategy; 64 static d_open_t vcdopen; 65 66 static struct dev_ops vcd_ops = { 67 { "vcd", 0, D_DISK }, 68 .d_open = vcdopen, 69 .d_close = nullclose, 70 .d_read = physread, 71 .d_write = physwrite, 72 .d_strategy = vcdstrategy, 73 }; 74 75 static void 76 vcdinit(void *dummy __unused) 77 { 78 struct vkdisk_info *dsk; 79 struct vcd_softc *sc; 80 struct disk_info info; 81 struct stat st; 82 int i; 83 84 for (i = 0; i < DiskNum; i++) { 85 /* check that the 'bus device' has been initialized */ 86 dsk = &DiskInfo[i]; 87 if (dsk == NULL || dsk->type != VKD_CD) 88 continue; 89 if (dsk->fd < 0 || fstat(dsk->fd, &st) < 0) 90 continue; 91 92 /* and create a new device */ 93 sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 94 sc->unit = dsk->unit; 95 sc->fd = dsk->fd; 96 bioq_init(&sc->bio_queue); 97 devstat_add_entry(&sc->stats, "vcd", sc->unit, 2048, 98 DEVSTAT_NO_ORDERED_TAGS, 99 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 100 DEVSTAT_PRIORITY_DISK); 101 sc->dev = disk_create(sc->unit, &sc->disk, &vcd_ops); 102 sc->dev->si_drv1 = sc; 103 sc->dev->si_iosize_max = 256 * 1024; 104 105 bzero(&info, sizeof(info)); 106 info.d_media_blksize = 2048; 107 info.d_media_blocks = st.st_size / info.d_media_blksize; 108 info.d_dsflags = DSO_ONESLICE | DSO_COMPATLABEL | DSO_COMPATPARTA | 109 DSO_RAWEXTENSIONS; 110 info.d_nheads = 1; 111 info.d_ncylinders = 1; 112 info.d_secpertrack = info.d_media_blocks; 113 info.d_secpercyl = info.d_secpertrack * info.d_nheads; 114 115 disk_setdiskinfo(&sc->disk, &info); 116 } 117 } 118 119 SYSINIT(vcdisk, SI_SUB_DRIVERS, SI_ORDER_FIRST, vcdinit, NULL); 120 121 static int 122 vcdopen(struct dev_open_args *ap) 123 { 124 struct vcd_softc *sc; 125 struct stat st; 126 cdev_t dev; 127 128 dev = ap->a_head.a_dev; 129 sc = dev->si_drv1; 130 if (fstat(sc->fd, &st) < 0 || st.st_size == 0) 131 return(ENXIO); 132 133 return(0); 134 } 135 136 static int 137 vcdstrategy(struct dev_strategy_args *ap) 138 { 139 struct bio *bio = ap->a_bio; 140 struct buf *bp; 141 struct vcd_softc *sc; 142 cdev_t dev; 143 int n; 144 145 dev = ap->a_head.a_dev; 146 sc = dev->si_drv1; 147 148 bioqdisksort(&sc->bio_queue, bio); 149 while ((bio = bioq_takefirst(&sc->bio_queue)) != NULL) { 150 bp = bio->bio_buf; 151 152 devstat_start_transaction(&sc->stats); 153 154 switch(bp->b_cmd) { 155 case BUF_CMD_READ: 156 n = pread(sc->fd, bp->b_data, 157 bp->b_bcount, bio->bio_offset); 158 break; 159 case BUF_CMD_WRITE: 160 /* XXX HANDLE SHORT WRITE XXX */ 161 n = pwrite(sc->fd, bp->b_data, 162 bp->b_bcount, bio->bio_offset); 163 break; 164 default: 165 panic("vcd: bad b_cmd %d", bp->b_cmd); 166 break; /* not reached */ 167 } 168 if (n != bp->b_bcount) { 169 bp->b_error = EIO; 170 bp->b_flags |= B_ERROR; 171 } 172 173 bp->b_resid = bp->b_bcount - n; 174 devstat_end_transaction_buf(&sc->stats, bp); 175 biodone(bio); 176 } 177 return(0); 178 } 179