1 /*-
2  * Copyright (c) 2014 Nahanni Systems Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * USB emulation designed as following diagram. It devided into three layers:
29  *   HCD: USB host controller device layer, like xHCI, eHCI...
30  *   USB core: middle abstraction layer for USB statck.
31  *   USB Port Mapper: This layer supports to share physical USB
32  *     devices(physical ports) to spcified virtual USB port of
33  *     HCD DM. All the commands and data transfers are through
34  *     Libusb to access native USB stack.
35  *
36  *              +---------------+
37  *              |               |
38  *   +----------+----------+    |
39  *   |       ACRN DM       |    |
40  *   | +-----------------+ |    |
41  *   | |   HCD (xHCI)    | |    |
42  *   | +-----------------+ |    |
43  *   |          |          |    |
44  *   | +-----------------+ |    |
45  *   | |    USB Core     | |    |
46  *   | +-----------------+ |    |
47  *   |          |          |    |
48  *   | +-----------------+ |    |
49  *   | | USB Port Mapper | |    |
50  *   | +-----------------+ |    |
51  *   |          |          |    |
52  *   | +-----------------+ |    |
53  *   | |      Libusb     | |    |
54  *   | +-----------------+ |    |
55  *   +---------------------+    |
56  *    Service OS User Space     |     User OS User Space
57  *                              |
58  *  --------------------------  |  ---------------------------
59  *                              |
60  *   Service OS Kernel Space    |    User OS Kernel Space
61  *                              |
62  *                              |    +-----------------+
63  *                              |    |     USB Core    |
64  *                              |    +-----------------+
65  *                              |             |
66  *                              |    +-----------------+
67  *                              |    |       HCD       |
68  *                              |    | (xHCI/uHCI/...) |
69  *                              |    +--------+--------+
70  *                              |             |
71  *                              +-------------+
72  * Current distribution:
73  *   HCD: xhci.{h,c}
74  *   USB core: usb_core.{h,c}
75  *   USB device: usb_mouse.c usb_pmapper.{h,c}
76  */
77 
78 #include <sys/types.h>
79 #include <stdio.h>
80 #include <string.h>
81 #include <fcntl.h>
82 #include <unistd.h>
83 #include "usb_core.h"
84 #include "dm_string.h"
85 
86 SET_DECLARE(usb_emu_set, struct usb_devemu);
87 int usb_log_level;
88 
89 struct usb_devemu *
usb_emu_finddev(char * name)90 usb_emu_finddev(char *name)
91 {
92 	struct usb_devemu **udpp, *udp;
93 
94 	SET_FOREACH(udpp, usb_emu_set) {
95 		udp = *udpp;
96 		if (!strcmp(udp->ue_emu, name))
97 			return udp;
98 	}
99 
100 	return NULL;
101 }
102 
103 struct usb_block *
usb_block_append(struct usb_xfer * xfer,void * buf,int blen,void * hcb,int hcb_len)104 usb_block_append(struct usb_xfer *xfer, void *buf, int blen, void *hcb,
105 		int hcb_len)
106 {
107 	struct usb_block *xb;
108 
109 	if (xfer->ndata >= xfer->max_blk_cnt)
110 		return NULL;
111 
112 	if (hcb == NULL)
113 		return NULL;
114 
115 	xb = &xfer->data[xfer->tail];
116 	xb->buf = buf;
117 	xb->blen = blen;
118 	memcpy(xb->hcb, hcb, hcb_len);
119 	xb->stat = USB_BLOCK_FREE;
120 	xb->bdone = 0;
121 	xb->type = USB_DATA_NONE;
122 	xfer->ndata++;
123 	xfer->tail = index_inc(xfer->tail, xfer->max_blk_cnt);
124 	return xb;
125 }
126 
127 int
usb_native_is_bus_existed(uint8_t bus_num)128 usb_native_is_bus_existed(uint8_t bus_num)
129 {
130 	char buf[128];
131 
132 	snprintf(buf, sizeof(buf), "%s/usb%d", NATIVE_USBSYS_DEVDIR, bus_num);
133 	return access(buf, R_OK) ? 0 : 1;
134 }
135 
136 int
usb_native_is_port_existed(uint8_t bus_num,uint8_t port_num)137 usb_native_is_port_existed(uint8_t bus_num, uint8_t port_num)
138 {
139 	int native_port_cnt;
140 	int rc, fd;
141 	char buf[128];
142 	char cnt[8];
143 
144 	if (!usb_native_is_bus_existed(bus_num))
145 		return 0;
146 
147 	snprintf(buf, sizeof(buf), "%s/usb%d/maxchild", NATIVE_USBSYS_DEVDIR,
148 			bus_num);
149 	if (access(buf, R_OK)) {
150 		UPRINTF(LWRN, "can't find maxchild file\r\n");
151 		return 0;
152 	}
153 
154 	fd = open(buf, O_RDONLY);
155 	if (fd < 0) {
156 		UPRINTF(LWRN, "fail to open maxchild file\r\n");
157 		return 0;
158 	}
159 
160 	rc = read(fd, &cnt, sizeof(cnt));
161 	if (rc < 0) {
162 		UPRINTF(LWRN, "fail to read maxchild file\r\n");
163 		close(fd);
164 		return 0;
165 	}
166 
167 	rc = dm_strtoi(cnt, (char **)&cnt, 10, &native_port_cnt);
168 	if (rc) {
169 		UPRINTF(LWRN, "fail to get maxchild number\r\n");
170 		close(fd);
171 		return 0;
172 	}
173 
174 	if (port_num > native_port_cnt || port_num < 0) {
175 		UPRINTF(LWRN, "invalid port_num %d, max port count %d\r\n",
176 				port_num, native_port_cnt);
177 		close(fd);
178 		return 0;
179 	}
180 	close(fd);
181 	return 1;
182 }
183 
184 int
usb_native_is_device_existed(struct usb_devpath * path)185 usb_native_is_device_existed(struct usb_devpath *path)
186 {
187 	char _path[128];
188 	int ret = 0;
189 
190 	if (path) {
191 		snprintf(_path, sizeof(_path), "%s/%s", NATIVE_USBSYS_DEVDIR,
192 				usb_dev_path(path));
193 		ret = (access(_path, F_OK) == 0);
194 	}
195 	return ret;
196 }
197 
usb_parse_log_level(char level)198 void usb_parse_log_level(char level)
199 {
200 	switch (level) {
201 	case 'F':
202 	case 'f':
203 		usb_set_log_level(LFTL);
204 		break;
205 	case 'W':
206 	case 'w':
207 		usb_set_log_level(LWRN);
208 		break;
209 	case 'I':
210 	case 'i':
211 		usb_set_log_level(LINF);
212 		break;
213 	case 'D':
214 	case 'd':
215 		usb_set_log_level(LDBG);
216 		break;
217 	case 'V':
218 	case 'v':
219 		usb_set_log_level(LVRB);
220 		break;
221 	default:
222 		usb_set_log_level(LFTL);
223 	}
224 }
225 
226 char *
usb_dev_path(struct usb_devpath * path)227 usb_dev_path(struct usb_devpath *path)
228 {
229 	static char output[sizeof("01.02.03.04.05.06.07")+1];
230 	int i, r, n;
231 
232 	if (!path)
233 		return NULL;
234 
235 	r = n = sizeof(output);
236 	r -= snprintf(output, n, "%d", path->path[0]);
237 
238 	for (i = 1; i < path->depth; i++) {
239 		r -= snprintf(output + n - r, r, ".%d", path->path[i]);
240 		if (r < 0)
241 			return NULL;
242 	}
243 
244 	return output;
245 }
246 
247 bool
usb_dev_path_cmp(struct usb_devpath * p1,struct usb_devpath * p2)248 usb_dev_path_cmp(struct usb_devpath *p1, struct usb_devpath *p2)
249 {
250 	if (!p1 || !p2)
251 		return false;
252 
253 	return (p1->bus == p2->bus && p1->depth == p2->depth &&
254 				memcmp(p1->path, p2->path, p1->depth) == 0);
255 }
256 
257 int
usb_get_hub_port_num(struct usb_devpath * path)258 usb_get_hub_port_num(struct usb_devpath *path)
259 {
260 	int rc, fd;
261 	int icnt;
262 	char buf[128];
263 	char cnt[8];
264 
265 	if (!usb_native_is_bus_existed(path->bus))
266 		return -1;
267 
268 	snprintf(buf, sizeof(buf), "%s/%d-%s/maxchild", NATIVE_USBSYS_DEVDIR,
269 			path->bus, usb_dev_path(path));
270 	if (access(buf, R_OK)) {
271 		UPRINTF(LWRN, "can't find maxchild file\r\n");
272 		return -1;
273 	}
274 
275 	fd = open(buf, O_RDONLY);
276 	if (fd < 0) {
277 		UPRINTF(LWRN, "fail to open maxchild file\r\n");
278 		return -1;
279 	}
280 
281 	rc = read(fd, &cnt, sizeof(cnt));
282 	if (rc < 0) {
283 		UPRINTF(LWRN, "fail to read maxchild file\r\n");
284 		close(fd);
285 		return -1;
286 	}
287 
288 	close(fd);
289 
290 	rc = dm_strtoi(cnt, (char **)&cnt, 10, &icnt);
291 	if (rc) {
292 		UPRINTF(LWRN, "fail to get maxchild\r\n");
293 		return -1;
294 	}
295 
296 	return icnt;
297 }
298