9296f9626bcb2c5b882b07bfa19e9c44fc659f50
[deliverable/linux.git] / drivers / staging / usbip / userspace / libsrc / vhci_driver.c
1 /*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
4
5
6 #include "usbip.h"
7
8 struct usbip_vhci_driver *vhci_driver;
9
10 static struct usbip_imported_device *imported_device_init(struct usbip_imported_device *idev, char *busid)
11 {
12 struct sysfs_device *sudev;
13
14 sudev = sysfs_open_device("usb", busid);
15 if (!sudev) {
16 err("sysfs_open_device %s", busid);
17 goto err;
18 }
19 read_usb_device(sudev, &idev->udev);
20 sysfs_close_device(sudev);
21
22 /* add class devices of this imported device */
23 struct usbip_class_device *cdev;
24 dlist_for_each_data(vhci_driver->cdev_list, cdev,
25 struct usbip_class_device) {
26 if (!strncmp(cdev->dev_path, idev->udev.path,
27 strlen(idev->udev.path))) {
28 struct usbip_class_device *new_cdev;
29
30 /* alloc and copy because dlist is linked from only one list */
31 new_cdev = calloc(1, sizeof(*new_cdev));
32 if (!new_cdev)
33 goto err;
34
35 memcpy(new_cdev, cdev, sizeof(*new_cdev));
36 dlist_unshift(idev->cdev_list, (void*) new_cdev);
37 }
38 }
39
40 return idev;
41
42 err:
43 return NULL;
44 }
45
46
47
48 static int parse_status(char *value)
49 {
50 int ret = 0;
51 char *c;
52
53
54 for (int i = 0; i < vhci_driver->nports; i++)
55 bzero(&vhci_driver->idev[i], sizeof(struct usbip_imported_device));
56
57
58 /* skip a header line */
59 c = strchr(value, '\n') + 1;
60
61 while (*c != '\0') {
62 int port, status, speed, devid;
63 unsigned long socket;
64 char lbusid[SYSFS_BUS_ID_SIZE];
65
66 ret = sscanf(c, "%d %d %d %x %lx %s\n",
67 &port, &status, &speed,
68 &devid, &socket, lbusid);
69
70 if (ret < 5) {
71 err("scanf %d", ret);
72 BUG();
73 }
74
75 dbg("port %d status %d speed %d devid %x",
76 port, status, speed, devid);
77 dbg("socket %lx lbusid %s", socket, lbusid);
78
79
80 /* if a device is connected, look at it */
81 {
82 struct usbip_imported_device *idev = &vhci_driver->idev[port];
83
84 idev->port = port;
85 idev->status = status;
86
87 idev->devid = devid;
88
89 idev->busnum = (devid >> 16);
90 idev->devnum = (devid & 0x0000ffff);
91
92 idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
93 if (!idev->cdev_list) {
94 err("init new device");
95 return -1;
96 }
97
98 if (idev->status != VDEV_ST_NULL && idev->status != VDEV_ST_NOTASSIGNED) {
99 idev = imported_device_init(idev, lbusid);
100 if (!idev) {
101 err("init new device");
102 return -1;
103 }
104 }
105 }
106
107
108 /* go to the next line */
109 c = strchr(c, '\n') + 1;
110 }
111
112 dbg("exit");
113
114 return 0;
115 }
116
117
118 static int check_usbip_device(struct sysfs_class_device *cdev)
119 {
120 char class_path[SYSFS_PATH_MAX]; /* /sys/class/video4linux/video0/device */
121 char dev_path[SYSFS_PATH_MAX]; /* /sys/devices/platform/vhci_hcd/usb6/6-1:1.1 */
122 int ret;
123 struct usbip_class_device *usbip_cdev;
124
125 snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
126
127 ret = sysfs_get_link(class_path, dev_path, sizeof(dev_path));
128 if (ret == 0) {
129 if (!strncmp(dev_path, vhci_driver->hc_device->path,
130 strlen(vhci_driver->hc_device->path))) {
131 /* found usbip device */
132 usbip_cdev = calloc(1, sizeof(*usbip_cdev));
133 if (!cdev) {
134 err("calloc usbip_cdev");
135 return -1;
136 }
137 dlist_unshift(vhci_driver->cdev_list, usbip_cdev);
138 strncpy(usbip_cdev->class_path, class_path,
139 sizeof(usbip_cdev->class_path));
140 strncpy(usbip_cdev->dev_path, dev_path,
141 sizeof(usbip_cdev->dev_path));
142 dbg(" found %s %s", class_path, dev_path);
143 }
144 }
145
146 return 0;
147 }
148
149
150 static int search_class_for_usbip_device(char *cname)
151 {
152 struct sysfs_class *class;
153 struct dlist *cdev_list;
154 struct sysfs_class_device *cdev;
155 int ret = 0;
156
157 class = sysfs_open_class(cname);
158 if (!class) {
159 err("open class");
160 return -1;
161 }
162
163 dbg("class %s", class->name);
164
165 cdev_list = sysfs_get_class_devices(class);
166 if (!cdev_list)
167 /* nothing */
168 goto out;
169
170 dlist_for_each_data(cdev_list, cdev, struct sysfs_class_device) {
171 dbg(" cdev %s", cdev->name);
172 ret = check_usbip_device(cdev);
173 if (ret < 0)
174 goto out;
175 }
176
177 out:
178 sysfs_close_class(class);
179
180 return ret;
181 }
182
183
184 static int refresh_class_device_list(void)
185 {
186 int ret;
187 struct dlist *cname_list;
188 char *cname;
189
190 /* search under /sys/class */
191 cname_list = sysfs_open_directory_list("/sys/class");
192 if (!cname_list) {
193 err("open class directory");
194 return -1;
195 }
196
197 dlist_for_each_data(cname_list, cname, char) {
198 ret = search_class_for_usbip_device(cname);
199 if (ret < 0) {
200 sysfs_close_list(cname_list);
201 return -1;
202 }
203 }
204
205 sysfs_close_list(cname_list);
206
207 /* seach under /sys/block */
208 ret = search_class_for_usbip_device(SYSFS_BLOCK_NAME);
209 if (ret < 0)
210 return -1;
211
212 return 0;
213 }
214
215
216 static int refresh_imported_device_list(void)
217 {
218 struct sysfs_attribute *attr_status;
219
220
221 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
222 if (!attr_status) {
223 err("get attr %s of %s", "status", vhci_driver->hc_device->name);
224 return -1;
225 }
226
227 dbg("name %s, path %s, len %d, method %d\n", attr_status->name,
228 attr_status->path, attr_status->len, attr_status->method);
229
230 dbg("%s", attr_status->value);
231
232 return parse_status(attr_status->value);
233 }
234
235 static int get_nports(void)
236 {
237 int nports = 0;
238 struct sysfs_attribute *attr_status;
239
240 attr_status = sysfs_get_device_attr(vhci_driver->hc_device, "status");
241 if (!attr_status) {
242 err("get attr %s of %s", "status", vhci_driver->hc_device->name);
243 return -1;
244 }
245
246 dbg("name %s, path %s, len %d, method %d\n", attr_status->name,
247 attr_status->path, attr_status->len, attr_status->method);
248
249 dbg("%s", attr_status->value);
250
251 {
252 char *c;
253
254 /* skip a header line */
255 c = strchr(attr_status->value, '\n') + 1;
256
257 while (*c != '\0') {
258 /* go to the next line */
259 c = strchr(c, '\n') + 1;
260 nports += 1;
261 }
262 }
263
264 return nports;
265 }
266
267 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
268 {
269 struct sysfs_driver *sdriver;
270 char sdriver_path[SYSFS_PATH_MAX];
271
272 struct sysfs_device *hc_dev;
273 struct dlist *hc_devs;
274
275 int found = 0;
276
277 snprintf(sdriver_path, SYSFS_PATH_MAX, "%s/%s/platform/%s/%s",
278 sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME,
279 USBIP_VHCI_DRV_NAME);
280
281 sdriver = sysfs_open_driver_path(sdriver_path);
282 if (!sdriver) {
283 info("%s is not found", sdriver_path);
284 info("please load " USBIP_CORE_MOD_NAME ".ko and "
285 USBIP_VHCI_DRV_NAME ".ko!");
286 return -1;
287 }
288
289 hc_devs = sysfs_get_driver_devices(sdriver);
290 if (!hc_devs) {
291 err("get hc list");
292 goto err;
293 }
294
295 /* assume only one vhci_hcd */
296 dlist_for_each_data(hc_devs, hc_dev, struct sysfs_device) {
297 strncpy(hc_busid, hc_dev->bus_id, SYSFS_BUS_ID_SIZE);
298 found = 1;
299 }
300
301 err:
302 sysfs_close_driver(sdriver);
303
304 if (found)
305 return 0;
306
307 err("not found usbip hc");
308 return -1;
309 }
310
311
312 /* ---------------------------------------------------------------------- */
313
314 int usbip_vhci_driver_open(void)
315 {
316 int ret;
317 char hc_busid[SYSFS_BUS_ID_SIZE];
318
319 vhci_driver = (struct usbip_vhci_driver *) calloc(1, sizeof(*vhci_driver));
320 if (!vhci_driver) {
321 err("alloc vhci_driver");
322 return -1;
323 }
324
325 ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
326 if (ret < 0) {
327 err("sysfs must be mounted");
328 goto err;
329 }
330
331 ret = get_hc_busid(vhci_driver->sysfs_mntpath, hc_busid);
332 if (ret < 0)
333 goto err;
334
335 /* will be freed in usbip_driver_close() */
336 vhci_driver->hc_device = sysfs_open_device("platform", hc_busid);
337 if (!vhci_driver->hc_device) {
338 err("get sysfs vhci_driver");
339 goto err;
340 }
341
342 vhci_driver->nports = get_nports();
343
344 info("%d ports available\n", vhci_driver->nports);
345
346 vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
347 if (!vhci_driver->cdev_list)
348 goto err;
349
350 if (refresh_class_device_list())
351 goto err;
352
353 if (refresh_imported_device_list())
354 goto err;
355
356
357 return 0;
358
359
360 err:
361 if (vhci_driver->cdev_list)
362 dlist_destroy(vhci_driver->cdev_list);
363 if (vhci_driver->hc_device)
364 sysfs_close_device(vhci_driver->hc_device);
365 if (vhci_driver)
366 free(vhci_driver);
367
368 vhci_driver = NULL;
369 return -1;
370 }
371
372
373 void usbip_vhci_driver_close()
374 {
375 if (!vhci_driver)
376 return;
377
378 if (vhci_driver->cdev_list)
379 dlist_destroy(vhci_driver->cdev_list);
380
381 for (int i = 0; i < vhci_driver->nports; i++) {
382 if (vhci_driver->idev[i].cdev_list)
383 dlist_destroy(vhci_driver->idev[i].cdev_list);
384 }
385
386 if (vhci_driver->hc_device)
387 sysfs_close_device(vhci_driver->hc_device);
388 free(vhci_driver);
389
390 vhci_driver = NULL;
391 }
392
393
394 int usbip_vhci_refresh_device_list(void)
395 {
396 if (vhci_driver->cdev_list)
397 dlist_destroy(vhci_driver->cdev_list);
398
399
400 for (int i = 0; i < vhci_driver->nports; i++) {
401 if (vhci_driver->idev[i].cdev_list)
402 dlist_destroy(vhci_driver->idev[i].cdev_list);
403 }
404
405 vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
406 if (!vhci_driver->cdev_list)
407 goto err;
408
409 if (refresh_class_device_list())
410 goto err;
411
412 if (refresh_imported_device_list())
413 goto err;
414
415 return 0;
416 err:
417 if (vhci_driver->cdev_list)
418 dlist_destroy(vhci_driver->cdev_list);
419
420 for (int i = 0; i < vhci_driver->nports; i++) {
421 if (vhci_driver->idev[i].cdev_list)
422 dlist_destroy(vhci_driver->idev[i].cdev_list);
423 }
424
425 err("refresh device list");
426 return -1;
427 }
428
429
430 int usbip_vhci_get_free_port(void)
431 {
432 for (int i = 0; i < vhci_driver->nports; i++) {
433 if (vhci_driver->idev[i].status == VDEV_ST_NULL)
434 return i;
435 }
436
437 return -1;
438 }
439
440 int usbip_vhci_attach_device2(uint8_t port, int sockfd, uint32_t devid,
441 uint32_t speed) {
442 struct sysfs_attribute *attr_attach;
443 char buff[200]; /* what size should be ? */
444 int ret;
445
446 attr_attach = sysfs_get_device_attr(vhci_driver->hc_device, "attach");
447 if (!attr_attach) {
448 err("get attach");
449 return -1;
450 }
451
452 snprintf(buff, sizeof(buff), "%u %u %u %u",
453 port, sockfd, devid, speed);
454 dbg("writing: %s", buff);
455
456 ret = sysfs_write_attribute(attr_attach, buff, strlen(buff));
457 if (ret < 0) {
458 err("write to attach failed");
459 return -1;
460 }
461
462 info("port %d attached", port);
463
464 return 0;
465 }
466
467 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
468 {
469 return (busnum << 16) | devnum;
470 }
471
472 /* will be removed */
473 int usbip_vhci_attach_device(uint8_t port, int sockfd, uint8_t busnum,
474 uint8_t devnum, uint32_t speed)
475 {
476 int devid = get_devid(busnum, devnum);
477
478 return usbip_vhci_attach_device2(port, sockfd, devid, speed);
479 }
480
481 int usbip_vhci_detach_device(uint8_t port)
482 {
483 struct sysfs_attribute *attr_detach;
484 char buff[200]; /* what size should be ? */
485 int ret;
486
487 attr_detach = sysfs_get_device_attr(vhci_driver->hc_device, "detach");
488 if (!attr_detach) {
489 err("get detach");
490 return -1;
491 }
492
493 snprintf(buff, sizeof(buff), "%u", port);
494 dbg("writing to detach");
495 dbg("writing: %s", buff);
496
497 ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
498 if (ret < 0) {
499 err("write to detach failed");
500 return -1;
501 }
502
503 info("port %d detached", port);
504
505 return 0;
506 }
This page took 0.040895 seconds and 4 git commands to generate.