Merge branch 'for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck...
[linux-2.6-microblaze.git] / drivers / usb / usbip / stub_main.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2003-2008 Takahiro Hirofuchi
4  */
5
6 #include <linux/string.h>
7 #include <linux/module.h>
8 #include <linux/device.h>
9
10 #include "usbip_common.h"
11 #include "stub.h"
12
13 #define DRIVER_AUTHOR "Takahiro Hirofuchi"
14 #define DRIVER_DESC "USB/IP Host Driver"
15
16 struct kmem_cache *stub_priv_cache;
17 /*
18  * busid_tables defines matching busids that usbip can grab. A user can change
19  * dynamically what device is locally used and what device is exported to a
20  * remote host.
21  */
22 #define MAX_BUSID 16
23 static struct bus_id_priv busid_table[MAX_BUSID];
24 static spinlock_t busid_table_lock;
25
26 static void init_busid_table(void)
27 {
28         /*
29          * This also sets the bus_table[i].status to
30          * STUB_BUSID_OTHER, which is 0.
31          */
32         memset(busid_table, 0, sizeof(busid_table));
33
34         spin_lock_init(&busid_table_lock);
35 }
36
37 /*
38  * Find the index of the busid by name.
39  * Must be called with busid_table_lock held.
40  */
41 static int get_busid_idx(const char *busid)
42 {
43         int i;
44         int idx = -1;
45
46         for (i = 0; i < MAX_BUSID; i++)
47                 if (busid_table[i].name[0])
48                         if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
49                                 idx = i;
50                                 break;
51                         }
52         return idx;
53 }
54
55 struct bus_id_priv *get_busid_priv(const char *busid)
56 {
57         int idx;
58         struct bus_id_priv *bid = NULL;
59
60         spin_lock(&busid_table_lock);
61         idx = get_busid_idx(busid);
62         if (idx >= 0)
63                 bid = &(busid_table[idx]);
64         spin_unlock(&busid_table_lock);
65
66         return bid;
67 }
68
69 static int add_match_busid(char *busid)
70 {
71         int i;
72         int ret = -1;
73
74         spin_lock(&busid_table_lock);
75         /* already registered? */
76         if (get_busid_idx(busid) >= 0) {
77                 ret = 0;
78                 goto out;
79         }
80
81         for (i = 0; i < MAX_BUSID; i++)
82                 if (!busid_table[i].name[0]) {
83                         strlcpy(busid_table[i].name, busid, BUSID_SIZE);
84                         if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
85                             (busid_table[i].status != STUB_BUSID_REMOV))
86                                 busid_table[i].status = STUB_BUSID_ADDED;
87                         ret = 0;
88                         break;
89                 }
90
91 out:
92         spin_unlock(&busid_table_lock);
93
94         return ret;
95 }
96
97 int del_match_busid(char *busid)
98 {
99         int idx;
100         int ret = -1;
101
102         spin_lock(&busid_table_lock);
103         idx = get_busid_idx(busid);
104         if (idx < 0)
105                 goto out;
106
107         /* found */
108         ret = 0;
109
110         if (busid_table[idx].status == STUB_BUSID_OTHER)
111                 memset(busid_table[idx].name, 0, BUSID_SIZE);
112
113         if ((busid_table[idx].status != STUB_BUSID_OTHER) &&
114             (busid_table[idx].status != STUB_BUSID_ADDED))
115                 busid_table[idx].status = STUB_BUSID_REMOV;
116
117 out:
118         spin_unlock(&busid_table_lock);
119
120         return ret;
121 }
122
123 static ssize_t match_busid_show(struct device_driver *drv, char *buf)
124 {
125         int i;
126         char *out = buf;
127
128         spin_lock(&busid_table_lock);
129         for (i = 0; i < MAX_BUSID; i++)
130                 if (busid_table[i].name[0])
131                         out += sprintf(out, "%s ", busid_table[i].name);
132         spin_unlock(&busid_table_lock);
133         out += sprintf(out, "\n");
134
135         return out - buf;
136 }
137
138 static ssize_t match_busid_store(struct device_driver *dev, const char *buf,
139                                  size_t count)
140 {
141         int len;
142         char busid[BUSID_SIZE];
143
144         if (count < 5)
145                 return -EINVAL;
146
147         /* busid needs to include \0 termination */
148         len = strlcpy(busid, buf + 4, BUSID_SIZE);
149         if (sizeof(busid) <= len)
150                 return -EINVAL;
151
152         if (!strncmp(buf, "add ", 4)) {
153                 if (add_match_busid(busid) < 0)
154                         return -ENOMEM;
155
156                 pr_debug("add busid %s\n", busid);
157                 return count;
158         }
159
160         if (!strncmp(buf, "del ", 4)) {
161                 if (del_match_busid(busid) < 0)
162                         return -ENODEV;
163
164                 pr_debug("del busid %s\n", busid);
165                 return count;
166         }
167
168         return -EINVAL;
169 }
170 static DRIVER_ATTR_RW(match_busid);
171
172 static ssize_t rebind_store(struct device_driver *dev, const char *buf,
173                                  size_t count)
174 {
175         int ret;
176         int len;
177         struct bus_id_priv *bid;
178
179         /* buf length should be less that BUSID_SIZE */
180         len = strnlen(buf, BUSID_SIZE);
181
182         if (!(len < BUSID_SIZE))
183                 return -EINVAL;
184
185         bid = get_busid_priv(buf);
186         if (!bid)
187                 return -ENODEV;
188
189         /* device_attach() callers should hold parent lock for USB */
190         if (bid->udev->dev.parent)
191                 device_lock(bid->udev->dev.parent);
192         ret = device_attach(&bid->udev->dev);
193         if (bid->udev->dev.parent)
194                 device_unlock(bid->udev->dev.parent);
195         if (ret < 0) {
196                 dev_err(&bid->udev->dev, "rebind failed\n");
197                 return ret;
198         }
199
200         return count;
201 }
202
203 static DRIVER_ATTR_WO(rebind);
204
205 static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
206 {
207         struct stub_priv *priv, *tmp;
208
209         list_for_each_entry_safe(priv, tmp, listhead, list) {
210                 list_del(&priv->list);
211                 return priv;
212         }
213
214         return NULL;
215 }
216
217 static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
218 {
219         unsigned long flags;
220         struct stub_priv *priv;
221
222         spin_lock_irqsave(&sdev->priv_lock, flags);
223
224         priv = stub_priv_pop_from_listhead(&sdev->priv_init);
225         if (priv)
226                 goto done;
227
228         priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
229         if (priv)
230                 goto done;
231
232         priv = stub_priv_pop_from_listhead(&sdev->priv_free);
233
234 done:
235         spin_unlock_irqrestore(&sdev->priv_lock, flags);
236
237         return priv;
238 }
239
240 void stub_device_cleanup_urbs(struct stub_device *sdev)
241 {
242         struct stub_priv *priv;
243         struct urb *urb;
244
245         dev_dbg(&sdev->udev->dev, "Stub device cleaning up urbs\n");
246
247         while ((priv = stub_priv_pop(sdev))) {
248                 urb = priv->urb;
249                 dev_dbg(&sdev->udev->dev, "free urb seqnum %lu\n",
250                         priv->seqnum);
251                 usb_kill_urb(urb);
252
253                 kmem_cache_free(stub_priv_cache, priv);
254
255                 kfree(urb->transfer_buffer);
256                 urb->transfer_buffer = NULL;
257
258                 kfree(urb->setup_packet);
259                 urb->setup_packet = NULL;
260
261                 usb_free_urb(urb);
262         }
263 }
264
265 static int __init usbip_host_init(void)
266 {
267         int ret;
268
269         init_busid_table();
270
271         stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN);
272         if (!stub_priv_cache) {
273                 pr_err("kmem_cache_create failed\n");
274                 return -ENOMEM;
275         }
276
277         ret = usb_register_device_driver(&stub_driver, THIS_MODULE);
278         if (ret) {
279                 pr_err("usb_register failed %d\n", ret);
280                 goto err_usb_register;
281         }
282
283         ret = driver_create_file(&stub_driver.drvwrap.driver,
284                                  &driver_attr_match_busid);
285         if (ret) {
286                 pr_err("driver_create_file failed\n");
287                 goto err_create_file;
288         }
289
290         ret = driver_create_file(&stub_driver.drvwrap.driver,
291                                  &driver_attr_rebind);
292         if (ret) {
293                 pr_err("driver_create_file failed\n");
294                 goto err_create_file;
295         }
296
297         return ret;
298
299 err_create_file:
300         usb_deregister_device_driver(&stub_driver);
301 err_usb_register:
302         kmem_cache_destroy(stub_priv_cache);
303         return ret;
304 }
305
306 static void __exit usbip_host_exit(void)
307 {
308         driver_remove_file(&stub_driver.drvwrap.driver,
309                            &driver_attr_match_busid);
310
311         driver_remove_file(&stub_driver.drvwrap.driver,
312                            &driver_attr_rebind);
313
314         /*
315          * deregister() calls stub_disconnect() for all devices. Device
316          * specific data is cleared in stub_disconnect().
317          */
318         usb_deregister_device_driver(&stub_driver);
319
320         kmem_cache_destroy(stub_priv_cache);
321 }
322
323 module_init(usbip_host_init);
324 module_exit(usbip_host_exit);
325
326 MODULE_AUTHOR(DRIVER_AUTHOR);
327 MODULE_DESCRIPTION(DRIVER_DESC);
328 MODULE_LICENSE("GPL");