root/drivers/staging/wusbcore/wusbhc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. usbhc_dev_to_wusbhc
  2. wusb_trust_timeout_show
  3. wusb_trust_timeout_store
  4. wusb_chid_show
  5. wusb_chid_store
  6. wusb_phy_rate_show
  7. wusb_phy_rate_store
  8. wusb_dnts_show
  9. wusb_dnts_store
  10. wusb_retry_count_show
  11. wusb_retry_count_store
  12. wusbhc_create
  13. wusbhc_kobj
  14. wusbhc_b_create
  15. wusbhc_b_destroy
  16. wusbhc_destroy
  17. wusb_cluster_id_get
  18. wusb_cluster_id_put
  19. wusbhc_giveback_urb
  20. wusbhc_reset_all
  21. wusbcore_init
  22. wusbcore_exit

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

/* [<][>][^][v][top][bottom][index][help] */