Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
stub_main.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003-2008 Takahiro Hirofuchi
3  *
4  * This is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
17  * USA.
18  */
19 
20 #include <linux/string.h>
21 #include <linux/module.h>
22 
23 #include "usbip_common.h"
24 #include "stub.h"
25 
26 #define DRIVER_AUTHOR "Takahiro Hirofuchi"
27 #define DRIVER_DESC "USB/IP Host Driver"
28 
30 /*
31  * busid_tables defines matching busids that usbip can grab. A user can change
32  * dynamically what device is locally used and what device is exported to a
33  * remote host.
34  */
35 #define MAX_BUSID 16
36 static struct bus_id_priv busid_table[MAX_BUSID];
37 static spinlock_t busid_table_lock;
38 
39 static void init_busid_table(void)
40 {
41  int i;
42 
43  memset(busid_table, 0, sizeof(busid_table));
44  for (i = 0; i < MAX_BUSID; i++)
45  busid_table[i].status = STUB_BUSID_OTHER;
46 
47  spin_lock_init(&busid_table_lock);
48 }
49 
50 /*
51  * Find the index of the busid by name.
52  * Must be called with busid_table_lock held.
53  */
54 static int get_busid_idx(const char *busid)
55 {
56  int i;
57  int idx = -1;
58 
59  for (i = 0; i < MAX_BUSID; i++)
60  if (busid_table[i].name[0])
61  if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
62  idx = i;
63  break;
64  }
65  return idx;
66 }
67 
68 struct bus_id_priv *get_busid_priv(const char *busid)
69 {
70  int idx;
71  struct bus_id_priv *bid = NULL;
72 
73  spin_lock(&busid_table_lock);
74  idx = get_busid_idx(busid);
75  if (idx >= 0)
76  bid = &(busid_table[idx]);
77  spin_unlock(&busid_table_lock);
78 
79  return bid;
80 }
81 
82 static int add_match_busid(char *busid)
83 {
84  int i;
85  int ret = -1;
86 
87  spin_lock(&busid_table_lock);
88  /* already registered? */
89  if (get_busid_idx(busid) >= 0) {
90  ret = 0;
91  goto out;
92  }
93 
94  for (i = 0; i < MAX_BUSID; i++)
95  if (!busid_table[i].name[0]) {
96  strncpy(busid_table[i].name, busid, BUSID_SIZE);
97  if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
98  (busid_table[i].status != STUB_BUSID_REMOV))
99  busid_table[i].status = STUB_BUSID_ADDED;
100  ret = 0;
101  break;
102  }
103 
104 out:
105  spin_unlock(&busid_table_lock);
106 
107  return ret;
108 }
109 
110 int del_match_busid(char *busid)
111 {
112  int idx;
113  int ret = -1;
114 
115  spin_lock(&busid_table_lock);
116  idx = get_busid_idx(busid);
117  if (idx < 0)
118  goto out;
119 
120  /* found */
121  ret = 0;
122 
123  if (busid_table[idx].status == STUB_BUSID_OTHER)
124  memset(busid_table[idx].name, 0, BUSID_SIZE);
125 
126  if ((busid_table[idx].status != STUB_BUSID_OTHER) &&
127  (busid_table[idx].status != STUB_BUSID_ADDED))
128  busid_table[idx].status = STUB_BUSID_REMOV;
129 
130 out:
131  spin_unlock(&busid_table_lock);
132 
133  return ret;
134 }
135 
136 static ssize_t show_match_busid(struct device_driver *drv, char *buf)
137 {
138  int i;
139  char *out = buf;
140 
141  spin_lock(&busid_table_lock);
142  for (i = 0; i < MAX_BUSID; i++)
143  if (busid_table[i].name[0])
144  out += sprintf(out, "%s ", busid_table[i].name);
145  spin_unlock(&busid_table_lock);
146  out += sprintf(out, "\n");
147 
148  return out - buf;
149 }
150 
151 static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
152  size_t count)
153 {
154  int len;
155  char busid[BUSID_SIZE];
156 
157  if (count < 5)
158  return -EINVAL;
159 
160  /* strnlen() does not include \0 */
161  len = strnlen(buf + 4, BUSID_SIZE);
162 
163  /* busid needs to include \0 termination */
164  if (!(len < BUSID_SIZE))
165  return -EINVAL;
166 
167  strncpy(busid, buf + 4, BUSID_SIZE);
168 
169  if (!strncmp(buf, "add ", 4)) {
170  if (add_match_busid(busid) < 0) {
171  return -ENOMEM;
172  } else {
173  pr_debug("add busid %s\n", busid);
174  return count;
175  }
176  } else if (!strncmp(buf, "del ", 4)) {
177  if (del_match_busid(busid) < 0) {
178  return -ENODEV;
179  } else {
180  pr_debug("del busid %s\n", busid);
181  return count;
182  }
183  } else {
184  return -EINVAL;
185  }
186 }
187 static DRIVER_ATTR(match_busid, S_IRUSR | S_IWUSR, show_match_busid,
188  store_match_busid);
189 
190 static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
191 {
192  struct stub_priv *priv, *tmp;
193 
194  list_for_each_entry_safe(priv, tmp, listhead, list) {
195  list_del(&priv->list);
196  return priv;
197  }
198 
199  return NULL;
200 }
201 
202 static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
203 {
204  unsigned long flags;
205  struct stub_priv *priv;
206 
207  spin_lock_irqsave(&sdev->priv_lock, flags);
208 
209  priv = stub_priv_pop_from_listhead(&sdev->priv_init);
210  if (priv)
211  goto done;
212 
213  priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
214  if (priv)
215  goto done;
216 
217  priv = stub_priv_pop_from_listhead(&sdev->priv_free);
218 
219 done:
220  spin_unlock_irqrestore(&sdev->priv_lock, flags);
221 
222  return priv;
223 }
224 
226 {
227  struct stub_priv *priv;
228  struct urb *urb;
229 
230  dev_dbg(&sdev->udev->dev, "free sdev %p\n", sdev);
231 
232  while ((priv = stub_priv_pop(sdev))) {
233  urb = priv->urb;
234  dev_dbg(&sdev->udev->dev, "free urb %p\n", urb);
235  usb_kill_urb(urb);
236 
237  kmem_cache_free(stub_priv_cache, priv);
238 
239  kfree(urb->transfer_buffer);
240  kfree(urb->setup_packet);
241  usb_free_urb(urb);
242  }
243 }
244 
245 static int __init usbip_host_init(void)
246 {
247  int ret;
248 
249  init_busid_table();
250 
251  stub_priv_cache = KMEM_CACHE(stub_priv, SLAB_HWCACHE_ALIGN);
252  if (!stub_priv_cache) {
253  pr_err("kmem_cache_create failed\n");
254  return -ENOMEM;
255  }
256 
257  ret = usb_register(&stub_driver);
258  if (ret < 0) {
259  pr_err("usb_register failed %d\n", ret);
260  goto err_usb_register;
261  }
262 
263  ret = driver_create_file(&stub_driver.drvwrap.driver,
264  &driver_attr_match_busid);
265  if (ret < 0) {
266  pr_err("driver_create_file failed\n");
267  goto err_create_file;
268  }
269 
270  pr_info(DRIVER_DESC " v" USBIP_VERSION "\n");
271  return ret;
272 
273 err_create_file:
274  usb_deregister(&stub_driver);
275 err_usb_register:
276  kmem_cache_destroy(stub_priv_cache);
277  return ret;
278 }
279 
280 static void __exit usbip_host_exit(void)
281 {
282  driver_remove_file(&stub_driver.drvwrap.driver,
283  &driver_attr_match_busid);
284 
285  /*
286  * deregister() calls stub_disconnect() for all devices. Device
287  * specific data is cleared in stub_disconnect().
288  */
289  usb_deregister(&stub_driver);
290 
291  kmem_cache_destroy(stub_priv_cache);
292 }
293 
294 module_init(usbip_host_init);
295 module_exit(usbip_host_exit);
296 
299 MODULE_LICENSE("GPL");