static void whc_remove(struct umc_dev *umc) { struct usb_hcd *usb_hcd = dev_get_drvdata(&umc->dev); struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd); struct whc *whc = wusbhc_to_whc(wusbhc); if (usb_hcd) { whc_dbg_clean_up(whc); wusbhc_b_destroy(wusbhc); usb_remove_hcd(usb_hcd); wusbhc_destroy(wusbhc); uwb_rc_put(wusbhc->uwb_rc); whc_clean_up(whc); usb_put_hcd(usb_hcd); } }
int whc_init(struct whc *whc) { u32 whcsparams; int ret, i; resource_size_t start, len; spin_lock_init(&whc->lock); mutex_init(&whc->mutex); init_waitqueue_head(&whc->cmd_wq); init_waitqueue_head(&whc->async_list_wq); init_waitqueue_head(&whc->periodic_list_wq); whc->workqueue = alloc_ordered_workqueue(dev_name(&whc->umc->dev), 0); if (whc->workqueue == NULL) { ret = -ENOMEM; goto error; } INIT_WORK(&whc->dn_work, whc_dn_work); INIT_WORK(&whc->async_work, scan_async_work); INIT_LIST_HEAD(&whc->async_list); INIT_LIST_HEAD(&whc->async_removed_list); INIT_WORK(&whc->periodic_work, scan_periodic_work); for (i = 0; i < 5; i++) INIT_LIST_HEAD(&whc->periodic_list[i]); INIT_LIST_HEAD(&whc->periodic_removed_list); /* Map HC registers. */ start = whc->umc->resource.start; len = whc->umc->resource.end - start + 1; if (!request_mem_region(start, len, "whci-hc")) { dev_err(&whc->umc->dev, "can't request HC region\n"); ret = -EBUSY; goto error; } whc->base_phys = start; whc->base = ioremap(start, len); if (!whc->base) { dev_err(&whc->umc->dev, "ioremap\n"); ret = -ENOMEM; goto error; } whc_hw_reset(whc); /* Read maximum number of devices, keys and MMC IEs. */ whcsparams = le_readl(whc->base + WHCSPARAMS); whc->n_devices = WHCSPARAMS_TO_N_DEVICES(whcsparams); whc->n_keys = WHCSPARAMS_TO_N_KEYS(whcsparams); whc->n_mmc_ies = WHCSPARAMS_TO_N_MMC_IES(whcsparams); dev_dbg(&whc->umc->dev, "N_DEVICES = %d, N_KEYS = %d, N_MMC_IES = %d\n", whc->n_devices, whc->n_keys, whc->n_mmc_ies); whc->qset_pool = dma_pool_create("qset", &whc->umc->dev, sizeof(struct whc_qset), 64, 0); if (whc->qset_pool == NULL) { ret = -ENOMEM; goto error; } ret = asl_init(whc); if (ret < 0) goto error; ret = pzl_init(whc); if (ret < 0) goto error; /* Allocate and initialize a buffer for generic commands, the Device Information buffer, and the Device Notification buffer. */ whc->gen_cmd_buf = dma_alloc_coherent(&whc->umc->dev, WHC_GEN_CMD_DATA_LEN, &whc->gen_cmd_buf_dma, GFP_KERNEL); if (whc->gen_cmd_buf == NULL) { ret = -ENOMEM; goto error; } whc->dn_buf = dma_alloc_coherent(&whc->umc->dev, sizeof(struct dn_buf_entry) * WHC_N_DN_ENTRIES, &whc->dn_buf_dma, GFP_KERNEL); if (!whc->dn_buf) { ret = -ENOMEM; goto error; } whc_hw_init_dn_buf(whc); whc->di_buf = dma_alloc_coherent(&whc->umc->dev, sizeof(struct di_buf_entry) * whc->n_devices, &whc->di_buf_dma, GFP_KERNEL); if (!whc->di_buf) { ret = -ENOMEM; goto error; } whc_hw_init_di_buf(whc); return 0; error: whc_clean_up(whc); return ret; }
static int whc_probe(struct umc_dev *umc) { int ret = -ENOMEM; struct usb_hcd *usb_hcd; struct wusbhc *wusbhc = NULL; struct whc *whc = NULL; struct device *dev = &umc->dev; usb_hcd = usb_create_hcd(&whc_hc_driver, dev, "whci"); if (usb_hcd == NULL) { dev_err(dev, "unable to create hcd\n"); goto error; } usb_hcd->wireless = 1; usb_hcd->self.sg_tablesize = 2048; /* somewhat arbitrary */ wusbhc = usb_hcd_to_wusbhc(usb_hcd); whc = wusbhc_to_whc(wusbhc); whc->umc = umc; ret = whc_init(whc); if (ret) goto error; wusbhc->dev = dev; wusbhc->uwb_rc = uwb_rc_get_by_grandpa(umc->dev.parent); if (!wusbhc->uwb_rc) { ret = -ENODEV; dev_err(dev, "cannot get radio controller\n"); goto error; } if (whc->n_devices > USB_MAXCHILDREN) { dev_warn(dev, "USB_MAXCHILDREN too low for WUSB adapter (%u ports)\n", whc->n_devices); wusbhc->ports_max = USB_MAXCHILDREN; } else wusbhc->ports_max = whc->n_devices; wusbhc->mmcies_max = whc->n_mmc_ies; wusbhc->start = whc_wusbhc_start; wusbhc->stop = whc_wusbhc_stop; wusbhc->mmcie_add = whc_mmcie_add; wusbhc->mmcie_rm = whc_mmcie_rm; wusbhc->dev_info_set = whc_dev_info_set; wusbhc->bwa_set = whc_bwa_set; wusbhc->set_num_dnts = whc_set_num_dnts; wusbhc->set_ptk = whc_set_ptk; wusbhc->set_gtk = whc_set_gtk; ret = wusbhc_create(wusbhc); if (ret) goto error_wusbhc_create; ret = usb_add_hcd(usb_hcd, whc->umc->irq, IRQF_SHARED); if (ret) { dev_err(dev, "cannot add HCD: %d\n", ret); goto error_usb_add_hcd; } ret = wusbhc_b_create(wusbhc); if (ret) { dev_err(dev, "WUSBHC phase B setup failed: %d\n", ret); goto error_wusbhc_b_create; } whc_dbg_init(whc); return 0; error_wusbhc_b_create: usb_remove_hcd(usb_hcd); error_usb_add_hcd: wusbhc_destroy(wusbhc); error_wusbhc_create: uwb_rc_put(wusbhc->uwb_rc); error: whc_clean_up(whc); if (usb_hcd) usb_put_hcd(usb_hcd); return ret; }