Esempio n. 1
0
/*
 * Start the wireless host controller.
 *
 * Start device notification.
 *
 * Put hc into run state, set DNTS parameters.
 */
static int whc_start(struct usb_hcd *usb_hcd)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u8 bcid;
	int ret;

	mutex_lock(&wusbhc->mutex);

	le_writel(WUSBINTR_GEN_CMD_DONE
		  | WUSBINTR_HOST_ERR
		  | WUSBINTR_ASYNC_SCHED_SYNCED
		  | WUSBINTR_DNTS_INT
		  | WUSBINTR_ERR_INT
		  | WUSBINTR_INT,
		  whc->base + WUSBINTR);

	/* set cluster ID */
	bcid = wusb_cluster_id_get();
	ret = whc_set_cluster_id(whc, bcid);
	if (ret < 0)
		goto out;
	wusbhc->cluster_id = bcid;

	/* start HC */
	whc_write_wusbcmd(whc, WUSBCMD_RUN, WUSBCMD_RUN);

	usb_hcd->uses_new_polling = 1;
	set_bit(HCD_FLAG_POLL_RH, &usb_hcd->flags);
	usb_hcd->state = HC_STATE_RUNNING;

out:
	mutex_unlock(&wusbhc->mutex);
	return ret;
}
Esempio n. 2
0
irqreturn_t whc_int_handler(struct usb_hcd *hcd)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 sts;

	sts = le_readl(whc->base + WUSBSTS);
	if (!(sts & WUSBSTS_INT_MASK))
		return IRQ_NONE;
	le_writel(sts & WUSBSTS_INT_MASK, whc->base + WUSBSTS);

	if (sts & WUSBSTS_GEN_CMD_DONE)
		wake_up(&whc->cmd_wq);

	if (sts & WUSBSTS_HOST_ERR)
		dev_err(&whc->umc->dev, "FIXME: host system error\n");

	if (sts & WUSBSTS_ASYNC_SCHED_SYNCED)
		wake_up(&whc->async_list_wq);

	if (sts & WUSBSTS_PERIODIC_SCHED_SYNCED)
		wake_up(&whc->periodic_list_wq);

	if (sts & WUSBSTS_DNTS_INT)
		queue_work(whc->workqueue, &whc->dn_work);

	
	if (sts & (WUSBSTS_INT | WUSBSTS_ERR_INT))
		transfer_done(whc);

	return IRQ_HANDLED;
}
int whc_bwa_set(struct wusbhc *wusbhc, s8 stream_index, const struct uwb_mas_bm *mas_bm)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);

	if (stream_index >= 0)
		whc_write_wusbcmd(whc, WUSBCMD_WUSBSI_MASK, WUSBCMD_WUSBSI(stream_index));

	return whc_do_gencmd(whc, WUSBGENCMDSTS_SET_MAS, 0, (void *)mas_bm, sizeof(*mas_bm));
}
int whc_mmcie_rm(struct wusbhc *wusbhc, u8 handle)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 params;

	params = handle;

	return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_RM, params, NULL, 0);
}
int whc_wusbhc_start(struct wusbhc *wusbhc)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);

	asl_start(whc);
	pzl_start(whc);

	return 0;
}
/*
 * Set the number of Device Notification Time Slots (DNTS) and enable
 * device notifications.
 */
int whc_set_num_dnts(struct wusbhc *wusbhc, u8 interval, u8 slots)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 dntsctrl;

	dntsctrl = WUSBDNTSCTRL_ACTIVE
		| WUSBDNTSCTRL_INTERVAL(interval)
		| WUSBDNTSCTRL_SLOTS(slots);

	le_writel(dntsctrl, whc->base + WUSBDNTSCTRL);

	return 0;
}
int whc_mmcie_add(struct wusbhc *wusbhc, u8 interval, u8 repeat_cnt,
		  u8 handle, struct wuie_hdr *wuie)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 params;

	params = (interval << 24)
		| (repeat_cnt << 16)
		| (wuie->bLength << 8)
		| handle;

	return whc_do_gencmd(whc, WUSBGENCMDSTS_MMCIE_ADD, params, wuie, wuie->bLength);
}
/**
 * whc_set_gtk - set the GTK for subsequent broadcast packets
 *
 * The GTK is stored in the last entry in the key table (the previous
 * N_DEVICES entries are for the per-device PTKs).
 */
int whc_set_gtk(struct wusbhc *wusbhc, u32 tkid,
		const void *gtk, size_t key_size)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	int ret;

	mutex_lock(&whc->mutex);

	ret = whc_set_key(whc, whc->n_devices, tkid, gtk, key_size, true);

	mutex_unlock(&whc->mutex);

	return ret;
}
void whc_wusbhc_stop(struct wusbhc *wusbhc, int delay)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	u32 stop_time, now_time;
	int ret;

	pzl_stop(whc);
	asl_stop(whc);

	now_time = le_readl(whc->base + WUSBTIME) & WUSBTIME_CHANNEL_TIME_MASK;
	stop_time = (now_time + ((delay * 8) << 7)) & 0x00ffffff;
	ret = whc_do_gencmd(whc, WUSBGENCMDSTS_CHAN_STOP, stop_time, NULL, 0);
	if (ret == 0)
		msleep(delay);
}
Esempio n. 10
0
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);
	}
}
Esempio n. 11
0
/*
 * Wait for all URBs to the endpoint to be completed, then delete the
 * qset.
 */
static void whc_endpoint_disable(struct usb_hcd *usb_hcd,
				 struct usb_host_endpoint *ep)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	struct whc_qset *qset;

	qset = ep->hcpriv;
	if (qset) {
		ep->hcpriv = NULL;
		if (usb_endpoint_xfer_bulk(&ep->desc)
		    || usb_endpoint_xfer_control(&ep->desc))
			asl_qset_delete(whc, qset);
		else
			pzl_qset_delete(whc, qset);
	}
}
Esempio n. 12
0
/*
 * Stop the wireless host controller.
 *
 * Stop device notification.
 *
 * Wait for pending transfer to stop? Put hc into stop state?
 */
static void whc_stop(struct usb_hcd *usb_hcd)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);

	mutex_lock(&wusbhc->mutex);

	/* stop HC */
	le_writel(0, whc->base + WUSBINTR);
	whc_write_wusbcmd(whc, WUSBCMD_RUN, 0);
	whci_wait_for(&whc->umc->dev, whc->base + WUSBSTS,
		      WUSBSTS_HCHALTED, WUSBSTS_HCHALTED,
		      100, "HC to halt");

	wusb_cluster_id_put(wusbhc->cluster_id);

	mutex_unlock(&wusbhc->mutex);
}
Esempio n. 13
0
int whc_dev_info_set(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	int idx = wusb_dev->port_idx;
	struct di_buf_entry *di = &whc->di_buf[idx];
	int ret;

	mutex_lock(&whc->mutex);

	uwb_mas_bm_copy_le(di->availability_info, &wusb_dev->availability);
	di->addr_sec_info &= ~(WHC_DI_DISABLE | WHC_DI_DEV_ADDR_MASK);
	di->addr_sec_info |= WHC_DI_DEV_ADDR(wusb_dev->addr);

	ret = whc_update_di(whc, idx);

	mutex_unlock(&whc->mutex);

	return ret;
}
Esempio n. 14
0
/*
 * Remove a queued URB from the ASL or PZL.
 */
static int whc_urb_dequeue(struct usb_hcd *usb_hcd, struct urb *urb, int status)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	int ret;

	switch (usb_pipetype(urb->pipe)) {
	case PIPE_INTERRUPT:
		ret = pzl_urb_dequeue(whc, urb, status);
		break;
	case PIPE_ISOCHRONOUS:
		ret = -ENOTSUPP;
		break;
	case PIPE_CONTROL:
	case PIPE_BULK:
	default:
		ret = asl_urb_dequeue(whc, urb, status);
		break;
	};

	return ret;
}
Esempio n. 15
0
static void whc_endpoint_reset(struct usb_hcd *usb_hcd,
			       struct usb_host_endpoint *ep)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	struct whc_qset *qset;
	unsigned long flags;

	spin_lock_irqsave(&whc->lock, flags);

	qset = ep->hcpriv;
	if (qset) {
		qset->remove = 1;
		qset->reset = 1;

		if (usb_endpoint_xfer_bulk(&ep->desc)
		    || usb_endpoint_xfer_control(&ep->desc))
			queue_work(whc->workqueue, &whc->async_work);
		else
			queue_work(whc->workqueue, &whc->periodic_work);
	}

	spin_unlock_irqrestore(&whc->lock, flags);
}
Esempio n. 16
0
/*
 * Queue an URB to the ASL or PZL
 */
static int whc_urb_enqueue(struct usb_hcd *usb_hcd, struct urb *urb,
			   gfp_t mem_flags)
{
	struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
	struct whc *whc = wusbhc_to_whc(wusbhc);
	int ret;

	switch (usb_pipetype(urb->pipe)) {
	case PIPE_INTERRUPT:
		ret = pzl_urb_enqueue(whc, urb, mem_flags);
		break;
	case PIPE_ISOCHRONOUS:
		dev_err(&whc->umc->dev, "isochronous transfers unsupported\n");
		ret = -ENOTSUPP;
		break;
	case PIPE_CONTROL:
	case PIPE_BULK:
	default:
		ret = asl_urb_enqueue(whc, urb, mem_flags);
		break;
	};

	return ret;
}
Esempio n. 17
0
/**
 * whc_set_ptk - set the PTK to use for a device.
 *
 * The index into the key table for this PTK is the same as the
 * device's port index.
 */
int whc_set_ptk(struct wusbhc *wusbhc, u8 port_idx, u32 tkid,
		const void *ptk, size_t key_size)
{
	struct whc *whc = wusbhc_to_whc(wusbhc);
	struct di_buf_entry *di = &whc->di_buf[port_idx];
	int ret;

	mutex_lock(&whc->mutex);

	if (ptk) {
		ret = whc_set_key(whc, port_idx, tkid, ptk, key_size, false);
		if (ret)
			goto out;

		di->addr_sec_info &= ~WHC_DI_KEY_IDX_MASK;
		di->addr_sec_info |= WHC_DI_SECURE | WHC_DI_KEY_IDX(port_idx);
	} else
		di->addr_sec_info &= ~WHC_DI_SECURE;

	ret = whc_update_di(whc, port_idx);
out:
	mutex_unlock(&whc->mutex);
	return ret;
}
Esempio n. 18
0
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;
}