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