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