static irqreturn_t st95hf_irq_thread_handler()

in st95hf/core.c [767:867]


static irqreturn_t st95hf_irq_thread_handler(int irq, void  *st95hfcontext)
{
	int result = 0;
	int res_len;
	static bool wtx;
	struct device *spidevice;
	struct sk_buff *skb_resp;
	struct st95hf_context *stcontext  =
		(struct st95hf_context *)st95hfcontext;
	struct st95_digital_cmd_complete_arg *cb_arg;

	spidevice = &stcontext->spicontext.spidev->dev;

	/*
	 * check semaphore, if not down() already, then we don't
	 * know in which context the ISR is called and surely it
	 * will be a bug. Note that down() of the semaphore is done
	 * in the corresponding st95hf_in_send_cmd() and then
	 * only this ISR should be called. ISR will up() the
	 * semaphore before leaving. Hence when the ISR is called
	 * the correct behaviour is down_trylock() should always
	 * return 1 (indicating semaphore cant be taken and hence no
	 * change in semaphore count).
	 * If not, then we up() the semaphore and crash on
	 * a BUG() !
	 */
	if (!down_trylock(&stcontext->exchange_lock)) {
		up(&stcontext->exchange_lock);
		WARN(1, "unknown context in ST95HF ISR");
		return IRQ_NONE;
	}

	cb_arg = &stcontext->complete_cb_arg;
	skb_resp = cb_arg->skb_resp;

	mutex_lock(&stcontext->rm_lock);
	res_len = st95hf_spi_recv_response(&stcontext->spicontext,
					   skb_resp->data);
	if (res_len < 0) {
		dev_err(spidevice, "TISR spi response err = 0x%x\n", res_len);
		result = res_len;
		goto end;
	}

	/* if stcontext->nfcdev_free is true, it means remove already ran */
	if (stcontext->nfcdev_free) {
		result = -ENODEV;
		goto end;
	}

	if (skb_resp->data[2] == WTX_REQ_FROM_TAG) {
		/* Request for new FWT from tag */
		result = st95hf_handle_wtx(stcontext, true, skb_resp->data[3]);
		if (result)
			goto end;

		wtx = true;
		mutex_unlock(&stcontext->rm_lock);
		return IRQ_HANDLED;
	}

	result = st95hf_error_handling(stcontext, skb_resp, res_len);
	if (result)
		goto end;

	result = st95hf_response_handler(stcontext, skb_resp, res_len);
	if (result)
		goto end;

	/*
	 * If select protocol is done on wtx req. do select protocol
	 * again with default values
	 */
	if (wtx) {
		wtx = false;
		result = st95hf_handle_wtx(stcontext, false, 0);
		if (result)
			goto end;
	}

	/* call digital layer callback */
	cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);

	/* up the semaphore before returning */
	up(&stcontext->exchange_lock);
	mutex_unlock(&stcontext->rm_lock);

	return IRQ_HANDLED;

end:
	kfree_skb(skb_resp);
	wtx = false;
	cb_arg->rats = false;
	skb_resp = ERR_PTR(result);
	/* call of callback with error */
	cb_arg->complete_cb(stcontext->ddev, cb_arg->cb_usrarg, skb_resp);
	/* up the semaphore before returning */
	up(&stcontext->exchange_lock);
	mutex_unlock(&stcontext->rm_lock);
	return IRQ_HANDLED;
}