1/* $FreeBSD: stable/11/stand/usb/storage/umass_loader.c 329100 2018-02-10 04:56:07Z kevans $ */
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
46static int umass_disk_init(void);
47static int umass_disk_open(struct open_file *,...);
48static int umass_disk_close(struct open_file *);
49static void umass_disk_cleanup(void);
50static int umass_disk_ioctl(struct open_file *, u_long, void *);
51static int umass_disk_strategy(void *, int, daddr_t, size_t, char *, size_t *);
52static int umass_disk_print(int);
53
54struct 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
66static int
67umass_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
86static int
87umass_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
111static int
112umass_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
123static int
124umass_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
140static int
141umass_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
174static int
175umass_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
183static int
184umass_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 = -1;
200	dev.d_partition = -1;
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
209static void
210umass_disk_cleanup(void)
211{
212
213	usb_uninit();
214}
215
216
217/* USB specific functions */
218
219extern void callout_process(int);
220extern void usb_idle(void);
221extern void usb_init(void);
222extern void usb_uninit(void);
223
224void
225DELAY(unsigned int usdelay)
226{
227	delay(usdelay);
228}
229
230int
231pause(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