static int manage_channel()

in core-iso.c [242:292]


static int manage_channel(struct fw_card *card, int irm_id, int generation,
		u32 channels_mask, u64 offset, bool allocate)
{
	__be32 bit, all, old;
	__be32 data[2];
	int channel, ret = -EIO, retry = 5;

	old = all = allocate ? cpu_to_be32(~0) : 0;

	for (channel = 0; channel < 32; channel++) {
		if (!(channels_mask & 1 << channel))
			continue;

		ret = -EBUSY;

		bit = cpu_to_be32(1 << (31 - channel));
		if ((old & bit) != (all & bit))
			continue;

		data[0] = old;
		data[1] = old ^ bit;
		switch (fw_run_transaction(card, TCODE_LOCK_COMPARE_SWAP,
					   irm_id, generation, SCODE_100,
					   offset, data, 8)) {
		case RCODE_GENERATION:
			/* A generation change frees all channels. */
			return allocate ? -EAGAIN : channel;

		case RCODE_COMPLETE:
			if (data[0] == old)
				return channel;

			old = data[0];

			/* Is the IRM 1394a-2000 compliant? */
			if ((data[0] & bit) == (data[1] & bit))
				continue;

			fallthrough;	/* It's a 1394-1995 IRM, retry */
		default:
			if (retry) {
				retry--;
				channel--;
			} else {
				ret = -EIO;
			}
		}
	}

	return ret;
}