예제 #1
0
int cw1200_core_probe(const struct sbus_ops *sbus_ops,
		      struct sbus_priv *sbus,
		      struct device *pdev,
		      struct cw1200_common **pself,
		      u8 *mac_addr)
{
	int err = -ENOMEM;
	u16 ctrl_reg;
	struct ieee80211_hw *dev;
	struct cw1200_common *priv;
	struct wsm_operational_mode mode = {
		.power_mode = wsm_power_mode_quiescent,
		.disableMoreFlagUsage = true,
	};

	dev = cw1200_init_common(sizeof(struct cw1200_common), mac_addr);
	if (!dev)
		goto err;

	priv = dev->priv;

	priv->sbus_ops = sbus_ops;
	priv->sbus_priv = sbus;
	priv->pdev = pdev;
	SET_IEEE80211_DEV(priv->hw, pdev);

	/* WSM callbacks. */
	priv->wsm_cbc.scan_complete = cw1200_scan_complete_cb;
	priv->wsm_cbc.tx_confirm = cw1200_tx_confirm_cb;
	priv->wsm_cbc.rx = cw1200_rx_cb;
	priv->wsm_cbc.suspend_resume = cw1200_suspend_resume;
	/* priv->wsm_cbc.set_pm_complete = cw1200_set_pm_complete_cb; */
	priv->wsm_cbc.channel_switch = cw1200_channel_switch_cb;

	err = cw1200_register_bh(priv);
	if (err)
		goto err1;

	err = cw1200_load_firmware(priv);
	if (err)
		goto err2;
	priv->sbus_ops->lock(priv->sbus_priv);
	WARN_ON(priv->sbus_ops->set_block_size(priv->sbus_priv,
			SDIO_BLOCK_SIZE));
	priv->sbus_ops->unlock(priv->sbus_priv);

	if (wait_event_interruptible_timeout(priv->wsm_startup_done,
				priv->wsm_caps.firmwareReady, 3*HZ) <= 0) {
		/* TODO: Needs to find how to reset device */
		/*       in QUEUE mode properly.           */
		goto err3;
	}

	WARN_ON(cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
					ST90TDS_CONT_WUP_BIT));

	if (cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg))
		WARN_ON(cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID,
						&ctrl_reg));


	WARN_ON(!(ctrl_reg & ST90TDS_CONT_RDY_BIT));

	/* Set low-power mode. */
	WARN_ON(wsm_set_operational_mode(priv, &mode));

	/* Enable multi-TX confirmation */
	WARN_ON(wsm_use_multi_tx_conf(priv, true));

	err = cw1200_register_common(dev);
	if (err) {
		priv->sbus_ops->irq_unsubscribe(priv->sbus_priv);
		goto err3;
	}

	*pself = dev->priv;
	return err;

err3:
	sbus_ops->reset(sbus);
err2:
	cw1200_unregister_bh(priv);
err1:
	cw1200_free_common(dev);
err:
	return err;
}
EXPORT_SYMBOL_GPL(cw1200_core_probe);

void cw1200_core_release(struct cw1200_common *self)
{
	cw1200_unregister_common(self->hw);
	cw1200_free_common(self->hw);
	return;
}
예제 #2
0
int cw1200_core_start(struct cw1200_common *priv)
{
	int err = -EINVAL;
	u16 ctrl_reg;
	struct wsm_operational_mode mode = {
		.power_mode = wsm_power_mode_quiescent,
		.disableMoreFlagUsage = true,
	};

	/* Power on HW */
	err = priv->sbus_ops->power_up(priv->sbus_priv);
	if (WARN_ON(err))
		goto err1;

	err = cw1200_register_bh(priv);
	if (WARN_ON(err))
		goto err2;

	/* Before loading fw block size has to be 512B */
	priv->sbus_ops->lock(priv->sbus_priv);
	err = priv->sbus_ops->set_block_size(priv->sbus_priv, 512);
	priv->sbus_ops->unlock(priv->sbus_priv);
	if (err)
		goto err2;

	err = cw1200_load_firmware(priv);
	if (err)
		goto err2;

	/* device is up now */
	atomic_set(&priv->hw_state, 1);

	priv->sbus_ops->lock(priv->sbus_priv);
	err = priv->sbus_ops->set_block_size(priv->sbus_priv, SDIO_BLOCK_SIZE);
	priv->sbus_ops->unlock(priv->sbus_priv);
	if (err)
		goto err2;

	if (wait_event_interruptible_timeout(priv->wsm_startup_done,
				priv->wsm_caps.firmwareReady, 3*HZ) <= 0) {
		/* TODO: Needs to find how to reset device */
		/*       in QUEUE mode properly.           */
		goto err2;
	}

	WARN_ON(cw1200_reg_write_16(priv, ST90TDS_CONTROL_REG_ID,
					ST90TDS_CONT_WUP_BIT));

	if (cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID, &ctrl_reg))
		WARN_ON(cw1200_reg_read_16(priv,ST90TDS_CONTROL_REG_ID,
							&ctrl_reg));

	WARN_ON(!(ctrl_reg & ST90TDS_CONT_RDY_BIT));

	/* Set low-power mode. */
	WARN_ON(wsm_set_operational_mode(priv, &mode));

	/* Enable multi-TX confirmation */
	WARN_ON(wsm_use_multi_tx_conf(priv, true));

	return 0;

err2:
	cw1200_unregister_bh(priv);
	atomic_set(&priv->hw_state, 0);

err1:
	priv->sbus_ops->power_down(priv->sbus_priv);

	return err;
}

static void cw1200_common_cleanup(struct cw1200_common *priv)
{
	tx_policy_clean(priv);

	/* TODO: what else ?? */
	priv->wsm_rx_seq = 0;
	priv->wsm_tx_seq = 0;
}