block: fix warning with calling smp_processor_id() in preemptible section
[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 #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 }