root/drivers/staging/wusbcore/host/whci/hcd.c

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

DEFINITIONS

This source file includes following definitions.
  1. whc_reset
  2. whc_start
  3. whc_stop
  4. whc_get_frame_number
  5. whc_urb_enqueue
  6. whc_urb_dequeue
  7. whc_endpoint_disable
  8. whc_endpoint_reset
  9. whc_probe
  10. whc_remove
  11. whci_hc_driver_init
  12. whci_hc_driver_exit

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Wireless Host Controller (WHC) driver.
   4  *
   5  * Copyright (C) 2007 Cambridge Silicon Radio Ltd.
   6  */
   7 #include <linux/kernel.h>
   8 #include <linux/init.h>
   9 #include <linux/module.h>
  10 
  11 #include "../../../uwb/include/umc.h"
  12 #include "../../wusbhc.h"
  13 
  14 #include "whcd.h"
  15 
  16 /*
  17  * One time initialization.
  18  *
  19  * Nothing to do here.
  20  */
  21 static int whc_reset(struct usb_hcd *usb_hcd)
  22 {
  23         return 0;
  24 }
  25 
  26 /*
  27  * Start the wireless host controller.
  28  *
  29  * Start device notification.
  30  *
  31  * Put hc into run state, set DNTS parameters.
  32  */
  33 static int whc_start(struct usb_hcd *usb_hcd)
  34 {
  35         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
  36         struct whc *whc = wusbhc_to_whc(wusbhc);
  37         u8 bcid;
  38         int ret;
  39 
  40         mutex_lock(&wusbhc->mutex);
  41 
  42         le_writel(WUSBINTR_GEN_CMD_DONE
  43                   | WUSBINTR_HOST_ERR
  44                   | WUSBINTR_ASYNC_SCHED_SYNCED
  45                   | WUSBINTR_DNTS_INT
  46                   | WUSBINTR_ERR_INT
  47                   | WUSBINTR_INT,
  48                   whc->base + WUSBINTR);
  49 
  50         /* set cluster ID */
  51         bcid = wusb_cluster_id_get();
  52         ret = whc_set_cluster_id(whc, bcid);
  53         if (ret < 0)
  54                 goto out;
  55         wusbhc->cluster_id = bcid;
  56 
  57         /* start HC */
  58         whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);
  59 
  60         usb_hcd->uses_new_polling = 1;
  61         set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
  62         usb_hcd->state = HC_STATE_RUNNING;
  63 
  64 out:
  65         mutex_unlock(&wusbhc->mutex);
  66         return ret;
  67 }
  68 
  69 
  70 /*
  71  * Stop the wireless host controller.
  72  *
  73  * Stop device notification.
  74  *
  75  * Wait for pending transfer to stop? Put hc into stop state?
  76  */
  77 static void whc_stop(struct usb_hcd *usb_hcd)
  78 {
  79         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
  80         struct whc *whc = wusbhc_to_whc(wusbhc);
  81 
  82         mutex_lock(&wusbhc->mutex);
  83 
  84         /* stop HC */
  85         le_writel(0, whc->base + WUSBINTR);
  86         whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
  87         whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
  88                       WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
  89                       100, "HC to halt");
  90 
  91         wusb_cluster_id_put(wusbhc->cluster_id);
  92 
  93         mutex_unlock(&wusbhc->mutex);
  94 }
  95 
  96 static int whc_get_frame_number(struct usb_hcd *usb_hcd)
  97 {
  98         /* Frame numbers are not applicable to WUSB. */
  99         return -ENOSYS;
 100 }
 101 
 102 
 103 /*
 104  * Queue an URB to the ASL or PZL
 105  */
 106 static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
 107                            gfp_t mem_flags)
 108 {
 109         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 110         struct whc *whc = wusbhc_to_whc(wusbhc);
 111         int ret;
 112 
 113         switch (usb_pipetype(urb->pipe)) {
 114         case PIPE_INTERRUPT:
 115                 ret = pzl_urb_enqueue(whc, urb, mem_flags);
 116                 break;
 117         case PIPE_ISOCHRONOUS:
 118                 dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
 119                 ret = -ENOTSUPP;
 120                 break;
 121         case PIPE_CONTROL:
 122         case PIPE_BULK:
 123         default:
 124                 ret = asl_urb_enqueue(whc, urb, mem_flags);
 125                 break;
 126         }
 127 
 128         return ret;
 129 }
 130 
 131 /*
 132  * Remove a queued URB from the ASL or PZL.
 133  */
 134 static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
 135 {
 136         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 137         struct whc *whc = wusbhc_to_whc(wusbhc);
 138         int ret;
 139 
 140         switch (usb_pipetype(urb->pipe)) {
 141         case PIPE_INTERRUPT:
 142                 ret = pzl_urb_dequeue(whc, urb, status);
 143                 break;
 144         case PIPE_ISOCHRONOUS:
 145                 ret = -ENOTSUPP;
 146                 break;
 147         case PIPE_CONTROL:
 148         case PIPE_BULK:
 149         default:
 150                 ret = asl_urb_dequeue(whc, urb, status);
 151                 break;
 152         }
 153 
 154         return ret;
 155 }
 156 
 157 /*
 158  * Wait for all URBs to the endpoint to be completed, then delete the
 159  * qset.
 160  */
 161 static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
 162                                  struct usb_host_endpoint *ep)
 163 {
 164         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 165         struct whc *whc = wusbhc_to_whc(wusbhc);
 166         struct whc_qset *qset;
 167 
 168         qset = ep->hcpriv;
 169         if (qset) {
 170                 ep->hcpriv = NULL;
 171                 if (usb_endpoint_xfer_bulk(&ep->desc)
 172                     || usb_endpoint_xfer_control(&ep->desc))
 173                         asl_qset_delete(whc, qset);
 174                 else
 175                         pzl_qset_delete(whc, qset);
 176         }
 177 }
 178 
 179 static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
 180                                struct usb_host_endpoint *ep)
 181 {
 182         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 183         struct whc *whc = wusbhc_to_whc(wusbhc);
 184         struct whc_qset *qset;
 185         unsigned long flags;
 186 
 187         spin_lock_irqsave(&whc->lock, flags);
 188 
 189         qset = ep->hcpriv;
 190         if (qset) {
 191                 qset->remove = 1;
 192                 qset->reset = 1;
 193 
 194                 if (usb_endpoint_xfer_bulk(&ep->desc)
 195                     || usb_endpoint_xfer_control(&ep->desc))
 196                         queue_work(whc->workqueue, &whc->async_work);
 197                 else
 198                         queue_work(whc->workqueue, &whc->periodic_work);
 199         }
 200 
 201         spin_unlock_irqrestore(&whc->lock, flags);
 202 }
 203 
 204 
 205 static const struct hc_driver whc_hc_driver = {
 206         .description = "whci-hcd",
 207         .product_desc = "Wireless host controller",
 208         .hcd_priv_size = sizeof(struct whc) - sizeof(struct usb_hcd),
 209         .irq = whc_int_handler,
 210         .flags = HCD_USB2,
 211 
 212         .reset = whc_reset,
 213         .start = whc_start,
 214         .stop = whc_stop,
 215         .get_frame_number = whc_get_frame_number,
 216         .urb_enqueue = whc_urb_enqueue,
 217         .urb_dequeue = whc_urb_dequeue,
 218         .endpoint_disable = whc_endpoint_disable,
 219         .endpoint_reset = whc_endpoint_reset,
 220 
 221         .hub_status_data = wusbhc_rh_status_data,
 222         .hub_control = wusbhc_rh_control,
 223         .start_port_reset = wusbhc_rh_start_port_reset,
 224 };
 225 
 226 static int whc_probe(struct umc_dev *umc)
 227 {
 228         int ret;
 229         struct usb_hcd *usb_hcd;
 230         struct wusbhc *wusbhc;
 231         struct whc *whc;
 232         struct device *dev = &umc->dev;
 233 
 234         usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci");
 235         if (usb_hcd == NULL) {
 236                 dev_err(dev, "unable to create hcd\n");
 237                 return -ENOMEM;
 238         }
 239 
 240         usb_hcd->wireless = 1;
 241         usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */
 242 
 243         wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 244         whc = wusbhc_to_whc(wusbhc);
 245         whc->umc = umc;
 246 
 247         ret = whc_init(whc);
 248         if (ret)
 249                 goto error_whc_init;
 250 
 251         wusbhc->dev = dev;
 252         wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent);
 253         if (!wusbhc->uwb_rc) {
 254                 ret = -ENODEV;
 255                 dev_err(dev, "cannot get radio controller\n");
 256                 goto error_uwb_rc;
 257         }
 258 
 259         if (whc->n_devices > USB_MAXCHILDREN) {
 260                 dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n",
 261                          whc->n_devices);
 262                 wusbhc->ports_max = USB_MAXCHILDREN;
 263         } else
 264                 wusbhc->ports_max = whc->n_devices;
 265         wusbhc->mmcies_max      = whc->n_mmc_ies;
 266         wusbhc->start           = whc_wusbhc_start;
 267         wusbhc->stop            = whc_wusbhc_stop;
 268         wusbhc->mmcie_add       = whc_mmcie_add;
 269         wusbhc->mmcie_rm        = whc_mmcie_rm;
 270         wusbhc->dev_info_set    = whc_dev_info_set;
 271         wusbhc->bwa_set         = whc_bwa_set;
 272         wusbhc->set_num_dnts    = whc_set_num_dnts;
 273         wusbhc->set_ptk         = whc_set_ptk;
 274         wusbhc->set_gtk         = whc_set_gtk;
 275 
 276         ret = wusbhc_create(wusbhc);
 277         if (ret)
 278                 goto error_wusbhc_create;
 279 
 280         ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED);
 281         if (ret) {
 282                 dev_err(dev, "cannot add HCD: %d\n", ret);
 283                 goto error_usb_add_hcd;
 284         }
 285         device_wakeup_enable(usb_hcd->self.controller);
 286 
 287         ret = wusbhc_b_create(wusbhc);
 288         if (ret) {
 289                 dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret);
 290                 goto error_wusbhc_b_create;
 291         }
 292 
 293         whc_dbg_init(whc);
 294 
 295         return 0;
 296 
 297 error_wusbhc_b_create:
 298         usb_remove_hcd(usb_hcd);
 299 error_usb_add_hcd:
 300         wusbhc_destroy(wusbhc);
 301 error_wusbhc_create:
 302         uwb_rc_put(wusbhc->uwb_rc);
 303 error_uwb_rc:
 304         whc_clean_up(whc);
 305 error_whc_init:
 306         usb_put_hcd(usb_hcd);
 307         return ret;
 308 }
 309 
 310 
 311 static void whc_remove(struct umc_dev *umc)
 312 {
 313         struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev);
 314         struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 315         struct whc *whc = wusbhc_to_whc(wusbhc);
 316 
 317         if (usb_hcd) {
 318                 whc_dbg_clean_up(whc);
 319                 wusbhc_b_destroy(wusbhc);
 320                 usb_remove_hcd(usb_hcd);
 321                 wusbhc_destroy(wusbhc);
 322                 uwb_rc_put(wusbhc->uwb_rc);
 323                 whc_clean_up(whc);
 324                 usb_put_hcd(usb_hcd);
 325         }
 326 }
 327 
 328 static struct umc_driver whci_hc_driver = {
 329         .name =         "whci-hcd",
 330         .cap_id =       UMC_CAP_ID_WHCI_WUSB_HC,
 331         .probe =        whc_probe,
 332         .remove =       whc_remove,
 333 };
 334 
 335 static int __init whci_hc_driver_init(void)
 336 {
 337         return umc_driver_register(&whci_hc_driver);
 338 }
 339 module_init(whci_hc_driver_init);
 340 
 341 static void __exit whci_hc_driver_exit(void)
 342 {
 343         umc_driver_unregister(&whci_hc_driver);
 344 }
 345 module_exit(whci_hc_driver_exit);
 346 
 347 /* PCI device ID's that we handle (so it gets loaded) */
 348 static struct pci_device_id __used whci_hcd_id_table[] = {
 349         { PCI_DEVICE_CLASS(PCI_CLASS_WIRELESS_WHCI, ~0) },
 350         { /* empty last entry */ }
 351 };
 352 MODULE_DEVICE_TABLE(pci, whci_hcd_id_table);
 353 
 354 MODULE_DESCRIPTION("WHCI Wireless USB host controller driver");
 355 MODULE_AUTHOR("Cambridge Silicon Radio Ltd.");
 356 MODULE_LICENSE("GPL");

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