Ejemplo n.º 1
0
/**
 * Push RX pdu for any modem command
 *
 */
static int dlp_ctrl_push_rx_pdu(struct dlp_channel *ch_ctx)
{
	int ret;
	struct hsi_msg *rx_msg;
	struct dlp_command *dlp_cmd;

	/* Allocate the DLP command */
	dlp_cmd = dlp_ctrl_cmd_alloc(ch_ctx, DLP_CMD_NOP, 0, 0, 0);
	if (!dlp_cmd) {
		pr_err(DRVNAME ": Out of memory (rx_pdu)\n");
		ret = -ENOMEM;
		goto out;
	}

	/* Allocate a new RX msg */
	rx_msg = dlp_pdu_alloc(DLP_CHANNEL_CTRL,
			       HSI_MSG_READ,
			       DLP_CTRL_RX_PDU_SIZE,
			       1,
			       dlp_cmd,
			       dlp_ctrl_complete_rx, dlp_ctrl_msg_destruct);

	if (!rx_msg) {
		pr_err(DRVNAME ": dlp_pdu_alloc() failed\n");
		ret = -ENOMEM;
		goto free_cmd;
	}

	/* Send the RX HSI msg */
	ret = hsi_async(rx_msg->cl, rx_msg);
	if (ret) {
		pr_err(DRVNAME ": RX push failed, ret:%d\n", ret);
		ret = -EIO;
		goto free_msg;
	}

	return 0;

free_msg:
	/* Free the msg */
	dlp_pdu_free(rx_msg, rx_msg->channel);

free_cmd:
	/* Delete the command */
	kfree(dlp_cmd);

out:
	return ret;
}
Ejemplo n.º 2
0
/*
 * Push RX pdu on channel 0
 *
 */
static int dlp_flash_push_rx_pdu(struct dlp_channel *ch_ctx)
{
	int ret;
	struct hsi_msg *rx_msg;

	PROLOG();

	/* Allocate a new RX msg */
	rx_msg = dlp_pdu_alloc(ch_ctx->hsi_channel,
				HSI_MSG_READ,
				DLP_FLASH_RX_PDU_SIZE,
				1,
				ch_ctx,
				dlp_flash_complete_rx,
				dlp_flash_msg_destruct_fix);

	if (!rx_msg) {
		CRITICAL("dlp_pdu_alloc(RX) failed");
		ret = -ENOMEM;
		goto out;
	}

	/* Send the RX HSI msg */
	ret = hsi_async(rx_msg->cl, rx_msg);
	if (ret) {
		CRITICAL("hsi_async() failed, ret:%d", ret);
		ret = -EIO;
		goto free_msg;
	}

	EPILOG();
	return 0;

free_msg:
	/* Free the msg */
	dlp_pdu_free(rx_msg, rx_msg->channel);

out:
	EPILOG();
	return ret;
}
/*
 * Push RX pdu on channel 0
 *
 */
static int dlp_trace_push_rx_pdu(struct dlp_channel *ch_ctx)
{
	int ret;
	struct hsi_msg *rx_msg;

	/* Allocate a new RX msg */
	rx_msg = dlp_pdu_alloc(ch_ctx->hsi_channel,
				HSI_MSG_READ,
				DLP_TRACE_RX_PDU_SIZE,
				1,
				ch_ctx,
				dlp_trace_complete_rx,
				dlp_trace_msg_destruct);

	if (!rx_msg) {
		pr_err(DRVNAME": dlp_pdu_alloc(RX) failed\n");
		ret = -ENOMEM;
		goto out;
	}

	/* Send the RX HSI msg */
	ret = hsi_async(rx_msg->cl, rx_msg);
	if (ret) {
		pr_err(DRVNAME": hsi_async() failed, ret:%d\n", ret);
		ret = -EIO;
		goto free_msg;
	}

	return 0;

free_msg:
	/* Free the msg */
	dlp_pdu_free(rx_msg, rx_msg->channel);

out:
	return ret;
}
Ejemplo n.º 4
0
/**
 * Send an HSI msg AND wait for the status
 *
 * @ch_ctx: a reference to the channel context to use
 * @id: the DLP command id
 * @response_id: the expected response id
 * @interm_state: the intermidiate state (to be set when TX is OK)
 * @final_state: the final state (to be set when RX (response) is OK)
 * @param1: the DLP command params
 * @param2: the DLP command params
 * @param3: the DLP command params
 *
 * This function blocks the caller until a response is received
 * or the timeout expires
 */
static int dlp_ctrl_cmd_send(struct dlp_channel *ch_ctx,
				unsigned char id,
				unsigned char response_id,
				unsigned char interm_state,
				unsigned char final_state,
				unsigned char param1,
				unsigned char param2, unsigned char param3)
{
	int ret = 0, old_state;
	struct dlp_ctrl_context *ctrl_ctx;
	struct dlp_command *dlp_cmd;
	struct dlp_command_params expected_resp;
	struct hsi_msg *tx_msg = NULL;

	/* Check the link readiness (TTY still opened) */
	if (!dlp_tty_is_link_valid()) {
		if (EDLP_CTRL_TX_DATA_REPORT)
			pr_debug(DRVNAME ": CH%d (HSI CH%d) cmd 0x%X ignored (close:%d, Time out: %d)\n",
					ch_ctx->ch_id, ch_ctx->hsi_channel,
					id, dlp_drv.tty_closed,
					dlp_drv.tx_timeout);

		return ret;
	}

	ctrl_ctx = DLP_CTRL_CTX;

	mutex_lock(&ch_ctx->tx.cmd_sync);

	/* Save the current channel state */
	old_state = dlp_ctrl_get_channel_state(ch_ctx->hsi_channel);

	/* Backup RX callback */
	dlp_save_rx_callbacks(&ctrl_ctx->ehandler);

	/* Allocate the DLP command */
	dlp_cmd = dlp_ctrl_cmd_alloc(ch_ctx, id, param1, param2, param3);
	if (!dlp_cmd) {
		pr_err(DRVNAME ": Out of memory (dlp_cmd: 0x%X)\n", id);
		ret = -ENOMEM;
		goto out;
	}

	/* Allocate a new TX msg */
	tx_msg = dlp_pdu_alloc(DLP_CHANNEL_CTRL,
			       HSI_MSG_WRITE,
			       DLP_CTRL_TX_PDU_SIZE,
			       1,
			       dlp_cmd,
			       dlp_ctrl_complete_tx, dlp_ctrl_msg_destruct);

	if (!tx_msg) {
		pr_err(DRVNAME ": dlp_pdu_alloc(TX) failed\n");
		ret = -ENOMEM;
		goto free_cmd;
	}

	/* Copy the command data */
	memcpy(sg_virt(tx_msg->sgt.sgl),
	       &dlp_cmd->params, sizeof(struct dlp_command_params));

	/* Send the TX HSI msg */
	ret = hsi_async(tx_msg->cl, tx_msg);
	if (ret) {
		pr_err(DRVNAME ": Unable to send 0x%X cmd (ret:%d)\n",
			dlp_cmd->params.id, ret);

		/* Free the TX msg */
		dlp_pdu_free(tx_msg, tx_msg->channel);

		goto free_cmd;
	}

	/* Dump the TX command */
	if (EDLP_CTRL_TX_DATA_REPORT)
		pr_debug(DRVNAME ": CTRL_TX (0x%X)\n",
				*((u32 *)&dlp_cmd->params));

	/* Wait for TX msg to be sent */
	ret = wait_for_completion_timeout(&ch_ctx->tx.cmd_xfer_done,
					  msecs_to_jiffies(DLP_CMD_TX_TIMOUT));
	if (ret == 0) {
		pr_err(DRVNAME ": hsi_ch:%d, cmd:0x%X => TX timeout\n",
			dlp_cmd->params.channel, dlp_cmd->params.id);

		/* No need to call the complete sending call back,
		 * because of failure */
		tx_msg->complete = NULL;
		tx_msg->context = NULL;
		ret = -EIO;
		/* free only the cmd, because
		 * the message is already in the controller fifo.
		 * It will be freed when the controller fifo will be
		 * flushed/freed
		 */
		goto free_cmd;
	}

	/* TX msg sent, check the status */
	if (dlp_cmd->status) {
		pr_err(DRVNAME ": Failed to send cmd:0x%X\n",
				dlp_cmd->params.id);

		ret = -EIO;
		/* free only the command because
		 * the message has been already freed by the complete_tx
		 * callback
		 */
		goto free_cmd;
	}

	/* TX OK */
	/* 1. Set the intermidiate channel state */
	if (interm_state != DLP_CH_STATE_NONE)
		dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, interm_state);

	/* Wait for response ? */
	if (response_id == DLP_CMD_NONE) {
		ret = 0;
		goto no_resp;
	}

	/* 2. Wait for the response */
	ret = wait_for_completion_timeout(&ch_ctx->rx.cmd_xfer_done,
					  msecs_to_jiffies(DLP_CMD_RX_TIMOUT));
	if (ret == 0) {
		pr_err(DRVNAME ": hsi_ch:%d, cmd:0x%X => RX timeout\n",
			dlp_cmd->params.channel, dlp_cmd->params.id);

		ret = -EIO;
		goto free_cmd;
	}

	/* Set the expected response params */
	expected_resp.id = response_id;
	expected_resp.channel = ch_ctx->hsi_channel;

	switch (id) {
	case DLP_CMD_CLOSE_CONN:
		expected_resp.data1 = param3;
		expected_resp.data2 = param2;
		expected_resp.data3 = CMD_ID(param1, id);
		break;

	case DLP_CMD_OPEN_CONN:
	default:
		expected_resp.data1 = param1;
		expected_resp.data2 = param2;
		expected_resp.data3 = CMD_ID(param3, id);
	}

	/* Check the received response params */
	ret = 0;
	if (memcmp(&ctrl_ctx->response.params,
				&expected_resp,
				sizeof(expected_resp))) {
		pr_err(DRVNAME": cmd 0x%X unexpected response 0x%X (expected 0x%X)",
			id,
			(unsigned int)(*(u32 *)&ctrl_ctx->response.params),
			(unsigned int)(*(u32 *)(&expected_resp)));

		tx_msg->context = NULL;
		ret = -EIO;
		goto free_cmd;
	}

no_resp:
	/* Response received & OK => set the new channel state */
	if (final_state != DLP_CH_STATE_NONE)
		dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, final_state);

free_cmd:
	/* Free the DLP command */
	dlp_ctrl_cmd_free(dlp_cmd);

out:
	/* Restore RX callback */
	dlp_restore_rx_callbacks(&ctrl_ctx->ehandler);

	/* Restore the channel state in error case */
	if (ret)
		dlp_ctrl_set_channel_state(ch_ctx->hsi_channel, old_state);

	mutex_unlock(&ch_ctx->tx.cmd_sync);

	return ret;
}
Ejemplo n.º 5
0
static int dlp_ctrl_send_response(struct dlp_channel *ch_ctx,
					struct dlp_command_params *tx_params,
					int response)
{
	int ret, state;
	struct hsi_msg *tx_msg;
	struct dlp_command *dlp_cmd;
	unsigned long flags;

	/* Allocate the eDLP response */
	dlp_cmd = dlp_ctrl_cmd_alloc(ch_ctx,
				     response,
				     tx_params->data1,
				     tx_params->data2, tx_params->data3);
	if (!dlp_cmd) {
		pr_err(DRVNAME ": Out of memory (dlp_cmd: 0x%X)\n", response);
		return -ENOMEM;
	}

	/* Allocate a new TX msg */
	tx_msg = dlp_pdu_alloc(DLP_CHANNEL_CTRL,
			       HSI_MSG_WRITE,
			       DLP_CTRL_TX_PDU_SIZE,
			       1,
			       dlp_cmd,
			       dlp_ctrl_complete_tx_async,
			       dlp_ctrl_msg_destruct);

	if (!tx_msg) {
		pr_err(DRVNAME ": TX alloc failed\n");

		/* Delete the command */
		kfree(dlp_cmd);
		return -ENOMEM;
	}

	/* Copy the command data */
	memcpy(sg_virt(tx_msg->sgt.sgl),
	       &dlp_cmd->params, sizeof(struct dlp_command_params));

	spin_lock_irqsave(&ch_ctx->lock, flags);
	state = dlp_ctrl_get_channel_state(ch_ctx->ch_id);
	if ((state != DLP_CH_STATE_OPENING) && (state != DLP_CH_STATE_OPENED) &&
			(ch_ctx->ch_id != DLP_CHANNEL_TRACE))
		spin_unlock_irqrestore(&ch_ctx->lock, flags);

	else {
		spin_unlock_irqrestore(&ch_ctx->lock, flags);
		/* Send the TX HSI msg */
		ret = hsi_async(tx_msg->cl, tx_msg);
		if (ret)
			pr_err(DRVNAME ": TX xfer failed ! (cmd:0x%X, ret:%d)\n",
				dlp_cmd->params.id, ret);

		else {
			/* Dump the TX command */
			if (EDLP_CTRL_TX_DATA_REPORT)
				pr_debug(DRVNAME ": CTRL_TX (0x%X)\n",
						*((u32 *)&dlp_cmd->params));
			return 0;
		}
	}

	/* Free the TX msg */
	dlp_pdu_free(tx_msg, tx_msg->channel);

	/* Delete the command */
	kfree(dlp_cmd);

	return 0;
}