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