static int xilly_setupchannels()

in xillybus/xillybus_core.c [427:587]


static int xilly_setupchannels(struct xilly_endpoint *ep,
			       unsigned char *chandesc,
			       int entries)
{
	struct device *dev = ep->dev;
	int i, entry, rc;
	struct xilly_channel *channel;
	int channelnum, bufnum, bufsize, format, is_writebuf;
	int bytebufsize;
	int synchronous, allowpartial, exclusive_open, seekable;
	int supports_nonempty;
	int msg_buf_done = 0;

	struct xilly_alloc_state rd_alloc = {
		.salami = NULL,
		.left_of_salami = 0,
		.nbuffer = 1,
		.direction = DMA_TO_DEVICE,
		.regdirection = 0,
	};

	struct xilly_alloc_state wr_alloc = {
		.salami = NULL,
		.left_of_salami = 0,
		.nbuffer = 1,
		.direction = DMA_FROM_DEVICE,
		.regdirection = 0x80000000,
	};

	channel = devm_kcalloc(dev, ep->num_channels,
			       sizeof(struct xilly_channel), GFP_KERNEL);
	if (!channel)
		return -ENOMEM;

	ep->channels = devm_kcalloc(dev, ep->num_channels + 1,
				    sizeof(struct xilly_channel *),
				    GFP_KERNEL);
	if (!ep->channels)
		return -ENOMEM;

	ep->channels[0] = NULL; /* Channel 0 is message buf. */

	/* Initialize all channels with defaults */

	for (i = 1; i <= ep->num_channels; i++) {
		channel->wr_buffers = NULL;
		channel->rd_buffers = NULL;
		channel->num_wr_buffers = 0;
		channel->num_rd_buffers = 0;
		channel->wr_fpga_buf_idx = -1;
		channel->wr_host_buf_idx = 0;
		channel->wr_host_buf_pos = 0;
		channel->wr_empty = 1;
		channel->wr_ready = 0;
		channel->wr_sleepy = 1;
		channel->rd_fpga_buf_idx = 0;
		channel->rd_host_buf_idx = 0;
		channel->rd_host_buf_pos = 0;
		channel->rd_full = 0;
		channel->wr_ref_count = 0;
		channel->rd_ref_count = 0;

		spin_lock_init(&channel->wr_spinlock);
		spin_lock_init(&channel->rd_spinlock);
		mutex_init(&channel->wr_mutex);
		mutex_init(&channel->rd_mutex);
		init_waitqueue_head(&channel->rd_wait);
		init_waitqueue_head(&channel->wr_wait);
		init_waitqueue_head(&channel->wr_ready_wait);

		INIT_DELAYED_WORK(&channel->rd_workitem, xillybus_autoflush);

		channel->endpoint = ep;
		channel->chan_num = i;

		channel->log2_element_size = 0;

		ep->channels[i] = channel++;
	}

	for (entry = 0; entry < entries; entry++, chandesc += 4) {
		struct xilly_buffer **buffers = NULL;

		is_writebuf = chandesc[0] & 0x01;
		channelnum = (chandesc[0] >> 1) | ((chandesc[1] & 0x0f) << 7);
		format = (chandesc[1] >> 4) & 0x03;
		allowpartial = (chandesc[1] >> 6) & 0x01;
		synchronous = (chandesc[1] >> 7) & 0x01;
		bufsize = 1 << (chandesc[2] & 0x1f);
		bufnum = 1 << (chandesc[3] & 0x0f);
		exclusive_open = (chandesc[2] >> 7) & 0x01;
		seekable = (chandesc[2] >> 6) & 0x01;
		supports_nonempty = (chandesc[2] >> 5) & 0x01;

		if ((channelnum > ep->num_channels) ||
		    ((channelnum == 0) && !is_writebuf)) {
			dev_err(ep->dev,
				"IDT requests channel out of range. Aborting.\n");
			return -ENODEV;
		}

		channel = ep->channels[channelnum]; /* NULL for msg channel */

		if (!is_writebuf || channelnum > 0) {
			channel->log2_element_size = ((format > 2) ?
						      2 : format);

			bytebufsize = bufsize *
				(1 << channel->log2_element_size);

			buffers = devm_kcalloc(dev, bufnum,
					       sizeof(struct xilly_buffer *),
					       GFP_KERNEL);
			if (!buffers)
				return -ENOMEM;
		} else {
			bytebufsize = bufsize << 2;
		}

		if (!is_writebuf) {
			channel->num_rd_buffers = bufnum;
			channel->rd_buf_size = bytebufsize;
			channel->rd_allow_partial = allowpartial;
			channel->rd_synchronous = synchronous;
			channel->rd_exclusive_open = exclusive_open;
			channel->seekable = seekable;

			channel->rd_buffers = buffers;
			rc = xilly_get_dma_buffers(ep, &rd_alloc, buffers,
						   bufnum, bytebufsize);
		} else if (channelnum > 0) {
			channel->num_wr_buffers = bufnum;
			channel->wr_buf_size = bytebufsize;

			channel->seekable = seekable;
			channel->wr_supports_nonempty = supports_nonempty;

			channel->wr_allow_partial = allowpartial;
			channel->wr_synchronous = synchronous;
			channel->wr_exclusive_open = exclusive_open;

			channel->wr_buffers = buffers;
			rc = xilly_get_dma_buffers(ep, &wr_alloc, buffers,
						   bufnum, bytebufsize);
		} else {
			rc = xilly_get_dma_buffers(ep, &wr_alloc, NULL,
						   bufnum, bytebufsize);
			msg_buf_done++;
		}

		if (rc)
			return -ENOMEM;
	}

	if (!msg_buf_done) {
		dev_err(ep->dev,
			"Corrupt IDT: No message buffer. Aborting.\n");
		return -ENODEV;
	}
	return 0;
}