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