コード例 #1
0
static void handle_thp_avl_msg(struct sqn_private *priv
	, struct sqn_lsp_packet *lsp)
{
	struct sqn_sdio_card *card = priv->card;
	struct sk_buff *skb_reply = 0;
	enum sqn_thp_available_reply thp_rpl; 
	unsigned long irq_flags = 0;

	sqn_pr_enter();

	spin_lock_irqsave(&priv->drv_lock, irq_flags);
	/* if (card->is_card_sleeps) { */
	if (priv->is_tx_queue_empty(priv)) {
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX queue empty, thp_rpl=FINISH\n");
		}
		/* sqn_pr_dbg("card was asleep, thp_rpl=FINISH\n"); */
		thp_rpl = LSP_THPA_FINISHED;
		card->is_card_sleeps = 1;
		gHostWakeupFWEvent = 0;
	/* } else if (priv->is_tx_queue_empty(priv)) { */
		/* sqn_pr_dbg("card was not asleep and tx_queue is empty, thp_rpl=FINISHED\n"); */
		/* thp_rpl = LSP_THPA_FINISHED; */
		/* card->is_card_sleeps = 1; */
	} else {
		/* sqn_pr_info("card was not asleep but tx_queue is no empty, thp_rpl=EXIT\n"); */
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX queue not empty, thp_rpl=ACK\n");
		}
		/* sqn_pr_dbg("card was not asleep, thp_rpl=ACK\n"); */
		thp_rpl = LSP_THPA_ACK;
		card->is_card_sleeps = 0;
	}
	spin_unlock_irqrestore(&priv->drv_lock, irq_flags);
	skb_reply = construct_lsp_packet(THSP_THP_AVAILABLE_REPLY
			, ntohl(lsp->lsp_header.u.thp_avl.tid)
			, thp_rpl);
	if (0 != (skb_reply = sqn_sdio_prepare_skb_for_tx(skb_reply)))
		sqn_sdio_tx_skb(card, skb_reply, 0);
	wake_up_interruptible(&g_card_sleep_waitq);
	if (netif_queue_stopped(priv->dev))
		netif_wake_queue(priv->dev);

	if (!card->is_card_sleeps && !gHostWakeupFWEvent) {
		gHostWakeupFWEvent = 1; // Dump next TX packet after LSP ThpAvailableReply(ACK);
	}

	sqn_pr_leave();
}
コード例 #2
0
int sqn_handle_lsp_packet(struct sqn_private *priv
	, struct sk_buff *skb)
{
	struct sqn_sdio_card *card = priv->card;
	unsigned long irq_flags = 0;
	struct sqn_lsp_packet *lsp_response = (struct sqn_lsp_packet*)
		((u8*)skb->data + sizeof(struct sqn_eth_header));

	sqn_pr_enter();

	if (!sqn_is_rx_lsp_packet(skb)) {
		sqn_pr_dbg("not LSP packet\n");
		sqn_pr_leave();
		return 0;
	}

	sqn_pr_dbg("LSP packet\n");

	switch (ntohl(lsp_response->lsp_header.id)) {
	case THSP_GET_MEDIA_CONNECTION_STATE:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_GET_MEDIA_CONNECTION_STATE state=%xh\n"
				, ntohl(lsp_response->lsp_header.u.media_con_state));
		}
		sqn_pr_warn("THSP_GET_MEDIA_CONNECTION_STATE not implemented\n");
		break;
	case THSP_MEDIA_CONNECTION_STATE_CHANGE:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_MEDIA_CONNECTION_STATE_CHANGE state=%xh\n"
				, ntohl(lsp_response->lsp_header.u.media_con_state));
		}
		if (THSP_MEDIA_CONNECTION_ATTACHED
			== ntohl(lsp_response->lsp_header.u.media_con_state))
		{

#if IGNORE_CARRIER_STATE
            /* netif_carrier_on(priv->dev); */
            sqn_pr_info("WiMAX carrier PRESENT [ignored]\n");
#else
            netif_carrier_on(priv->dev);
			sqn_pr_info("WiMAX carrier PRESENT\n");
#endif
		} else {
#if IGNORE_CARRIER_STATE
			/* netif_carrier_off(priv->dev); */
			sqn_pr_info("WiMAX carrier LOST [ignored]\n");
#else
			netif_carrier_off(priv->dev);
			sqn_pr_info("WiMAX carrier LOST\n");
#endif
		}
		break;
	case THSP_SET_HOST_POWER_MODE_ACK:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_SET_HOST_POWER_MODE_ACK tid=0x%x\n"
				, ntohl(lsp_response->lsp_header.u.host_power.tid));
		}
		free_last_request();
		spin_lock_irqsave(&priv->drv_lock, irq_flags);
		card->is_card_sleeps = 1;
		spin_unlock_irqrestore(&priv->drv_lock, irq_flags);
		signal_pm_request_completion(priv);
		break;
	case THSP_SET_FW_POWER_MODE_ACK:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_SET_FW_POWER_MODE_ACK tid=0x%x\n"
				, ntohl(lsp_response->lsp_header.u.fw_power.tid));
		}
		sqn_pr_info("THSP_SET_FW_POWER_MODE_ACK not implemented\n");
		break;
	case THSP_SQN_STATE_CHANGE:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_SQN_STATE_CHANGE tid=0x%x, state=%xh\n"
				, ntohl(lsp_response->lsp_header.u.fw_state.tid)
				, ntohl(lsp_response->lsp_header.u.fw_state.state));
		}
		handle_sqn_state_change_msg(priv, lsp_response);
		break;
	case THSP_THP_AVAILABLE:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: THSP_THP_AVAILABLE tid=0x%x, reply=%xh\n"
				, ntohl(lsp_response->lsp_header.u.thp_avl.tid)
				, ntohl(lsp_response->lsp_header.u.thp_avl.reply));
		}
		handle_thp_avl_msg(priv, lsp_response);
		break;
	default:
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("RX LSP: UNKNOWN=0x%x\n"
				, ntohl(lsp_response->lsp_header.id));
		}
	}

	dev_kfree_skb_any(skb);
	sqn_pr_leave();

	return 1;
}
コード例 #3
0
static struct sk_buff *lsp_to_skb(struct sqn_lsp_packet *lsp_packet) /* RX */
{
	struct sqn_eth_header eth_header = {
		.len = htons(sizeof(struct sqn_lsp_packet))
	};

	struct sk_buff *skb =
		__dev_alloc_skb(sizeof(eth_header) + sizeof(struct sqn_lsp_packet)
				, GFP_ATOMIC | GFP_DMA);

	sqn_pr_enter();

	if (0 == skb)
		goto out;

	skb_reserve(skb, 2);

	memcpy(eth_header.dst_addr, g_lsp_device_mac, sizeof(g_lsp_device_mac));
	memcpy(eth_header.src_addr, g_lsp_host_mac, sizeof(g_lsp_host_mac));

	memcpy(skb->data, &eth_header, sizeof(eth_header));
	skb_put(skb, sizeof(eth_header));

	memcpy(skb->data + skb->len, lsp_packet, sizeof(struct sqn_lsp_packet));
	skb_put(skb, sizeof(struct sqn_lsp_packet));

	sqn_pr_leave();

out:
	return skb;

}


static struct sk_buff* construct_lsp_packet(u32 id, u32 param1, u32 param2)
{
	struct sqn_lsp_packet lsp_packet = {
		.thp_header = {
			.transport_version = 1
			, .flags = 1
			, .seq_number = 0
			, .ack_number = 0
		}
		, .lsp_header = {
			.id = htonl(id)
		}
	};

	struct sk_buff *skb = 0;

	sqn_pr_enter();

	switch (id) {
	case THSP_GET_MEDIA_CONNECTION_STATE:
		/* no parameters are needed */
		if (mmc_wimax_get_sdio_lsp_log())
			sqn_pr_info("TX LSP: THSP_GET_MEDIA_CONNECTION_STATE\n");
		lsp_packet.thp_header.length =
			htons(sizeof(struct sqn_lsp_header) - 4);
		lsp_packet.thp_header.total_length =
			htonl(sizeof(struct sqn_lsp_header) - 4);
		break;
	case THSP_SET_POWER_MODE:
		/* deprecated */
		if (mmc_wimax_get_sdio_lsp_log())
			sqn_pr_info("TX LSP: THSP_SET_POWER_MODE (deprecated)\n");
		break;
	case THSP_SET_HOST_POWER_MODE:
		lsp_packet.thp_header.length =
			htons(sizeof(struct sqn_lsp_header));
		lsp_packet.thp_header.total_length =
			htonl(sizeof(struct sqn_lsp_header));
		lsp_packet.lsp_header.u.host_power.tid = htonl(get_next_tid());
		lsp_packet.lsp_header.u.host_power.mode = htonl(param1);
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX LSP: THSP_SET_HOST_POWER_MODE, tid: 0x%x, mode: %d\n"
				, ntohl(lsp_packet.lsp_header.u.host_power.tid)
				, param1);
		}
		break;
	case THSP_SET_FW_POWER_MODE:
		lsp_packet.thp_header.length =
			htons(sizeof(struct sqn_lsp_header));
		lsp_packet.thp_header.total_length =
			htonl(sizeof(struct sqn_lsp_header));
		lsp_packet.lsp_header.u.fw_power.tid = htonl(get_next_tid());
		lsp_packet.lsp_header.u.fw_power.mode = htonl(param1);
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX LSP: THSP_SET_FW_POWER_MODE, tid: 0x%x, mode: %d\n"
				, htonl(lsp_packet.lsp_header.u.fw_power.tid)
				, param1);
		}
		break;
	case THSP_SQN_STATE_CHANGE_REPLY:
		lsp_packet.thp_header.length =
			htons(sizeof(struct sqn_lsp_header) - 4);
		lsp_packet.thp_header.total_length =
			htonl(sizeof(struct sqn_lsp_header) - 4);
		lsp_packet.lsp_header.u.fw_state.tid = htonl(param1);
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX LSP: THSP_SQN_STATE_CHANGE_REPLY, tid: %xh\n"
				, param1);
		}
		break;
	case THSP_THP_AVAILABLE_REPLY:
		lsp_packet.thp_header.length =
			htons(sizeof(struct sqn_lsp_header));
		lsp_packet.thp_header.total_length =
			htonl(sizeof(struct sqn_lsp_header));
		lsp_packet.lsp_header.u.thp_avl.tid = htonl(param1);
		lsp_packet.lsp_header.u.thp_avl.reply = htonl(param2);
		if (mmc_wimax_get_sdio_lsp_log()) {
			sqn_pr_info("TX LSP: THSP_THP_AVAILABLE_REPLY, tid: 0x%x, reply: %d\n"
				, param1, param2);
		}
		break;
	default:
		if (mmc_wimax_get_sdio_lsp_log())
			sqn_pr_info("TX LSP: UNKNOWN\n");
	}

	skb = lsp_to_skb(&lsp_packet);

	sqn_pr_leave();

	return skb;
}