Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[cascardo/linux.git] / tools / usb / usbip / libsrc / usbip_host_common.c
1 /*
2  * Copyright (C) 2015-2016 Samsung Electronics
3  *               Igor Kotrasinski <i.kotrasinsk@samsung.com>
4  *               Krzysztof Opasiak <k.opasiak@samsung.com>
5  *
6  * Refactored from usbip_host_driver.c, which is:
7  * Copyright (C) 2011 matt mooney <mfm@muteddisk.com>
8  *               2005-2007 Takahiro Hirofuchi
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27
28 #include <errno.h>
29 #include <unistd.h>
30
31 #include <libudev.h>
32
33 #include "usbip_common.h"
34 #include "usbip_host_common.h"
35 #include "list.h"
36 #include "sysfs_utils.h"
37
38 struct udev *udev_context;
39
40 static int32_t read_attr_usbip_status(struct usbip_usb_device *udev)
41 {
42         char status_attr_path[SYSFS_PATH_MAX];
43         int fd;
44         int length;
45         char status;
46         int value = 0;
47
48         snprintf(status_attr_path, SYSFS_PATH_MAX, "%s/usbip_status",
49                  udev->path);
50
51         fd = open(status_attr_path, O_RDONLY);
52         if (fd < 0) {
53                 err("error opening attribute %s", status_attr_path);
54                 return -1;
55         }
56
57         length = read(fd, &status, 1);
58         if (length < 0) {
59                 err("error reading attribute %s", status_attr_path);
60                 close(fd);
61                 return -1;
62         }
63
64         value = atoi(&status);
65
66         return value;
67 }
68
69 static
70 struct usbip_exported_device *usbip_exported_device_new(
71                 struct usbip_host_driver *hdriver, const char *sdevpath)
72 {
73         struct usbip_exported_device *edev = NULL;
74         struct usbip_exported_device *edev_old;
75         size_t size;
76         int i;
77
78         edev = calloc(1, sizeof(struct usbip_exported_device));
79
80         edev->sudev =
81                 udev_device_new_from_syspath(udev_context, sdevpath);
82         if (!edev->sudev) {
83                 err("udev_device_new_from_syspath: %s", sdevpath);
84                 goto err;
85         }
86
87         if (hdriver->ops.read_device(edev->sudev, &edev->udev) < 0)
88                 goto err;
89
90         edev->status = read_attr_usbip_status(&edev->udev);
91         if (edev->status < 0)
92                 goto err;
93
94         /* reallocate buffer to include usb interface data */
95         size = sizeof(struct usbip_exported_device) +
96                 edev->udev.bNumInterfaces * sizeof(struct usbip_usb_interface);
97
98         edev_old = edev;
99         edev = realloc(edev, size);
100         if (!edev) {
101                 edev = edev_old;
102                 dbg("realloc failed");
103                 goto err;
104         }
105
106         for (i = 0; i < edev->udev.bNumInterfaces; i++) {
107                 /* vudc does not support reading interfaces */
108                 if (!hdriver->ops.read_interface)
109                         break;
110                 hdriver->ops.read_interface(&edev->udev, i, &edev->uinf[i]);
111         }
112
113         return edev;
114 err:
115         if (edev->sudev)
116                 udev_device_unref(edev->sudev);
117         if (edev)
118                 free(edev);
119
120         return NULL;
121 }
122
123 static int refresh_exported_devices(struct usbip_host_driver *hdriver)
124 {
125         struct usbip_exported_device *edev;
126         struct udev_enumerate *enumerate;
127         struct udev_list_entry *devices, *dev_list_entry;
128         struct udev_device *dev;
129         const char *path;
130
131         enumerate = udev_enumerate_new(udev_context);
132         udev_enumerate_add_match_subsystem(enumerate, hdriver->udev_subsystem);
133         udev_enumerate_scan_devices(enumerate);
134
135         devices = udev_enumerate_get_list_entry(enumerate);
136
137         udev_list_entry_foreach(dev_list_entry, devices) {
138                 path = udev_list_entry_get_name(dev_list_entry);
139                 dev = udev_device_new_from_syspath(udev_context,
140                                                    path);
141                 if (dev == NULL)
142                         continue;
143
144                 /* Check whether device uses usbip driver. */
145                 if (hdriver->ops.is_my_device(dev)) {
146                         edev = usbip_exported_device_new(hdriver, path);
147                         if (!edev) {
148                                 dbg("usbip_exported_device_new failed");
149                                 continue;
150                         }
151
152                         list_add(&edev->node, &hdriver->edev_list);
153                         hdriver->ndevs++;
154                 }
155         }
156
157         return 0;
158 }
159
160 static void usbip_exported_device_destroy(struct list_head *devs)
161 {
162         struct list_head *i, *tmp;
163         struct usbip_exported_device *edev;
164
165         list_for_each_safe(i, tmp, devs) {
166                 edev = list_entry(i, struct usbip_exported_device, node);
167                 list_del(i);
168                 free(edev);
169         }
170 }
171
172 int usbip_generic_driver_open(struct usbip_host_driver *hdriver)
173 {
174         int rc;
175
176         udev_context = udev_new();
177         if (!udev_context) {
178                 err("udev_new failed");
179                 return -1;
180         }
181
182         rc = refresh_exported_devices(hdriver);
183         if (rc < 0)
184                 goto err;
185         return 0;
186 err:
187         udev_unref(udev_context);
188         return -1;
189 }
190
191 void usbip_generic_driver_close(struct usbip_host_driver *hdriver)
192 {
193         if (!hdriver)
194                 return;
195
196         usbip_exported_device_destroy(&hdriver->edev_list);
197
198         udev_unref(udev_context);
199 }
200
201 int usbip_generic_refresh_device_list(struct usbip_host_driver *hdriver)
202 {
203         int rc;
204
205         usbip_exported_device_destroy(&hdriver->edev_list);
206
207         hdriver->ndevs = 0;
208         INIT_LIST_HEAD(&hdriver->edev_list);
209
210         rc = refresh_exported_devices(hdriver);
211         if (rc < 0)
212                 return -1;
213
214         return 0;
215 }
216
217 int usbip_export_device(struct usbip_exported_device *edev, int sockfd)
218 {
219         char attr_name[] = "usbip_sockfd";
220         char sockfd_attr_path[SYSFS_PATH_MAX];
221         char sockfd_buff[30];
222         int ret;
223
224         if (edev->status != SDEV_ST_AVAILABLE) {
225                 dbg("device not available: %s", edev->udev.busid);
226                 switch (edev->status) {
227                 case SDEV_ST_ERROR:
228                         dbg("status SDEV_ST_ERROR");
229                         break;
230                 case SDEV_ST_USED:
231                         dbg("status SDEV_ST_USED");
232                         break;
233                 default:
234                         dbg("status unknown: 0x%x", edev->status);
235                 }
236                 return -1;
237         }
238
239         /* only the first interface is true */
240         snprintf(sockfd_attr_path, sizeof(sockfd_attr_path), "%s/%s",
241                  edev->udev.path, attr_name);
242
243         snprintf(sockfd_buff, sizeof(sockfd_buff), "%d\n", sockfd);
244
245         ret = write_sysfs_attribute(sockfd_attr_path, sockfd_buff,
246                                     strlen(sockfd_buff));
247         if (ret < 0) {
248                 err("write_sysfs_attribute failed: sockfd %s to %s",
249                     sockfd_buff, sockfd_attr_path);
250                 return ret;
251         }
252
253         info("connect: %s", edev->udev.busid);
254
255         return ret;
256 }
257
258 struct usbip_exported_device *usbip_generic_get_device(
259                 struct usbip_host_driver *hdriver, int num)
260 {
261         struct list_head *i;
262         struct usbip_exported_device *edev;
263         int cnt = 0;
264
265         list_for_each(i, &hdriver->edev_list) {
266                 edev = list_entry(i, struct usbip_exported_device, node);
267                 if (num == cnt)
268                         return edev;
269                 cnt++;
270         }
271
272         return NULL;
273 }