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