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