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