~ubuntu-branches/ubuntu/trusty/linux-linaro-omap/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): John Rigby, John Rigby
  • Date: 2011-09-26 10:44:23 UTC
  • Revision ID: package-import@ubuntu.com-20110926104423-57i0gl3v99b3lkfg
Tags: 3.0.0-1007.9
[ John Rigby ]

Enable crypto modules and remove crypto-modules from
exclude-module files
LP: #826021

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005-2007 Takahiro Hirofuchi
 
3
 */
 
4
 
 
5
#include <sys/types.h>
 
6
#include <sys/stat.h>
 
7
#include <unistd.h>
 
8
 
 
9
#include "usbip.h"
 
10
 
 
11
/* kernel module name */
 
12
static const char *usbip_stub_driver_name = "usbip-host";
 
13
 
 
14
 
 
15
struct usbip_stub_driver *stub_driver;
 
16
 
 
17
static struct sysfs_driver *open_sysfs_stub_driver(void)
 
18
{
 
19
        int ret;
 
20
 
 
21
        char sysfs_mntpath[SYSFS_PATH_MAX];
 
22
        char stub_driver_path[SYSFS_PATH_MAX];
 
23
        struct sysfs_driver *stub_driver;
 
24
 
 
25
 
 
26
        ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
 
27
        if (ret < 0) {
 
28
                err("sysfs must be mounted");
 
29
                return NULL;
 
30
        }
 
31
 
 
32
        snprintf(stub_driver_path, SYSFS_PATH_MAX, "%s/%s/usb/%s/%s",
 
33
                        sysfs_mntpath, SYSFS_BUS_NAME, SYSFS_DRIVERS_NAME,
 
34
                        usbip_stub_driver_name);
 
35
 
 
36
        stub_driver = sysfs_open_driver_path(stub_driver_path);
 
37
        if (!stub_driver) {
 
38
                err("usbip-core.ko and usbip-host.ko must be loaded");
 
39
                return NULL;
 
40
        }
 
41
 
 
42
        return stub_driver;
 
43
}
 
44
 
 
45
 
 
46
#define SYSFS_OPEN_RETRIES 100
 
47
 
 
48
/* only the first interface value is true! */
 
49
static int32_t read_attr_usbip_status(struct usb_device *udev)
 
50
{
 
51
        char attrpath[SYSFS_PATH_MAX];
 
52
        struct sysfs_attribute *attr;
 
53
        int value = 0;
 
54
        int  ret;
 
55
        struct stat s;
 
56
        int retries = SYSFS_OPEN_RETRIES;
 
57
 
 
58
        /* This access is racy!
 
59
         *
 
60
         * Just after detach, our driver removes the sysfs
 
61
         * files and recreates them.
 
62
         *
 
63
         * We may try and fail to open the usbip_status of
 
64
         * an exported device in the (short) window where
 
65
         * it has been removed and not yet recreated.
 
66
         *
 
67
         * This is a bug in the interface. Nothing we can do
 
68
         * except work around it here by polling for the sysfs
 
69
         * usbip_status to reappear.
 
70
         */
 
71
 
 
72
        snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status",
 
73
                        udev->path, udev->busid,
 
74
                        udev->bConfigurationValue,
 
75
                        0);
 
76
 
 
77
        while (retries > 0) {
 
78
                if (stat(attrpath, &s) == 0)
 
79
                        break;
 
80
 
 
81
                if (errno != ENOENT) {
 
82
                        err("error stat'ing %s", attrpath);
 
83
                        return -1;
 
84
                }
 
85
 
 
86
                usleep(10000); /* 10ms */
 
87
                retries--;
 
88
        }
 
89
 
 
90
        if (retries == 0)
 
91
                err("usbip_status not ready after %d retries",
 
92
                        SYSFS_OPEN_RETRIES);
 
93
        else if (retries < SYSFS_OPEN_RETRIES)
 
94
                info("warning: usbip_status ready after %d retries",
 
95
                         SYSFS_OPEN_RETRIES - retries);
 
96
 
 
97
        attr = sysfs_open_attribute(attrpath);
 
98
        if (!attr) {
 
99
                err("open %s", attrpath);
 
100
                return -1;
 
101
        }
 
102
 
 
103
        ret = sysfs_read_attribute(attr);
 
104
        if (ret) {
 
105
                err("read %s", attrpath);
 
106
                sysfs_close_attribute(attr);
 
107
                return -1;
 
108
        }
 
109
 
 
110
        value = atoi(attr->value);
 
111
 
 
112
        sysfs_close_attribute(attr);
 
113
 
 
114
        return value;
 
115
}
 
116
 
 
117
 
 
118
static void usbip_exported_device_delete(void *dev)
 
119
{
 
120
        struct usbip_exported_device *edev =
 
121
                (struct usbip_exported_device *) dev;
 
122
 
 
123
        sysfs_close_device(edev->sudev);
 
124
        free(dev);
 
125
}
 
126
 
 
127
 
 
128
static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
 
129
{
 
130
        struct usbip_exported_device *edev = NULL;
 
131
 
 
132
        edev = (struct usbip_exported_device *) calloc(1, sizeof(*edev));
 
133
        if (!edev) {
 
134
                err("alloc device");
 
135
                return NULL;
 
136
        }
 
137
 
 
138
        edev->sudev = sysfs_open_device_path(sdevpath);
 
139
        if (!edev->sudev) {
 
140
                err("open %s", sdevpath);
 
141
                goto err;
 
142
        }
 
143
 
 
144
        read_usb_device(edev->sudev, &edev->udev);
 
145
 
 
146
        edev->status = read_attr_usbip_status(&edev->udev);
 
147
        if (edev->status < 0)
 
148
                goto err;
 
149
 
 
150
        /* reallocate buffer to include usb interface data */
 
151
        size_t size = sizeof(*edev) + edev->udev.bNumInterfaces * sizeof(struct usb_interface);
 
152
        edev = (struct usbip_exported_device *) realloc(edev, size);
 
153
        if (!edev) {
 
154
                err("alloc device");
 
155
                goto err;
 
156
        }
 
157
 
 
158
        for (int i=0; i < edev->udev.bNumInterfaces; i++)
 
159
                read_usb_interface(&edev->udev, i, &edev->uinf[i]);
 
160
 
 
161
        return edev;
 
162
 
 
163
err:
 
164
        if (edev && edev->sudev)
 
165
                sysfs_close_device(edev->sudev);
 
166
        if (edev)
 
167
                free(edev);
 
168
        return NULL;
 
169
}
 
170
 
 
171
 
 
172
static int check_new(struct dlist *dlist, struct sysfs_device *target)
 
173
{
 
174
        struct sysfs_device *dev;
 
175
 
 
176
        dlist_for_each_data(dlist, dev, struct sysfs_device) {
 
177
                if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE))
 
178
                        /* found. not new */
 
179
                        return 0;
 
180
        }
 
181
 
 
182
        return 1;
 
183
}
 
184
 
 
185
static void delete_nothing(void *dev __attribute__((unused)))
 
186
{
 
187
        /* do not delete anything. but, its container will be deleted. */
 
188
}
 
189
 
 
190
static int refresh_exported_devices(void)
 
191
{
 
192
        struct sysfs_device     *suinf;  /* sysfs_device of usb_interface */
 
193
        struct dlist            *suinf_list;
 
194
 
 
195
        struct sysfs_device     *sudev;  /* sysfs_device of usb_device */
 
196
        struct dlist            *sudev_list;
 
197
 
 
198
 
 
199
        sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), delete_nothing);
 
200
 
 
201
        suinf_list = sysfs_get_driver_devices(stub_driver->sysfs_driver);
 
202
        if (!suinf_list) {
 
203
                printf("Bind usbip-host.ko to a usb device to be exportable!\n");
 
204
                goto bye;
 
205
        }
 
206
 
 
207
        /* collect unique USB devices (not interfaces) */
 
208
        dlist_for_each_data(suinf_list, suinf, struct sysfs_device) {
 
209
 
 
210
                /* get usb device of this usb interface */
 
211
                sudev = sysfs_get_device_parent(suinf);
 
212
                if (!sudev) {
 
213
                        err("get parent dev of %s", suinf->name);
 
214
                        continue;
 
215
                }
 
216
 
 
217
                if (check_new(sudev_list, sudev)) {
 
218
                        dlist_unshift(sudev_list, sudev);
 
219
                }
 
220
        }
 
221
 
 
222
        dlist_for_each_data(sudev_list, sudev, struct sysfs_device) {
 
223
                struct usbip_exported_device *edev;
 
224
 
 
225
                edev = usbip_exported_device_new(sudev->path);
 
226
                if (!edev) {
 
227
                        err("usbip_exported_device new");
 
228
                        continue;
 
229
                }
 
230
 
 
231
                dlist_unshift(stub_driver->edev_list, (void *) edev);
 
232
                stub_driver->ndevs++;
 
233
        }
 
234
 
 
235
 
 
236
        dlist_destroy(sudev_list);
 
237
 
 
238
bye:
 
239
 
 
240
        return 0;
 
241
}
 
242
 
 
243
int usbip_stub_refresh_device_list(void)
 
244
{
 
245
        int ret;
 
246
 
 
247
        if (stub_driver->edev_list)
 
248
                dlist_destroy(stub_driver->edev_list);
 
249
 
 
250
        stub_driver->ndevs = 0;
 
251
 
 
252
        stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device),
 
253
                        usbip_exported_device_delete);
 
254
        if (!stub_driver->edev_list) {
 
255
                err("alloc dlist");
 
256
                return -1;
 
257
        }
 
258
 
 
259
        ret = refresh_exported_devices();
 
260
        if (ret < 0)
 
261
                return ret;
 
262
 
 
263
        return 0;
 
264
}
 
265
 
 
266
int usbip_stub_driver_open(void)
 
267
{
 
268
        int ret;
 
269
 
 
270
 
 
271
        stub_driver = (struct usbip_stub_driver *) calloc(1, sizeof(*stub_driver));
 
272
        if (!stub_driver) {
 
273
                err("alloc stub_driver");
 
274
                return -1;
 
275
        }
 
276
 
 
277
        stub_driver->ndevs = 0;
 
278
 
 
279
        stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device),
 
280
                        usbip_exported_device_delete);
 
281
        if (!stub_driver->edev_list) {
 
282
                err("alloc dlist");
 
283
                goto err;
 
284
        }
 
285
 
 
286
        stub_driver->sysfs_driver = open_sysfs_stub_driver();
 
287
        if (!stub_driver->sysfs_driver)
 
288
                goto err;
 
289
 
 
290
        ret = refresh_exported_devices();
 
291
        if (ret < 0)
 
292
                goto err;
 
293
 
 
294
        return 0;
 
295
 
 
296
 
 
297
err:
 
298
        if (stub_driver->sysfs_driver)
 
299
                sysfs_close_driver(stub_driver->sysfs_driver);
 
300
        if (stub_driver->edev_list)
 
301
                dlist_destroy(stub_driver->edev_list);
 
302
        free(stub_driver);
 
303
 
 
304
        stub_driver = NULL;
 
305
        return -1;
 
306
}
 
307
 
 
308
 
 
309
void usbip_stub_driver_close(void)
 
310
{
 
311
        if (!stub_driver)
 
312
                return;
 
313
 
 
314
        if (stub_driver->edev_list)
 
315
                dlist_destroy(stub_driver->edev_list);
 
316
        if (stub_driver->sysfs_driver)
 
317
                sysfs_close_driver(stub_driver->sysfs_driver);
 
318
        free(stub_driver);
 
319
 
 
320
        stub_driver = NULL;
 
321
}
 
322
 
 
323
int usbip_stub_export_device(struct usbip_exported_device *edev, int sockfd)
 
324
{
 
325
        char attrpath[SYSFS_PATH_MAX];
 
326
        struct sysfs_attribute *attr;
 
327
        char sockfd_buff[30];
 
328
        int ret;
 
329
 
 
330
 
 
331
        if (edev->status != SDEV_ST_AVAILABLE) {
 
332
                info("device not available, %s", edev->udev.busid);
 
333
                switch( edev->status ) {
 
334
                        case SDEV_ST_ERROR:
 
335
                                info("     status SDEV_ST_ERROR");
 
336
                                break;
 
337
                        case SDEV_ST_USED:
 
338
                                info("     status SDEV_ST_USED");
 
339
                                break;
 
340
                        default:
 
341
                                info("     status unknown: 0x%x", edev->status);
 
342
                }
 
343
                return -1;
 
344
        }
 
345
 
 
346
        /* only the first interface is true */
 
347
        snprintf(attrpath, sizeof(attrpath), "%s/%s:%d.%d/%s",
 
348
                        edev->udev.path,
 
349
                        edev->udev.busid,
 
350
                        edev->udev.bConfigurationValue, 0,
 
351
                        "usbip_sockfd");
 
352
 
 
353
        attr = sysfs_open_attribute(attrpath);
 
354
        if (!attr) {
 
355
                err("open %s", attrpath);
 
356
                return -1;
 
357
        }
 
358
 
 
359
        snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
 
360
 
 
361
        dbg("write: %s", sockfd_buff);
 
362
 
 
363
        ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff));
 
364
        if (ret < 0) {
 
365
                err("write sockfd %s to %s", sockfd_buff, attrpath);
 
366
                goto err_write_sockfd;
 
367
        }
 
368
 
 
369
        info("connect %s", edev->udev.busid);
 
370
 
 
371
err_write_sockfd:
 
372
        sysfs_close_attribute(attr);
 
373
 
 
374
        return ret;
 
375
}
 
376
 
 
377
struct usbip_exported_device *usbip_stub_get_device(int num)
 
378
{
 
379
        struct usbip_exported_device *edev;
 
380
        struct dlist            *dlist = stub_driver->edev_list;
 
381
        int count = 0;
 
382
 
 
383
        dlist_for_each_data(dlist, edev, struct usbip_exported_device) {
 
384
                if (num == count)
 
385
                        return edev;
 
386
                else
 
387
                        count++ ;
 
388
        }
 
389
 
 
390
        return NULL;
 
391
}