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 }; 65 66 static int 67 umass_disk_init(void) 68 { 69 uint32_t time; 70 71 usb_init(); 72 usb_needs_explore_all(); 73 74 /* wait 8 seconds for a USB mass storage device to appear */ 75 for (time = 0; time < (8 * hz); time++) { 76 usb_idle(); 77 delay(1000000 / hz); 78 time++; 79 callout_process(1); 80 if (umass_uaa.device != NULL) 81 return (0); 82 } 83 return (0); 84 } 85 86 static int 87 umass_disk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, 88 char *buf, size_t *rsizep) 89 { 90 if (umass_uaa.device == NULL) 91 return (ENXIO); 92 if (rsizep != NULL) 93 *rsizep = 0; 94 95 flag &= F_MASK; 96 if (flag == F_WRITE) { 97 if (usb_msc_write_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 98 return (EINVAL); 99 } else if (flag == F_READ) { 100 if (usb_msc_read_10(umass_uaa.device, 0, dblk, size >> 9, buf) != 0) 101 return (EINVAL); 102 } else { 103 return (EROFS); 104 } 105 106 if (rsizep != NULL) 107 *rsizep = size; 108 return (0); 109 } 110 111 static int 112 umass_disk_open_sub(struct disk_devdesc *dev) 113 { 114 uint32_t nblock; 115 uint32_t blocksize; 116 117 if (usb_msc_read_capacity(umass_uaa.device, 0, &nblock, &blocksize) != 0) 118 return (EINVAL); 119 120 return (disk_open(dev, ((uint64_t)nblock + 1) * (uint64_t)blocksize, blocksize)); 121 } 122 123 static int 124 umass_disk_open(struct open_file *f,...) 125 { 126 va_list ap; 127 struct disk_devdesc *dev; 128 129 va_start(ap, f); 130 dev = va_arg(ap, struct disk_devdesc *); 131 va_end(ap); 132 133 if (umass_uaa.device == NULL) 134 return (ENXIO); 135 if (dev->d_unit != 0) 136 return (EIO); 137 return (umass_disk_open_sub(dev)); 138 } 139 140 static int 141 umass_disk_ioctl(struct open_file *f, u_long cmd, void *buf) 142 { 143 struct disk_devdesc *dev; 144 uint32_t nblock; 145 uint32_t blocksize; 146 int rc; 147 148 dev = (struct disk_devdesc *)(f->f_devdata); 149 if (dev == NULL) 150 return (EINVAL); 151 152 rc = disk_ioctl(dev, cmd, buf); 153 if (rc != ENOTTY) 154 return (rc); 155 156 switch (cmd) { 157 case DIOCGSECTORSIZE: 158 case DIOCGMEDIASIZE: 159 if (usb_msc_read_capacity(umass_uaa.device, 0, 160 &nblock, &blocksize) != 0) 161 return (EINVAL); 162 163 if (cmd == DIOCGMEDIASIZE) 164 *(uint64_t*)buf = nblock; 165 else 166 *(uint32_t*)buf = blocksize; 167 168 return (0); 169 default: 170 return (ENXIO); 171 } 172 } 173 174 static int 175 umass_disk_close(struct open_file *f) 176 { 177 struct disk_devdesc *dev; 178 179 dev = (struct disk_devdesc *)f->f_devdata; 180 return (disk_close(dev)); 181 } 182 183 static int 184 umass_disk_print(int verbose) 185 { 186 struct disk_devdesc dev; 187 188 printf("%s devices:", umass_disk.dv_name); 189 if (pager_output("\n") != 0) 190 return (1); 191 192 memset(&dev, 0, sizeof(dev)); 193 194 ret = pager_output(" umass0 UMASS device\n"); 195 if (ret != 0) 196 return (ret); 197 dev.d_dev = &umass_disk; 198 dev.d_unit = 0; 199 dev.d_slice = D_SLICENONE; 200 dev.d_partition = D_PARTNONE; 201 202 if (umass_disk_open_sub(&dev) == 0) { 203 ret = disk_print(&dev, " umass0", verbose); 204 disk_close(&dev); 205 } 206 return (ret); 207 } 208 209 static void 210 umass_disk_cleanup(void) 211 { 212 213 usb_uninit(); 214 } 215 216 217 /* USB specific functions */ 218 219 extern void callout_process(int); 220 extern void usb_idle(void); 221 extern void usb_init(void); 222 extern void usb_uninit(void); 223 224 void 225 DELAY(unsigned int usdelay) 226 { 227 delay(usdelay); 228 } 229 230 int 231 pause(const char *what, int timeout) 232 { 233 if (timeout == 0) 234 timeout = 1; 235 236 delay((1000000 / hz) * timeout); 237 238 return (0); 239 } 240