linux/drivers/usb/wusbcore/wusbhc.c
<<
>>
Prefs
   1/*
   2 * Wireless USB Host Controller
   3 * sysfs glue, wusbcore module support and life cycle management
   4 *
   5 *
   6 * Copyright (C) 2005-2006 Intel Corporation
   7 * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
   8 *
   9 * This program is free software; you can redistribute it and/or
  10 * modify it under the terms of the GNU General Public License version
  11 * 2 as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  21 * 02110-1301, USA.
  22 *
  23 *
  24 * Creation/destruction of wusbhc is split in two parts; that that
  25 * doesn't require the HCD to be added (wusbhc_{create,destroy}) and
  26 * the one that requires (phase B, wusbhc_b_{create,destroy}).
  27 *
  28 * This is so because usb_add_hcd() will start the HC, and thus, all
  29 * the HC specific stuff has to be already initialized (like sysfs
  30 * thingies).
  31 */
  32#include <linux/device.h>
  33#include <linux/module.h>
  34#include "wusbhc.h"
  35
  36/**
  37 * Extract the wusbhc that corresponds to a USB Host Controller class device
  38 *
  39 * WARNING! Apply only if @dev is that of a
  40 *          wusbhc.usb_hcd.self->class_dev; otherwise, you loose.
  41 */
  42static struct wusbhc *usbhc_dev_to_wusbhc(struct device *dev)
  43{
  44        struct usb_bus *usb_bus = dev_get_drvdata(dev);
  45        struct usb_hcd *usb_hcd = bus_to_hcd(usb_bus);
  46        return usb_hcd_to_wusbhc(usb_hcd);
  47}
  48
  49/*
  50 * Show & store the current WUSB trust timeout
  51 *
  52 * We don't do locking--it is an 'atomic' value.
  53 *
  54 * The units that we store/show are always MILLISECONDS. However, the
  55 * value of trust_timeout is jiffies.
  56 */
  57static ssize_t wusb_trust_timeout_show(struct device *dev,
  58                                        struct device_attribute *attr,
  59                                        char *buf)
  60{
  61        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
  62
  63        return scnprintf(buf, PAGE_SIZE, "%u\n", wusbhc->trust_timeout);
  64}
  65
  66static ssize_t wusb_trust_timeout_store(struct device *dev,
  67                                        struct device_attribute *attr,
  68                                        const char *buf, size_t size)
  69{
  70        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
  71        ssize_t result = -ENOSYS;
  72        unsigned trust_timeout;
  73
  74        result = sscanf(buf, "%u", &trust_timeout);
  75        if (result != 1) {
  76                result = -EINVAL;
  77                goto out;
  78        }
  79        wusbhc->trust_timeout = min_t(unsigned, trust_timeout, 500);
  80        cancel_delayed_work(&wusbhc->keep_alive_timer);
  81        flush_workqueue(wusbd);
  82        queue_delayed_work(wusbd, &wusbhc->keep_alive_timer,
  83                           msecs_to_jiffies(wusbhc->trust_timeout / 2));
  84out:
  85        return result < 0 ? result : size;
  86}
  87static DEVICE_ATTR(wusb_trust_timeout, 0644, wusb_trust_timeout_show,
  88                                             wusb_trust_timeout_store);
  89
  90/*
  91 * Show the current WUSB CHID.
  92 */
  93static ssize_t wusb_chid_show(struct device *dev,
  94                              struct device_attribute *attr, char *buf)
  95{
  96        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
  97        const struct wusb_ckhdid *chid;
  98        ssize_t result = 0;
  99
 100        if (wusbhc->wuie_host_info != NULL)
 101                chid = &wusbhc->wuie_host_info->CHID;
 102        else
 103                chid = &wusb_ckhdid_zero;
 104
 105        result += ckhdid_printf(buf, PAGE_SIZE, chid);
 106        result += sprintf(buf + result, "\n");
 107
 108        return result;
 109}
 110
 111/*
 112 * Store a new CHID.
 113 *
 114 * - Write an all zeros CHID and it will stop the controller
 115 * - Write a non-zero CHID and it will start it.
 116 *
 117 * See wusbhc_chid_set() for more info.
 118 */
 119static ssize_t wusb_chid_store(struct device *dev,
 120                               struct device_attribute *attr,
 121                               const char *buf, size_t size)
 122{
 123        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 124        struct wusb_ckhdid chid;
 125        ssize_t result;
 126
 127        result = sscanf(buf,
 128                        "%02hhx %02hhx %02hhx %02hhx "
 129                        "%02hhx %02hhx %02hhx %02hhx "
 130                        "%02hhx %02hhx %02hhx %02hhx "
 131                        "%02hhx %02hhx %02hhx %02hhx\n",
 132                        &chid.data[0] , &chid.data[1] ,
 133                        &chid.data[2] , &chid.data[3] ,
 134                        &chid.data[4] , &chid.data[5] ,
 135                        &chid.data[6] , &chid.data[7] ,
 136                        &chid.data[8] , &chid.data[9] ,
 137                        &chid.data[10], &chid.data[11],
 138                        &chid.data[12], &chid.data[13],
 139                        &chid.data[14], &chid.data[15]);
 140        if (result != 16) {
 141                dev_err(dev, "Unrecognized CHID (need 16 8-bit hex digits): "
 142                        "%d\n", (int)result);
 143                return -EINVAL;
 144        }
 145        result = wusbhc_chid_set(wusbhc, &chid);
 146        return result < 0 ? result : size;
 147}
 148static DEVICE_ATTR(wusb_chid, 0644, wusb_chid_show, wusb_chid_store);
 149
 150
 151static ssize_t wusb_phy_rate_show(struct device *dev,
 152                                  struct device_attribute *attr,
 153                                  char *buf)
 154{
 155        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 156
 157        return sprintf(buf, "%d\n", wusbhc->phy_rate);
 158}
 159
 160static ssize_t wusb_phy_rate_store(struct device *dev,
 161                                   struct device_attribute *attr,
 162                                   const char *buf, size_t size)
 163{
 164        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 165        uint8_t phy_rate;
 166        ssize_t result;
 167
 168        result = sscanf(buf, "%hhu", &phy_rate);
 169        if (result != 1)
 170                return -EINVAL;
 171        if (phy_rate >= UWB_PHY_RATE_INVALID)
 172                return -EINVAL;
 173
 174        wusbhc->phy_rate = phy_rate;
 175        return size;
 176}
 177static DEVICE_ATTR(wusb_phy_rate, 0644, wusb_phy_rate_show,
 178                        wusb_phy_rate_store);
 179
 180static ssize_t wusb_dnts_show(struct device *dev,
 181                                  struct device_attribute *attr,
 182                                  char *buf)
 183{
 184        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 185
 186        return sprintf(buf, "num slots: %d\ninterval: %dms\n",
 187                        wusbhc->dnts_num_slots, wusbhc->dnts_interval);
 188}
 189
 190static ssize_t wusb_dnts_store(struct device *dev,
 191                                   struct device_attribute *attr,
 192                                   const char *buf, size_t size)
 193{
 194        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 195        uint8_t num_slots, interval;
 196        ssize_t result;
 197
 198        result = sscanf(buf, "%hhu %hhu", &num_slots, &interval);
 199
 200        if (result != 2)
 201                return -EINVAL;
 202
 203        wusbhc->dnts_num_slots = num_slots;
 204        wusbhc->dnts_interval = interval;
 205
 206        return size;
 207}
 208static DEVICE_ATTR(wusb_dnts, 0644, wusb_dnts_show, wusb_dnts_store);
 209
 210static ssize_t wusb_retry_count_show(struct device *dev,
 211                                  struct device_attribute *attr,
 212                                  char *buf)
 213{
 214        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 215
 216        return sprintf(buf, "%d\n", wusbhc->retry_count);
 217}
 218
 219static ssize_t wusb_retry_count_store(struct device *dev,
 220                                   struct device_attribute *attr,
 221                                   const char *buf, size_t size)
 222{
 223        struct wusbhc *wusbhc = usbhc_dev_to_wusbhc(dev);
 224        uint8_t retry_count;
 225        ssize_t result;
 226
 227        result = sscanf(buf, "%hhu", &retry_count);
 228
 229        if (result != 1)
 230                return -EINVAL;
 231
 232        wusbhc->retry_count = max_t(uint8_t, retry_count,
 233                                        WUSB_RETRY_COUNT_MAX);
 234
 235        return size;
 236}
 237static DEVICE_ATTR(wusb_retry_count, 0644, wusb_retry_count_show,
 238        wusb_retry_count_store);
 239
 240/* Group all the WUSBHC attributes */
 241static struct attribute *wusbhc_attrs[] = {
 242                &dev_attr_wusb_trust_timeout.attr,
 243                &dev_attr_wusb_chid.attr,
 244                &dev_attr_wusb_phy_rate.attr,
 245                &dev_attr_wusb_dnts.attr,
 246                &dev_attr_wusb_retry_count.attr,
 247                NULL,
 248};
 249
 250static struct attribute_group wusbhc_attr_group = {
 251        .name = NULL,   /* we want them in the same directory */
 252        .attrs = wusbhc_attrs,
 253};
 254
 255/*
 256 * Create a wusbhc instance
 257 *
 258 * NOTEs:
 259 *
 260 *  - assumes *wusbhc has been zeroed and wusbhc->usb_hcd has been
 261 *    initialized but not added.
 262 *
 263 *  - fill out ports_max, mmcies_max and mmcie_{add,rm} before calling.
 264 *
 265 *  - fill out wusbhc->uwb_rc and refcount it before calling
 266 *  - fill out the wusbhc->sec_modes array
 267 */
 268int wusbhc_create(struct wusbhc *wusbhc)
 269{
 270        int result = 0;
 271
 272        /* set defaults.  These can be overwritten using sysfs attributes. */
 273        wusbhc->trust_timeout = WUSB_TRUST_TIMEOUT_MS;
 274        wusbhc->phy_rate = UWB_PHY_RATE_INVALID - 1;
 275        wusbhc->dnts_num_slots = 4;
 276        wusbhc->dnts_interval = 2;
 277        wusbhc->retry_count = WUSB_RETRY_COUNT_INFINITE;
 278
 279        mutex_init(&wusbhc->mutex);
 280        result = wusbhc_mmcie_create(wusbhc);
 281        if (result < 0)
 282                goto error_mmcie_create;
 283        result = wusbhc_devconnect_create(wusbhc);
 284        if (result < 0)
 285                goto error_devconnect_create;
 286        result = wusbhc_rh_create(wusbhc);
 287        if (result < 0)
 288                goto error_rh_create;
 289        result = wusbhc_sec_create(wusbhc);
 290        if (result < 0)
 291                goto error_sec_create;
 292        return 0;
 293
 294error_sec_create:
 295        wusbhc_rh_destroy(wusbhc);
 296error_rh_create:
 297        wusbhc_devconnect_destroy(wusbhc);
 298error_devconnect_create:
 299        wusbhc_mmcie_destroy(wusbhc);
 300error_mmcie_create:
 301        return result;
 302}
 303EXPORT_SYMBOL_GPL(wusbhc_create);
 304
 305static inline struct kobject *wusbhc_kobj(struct wusbhc *wusbhc)
 306{
 307        return &wusbhc->usb_hcd.self.controller->kobj;
 308}
 309
 310/*
 311 * Phase B of a wusbhc instance creation
 312 *
 313 * Creates fields that depend on wusbhc->usb_hcd having been
 314 * added. This is where we create the sysfs files in
 315 * /sys/class/usb_host/usb_hostX/.
 316 *
 317 * NOTE: Assumes wusbhc->usb_hcd has been already added by the upper
 318 *       layer (hwahc or whci)
 319 */
 320int wusbhc_b_create(struct wusbhc *wusbhc)
 321{
 322        int result = 0;
 323        struct device *dev = wusbhc->usb_hcd.self.controller;
 324
 325        result = sysfs_create_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
 326        if (result < 0) {
 327                dev_err(dev, "Cannot register WUSBHC attributes: %d\n",
 328                        result);
 329                goto error_create_attr_group;
 330        }
 331
 332        return 0;
 333error_create_attr_group:
 334        return result;
 335}
 336EXPORT_SYMBOL_GPL(wusbhc_b_create);
 337
 338void wusbhc_b_destroy(struct wusbhc *wusbhc)
 339{
 340        wusbhc_pal_unregister(wusbhc);
 341        sysfs_remove_group(wusbhc_kobj(wusbhc), &wusbhc_attr_group);
 342}
 343EXPORT_SYMBOL_GPL(wusbhc_b_destroy);
 344
 345void wusbhc_destroy(struct wusbhc *wusbhc)
 346{
 347        wusbhc_sec_destroy(wusbhc);
 348        wusbhc_rh_destroy(wusbhc);
 349        wusbhc_devconnect_destroy(wusbhc);
 350        wusbhc_mmcie_destroy(wusbhc);
 351}
 352EXPORT_SYMBOL_GPL(wusbhc_destroy);
 353
 354struct workqueue_struct *wusbd;
 355EXPORT_SYMBOL_GPL(wusbd);
 356
 357/*
 358 * WUSB Cluster ID allocation map
 359 *
 360 * Each WUSB bus in a channel is identified with a Cluster Id in the
 361 * unauth address pace (WUSB1.0[4.3]). We take the range 0xe0 to 0xff
 362 * (that's space for 31 WUSB controllers, as 0xff can't be taken). We
 363 * start taking from 0xff, 0xfe, 0xfd... (hence the += or -= 0xff).
 364 *
 365 * For each one we taken, we pin it in the bitap
 366 */
 367#define CLUSTER_IDS 32
 368static DECLARE_BITMAP(wusb_cluster_id_table, CLUSTER_IDS);
 369static DEFINE_SPINLOCK(wusb_cluster_ids_lock);
 370
 371/*
 372 * Get a WUSB Cluster ID
 373 *
 374 * Need to release with wusb_cluster_id_put() when done w/ it.
 375 */
 376/* FIXME: coordinate with the choose_addres() from the USB stack */
 377/* we want to leave the top of the 128 range for cluster addresses and
 378 * the bottom for device addresses (as we map them one on one with
 379 * ports). */
 380u8 wusb_cluster_id_get(void)
 381{
 382        u8 id;
 383        spin_lock(&wusb_cluster_ids_lock);
 384        id = find_first_zero_bit(wusb_cluster_id_table, CLUSTER_IDS);
 385        if (id >= CLUSTER_IDS) {
 386                id = 0;
 387                goto out;
 388        }
 389        set_bit(id, wusb_cluster_id_table);
 390        id = (u8) 0xff - id;
 391out:
 392        spin_unlock(&wusb_cluster_ids_lock);
 393        return id;
 394
 395}
 396EXPORT_SYMBOL_GPL(wusb_cluster_id_get);
 397
 398/*
 399 * Release a WUSB Cluster ID
 400 *
 401 * Obtained it with wusb_cluster_id_get()
 402 */
 403void wusb_cluster_id_put(u8 id)
 404{
 405        id = 0xff - id;
 406        BUG_ON(id >= CLUSTER_IDS);
 407        spin_lock(&wusb_cluster_ids_lock);
 408        WARN_ON(!test_bit(id, wusb_cluster_id_table));
 409        clear_bit(id, wusb_cluster_id_table);
 410        spin_unlock(&wusb_cluster_ids_lock);
 411}
 412EXPORT_SYMBOL_GPL(wusb_cluster_id_put);
 413
 414/**
 415 * wusbhc_giveback_urb - return an URB to the USB core
 416 * @wusbhc: the host controller the URB is from.
 417 * @urb:    the URB.
 418 * @status: the URB's status.
 419 *
 420 * Return an URB to the USB core doing some additional WUSB specific
 421 * processing.
 422 *
 423 *  - After a successful transfer, update the trust timeout timestamp
 424 *    for the WUSB device.
 425 *
 426 *  - [WUSB] sections 4.13 and 7.5.1 specify the stop retransmission
 427 *    condition for the WCONNECTACK_IE is that the host has observed
 428 *    the associated device responding to a control transfer.
 429 */
 430void wusbhc_giveback_urb(struct wusbhc *wusbhc, struct urb *urb, int status)
 431{
 432        struct wusb_dev *wusb_dev = __wusb_dev_get_by_usb_dev(wusbhc,
 433                                        urb->dev);
 434
 435        if (status == 0 && wusb_dev) {
 436                wusb_dev->entry_ts = jiffies;
 437
 438                /* wusbhc_devconnect_acked() can't be called from
 439                   atomic context so defer it to a work queue. */
 440                if (!list_empty(&wusb_dev->cack_node))
 441                        queue_work(wusbd, &wusb_dev->devconnect_acked_work);
 442                else
 443                        wusb_dev_put(wusb_dev);
 444        }
 445
 446        usb_hcd_giveback_urb(&wusbhc->usb_hcd, urb, status);
 447}
 448EXPORT_SYMBOL_GPL(wusbhc_giveback_urb);
 449
 450/**
 451 * wusbhc_reset_all - reset the HC hardware
 452 * @wusbhc: the host controller to reset.
 453 *
 454 * Request a full hardware reset of the chip.  This will also reset
 455 * the radio controller and any other PALs.
 456 */
 457void wusbhc_reset_all(struct wusbhc *wusbhc)
 458{
 459        if (wusbhc->uwb_rc)
 460                uwb_rc_reset_all(wusbhc->uwb_rc);
 461}
 462EXPORT_SYMBOL_GPL(wusbhc_reset_all);
 463
 464static struct notifier_block wusb_usb_notifier = {
 465        .notifier_call = wusb_usb_ncb,
 466        .priority = INT_MAX     /* Need to be called first of all */
 467};
 468
 469static int __init wusbcore_init(void)
 470{
 471        int result;
 472        result = wusb_crypto_init();
 473        if (result < 0)
 474                goto error_crypto_init;
 475        /* WQ is singlethread because we need to serialize notifications */
 476        wusbd = create_singlethread_workqueue("wusbd");
 477        if (wusbd == NULL) {
 478                result = -ENOMEM;
 479                printk(KERN_ERR "WUSB-core: Cannot create wusbd workqueue\n");
 480                goto error_wusbd_create;
 481        }
 482        usb_register_notify(&wusb_usb_notifier);
 483        bitmap_zero(wusb_cluster_id_table, CLUSTER_IDS);
 484        set_bit(0, wusb_cluster_id_table);      /* reserve Cluster ID 0xff */
 485        return 0;
 486
 487error_wusbd_create:
 488        wusb_crypto_exit();
 489error_crypto_init:
 490        return result;
 491
 492}
 493module_init(wusbcore_init);
 494
 495static void __exit wusbcore_exit(void)
 496{
 497        clear_bit(0, wusb_cluster_id_table);
 498        if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
 499                char buf[256];
 500                bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table,
 501                                 CLUSTER_IDS);
 502                printk(KERN_ERR "BUG: WUSB Cluster IDs not released "
 503                       "on exit: %s\n", buf);
 504                WARN_ON(1);
 505        }
 506        usb_unregister_notify(&wusb_usb_notifier);
 507        destroy_workqueue(wusbd);
 508        wusb_crypto_exit();
 509}
 510module_exit(wusbcore_exit);
 511
 512MODULE_AUTHOR("Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>");
 513MODULE_DESCRIPTION("Wireless USB core");
 514MODULE_LICENSE("GPL");
 515