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 stat st; 81 int i; 82 83 for (i = 0; i < DiskNum; i++) { 84 /* check that the 'bus device' has been initialized */ 85 dsk = &DiskInfo[i]; 86 if (dsk == NULL || dsk->type != VKD_CD) 87 continue; 88 if (dsk->fd < 0 || fstat(dsk->fd, &st) < 0) 89 continue; 90 91 /* and create a new device */ 92 sc = kmalloc(sizeof(*sc), M_DEVBUF, M_WAITOK | M_ZERO); 93 sc->unit = dsk->unit; 94 sc->fd = dsk->fd; 95 bioq_init(&sc->bio_queue); 96 devstat_add_entry(&sc->stats, "vcd", sc->unit, 2048, 97 DEVSTAT_NO_ORDERED_TAGS, 98 DEVSTAT_TYPE_DIRECT | DEVSTAT_TYPE_IF_OTHER, 99 DEVSTAT_PRIORITY_DISK); 100 sc->dev = disk_create(sc->unit, &sc->disk, &vcd_ops); 101 sc->dev->si_drv1 = sc; 102 sc->dev->si_iosize_max = 256 * 1024; 103 } 104 } 105 106 SYSINIT(vcdisk, SI_SUB_DRIVERS, SI_ORDER_FIRST, vcdinit, NULL); 107 108 static int 109 vcdopen(struct dev_open_args *ap) 110 { 111 struct vcd_softc *sc; 112 struct disk_info info; 113 struct stat st; 114 cdev_t dev; 115 116 dev = ap->a_head.a_dev; 117 sc = dev->si_drv1; 118 if (fstat(sc->fd, &st) < 0 || st.st_size == 0) 119 return(ENXIO); 120 121 bzero(&info, sizeof(info)); 122 info.d_media_blksize = 2048; 123 info.d_media_blocks = st.st_size / info.d_media_blksize; 124 info.d_dsflags = DSO_ONESLICE | DSO_COMPATLABEL | DSO_COMPATPARTA | 125 DSO_RAWEXTENSIONS; 126 info.d_nheads = 1; 127 info.d_ncylinders = 1; 128 info.d_secpertrack = info.d_media_blocks; 129 info.d_secpercyl = info.d_secpertrack * info.d_nheads; 130 131 disk_setdiskinfo(&sc->disk, &info); 132 return(0); 133 } 134 135 static int 136 vcdstrategy(struct dev_strategy_args *ap) 137 { 138 struct bio *bio = ap->a_bio; 139 struct buf *bp; 140 struct vcd_softc *sc; 141 cdev_t dev; 142 int n; 143 144 dev = ap->a_head.a_dev; 145 sc = dev->si_drv1; 146 147 bioqdisksort(&sc->bio_queue, bio); 148 while ((bio = bioq_takefirst(&sc->bio_queue)) != NULL) { 149 bp = bio->bio_buf; 150 151 devstat_start_transaction(&sc->stats); 152 153 switch(bp->b_cmd) { 154 case BUF_CMD_READ: 155 n = pread(sc->fd, bp->b_data, 156 bp->b_bcount, bio->bio_offset); 157 break; 158 case BUF_CMD_WRITE: 159 /* XXX HANDLE SHORT WRITE XXX */ 160 n = pwrite(sc->fd, bp->b_data, 161 bp->b_bcount, bio->bio_offset); 162 break; 163 default: 164 panic("vcd: bad b_cmd %d", bp->b_cmd); 165 break; /* not reached */ 166 } 167 if (n != bp->b_bcount) { 168 bp->b_error = EIO; 169 bp->b_flags |= B_ERROR; 170 } 171 172 bp->b_resid = bp->b_bcount - n; 173 devstat_end_transaction_buf(&sc->stats, bp); 174 biodone(bio); 175 } 176 return(0); 177 } 178