1 /* $FreeBSD$ */ 2 /*- 3 * Copyright (c) 2014 Hans Petter Selasky <hselasky@FreeBSD.org> 4 * All rights reserved. 5 * 6 * This software was developed by SRI International and the University of 7 * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 8 * ("CTSRD"), as part of the DARPA CRASH research programme. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/param.h> 33 34 #include <bootstrap.h> 35 #include <stdarg.h> 36 37 #include <stand.h> 38 #include <disk.h> 39 40 #define HAVE_STANDARD_DEFS 41 42 #include USB_GLOBAL_INCLUDE_FILE 43 44 #include "umass_common.h" 45 46 static int umass_disk_init(void); 47 static int umass_disk_open(struct open_file *,...); 48 static int umass_disk_close(struct open_file *); 49 static void umass_disk_cleanup(void); 50 static int umass_disk_ioctl(struct open_file *, u_long, void *); 51 static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); 52 static int umass_disk_print(int); 53 54 struct devsw umass_disk = { 55 .dv_name = "umass", 56 .dv_type = DEVT_DISK, 57 .dv_init = umass_disk_init, 58 .dv_strategy = umass_disk_strategy, 59 .dv_open = umass_disk_open, 60 .dv_close = umass_disk_close, 61 .dv_ioctl = umass_disk_ioctl, 62 .dv_print = umass_disk_print, 63 .dv_cleanup = umass_disk_cleanup, 64 .dv_fmtdev = disk_fmtdev, 65 .dv_parsedev = disk_parsedev, 66 }; 67 68 static int 69 umass_disk_init(void) 70 { 71 uint32_t time; 72 73 usb_init(); 74 usb_needs_explore_all(); 75 76 /* wait 8 seconds for a USB mass storage device to appear */ 77 for (time = 0; time < (8 * hz); time++) { 78 usb_idle(); 79 delay(1000000 / hz); 80 time++; 81 callout_process(1); 82 if (umass_uaa.device != NULL) 83 return (0); 84 } 85 return (0); 86 } 87 88 static int 89 umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 90 char *buf, size_t *rsizep) 91 { 92 if (umass_uaa.device == NULL) 93 return (ENXIO); 94 if (rsizep != NULL) 95 *rsizep = 0; 96 97 flag &= F_MASK; 98 if (flag == F_WRITE) { 99 if (usb_msc_write_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 100 return (EINVAL); 101 } else if (flag == F_READ) { 102 if (usb_msc_read_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 103 return (EINVAL); 104 } else { 105 return (EROFS); 106 } 107 108 if (rsizep != NULL) 109 *rsizep = size; 110 return (0); 111 } 112 113 static int 114 umass_disk_open_sub(struct disk_devdesc *dev) 115 { 116 uint32_t nblock; 117 uint32_t blocksize; 118 119 if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) 120 return (EINVAL); 121 122 return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize)); 123 } 124 125 static int 126 umass_disk_open(struct open_file *f,...) 127 { 128 va_list ap; 129 struct disk_devdesc *dev; 130 131 va_start(ap, f); 132 dev = va_arg(ap, struct disk_devdesc *); 133 va_end(ap); 134 135 if (umass_uaa.device == NULL) 136 return (ENXIO); 137 if (dev->d_unit != 0) 138 return (EIO); 139 return (umass_disk_open_sub(dev)); 140 } 141 142 static int 143 umass_disk_ioctl(struct open_file *f, u_long cmd, void *buf) 144 { 145 struct disk_devdesc *dev; 146 uint32_t nblock; 147 uint32_t blocksize; 148 int rc; 149 150 dev = (struct disk_devdesc *)(f->f_devdata); 151 if (dev == NULL) 152 return (EINVAL); 153 154 rc = disk_ioctl(dev, cmd, buf); 155 if (rc != ENOTTY) 156 return (rc); 157 158 switch (cmd) { 159 case DIOCGSECTORSIZE: 160 case DIOCGMEDIASIZE: 161 if (usb_msc_read_capacity(umass_uaa.device, 0, 162 &nblock, &blocksize) != 0) 163 return (EINVAL); 164 165 if (cmd == DIOCGMEDIASIZE) 166 *(uint64_t*)buf = nblock; 167 else 168 *(uint32_t*)buf = blocksize; 169 170 return (0); 171 default: 172 return (ENXIO); 173 } 174 } 175 176 static int 177 umass_disk_close(struct open_file *f) 178 { 179 struct disk_devdesc *dev; 180 181 dev = (struct disk_devdesc *)f->f_devdata; 182 return (disk_close(dev)); 183 } 184 185 static int 186 umass_disk_print(int verbose) 187 { 188 struct disk_devdesc dev; 189 190 printf("%s devices:", umass_disk.dv_name); 191 if (pager_output("\n") != 0) 192 return (1); 193 194 memset(&dev, 0, sizeof(dev)); 195 196 ret = pager_output(" umass0 UMASS device\n"); 197 if (ret != 0) 198 return (ret); 199 dev.d_dev = &umass_disk; 200 dev.d_unit = 0; 201 dev.d_slice = D_SLICENONE; 202 dev.d_partition = D_PARTNONE; 203 204 if (umass_disk_open_sub(&dev) == 0) { 205 ret = disk_print(&dev, " umass0", verbose); 206 disk_close(&dev); 207 } 208 return (ret); 209 } 210 211 static void 212 umass_disk_cleanup(void) 213 { 214 215 usb_uninit(); 216 } 217 218 219 /* USB specific functions */ 220 221 extern void callout_process(int); 222 extern void usb_idle(void); 223 extern void usb_init(void); 224 extern void usb_uninit(void); 225 226 void 227 DELAY(unsigned int usdelay) 228 { 229 delay(usdelay); 230 } 231 232 int 233 pause(const char *what, int timeout) 234 { 235 if (timeout == 0) 236 timeout = 1; 237 238 delay((1000000 / hz) * timeout); 239 240 return (0); 241 } 242