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 45static int umass_disk_init(void); 46static int umass_disk_open(struct open_file *,...); 47static int umass_disk_close(struct open_file *); 48static void umass_disk_cleanup(void); 49static int umass_disk_ioctl(struct open_file *, u_long, void *); 50static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *); 51static int umass_disk_print(int); 52 53struct 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 67static int 68umass_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 87static int 88umass_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 112static int 113umass_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 124static int 125umass_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 141static int 142umass_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 175static int 176umass_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 184static int 185umass_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 210static void 211umass_disk_cleanup(void) 212{ 213 214 usb_uninit(); 215} 216 217 218/* USB specific functions */ 219 220extern void callout_process(int); 221extern void usb_idle(void); 222extern void usb_init(void); 223extern void usb_uninit(void); 224 225void 226DELAY(unsigned int usdelay) 227{ 228 delay(usdelay); 229} 230 231int 232pause(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