staging: usbip: userspace: usbip list: move output header
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / usbip / userspace / libsrc / stub_driver.c
blob604aed1de37b176a4e7825cb74f95ff18562ef9b
1 /*
2 * Copyright (C) 2005-2007 Takahiro Hirofuchi
3 */
5 #include <sys/types.h>
6 #include <sys/stat.h>
8 #include <errno.h>
9 #include <unistd.h>
11 #include "usbip_common.h"
12 #include "stub_driver.h"
14 #undef PROGNAME
15 #define PROGNAME "libusbip"
17 struct usbip_stub_driver *stub_driver;
19 static struct sysfs_driver *open_sysfs_stub_driver(void)
21 int ret;
23 char sysfs_mntpath[SYSFS_PATH_MAX];
24 char stub_driver_path[SYSFS_PATH_MAX];
25 struct sysfs_driver *stub_driver;
28 ret = sysfs_get_mnt_path(sysfs_mntpath, SYSFS_PATH_MAX);
29 if (ret < 0) {
30 dbg("sysfs_get_mnt_path failed");
31 return NULL;
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);
38 stub_driver = sysfs_open_driver_path(stub_driver_path);
39 if (!stub_driver) {
40 dbg("sysfs_open_driver_path failed");
41 return NULL;
44 return stub_driver;
48 #define SYSFS_OPEN_RETRIES 100
50 /* only the first interface value is true! */
51 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
53 char attrpath[SYSFS_PATH_MAX];
54 struct sysfs_attribute *attr;
55 int value = 0;
56 int ret;
57 struct stat s;
58 int retries = SYSFS_OPEN_RETRIES;
60 /* This access is racy!
62 * Just after detach, our driver removes the sysfs
63 * files and recreates them.
65 * We may try and fail to open the usbip_status of
66 * an exported device in the (short) window where
67 * it has been removed and not yet recreated.
69 * This is a bug in the interface. Nothing we can do
70 * except work around it here by polling for the sysfs
71 * usbip_status to reappear.
74 snprintf(attrpath, SYSFS_PATH_MAX, "%s/%s:%d.%d/usbip_status",
75 udev->path, udev->busid,
76 udev->bConfigurationValue,
77 0);
79 while (retries > 0) {
80 if (stat(attrpath, &s) == 0)
81 break;
83 if (errno != ENOENT) {
84 dbg("stat failed: %s", attrpath);
85 return -1;
88 usleep(10000); /* 10ms */
89 retries--;
92 if (retries == 0)
93 dbg("usbip_status not ready after %d retries",
94 SYSFS_OPEN_RETRIES);
95 else if (retries < SYSFS_OPEN_RETRIES)
96 dbg("warning: usbip_status ready after %d retries",
97 SYSFS_OPEN_RETRIES - retries);
99 attr = sysfs_open_attribute(attrpath);
100 if (!attr) {
101 dbg("sysfs_open_attribute failed: %s", attrpath);
102 return -1;
105 ret = sysfs_read_attribute(attr);
106 if (ret) {
107 dbg("sysfs_read_attribute failed: %s", attrpath);
108 sysfs_close_attribute(attr);
109 return -1;
112 value = atoi(attr->value);
114 sysfs_close_attribute(attr);
116 return value;
120 static void usbip_exported_device_delete(void *dev)
122 struct usbip_exported_device *edev =
123 (struct usbip_exported_device *) dev;
125 sysfs_close_device(edev->sudev);
126 free(dev);
130 static struct usbip_exported_device *usbip_exported_device_new(char *sdevpath)
132 struct usbip_exported_device *edev = NULL;
134 edev = (struct usbip_exported_device *) calloc(1, sizeof(*edev));
135 if (!edev) {
136 dbg("calloc failed");
137 return NULL;
140 edev->sudev = sysfs_open_device_path(sdevpath);
141 if (!edev->sudev) {
142 dbg("sysfs_open_device_path failed: %s", sdevpath);
143 goto err;
146 read_usb_device(edev->sudev, &edev->udev);
148 edev->status = read_attr_usbip_status(&edev->udev);
149 if (edev->status < 0)
150 goto err;
152 /* reallocate buffer to include usb interface data */
153 size_t size = sizeof(*edev) + edev->udev.bNumInterfaces *
154 sizeof(struct usbip_usb_interface);
155 edev = (struct usbip_exported_device *) realloc(edev, size);
156 if (!edev) {
157 dbg("realloc failed");
158 goto err;
161 for (int i=0; i < edev->udev.bNumInterfaces; i++)
162 read_usb_interface(&edev->udev, i, &edev->uinf[i]);
164 return edev;
166 err:
167 if (edev && edev->sudev)
168 sysfs_close_device(edev->sudev);
169 if (edev)
170 free(edev);
171 return NULL;
175 static int check_new(struct dlist *dlist, struct sysfs_device *target)
177 struct sysfs_device *dev;
179 dlist_for_each_data(dlist, dev, struct sysfs_device) {
180 if (!strncmp(dev->bus_id, target->bus_id, SYSFS_BUS_ID_SIZE))
181 /* found. not new */
182 return 0;
185 return 1;
188 static void delete_nothing(void *dev __attribute__((unused)))
190 /* do not delete anything. but, its container will be deleted. */
193 static int refresh_exported_devices(void)
195 struct sysfs_device *suinf; /* sysfs_device of usb_interface */
196 struct dlist *suinf_list;
198 struct sysfs_device *sudev; /* sysfs_device of usb_device */
199 struct dlist *sudev_list;
202 sudev_list = dlist_new_with_delete(sizeof(struct sysfs_device), delete_nothing);
204 suinf_list = sysfs_get_driver_devices(stub_driver->sysfs_driver);
205 if (!suinf_list) {
206 dbg("bind " USBIP_HOST_DRV_NAME ".ko to a usb device to be "
207 "exportable!\n");
208 goto bye;
211 /* collect unique USB devices (not interfaces) */
212 dlist_for_each_data(suinf_list, suinf, struct sysfs_device) {
214 /* get usb device of this usb interface */
215 sudev = sysfs_get_device_parent(suinf);
216 if (!sudev) {
217 dbg("sysfs_get_device_parent failed: %s", suinf->name);
218 continue;
221 if (check_new(sudev_list, sudev)) {
222 dlist_unshift(sudev_list, sudev);
226 dlist_for_each_data(sudev_list, sudev, struct sysfs_device) {
227 struct usbip_exported_device *edev;
229 edev = usbip_exported_device_new(sudev->path);
230 if (!edev) {
231 dbg("usbip_exported_device_new failed");
232 continue;
235 dlist_unshift(stub_driver->edev_list, (void *) edev);
236 stub_driver->ndevs++;
240 dlist_destroy(sudev_list);
242 bye:
244 return 0;
247 int usbip_stub_refresh_device_list(void)
249 int ret;
251 if (stub_driver->edev_list)
252 dlist_destroy(stub_driver->edev_list);
254 stub_driver->ndevs = 0;
256 stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device),
257 usbip_exported_device_delete);
258 if (!stub_driver->edev_list) {
259 dbg("dlist_new_with_delete failed");
260 return -1;
263 ret = refresh_exported_devices();
264 if (ret < 0)
265 return ret;
267 return 0;
270 int usbip_stub_driver_open(void)
272 int ret;
275 stub_driver = (struct usbip_stub_driver *) calloc(1, sizeof(*stub_driver));
276 if (!stub_driver) {
277 dbg("calloc failed");
278 return -1;
281 stub_driver->ndevs = 0;
283 stub_driver->edev_list = dlist_new_with_delete(sizeof(struct usbip_exported_device),
284 usbip_exported_device_delete);
285 if (!stub_driver->edev_list) {
286 dbg("dlist_new_with_delete failed");
287 goto err;
290 stub_driver->sysfs_driver = open_sysfs_stub_driver();
291 if (!stub_driver->sysfs_driver)
292 goto err;
294 ret = refresh_exported_devices();
295 if (ret < 0)
296 goto err;
298 return 0;
301 err:
302 if (stub_driver->sysfs_driver)
303 sysfs_close_driver(stub_driver->sysfs_driver);
304 if (stub_driver->edev_list)
305 dlist_destroy(stub_driver->edev_list);
306 free(stub_driver);
308 stub_driver = NULL;
309 return -1;
313 void usbip_stub_driver_close(void)
315 if (!stub_driver)
316 return;
318 if (stub_driver->edev_list)
319 dlist_destroy(stub_driver->edev_list);
320 if (stub_driver->sysfs_driver)
321 sysfs_close_driver(stub_driver->sysfs_driver);
322 free(stub_driver);
324 stub_driver = NULL;
327 int usbip_stub_export_device(struct usbip_exported_device *edev, int sockfd)
329 char attrpath[SYSFS_PATH_MAX];
330 struct sysfs_attribute *attr;
331 char sockfd_buff[30];
332 int ret;
335 if (edev->status != SDEV_ST_AVAILABLE) {
336 dbg("device not available: %s", edev->udev.busid);
337 switch( edev->status ) {
338 case SDEV_ST_ERROR:
339 dbg("status SDEV_ST_ERROR");
340 break;
341 case SDEV_ST_USED:
342 dbg("status SDEV_ST_USED");
343 break;
344 default:
345 dbg("status unknown: 0x%x", edev->status);
347 return -1;
350 /* only the first interface is true */
351 snprintf(attrpath, sizeof(attrpath), "%s/%s:%d.%d/%s",
352 edev->udev.path,
353 edev->udev.busid,
354 edev->udev.bConfigurationValue, 0,
355 "usbip_sockfd");
357 attr = sysfs_open_attribute(attrpath);
358 if (!attr) {
359 dbg("sysfs_open_attribute failed: %s", attrpath);
360 return -1;
363 snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
365 dbg("write: %s", sockfd_buff);
366 ret = sysfs_write_attribute(attr, sockfd_buff, strlen(sockfd_buff));
367 if (ret < 0) {
368 dbg("sysfs_write_attribute failed: sockfd %s to %s",
369 sockfd_buff, attrpath);
370 goto err_write_sockfd;
373 dbg("connect: %s", edev->udev.busid);
375 err_write_sockfd:
376 sysfs_close_attribute(attr);
378 return ret;
381 struct usbip_exported_device *usbip_stub_get_device(int num)
383 struct usbip_exported_device *edev;
384 struct dlist *dlist = stub_driver->edev_list;
385 int count = 0;
387 dlist_for_each_data(dlist, edev, struct usbip_exported_device) {
388 if (num == count)
389 return edev;
390 else
391 count++ ;
394 return NULL;