~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/usbip/userspace/libsrc/vhci_driver.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 (!usbip_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
}