staging: usbip: remove section dividers
[linux-2.6/linux-acpi-2.6/ibm-acpi-2.6.git] / drivers / staging / usbip / stub_main.c
blob6634e07e0e879061405a8dd87aaafa202e38240d
1 /*
2 * Copyright (C) 2003-2008 Takahiro Hirofuchi
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.
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.
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.
20 #include <linux/slab.h>
22 #include "usbip_common.h"
23 #include "stub.h"
25 /* Version Information */
26 #define DRIVER_VERSION "1.0"
27 #define DRIVER_AUTHOR "Takahiro Hirofuchi"
28 #define DRIVER_DESC "Stub Driver for USB/IP"
30 /* stub_priv is allocated from stub_priv_cache */
31 struct kmem_cache *stub_priv_cache;
34 * busid_tables defines matching busids that usbip can grab. A user can change
35 * dynamically what device is locally used and what device is exported to a
36 * remote host.
38 #define MAX_BUSID 16
39 static struct bus_id_priv busid_table[MAX_BUSID];
40 static spinlock_t busid_table_lock;
42 int match_busid(const char *busid)
44 int i;
46 spin_lock(&busid_table_lock);
48 for (i = 0; i < MAX_BUSID; i++)
49 if (busid_table[i].name[0])
50 if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
51 /* already registerd */
52 spin_unlock(&busid_table_lock);
53 return 0;
56 spin_unlock(&busid_table_lock);
58 return 1;
61 struct bus_id_priv *get_busid_priv(const char *busid)
63 int i;
65 spin_lock(&busid_table_lock);
67 for (i = 0; i < MAX_BUSID; i++)
68 if (busid_table[i].name[0])
69 if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
70 /* already registerd */
71 spin_unlock(&busid_table_lock);
72 return &(busid_table[i]);
75 spin_unlock(&busid_table_lock);
77 return NULL;
80 static ssize_t show_match_busid(struct device_driver *drv, char *buf)
82 int i;
83 char *out = buf;
85 spin_lock(&busid_table_lock);
87 for (i = 0; i < MAX_BUSID; i++)
88 if (busid_table[i].name[0])
89 out += sprintf(out, "%s ", busid_table[i].name);
91 spin_unlock(&busid_table_lock);
93 out += sprintf(out, "\n");
95 return out - buf;
98 static int add_match_busid(char *busid)
100 int i;
102 if (!match_busid(busid))
103 return 0;
105 spin_lock(&busid_table_lock);
107 for (i = 0; i < MAX_BUSID; i++)
108 if (!busid_table[i].name[0]) {
109 strncpy(busid_table[i].name, busid, BUSID_SIZE);
110 if ((busid_table[i].status != STUB_BUSID_ALLOC) &&
111 (busid_table[i].status != STUB_BUSID_REMOV))
112 busid_table[i].status = STUB_BUSID_ADDED;
113 spin_unlock(&busid_table_lock);
114 return 0;
117 spin_unlock(&busid_table_lock);
119 return -1;
122 int del_match_busid(char *busid)
124 int i;
126 spin_lock(&busid_table_lock);
128 for (i = 0; i < MAX_BUSID; i++)
129 if (!strncmp(busid_table[i].name, busid, BUSID_SIZE)) {
130 /* found */
131 if (busid_table[i].status == STUB_BUSID_OTHER)
132 memset(busid_table[i].name, 0, BUSID_SIZE);
133 if ((busid_table[i].status != STUB_BUSID_OTHER) &&
134 (busid_table[i].status != STUB_BUSID_ADDED)) {
135 busid_table[i].status = STUB_BUSID_REMOV;
137 spin_unlock(&busid_table_lock);
138 return 0;
141 spin_unlock(&busid_table_lock);
143 return -1;
146 static void init_busid_table(void)
148 int i;
150 for (i = 0; i < MAX_BUSID; i++) {
151 memset(busid_table[i].name, 0, BUSID_SIZE);
152 busid_table[i].status = STUB_BUSID_OTHER;
153 busid_table[i].interf_count = 0;
154 busid_table[i].sdev = NULL;
155 busid_table[i].shutdown_busid = 0;
158 spin_lock_init(&busid_table_lock);
161 static ssize_t store_match_busid(struct device_driver *dev, const char *buf,
162 size_t count)
164 int len;
165 char busid[BUSID_SIZE];
167 if (count < 5)
168 return -EINVAL;
170 /* strnlen() does not include \0 */
171 len = strnlen(buf + 4, BUSID_SIZE);
173 /* busid needs to include \0 termination */
174 if (!(len < BUSID_SIZE))
175 return -EINVAL;
177 strncpy(busid, buf + 4, BUSID_SIZE);
179 if (!strncmp(buf, "add ", 4)) {
180 if (add_match_busid(busid) < 0)
181 return -ENOMEM;
182 else {
183 usbip_udbg("add busid %s\n", busid);
184 return count;
186 } else if (!strncmp(buf, "del ", 4)) {
187 if (del_match_busid(busid) < 0)
188 return -ENODEV;
189 else {
190 usbip_udbg("del busid %s\n", busid);
191 return count;
193 } else
194 return -EINVAL;
196 static DRIVER_ATTR(match_busid, S_IRUSR|S_IWUSR, show_match_busid,
197 store_match_busid);
199 static struct stub_priv *stub_priv_pop_from_listhead(struct list_head *listhead)
201 struct stub_priv *priv, *tmp;
203 list_for_each_entry_safe(priv, tmp, listhead, list) {
204 list_del(&priv->list);
205 return priv;
208 return NULL;
211 static struct stub_priv *stub_priv_pop(struct stub_device *sdev)
213 unsigned long flags;
214 struct stub_priv *priv;
216 spin_lock_irqsave(&sdev->priv_lock, flags);
218 priv = stub_priv_pop_from_listhead(&sdev->priv_init);
219 if (priv) {
220 spin_unlock_irqrestore(&sdev->priv_lock, flags);
221 return priv;
224 priv = stub_priv_pop_from_listhead(&sdev->priv_tx);
225 if (priv) {
226 spin_unlock_irqrestore(&sdev->priv_lock, flags);
227 return priv;
230 priv = stub_priv_pop_from_listhead(&sdev->priv_free);
231 if (priv) {
232 spin_unlock_irqrestore(&sdev->priv_lock, flags);
233 return priv;
236 spin_unlock_irqrestore(&sdev->priv_lock, flags);
237 return NULL;
240 void stub_device_cleanup_urbs(struct stub_device *sdev)
242 struct stub_priv *priv;
244 usbip_udbg("free sdev %p\n", sdev);
246 while ((priv = stub_priv_pop(sdev))) {
247 struct urb *urb = priv->urb;
249 usbip_udbg(" free urb %p\n", urb);
250 usb_kill_urb(urb);
252 kmem_cache_free(stub_priv_cache, priv);
254 kfree(urb->transfer_buffer);
255 kfree(urb->setup_packet);
257 usb_free_urb(urb);
261 static int __init usb_stub_init(void)
263 int ret;
265 stub_priv_cache = kmem_cache_create("stub_priv",
266 sizeof(struct stub_priv), 0,
267 SLAB_HWCACHE_ALIGN, NULL);
269 if (!stub_priv_cache) {
270 printk(KERN_ERR KBUILD_MODNAME
271 ": create stub_priv_cache error\n");
272 return -ENOMEM;
275 ret = usb_register(&stub_driver);
276 if (ret) {
277 printk(KERN_ERR KBUILD_MODNAME ": usb_register failed %d\n",
278 ret);
279 goto error_usb_register;
282 printk(KERN_INFO KBUILD_MODNAME ":" DRIVER_DESC ":" DRIVER_VERSION
283 "\n");
285 init_busid_table();
287 ret = driver_create_file(&stub_driver.drvwrap.driver,
288 &driver_attr_match_busid);
290 if (ret) {
291 printk(KERN_ERR KBUILD_MODNAME ": create driver sysfs\n");
292 goto error_create_file;
295 return ret;
296 error_create_file:
297 usb_deregister(&stub_driver);
298 error_usb_register:
299 kmem_cache_destroy(stub_priv_cache);
300 return ret;
303 static void __exit usb_stub_exit(void)
305 driver_remove_file(&stub_driver.drvwrap.driver,
306 &driver_attr_match_busid);
309 * deregister() calls stub_disconnect() for all devices. Device
310 * specific data is cleared in stub_disconnect().
312 usb_deregister(&stub_driver);
314 kmem_cache_destroy(stub_priv_cache);
317 module_init(usb_stub_init);
318 module_exit(usb_stub_exit);
320 MODULE_AUTHOR(DRIVER_AUTHOR);
321 MODULE_DESCRIPTION(DRIVER_DESC);
322 MODULE_LICENSE("GPL");