Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
vhci_driver.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2007 Takahiro Hirofuchi
3  */
4 
5 #include "usbip_common.h"
6 #include "vhci_driver.h"
7 
8 #undef PROGNAME
9 #define PROGNAME "libusbip"
10 
12 
13 static 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) {
19  dbg("sysfs_open_device failed: %s", busid);
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 */
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;
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));
39  dlist_unshift(idev->cdev_list, (void*) new_cdev);
40  }
41  }
42 
43  return idev;
44 
45 err:
46  return NULL;
47 }
48 
49 
50 
51 static 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++)
58  memset(&vhci_driver->idev[i], 0, sizeof(vhci_driver->idev[i]));
59 
60 
61  /* skip a header line */
62  c = strchr(value, '\n');
63  if (!c)
64  return -1;
65  c++;
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) {
77  dbg("sscanf failed: %d", ret);
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 
98  idev->cdev_list = dlist_new(sizeof(struct usbip_class_device));
99  if (!idev->cdev_list) {
100  dbg("dlist_new failed");
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) {
107  dbg("imported_device_init failed");
108  return -1;
109  }
110  }
111  }
112 
113 
114  /* go to the next line */
115  c = strchr(c, '\n');
116  if (!c)
117  break;
118  c++;
119  }
120 
121  dbg("exit");
122 
123  return 0;
124 }
125 
126 
127 static int check_usbip_device(struct sysfs_class_device *cdev)
128 {
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 */
131  int ret;
132  struct usbip_class_device *usbip_cdev;
133 
134  snprintf(class_path, sizeof(class_path), "%s/device", cdev->path);
135 
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))) {
140  /* found usbip device */
141  usbip_cdev = calloc(1, sizeof(*usbip_cdev));
142  if (!usbip_cdev) {
143  dbg("calloc failed");
144  return -1;
145  }
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));
151  dbg("found: %s %s", class_path, dev_path);
152  }
153  }
154 
155  return 0;
156 }
157 
158 
159 static 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) {
168  dbg("sysfs_open_class failed");
169  return -1;
170  }
171 
172  dbg("class: %s", class->name);
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) {
180  dbg("cdev: %s", cdev->name);
181  ret = check_usbip_device(cdev);
182  if (ret < 0)
183  goto out;
184  }
185 
186 out:
187  sysfs_close_class(class);
188 
189  return ret;
190 }
191 
192 
193 static int refresh_class_device_list(void)
194 {
195  int ret;
196  struct dlist *cname_list;
197  char *cname;
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) {
203  dbg("sysfs_get_mnt_path failed");
204  return -1;
205  }
206 
207  snprintf(class_path, sizeof(class_path), "%s/%s", sysfs_mntpath,
208  SYSFS_CLASS_NAME);
209 
210  /* search under /sys/class */
211  cname_list = sysfs_open_directory_list(class_path);
212  if (!cname_list) {
213  dbg("sysfs_open_directory failed");
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 
236 static 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) {
243  dbg("sysfs_get_device_attr(\"status\") failed: %s",
244  vhci_driver->hc_device->name);
245  return -1;
246  }
247 
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);
251 
252  return parse_status(attr_status->value);
253 }
254 
255 static int get_nports(void)
256 {
257  char *c;
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) {
263  dbg("sysfs_get_device_attr(\"status\") failed: %s",
264  vhci_driver->hc_device->name);
265  return -1;
266  }
267 
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);
271 
272  /* skip a header line */
273  c = strchr(attr_status->value, '\n');
274  if (!c)
275  return 0;
276  c++;
277 
278  while (*c != '\0') {
279  /* go to the next line */
280  c = strchr(c, '\n');
281  if (!c)
282  return nports;
283  c++;
284  nports += 1;
285  }
286 
287  return nports;
288 }
289 
290 static int get_hc_busid(char *sysfs_mntpath, char *hc_busid)
291 {
292  struct sysfs_driver *sdriver;
293  char sdriver_path[SYSFS_PATH_MAX];
294 
295  struct sysfs_device *hc_dev;
296  struct dlist *hc_devs;
297 
298  int found = 0;
299 
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,
303 
304  sdriver = sysfs_open_driver_path(sdriver_path);
305  if (!sdriver) {
306  dbg("sysfs_open_driver_path failed: %s", sdriver_path);
307  dbg("make sure " USBIP_CORE_MOD_NAME ".ko and "
308  USBIP_VHCI_DRV_NAME ".ko are loaded!");
309  return -1;
310  }
311 
312  hc_devs = sysfs_get_driver_devices(sdriver);
313  if (!hc_devs) {
314  dbg("sysfs_get_driver failed");
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 
324 err:
325  sysfs_close_driver(sdriver);
326 
327  if (found)
328  return 0;
329 
330  dbg("%s not found", hc_busid);
331  return -1;
332 }
333 
334 
335 /* ---------------------------------------------------------------------- */
336 
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) {
344  dbg("calloc failed");
345  return -1;
346  }
347 
348  ret = sysfs_get_mnt_path(vhci_driver->sysfs_mntpath, SYSFS_PATH_MAX);
349  if (ret < 0) {
350  dbg("sysfs_get_mnt_path failed");
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() */
359  vhci_driver->hc_device = sysfs_open_device(USBIP_VHCI_BUS_TYPE,
360  hc_busid);
361  if (!vhci_driver->hc_device) {
362  dbg("sysfs_open_device failed");
363  goto err;
364  }
365 
366  vhci_driver->nports = get_nports();
367 
368  dbg("available ports: %d", vhci_driver->nports);
369 
370  vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
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 
384 err:
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 
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 
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 
429  vhci_driver->cdev_list = dlist_new(sizeof(struct usbip_class_device));
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;
440 err:
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 
449  dbg("failed to refresh device list");
450  return -1;
451 }
452 
453 
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 
464 int 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) {
472  dbg("sysfs_get_device_attr(\"attach\") failed: %s",
473  vhci_driver->hc_device->name);
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) {
483  dbg("sysfs_write_attribute failed");
484  return -1;
485  }
486 
487  dbg("attached port: %d", port);
488 
489  return 0;
490 }
491 
492 static unsigned long get_devid(uint8_t busnum, uint8_t devnum)
493 {
494  return (busnum << 16) | devnum;
495 }
496 
497 /* will be removed */
498 int 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 
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) {
514  dbg("sysfs_get_device_attr(\"detach\") failed: %s",
515  vhci_driver->hc_device->name);
516  return -1;
517  }
518 
519  snprintf(buff, sizeof(buff), "%u", port);
520  dbg("writing: %s", buff);
521 
522  ret = sysfs_write_attribute(attr_detach, buff, strlen(buff));
523  if (ret < 0) {
524  dbg("sysfs_write_attribute failed");
525  return -1;
526  }
527 
528  dbg("detached port: %d", port);
529 
530  return 0;
531 }