static int hilse_donode()

in serio/hil_mlc.c [617:766]


static int hilse_donode(hil_mlc *mlc)
{
	const struct hilse_node *node;
	int nextidx = 0;
	int sched_long = 0;
	unsigned long flags;

#ifdef HIL_MLC_DEBUG
	if (mlc->seidx && mlc->seidx != seidx &&
	    mlc->seidx != 41 && mlc->seidx != 42 && mlc->seidx != 43) {
		printk(KERN_DEBUG PREFIX "z%i \n {%i}", doze, mlc->seidx);
		doze = 0;
	}

	seidx = mlc->seidx;
#endif
	node = hil_mlc_se + mlc->seidx;

	switch (node->act) {
		int rc;
		hil_packet pack;

	case HILSE_FUNC:
		BUG_ON(node->object.func == NULL);
		rc = node->object.func(mlc, node->arg);
		nextidx = (rc > 0) ? node->ugly :
			((rc < 0) ? node->bad : node->good);
		if (nextidx == HILSEN_FOLLOW)
			nextidx = rc;
		break;

	case HILSE_EXPECT_LAST:
	case HILSE_EXPECT_DISC:
	case HILSE_EXPECT:
	case HILSE_IN:
		/* Already set up from previous HILSE_OUT_* */
		write_lock_irqsave(&mlc->lock, flags);
		rc = mlc->in(mlc, node->arg);
		if (rc == 2)  {
			nextidx = HILSEN_DOZE;
			sched_long = 1;
			write_unlock_irqrestore(&mlc->lock, flags);
			break;
		}
		if (rc == 1)
			nextidx = node->ugly;
		else if (rc == 0)
			nextidx = node->good;
		else
			nextidx = node->bad;
		mlc->istarted = 0;
		write_unlock_irqrestore(&mlc->lock, flags);
		break;

	case HILSE_OUT_LAST:
		write_lock_irqsave(&mlc->lock, flags);
		pack = node->object.packet;
		pack |= ((mlc->ddi + 1) << HIL_PKT_ADDR_SHIFT);
		goto out;

	case HILSE_OUT_DISC:
		write_lock_irqsave(&mlc->lock, flags);
		pack = node->object.packet;
		pack |= ((mlc->ddi + 2) << HIL_PKT_ADDR_SHIFT);
		goto out;

	case HILSE_OUT:
		write_lock_irqsave(&mlc->lock, flags);
		pack = node->object.packet;
	out:
		if (!mlc->istarted) {
			/* Prepare to receive input */
			if ((node + 1)->act & HILSE_IN)
				hilse_setup_input(mlc, node + 1);
		}

		write_unlock_irqrestore(&mlc->lock, flags);

		if (down_trylock(&mlc->osem)) {
			nextidx = HILSEN_DOZE;
			break;
		}
		up(&mlc->osem);

		write_lock_irqsave(&mlc->lock, flags);
		if (!mlc->ostarted) {
			mlc->ostarted = 1;
			mlc->opacket = pack;
			rc = mlc->out(mlc);
			nextidx = HILSEN_DOZE;
			write_unlock_irqrestore(&mlc->lock, flags);
			if (rc) {
				hil_mlc_stop = 1;
				return 1;
			}
			break;
		}
		mlc->ostarted = 0;
		mlc->instart = jiffies;
		write_unlock_irqrestore(&mlc->lock, flags);
		nextidx = HILSEN_NEXT;
		break;

	case HILSE_CTS:
		write_lock_irqsave(&mlc->lock, flags);
		rc = mlc->cts(mlc);
		nextidx = rc ? node->bad : node->good;
		write_unlock_irqrestore(&mlc->lock, flags);
		if (rc) {
			hil_mlc_stop = 1;
			return 1;
		}
		break;

	default:
		BUG();
	}

#ifdef HIL_MLC_DEBUG
	if (nextidx == HILSEN_DOZE)
		doze++;
#endif

	while (nextidx & HILSEN_SCHED) {
		unsigned long now = jiffies;

		if (!sched_long)
			goto sched;

		if (time_after(now, mlc->instart + mlc->intimeout))
			 goto sched;
		mod_timer(&hil_mlcs_kicker, mlc->instart + mlc->intimeout);
		break;
	sched:
		tasklet_schedule(&hil_mlcs_tasklet);
		break;
	}

	if (nextidx & HILSEN_DOWN)
		mlc->seidx += nextidx & HILSEN_MASK;
	else if (nextidx & HILSEN_UP)
		mlc->seidx -= nextidx & HILSEN_MASK;
	else
		mlc->seidx = nextidx & HILSEN_MASK;

	if (nextidx & HILSEN_BREAK)
		return 1;

	return 0;
}