Пример #1
0
int serial8250_tx_dma(struct uart_8250_port *p)
{
	struct uart_8250_dma		*dma = p->dma;
	struct circ_buf			*xmit = &p->port.state->xmit;
	struct dma_async_tx_descriptor	*desc;

	if (dma->tx_running) {
		uart_write_wakeup(&p->port);
		return -EBUSY;
	}

	dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	desc = dmaengine_prep_slave_single(dma->txchan,
					   dma->tx_addr + xmit->tail,
					   dma->tx_size, DMA_MEM_TO_DEV,
					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!desc)
		return -EBUSY;

	dma->tx_running = 1;

	desc->callback = __dma_tx_complete;
	desc->callback_param = p;

	dma->tx_cookie = dmaengine_submit(desc);

	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
				   UART_XMIT_SIZE, DMA_TO_DEVICE);

	dma_async_issue_pending(dma->txchan);

	return 0;
}
Пример #2
0
static int copy_sleep_history(struct sleep_history *buf, int count)
{
	int c, err;
	int head, tail;
	struct sleep_history *ring_buf;

	if (!buf) {
		err = -EINVAL;
		goto err_invalid;
	}
	memset(buf, 0, count * sizeof(struct sleep_history));

	ring_buf = (struct sleep_history *)(sleep_history_data.sleep_history.buf);
	head = sleep_history_data.sleep_history.head;
	tail = sleep_history_data.sleep_history.tail;

	c = CIRC_CNT(head, tail, SLEEP_HISTORY_RINGBUFFER_SIZE);
	if (c == 0) {
		err = -EINVAL;
		goto err_read;
	} else  if (c == SLEEP_HISTORY_RINGBUFFER_SIZE - 1) {
		c = CIRC_CNT_TO_END(head, tail, SLEEP_HISTORY_RINGBUFFER_SIZE);
		memcpy(buf, ring_buf + tail, c * sizeof(struct sleep_history));
		memcpy(buf + c, ring_buf,
			(SLEEP_HISTORY_RINGBUFFER_SIZE-c) * sizeof(struct sleep_history));
		c = SLEEP_HISTORY_RINGBUFFER_SIZE - 1;
	} else
		memcpy(buf, ring_buf + tail, c * sizeof(struct sleep_history));

	return c;

err_invalid:
err_read:
	return err;
}
/* Called with u->lock taken */
static void tegra_start_next_tx(struct tegra_uart_port *t)
{
	unsigned long tail;
	unsigned long count;

	struct circ_buf *xmit;

	xmit = &t->uport.state->xmit;
	tail = (unsigned long)&xmit->buf[xmit->tail];
	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);


	dev_vdbg(t->uport.dev, "+%s %lu %d\n", __func__, count,
		t->tx_in_progress);

	if (count == 0)
		goto out;

	if (!t->use_tx_dma || count < TEGRA_UART_MIN_DMA)
		tegra_start_pio_tx(t, count);
	else if (BYTES_TO_ALIGN(tail) > 0)
		tegra_start_pio_tx(t, BYTES_TO_ALIGN(tail));
	else
		tegra_start_dma_tx(t, count);

out:
	dev_vdbg(t->uport.dev, "-%s", __func__);
}
static void uart_task_action(unsigned long data)
{
	struct uart_pxa_port *up = (struct uart_pxa_port *)data;
	struct circ_buf *xmit = &up->port.state->xmit;
	unsigned char *tmp = up->uart_dma.txdma_addr;
	unsigned long flags;
	int count = 0, c;

	/* if the tx is stop, just return.*/
	if (up->uart_dma.tx_stop)
		return;

	spin_lock_irqsave(&up->port.lock, flags);
	if (up->uart_dma.dma_status & TX_DMA_RUNNING) {
		spin_unlock_irqrestore(&up->port.lock, flags);
		return;
	}

	up->uart_dma.dma_status |= TX_DMA_RUNNING;
	while (1) {
		c = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
		if (c <= 0)
			break;

		memcpy(tmp, xmit->buf + xmit->tail, c);
		xmit->tail = (xmit->tail + c) & (UART_XMIT_SIZE - 1);
		tmp += c;
		count += c;
		up->port.icount.tx += c;
	}
	spin_unlock_irqrestore(&up->port.lock, flags);

	pr_debug("count =%d", count);
	pxa_uart_transmit_dma_start(up, count);
}
static int stmp_appuart_copy_tx(struct uart_port *u, u8 *target,
		int tx_buffer_size)
{
	int last = 0, portion;
	struct circ_buf *xmit = &u->info->xmit;

	while (last < tx_buffer_size) {	/* let's fill the only descriptor */
		if (u->x_char) {
			target[last++] = u->x_char;
			u->x_char = 0;
		} else if (!uart_circ_empty(xmit) && !uart_tx_stopped(u)) {
			portion = min((u32)tx_buffer_size,
				(u32)uart_circ_chars_pending(xmit));
			portion = min((u32)portion,
				(u32)CIRC_CNT_TO_END(xmit->head, xmit->tail,
					UART_XMIT_SIZE));
			memcpy(target + last, &xmit->buf[xmit->tail], portion);
			xmit->tail = (xmit->tail + portion) &
				(UART_XMIT_SIZE - 1);
			if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
				uart_write_wakeup(u);
			last += portion;
		} else { /* All tx data copied into buffer */
			return last;
		}
	}
	return last;
}
Пример #6
0
static int spi_read(struct bathos_pipe *pipe, char *buf, int len)
{
	struct spi_data *data = &spi_data;
	int flags;
	int l;

	interrupt_disable(flags);
	l = min(len, CIRC_CNT_TO_END(data->cbufrx.head, data->cbufrx.tail,
				     SPI_BUF_SIZE));

	if (!l) {
		interrupt_restore(flags);
		return -EAGAIN;
	}

	memcpy(buf, &data->bufrx[data->cbufrx.tail], l);
	data->cbufrx.tail = (data->cbufrx.tail + l) & (SPI_BUF_SIZE - 1);
	data->overrun = 0;

	if (CIRC_CNT(data->cbufrx.head, data->cbufrx.tail, SPI_BUF_SIZE))
		pipe_dev_trigger_event(&__spi_dev, &evt_pipe_input_ready,
				       EVT_PRIO_MAX);

	interrupt_restore(flags);
	return l;
}
Пример #7
0
/********************************************************************************
 *  Description:
 *   Input Args:
 *  Output Args:
 * Return Value:
 ********************************************************************************/
int main (int argc, char **argv)
{
    int i, len;
    struct circ_buf        tx_ring; 
    char   data[LEN];
    char   buf[LEN];

    memset(&tx_ring, 0, sizeof(struct circ_buf)); 
    tx_ring.buf = malloc(CIRC_BUF_SIZE); 
    if( NULL == tx_ring.buf )
    {
        printf("Allocate Ring buffer failure.\n");
        return -1;
    }

    memset(data, 0, sizeof(data));
    /* Prepare for the data */
    for(i=0; i<sizeof(data); i++)
    {
        data[i] = 30+i;
    }

    printf("CIRC_SPACE: %d\n", CIRC_SPACE(tx_ring.head, tx_ring.tail, CIRC_BUF_SIZE));
    printf("CIRC_SPACE_TO_END: %d\n", CIRC_SPACE_TO_END(tx_ring.head, tx_ring.tail, CIRC_BUF_SIZE));
    printf("CIRC_CNT: %d\n", CIRC_CNT(tx_ring.head, tx_ring.tail, CIRC_BUF_SIZE));
    printf("CIRC_CNT_TO_END: %d\n", CIRC_CNT_TO_END(tx_ring.head, tx_ring.tail, CIRC_BUF_SIZE));
    while(1)
    {
       produce_item(&tx_ring, data, sizeof(data));
       len = consume_item(&tx_ring, buf, sizeof(buf) );
       sleep(1);
    }

    return 0;
} /* ----- End of main() ----- */
Пример #8
0
static ssize_t userio_char_read(struct file *file, char __user *user_buffer,
				size_t count, loff_t *ppos)
{
	struct userio_device *userio = file->private_data;
	int error;
	size_t nonwrap_len, copylen;
	unsigned char buf[USERIO_BUFSIZE];
	unsigned long flags;

	/*
	 * By the time we get here, the data that was waiting might have
	 * been taken by another thread. Grab the buffer lock and check if
	 * there's still any data waiting, otherwise repeat this process
	 * until we have data (unless the file descriptor is non-blocking
	 * of course).
	 */
	for (;;) {
		spin_lock_irqsave(&userio->buf_lock, flags);

		nonwrap_len = CIRC_CNT_TO_END(userio->head,
					      userio->tail,
					      USERIO_BUFSIZE);
		copylen = min(nonwrap_len, count);
		if (copylen) {
			memcpy(buf, &userio->buf[userio->tail], copylen);
			userio->tail = (userio->tail + copylen) %
							USERIO_BUFSIZE;
		}

		spin_unlock_irqrestore(&userio->buf_lock, flags);

		if (nonwrap_len)
			break;

		/* buffer was/is empty */
		if (file->f_flags & O_NONBLOCK)
			return -EAGAIN;

		/*
		 * count == 0 is special - no IO is done but we check
		 * for error conditions (see above).
		 */
		if (count == 0)
			return 0;

		error = wait_event_interruptible(userio->waitq,
						 userio->head != userio->tail);
		if (error)
			return error;
	}

	if (copylen)
		if (copy_to_user(user_buffer, buf, copylen))
			return -EFAULT;

	return copylen;
}
Пример #9
0
size_t whitebox_user_source_data_available(struct whitebox_user_source *user_source,
        unsigned long *src)
{
    long head, tail, data;
    head = ACCESS_ONCE(user_source->buf.head);
    tail = user_source->buf.tail;
    data = CIRC_CNT_TO_END(head, tail, user_source->buf_size);
    d_printk(7, "%ld\n", data);
    *src = (long)user_source->buf.buf + tail;
    return data;
}
Пример #10
0
int serial8250_tx_dma(struct uart_8250_port *p)
{
	struct uart_8250_dma		*dma = p->dma;
	struct circ_buf			*xmit = &p->port.state->xmit;
	struct dma_async_tx_descriptor	*desc;
	int ret;

	if (dma->tx_running)
		return 0;

	if (uart_tx_stopped(&p->port) || uart_circ_empty(xmit)) {
		/* We have been called from __dma_tx_complete() */
		serial8250_rpm_put_tx(p);
		return 0;
	}

	dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	desc = dmaengine_prep_slave_single(dma->txchan,
					   dma->tx_addr + xmit->tail,
					   dma->tx_size, DMA_MEM_TO_DEV,
					   DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
	if (!desc) {
		ret = -EBUSY;
		goto err;
	}

	dma->tx_running = 1;
	desc->callback = __dma_tx_complete;
	desc->callback_param = p;

	dma->tx_cookie = dmaengine_submit(desc);

	dma_sync_single_for_device(dma->txchan->device->dev, dma->tx_addr,
				   UART_XMIT_SIZE, DMA_TO_DEVICE);

	dma_async_issue_pending(dma->txchan);
	if (dma->tx_err) {
		dma->tx_err = 0;
		if (p->ier & UART_IER_THRI) {
			p->ier &= ~UART_IER_THRI;
			serial_out(p, UART_IER, p->ier);
		}
	}
	return 0;
err:
	dma->tx_err = 1;
	return ret;
}
Пример #11
0
static int sprd_tx_buf_remap(struct uart_port *port)
{
	struct sprd_uart_port *sp =
		container_of(port, struct sprd_uart_port, port);
	struct circ_buf *xmit = &port->state->xmit;

	sp->tx_dma.trans_len =
		CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	sp->tx_dma.phys_addr = dma_map_single(port->dev,
					      (void *)&(xmit->buf[xmit->tail]),
					      sp->tx_dma.trans_len,
					      DMA_TO_DEVICE);
	return dma_mapping_error(port->dev, sp->tx_dma.phys_addr);
}
Пример #12
0
static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
{
	while (!uart_circ_empty(xmit)) {
		unsigned long ra = __pa(xmit->buf + xmit->tail);
		unsigned long len, status, sent;

		len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
				      UART_XMIT_SIZE);
		status = sun4v_con_write(ra, len, &sent);
		if (status != HV_EOK)
			break;
		xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
		port->icount.tx += sent;
	}
}
Пример #13
0
static void tegra_tcu_uart_start_tx(struct uart_port *port)
{
	struct tegra_tcu *tcu = port->private_data;
	struct circ_buf *xmit = &port->state->xmit;
	unsigned long count;

	for (;;) {
		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
		if (!count)
			break;

		tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count);
		xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
	}

	uart_write_wakeup(port);
}
Пример #14
0
static void l4ser_shm_tx_chars(struct uart_port *port)
{
	struct l4ser_shm_uart_port *l4port = (struct l4ser_shm_uart_port *)port;
	struct circ_buf *xmit = &port->state->xmit;
	int c, do_trigger = 0;

	struct tty_struct *tty = port->state->port.tty;
	tty->hw_stopped = 0;
	tty->stopped = 0;

	if (port->x_char) {
		if (tx_buf(port, &port->x_char, 1)) {
			L4XV_V(f);
			port->icount.tx++;
			port->x_char = 0;
			L4XV_L(f);
			l4shmc_trigger(&l4port->tx_sig);
			L4XV_U(f);
		}
		return;
	}

	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
		return;
	}

	while (!uart_circ_empty(xmit)) {
		unsigned long r;
		c = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
		if (!(r = tx_buf(port, &xmit->buf[xmit->tail], c)))
			break;
		xmit->tail = (xmit->tail + r) & (UART_XMIT_SIZE - 1);
		port->icount.tx += r;
		do_trigger = 1;
	}

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(port);

	if (do_trigger) {
		L4XV_V(f);
		L4XV_L(f);
		l4shmc_trigger(&l4port->tx_sig);
		L4XV_U(f);
	}
}
Пример #15
0
/*
 * serial_buf_get
 *
 * Get data from the circular buffer and copy to the given buffer.
 * Restrict to the amount of data available.
 *
 * Return the number of bytes copied.
 */
static int serial_buf_get(struct circ_buf *cb, char *buf, int count)
{
	int c, ret = 0;
	while (1) {
		c = CIRC_CNT_TO_END(cb->head, cb->tail, AIRCABLE_BUF_SIZE);
		if (count < c)
			c = count;
		if (c <= 0)
			break;
		memcpy(buf, cb->buf + cb->tail, c);
		cb->tail = (cb->tail + c) & (AIRCABLE_BUF_SIZE-1);
		buf += c;
		count -= c;
		ret= c;
	}
	return ret;
}
Пример #16
0
static ssize_t arcmsr_sysfs_iop_message_read(struct file *filp,
					     struct kobject *kobj,
					     struct bin_attribute *bin,
					     char *buf, loff_t off,
					     size_t count)
{
	struct device *dev = container_of(kobj,struct device,kobj);
	struct Scsi_Host *host = class_to_shost(dev);
	struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata;
	uint8_t *ptmpQbuffer;
	int32_t allxfer_len = 0;
	unsigned long flags;

	if (!capable(CAP_SYS_ADMIN))
		return -EACCES;

	/* do message unit read. */
	ptmpQbuffer = (uint8_t *)buf;
	spin_lock_irqsave(&acb->rqbuffer_lock, flags);
	if (acb->rqbuf_getIndex != acb->rqbuf_putIndex) {
		unsigned int tail = acb->rqbuf_getIndex;
		unsigned int head = acb->rqbuf_putIndex;
		unsigned int cnt_to_end = CIRC_CNT_TO_END(head, tail, ARCMSR_MAX_QBUFFER);

		allxfer_len = CIRC_CNT(head, tail, ARCMSR_MAX_QBUFFER);
		if (allxfer_len > ARCMSR_API_DATA_BUFLEN)
			allxfer_len = ARCMSR_API_DATA_BUFLEN;

		if (allxfer_len <= cnt_to_end)
			memcpy(ptmpQbuffer, acb->rqbuffer + tail, allxfer_len);
		else {
			memcpy(ptmpQbuffer, acb->rqbuffer + tail, cnt_to_end);
			memcpy(ptmpQbuffer + cnt_to_end, acb->rqbuffer, allxfer_len - cnt_to_end);
		}
		acb->rqbuf_getIndex = (acb->rqbuf_getIndex + allxfer_len) % ARCMSR_MAX_QBUFFER;
	}
	if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) {
		struct QBUFFER __iomem *prbuffer;
		acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW;
		prbuffer = arcmsr_get_iop_rqbuffer(acb);
		if (arcmsr_Read_iop_rqbuffer_data(acb, prbuffer) == 0)
			acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW;
	}
	spin_unlock_irqrestore(&acb->rqbuffer_lock, flags);
	return allxfer_len;
}
Пример #17
0
void iforce_usb_xmit(struct iforce *iforce)
{
	int n, c;
	unsigned long flags;

	spin_lock_irqsave(&iforce->xmit_lock, flags);

	if (iforce->xmit.head == iforce->xmit.tail) {
		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
		return;
	}

	((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);
	n = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);

	iforce->out->transfer_buffer_length = n + 1;
	iforce->out->dev = iforce->usbdev;

	/* Copy rest of data then */
	c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
	if (n < c) c=n;

	memcpy(iforce->out->transfer_buffer + 1,
	       &iforce->xmit.buf[iforce->xmit.tail],
	       c);
	if (n != c) {
		memcpy(iforce->out->transfer_buffer + 1 + c,
		       &iforce->xmit.buf[0],
		       n-c);
	}
	XMIT_INC(iforce->xmit.tail, n);

	if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
		dev_warn(&iforce->intf->dev, "usb_submit_urb failed %d\n", n);
	}

	/* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended.
	 * As long as the urb completion handler is not called, the transmiting
	 * is considered to be running */
	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
Пример #18
0
void hsu_dma_tx(struct uart_hsu_port *up)
{
	struct circ_buf *xmit = &up->port.state->xmit;
	struct hsu_dma_buffer *dbuf = &up->txbuf;
	int count;

	/* test_and_set_bit may be better, but anyway it's in lock protected mode */
	if (up->dma_tx_on)
		return;

	/* Update the circ buf info */
	xmit->tail += dbuf->ofs;
	xmit->tail &= UART_XMIT_SIZE - 1;

	up->port.icount.tx += dbuf->ofs;
	dbuf->ofs = 0;

	/* Disable the channel */
	chan_writel(up->txc, HSU_CH_CR, 0x0);

	if (!uart_circ_empty(xmit) && !uart_tx_stopped(&up->port)) {
		dma_sync_single_for_device(up->port.dev,
					   dbuf->dma_addr,
					   dbuf->dma_size,
					   DMA_TO_DEVICE);

		count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
		dbuf->ofs = count;

		/* Reprogram the channel */
		chan_writel(up->txc, HSU_CH_D0SAR, dbuf->dma_addr + xmit->tail);
		chan_writel(up->txc, HSU_CH_D0TSR, count);

		/* Reenable the channel */
		chan_writel(up->txc, HSU_CH_DCR, 0x1
						 | (0x1 << 8)
						 | (0x1 << 16)
						 | (0x1 << 24));
		up->dma_tx_on = 1;
		chan_writel(up->txc, HSU_CH_CR, 0x1);
	}

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
		uart_write_wakeup(&up->port);
}
Пример #19
0
static void tegra_uart_start_next_tx(struct tegra_uart_port *tup)
{
	unsigned long tail;
	unsigned long count;
	struct circ_buf *xmit = &tup->uport.state->xmit;

	tail = (unsigned long)&xmit->buf[xmit->tail];
	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
	if (!count)
		return;

	if (count < TEGRA_UART_MIN_DMA)
		tegra_uart_start_pio_tx(tup, count);
	else if (BYTES_TO_ALIGN(tail) > 0)
		tegra_uart_start_pio_tx(tup, BYTES_TO_ALIGN(tail));
	else
		tegra_uart_start_tx_dma(tup, count);
}
Пример #20
0
/* Called with u->lock taken */
static void tegra_start_next_tx(struct tegra_uart_port *t)
{
	unsigned long tail;
	unsigned long count;
	unsigned long lsr;
	struct uart_port *u = &t->uport;

	struct circ_buf *xmit;

	xmit = &t->uport.state->xmit;
	tail = (unsigned long)&xmit->buf[xmit->tail];
	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);


	dev_vdbg(t->uport.dev, "+%s %lu %d\n", __func__, count,
		t->tx_in_progress);

	if (count == 0) {
		if (t->is_irda && !irda_loop) {
			do {
				lsr = uart_readb(t, UART_LSR);
				if (lsr & UART_LSR_TEMT)
					break;
			} while (1);
			tegra_start_rx(u);
		}
		goto out;
	}

	if (t->is_irda && !irda_loop) {
		if (t->rx_in_progress)
			tegra_stop_rx(u);
	}

	if (!t->use_tx_dma || count < TEGRA_UART_MIN_DMA)
		tegra_start_pio_tx(t, count);
	else if (BYTES_TO_ALIGN(tail) > 0)
		tegra_start_pio_tx(t, BYTES_TO_ALIGN(tail));
	else
		tegra_start_dma_tx(t, count);

out:
	dev_vdbg(t->uport.dev, "-%s", __func__);
}
void iforce_usb_xmit(struct iforce *iforce)
{
	int n, c;
	unsigned long flags;

	spin_lock_irqsave(&iforce->xmit_lock, flags);

	if (iforce->xmit.head == iforce->xmit.tail) {
		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
		spin_unlock_irqrestore(&iforce->xmit_lock, flags);
		return;
	}

	((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);
	n = iforce->xmit.buf[iforce->xmit.tail];
	XMIT_INC(iforce->xmit.tail, 1);

	iforce->out->transfer_buffer_length = n + 1;
	iforce->out->dev = iforce->usbdev;

	
	c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE);
	if (n < c) c=n;

	memcpy(iforce->out->transfer_buffer + 1,
	       &iforce->xmit.buf[iforce->xmit.tail],
	       c);
	if (n != c) {
		memcpy(iforce->out->transfer_buffer + 1 + c,
		       &iforce->xmit.buf[0],
		       n-c);
	}
	XMIT_INC(iforce->xmit.tail, n);

	if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) {
		clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags);
		dev_warn(&iforce->dev->dev, "usb_submit_urb failed %d\n", n);
	}

	spin_unlock_irqrestore(&iforce->xmit_lock, flags);
}
Пример #22
0
static int uart_read(struct bathos_pipe *pipe, char *buf, int len)
{
    struct uart_data *data = &uart_data;
    int l;

    l = min(len, CIRC_CNT_TO_END(data->cbuf.head, data->cbuf.tail,
                                 UART_BUF_SIZE));
    if (!l)
        return -EAGAIN;

    memcpy(buf, &data->buf[data->cbuf.tail], l);
    data->cbuf.tail = (data->cbuf.tail + l) & (UART_BUF_SIZE - 1);
    data->overrun = 0;

    if (CIRC_CNT(data->cbuf.head, data->cbuf.tail, UART_BUF_SIZE))
        pipe_dev_trigger_event(&__uart_dev, &evt_pipe_input_ready,
                               EVT_PRIO_MAX);

    return l;
}
Пример #23
0
int consume_item(struct circ_buf *ring, char *buf, int  count)
{
    int len = 0;
    int i, left, size;
    int to_end_space=0;

    if ( (size=CIRC_CNT(ring->head, ring->tail, CIRC_BUF_SIZE)) >= 1 )
    {
        left = len = count<=size ? count : size;
        to_end_space = CIRC_CNT_TO_END(ring->head, ring->tail, CIRC_BUF_SIZE);

        if(left > to_end_space)
        {
            memcpy(buf, &(ring->buf[ring->tail]), to_end_space);
            for(i=0; i<to_end_space; i++) 
            { 
                printf("consume_item %02d bytes: ring->buf[%02d]=%d\n", to_end_space, ring->tail+i, ring->buf[ring->tail+i]); 
            }
            ring->tail = (ring->tail + to_end_space) & (CIRC_BUF_SIZE - 1);
            left -= to_end_space;
        }
        else
        {
            to_end_space = 0;
        }

        memcpy(&buf[to_end_space], &(ring->buf[ring->tail]), left);
        for(i=0; i<left; i++)
        {
           printf("consume_item %02d bytes: ring->buf[%02d]=%d\n", left, ring->tail+i, ring->buf[ring->tail+i]);
        }
        ring->tail = (ring->tail + left) & (CIRC_BUF_SIZE - 1);
    }

    for(i=0; i<len; i++)
        printf("output_data %02d bytes: buf[%02d]=%d\n", len, i, buf[i]);

    printf("-----------------------------------------------------------------------------------------------\n");

    return len;
}
Пример #24
0
static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
{
	struct uart_port *port = &ourport->port;
	struct circ_buf *xmit = &port->state->xmit;
	unsigned long count;

	/* Get data size up to the end of buffer */
	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	if (!count) {
		s3c24xx_serial_stop_tx(port);
		return;
	}

	if (!ourport->dma || !ourport->dma->tx_chan ||
	    count < ourport->min_dma_size ||
	    xmit->tail & (dma_get_cache_alignment() - 1))
		s3c24xx_serial_start_tx_pio(ourport);
	else
		s3c24xx_serial_start_tx_dma(ourport, count);
}
Пример #25
0
void d_printk_loop(int level) {
    unsigned long src;
    struct circ_buf *mock_buf = &whitebox_device->mock_buf;
    struct whitebox_user_sink *user_sink = &whitebox_device->user_sink;
    struct whitebox_user_source *user_source = &whitebox_device->user_source;
    struct whitebox_rf_sink *rf_sink = &whitebox_device->rf_sink;
    struct whitebox_rf_source *rf_source = &whitebox_device->rf_source;
    u32 exciter_state = rf_sink->exciter->ops->get_state(rf_sink->exciter);
    u32 receiver_state = rf_source->receiver->ops->get_state(rf_source->receiver);

    d_printk(level, "stats %c%c user_source_data/space=%d/%d rf_sink_space=%d mock_data/space=%d/%d rf_source_data=%d user_sink_data/space=%d/%d\n",
        exciter_state & WES_TXEN ? 'T' : ' ',
        receiver_state & WRS_RXEN ? 'R' : ' ',
        whitebox_user_source_data_available(user_source, &src),
        whitebox_user_source_space_available(user_source, &src),
        whitebox_rf_sink_space_available(rf_sink, &src),
        CIRC_CNT_TO_END(mock_buf->head, mock_buf->tail, PAGE_SIZE << whitebox_mock_order),
        CIRC_SPACE_TO_END(mock_buf->head, mock_buf->tail, PAGE_SIZE << whitebox_mock_order),
        whitebox_rf_source_data_available(rf_source, &src),
        whitebox_user_sink_data_available(user_sink, &src),
        whitebox_user_sink_space_available(user_sink, &src));
}
Пример #26
0
static unsigned _fifo_read(struct m_fifo *q, void *dst,
			   unsigned count, copyfunc copy)
{
	unsigned n;
	unsigned head = *q->head;
	unsigned tail = *q->tail;
	unsigned size = q->size;

	if (CIRC_CNT(head, tail, size) < count)
		return 0;

	n = CIRC_CNT_TO_END(head, tail, size);

	if (likely(n >= count)) {
		copy(dst, q->data + tail, count);
	} else {
		copy(dst, q->data + tail, n);
		copy(dst + n, q->data, count - n);
	}
	//*q->tail = (tail + count) & (size - 1);

	return count;
}
Пример #27
0
static void genode_serial_tx_chars(struct uart_port *port) {
	struct genode_uart_port *l4port = (struct genode_uart_port *)port;
	struct circ_buf         *xmit   = &port->state->xmit;
	unsigned long            flags;
	unsigned                 c;

	if (port->x_char) {
		local_irq_save(flags);
		genode_terminal_writechar(l4port->idx, &port->x_char, sizeof(char));
		local_irq_restore(flags);
		port->icount.tx++;
		port->x_char = 0;
		return;
	}

	while (!uart_circ_empty(xmit)) {
		c = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
		local_irq_save(flags);
		genode_terminal_writechar(l4port->idx, &xmit->buf[xmit->tail], c);
		local_irq_restore(flags);
		xmit->tail = (xmit->tail + c) & (UART_XMIT_SIZE - 1);
		port->icount.tx += c;
	}
}
Пример #28
0
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
	struct s3c24xx_uart_port *ourport = id;
	struct uart_port *port = &ourport->port;
	struct circ_buf *xmit = &port->state->xmit;
	unsigned long flags;
	int count, dma_count = 0;

	spin_lock_irqsave(&port->lock, flags);

	count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);

	if (ourport->dma && ourport->dma->tx_chan &&
	    count >= ourport->min_dma_size) {
		int align = dma_get_cache_alignment() -
			(xmit->tail & (dma_get_cache_alignment() - 1));
		if (count-align >= ourport->min_dma_size) {
			dma_count = count-align;
			count = align;
		}
	}

	if (port->x_char) {
		wr_regb(port, S3C2410_UTXH, port->x_char);
		port->icount.tx++;
		port->x_char = 0;
		goto out;
	}

	/* if there isn't anything more to transmit, or the uart is now
	 * stopped, disable the uart and exit
	*/

	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
		s3c24xx_serial_stop_tx(port);
		goto out;
	}

	/* try and drain the buffer... */

	if (count > port->fifosize) {
		count = port->fifosize;
		dma_count = 0;
	}

	while (!uart_circ_empty(xmit) && count > 0) {
		if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
			break;

		wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
		port->icount.tx++;
		count--;
	}

	if (!count && dma_count) {
		s3c24xx_serial_start_tx_dma(ourport, dma_count);
		goto out;
	}

	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) {
		spin_unlock(&port->lock);
		uart_write_wakeup(port);
		spin_lock(&port->lock);
	}

	if (uart_circ_empty(xmit))
		s3c24xx_serial_stop_tx(port);

out:
	spin_unlock_irqrestore(&port->lock, flags);
	return IRQ_HANDLED;
}
Пример #29
0
static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
{
	struct uart_port *port = &sirfport->port;
	struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
	struct sirfsoc_int_en *uint_en = &sirfport->uart_reg->uart_int_en;
	struct circ_buf *xmit = &port->state->xmit;
	unsigned long tran_size;
	unsigned long tran_start;
	unsigned long pio_tx_size;

	tran_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
	tran_start = (unsigned long)(xmit->buf + xmit->tail);
	if (uart_circ_empty(xmit) || uart_tx_stopped(port) ||
			!tran_size)
		return;
	if (sirfport->tx_dma_state == TX_DMA_PAUSE) {
		dmaengine_resume(sirfport->tx_dma_chan);
		return;
	}
	if (sirfport->tx_dma_state == TX_DMA_RUNNING)
		return;
	if (!sirfport->is_atlas7)
		wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg)&
				~(uint_en->sirfsoc_txfifo_empty_en));
	else
		wr_regl(port, SIRFUART_INT_EN_CLR,
				uint_en->sirfsoc_txfifo_empty_en);
	/*
	 * DMA requires buffer address and buffer length are both aligned with
	 * 4 bytes, so we use PIO for
	 * 1. if address is not aligned with 4bytes, use PIO for the first 1~3
	 * bytes, and move to DMA for the left part aligned with 4bytes
	 * 2. if buffer length is not aligned with 4bytes, use DMA for aligned
	 * part first, move to PIO for the left 1~3 bytes
	 */
	if (tran_size < 4 || BYTES_TO_ALIGN(tran_start)) {
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)|
			SIRFUART_IO_MODE);
		if (BYTES_TO_ALIGN(tran_start)) {
			pio_tx_size = sirfsoc_uart_pio_tx_chars(sirfport,
				BYTES_TO_ALIGN(tran_start));
			tran_size -= pio_tx_size;
		}
		if (tran_size < 4)
			sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
		if (!sirfport->is_atlas7)
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				rd_regl(port, ureg->sirfsoc_int_en_reg)|
				uint_en->sirfsoc_txfifo_empty_en);
		else
			wr_regl(port, ureg->sirfsoc_int_en_reg,
				uint_en->sirfsoc_txfifo_empty_en);
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
	} else {
		/* tx transfer mode switch into dma mode */
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_STOP);
		wr_regl(port, ureg->sirfsoc_tx_dma_io_ctrl,
			rd_regl(port, ureg->sirfsoc_tx_dma_io_ctrl)&
			~SIRFUART_IO_MODE);
		wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
		tran_size &= ~(0x3);

		sirfport->tx_dma_addr = dma_map_single(port->dev,
			xmit->buf + xmit->tail,
			tran_size, DMA_TO_DEVICE);
		sirfport->tx_dma_desc = dmaengine_prep_slave_single(
			sirfport->tx_dma_chan, sirfport->tx_dma_addr,
			tran_size, DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
		if (!sirfport->tx_dma_desc) {
			dev_err(port->dev, "DMA prep slave single fail\n");
			return;
		}
		sirfport->tx_dma_desc->callback =
			sirfsoc_uart_tx_dma_complete_callback;
		sirfport->tx_dma_desc->callback_param = (void *)sirfport;
		sirfport->transfer_size = tran_size;

		dmaengine_submit(sirfport->tx_dma_desc);
		dma_async_issue_pending(sirfport->tx_dma_chan);
		sirfport->tx_dma_state = TX_DMA_RUNNING;
	}
}
static void ev3_uart_handle_rx_data(struct work_struct *work)
{
	struct ev3_uart_port_data *port =
		container_of(work, struct ev3_uart_port_data, rx_data_work);
	struct circ_buf *cb = &port->circ_buf;
	u8 message[EV3_UART_MAX_MESSAGE_SIZE + 2];
	int count = CIRC_CNT(cb->head, cb->tail, EV3_UART_BUFFER_SIZE);
	int i, speed, size_to_end;
	u8 cmd, cmd2, type, mode, msg_type, msg_size, chksum;

#ifdef DEBUG
	printk("received: ");
	for (i = 0; i < count; i++) {
		cmd = cb->buf[(cb->tail + i) % EV3_UART_BUFFER_SIZE];
		if (cmd >= 32 && cmd < 127)
			printk("%c ", cmd);
		else
			printk("0x%02x ", cmd);
	}
	printk("(%d)\n", count);
#endif

	/*
	 * To get in sync with the data stream from the sensor, we look
	 * for a valid TYPE command.
	 */
	while (!port->synced) {
		if (count < 3)
			return;
		cmd = cb->buf[cb->tail];
		cb->tail++;
		if (cb->tail >= EV3_UART_BUFFER_SIZE)
			cb->tail = 0;
		count--;
		if (cmd != (EV3_UART_MSG_TYPE_CMD | EV3_UART_CMD_TYPE))
			continue;
		type = cb->buf[cb->tail];
		if (!type || type > EV3_UART_TYPE_MAX)
			continue;
		chksum = 0xFF ^ cmd ^ type;
		if ((u8)cb->buf[(cb->tail + 1) % EV3_UART_BUFFER_SIZE] != chksum)
			continue;
		port->sensor.num_modes = 1;
		port->sensor.num_view_modes = 1;
		for (i = 0; i <= EV3_UART_MODE_MAX; i++)
			port->mode_info[i] = ev3_uart_default_mode_info;
		port->type_id = type;
		/* look up well-known driver names */
		port->device_name[0] = 0;
		for (i = 0; i < NUM_LEGO_EV3_SENSOR_TYPES; i++) {
			if (type == ev3_uart_sensor_defs[i].type_id) {
				snprintf(port->device_name, LEGO_SENSOR_NAME_SIZE,
					 "%s", ev3_uart_sensor_defs[i].name);
				break;
			}
		}
		/* or use generic name if well-known name is not found */
		if (!port->device_name[0])
			snprintf(port->device_name, LEGO_SENSOR_NAME_SIZE,
				 EV3_UART_SENSOR_NAME("%u"), type);
		port->info_flags = EV3_UART_INFO_FLAG_CMD_TYPE;
		port->synced = 1;
		port->info_done = 0;
		port->data_rec = 0;
		port->num_data_err = 0;
		cb->tail = (cb->tail + 2) % EV3_UART_BUFFER_SIZE;
		count -= 2;
	}
	if (!port->synced)
		return;

	while (count > 0)
	{
		/*
		 * Sometimes we get 0xFF after switching baud rates, so just
		 * ignore it.
		 */
		if ((u8)cb->buf[cb->tail] == 0xFF) {

			cb->tail++;
			if (cb->tail >= EV3_UART_BUFFER_SIZE)
				cb->tail = 0;
			count--;
			continue;
		}
		msg_size = ev3_uart_msg_size((u8)cb->buf[cb->tail]);
		if (msg_size > count)
			break;
		size_to_end = CIRC_CNT_TO_END(cb->head, cb->tail, EV3_UART_BUFFER_SIZE);
		if (msg_size > size_to_end) {
			memcpy(message, cb->buf + cb->tail, size_to_end);
			memcpy(message + size_to_end, cb->buf, msg_size - size_to_end);
			cb->tail = msg_size - size_to_end;
		} else {
			memcpy(message, cb->buf + cb->tail, msg_size);
			cb->tail += msg_size;
			if (cb->tail >= EV3_UART_BUFFER_SIZE)
				cb->tail = 0;
		}
		count -= msg_size;
#ifdef DEBUG
		printk("processing: ");
		for (i = 0; i < msg_size; i++)
			printk("0x%02x ", message[i]);
		printk(" (%d)\n", msg_size);
#endif
		if (msg_size > EV3_UART_MAX_MESSAGE_SIZE) {
			port->last_err = "Bad message size.";
			goto err_invalid_state;
		}
		msg_type = message[0] & EV3_UART_MSG_TYPE_MASK;
		cmd = message[0] & EV3_UART_MSG_CMD_MASK;
		mode = cmd;
		cmd2 = message[1];
		if (msg_size > 1) {
			chksum = 0xFF;
			for (i = 0; i < msg_size - 1; i++)
				chksum ^= message[i];
			debug_pr("chksum:%d, actual:%d\n",
			         chksum, message[msg_size - 1]);
			/*
			 * The LEGO EV3 color sensor sends bad checksums
			 * for RGB-RAW data (mode 4). The check here could be
			 * improved if someone can find a pattern.
			 */
			if (chksum != message[msg_size - 1]
			    && port->type_id != EV3_UART_TYPE_ID_COLOR
			    && message[0] != 0xDC)
			{
				port->last_err = "Bad checksum.";
				if (port->info_done) {
					port->num_data_err++;
					goto err_bad_data_msg_checksum;
				} else
					goto err_invalid_state;
			}
		}
		switch (msg_type) {
		case EV3_UART_MSG_TYPE_SYS:
			debug_pr("SYS:%d\n", message[0] & EV3_UART_MSG_CMD_MASK);
			switch(cmd) {
			case EV3_UART_SYS_SYNC:
				/* IR sensor (type 33) sends checksum after SYNC */
				if (msg_size > 1 && (cmd ^ cmd2) == 0xFF)
					msg_size++;
				break;
			case EV3_UART_SYS_ACK:
				if (!port->sensor.num_modes) {
					port->last_err = "Received ACK before all mode INFO.";
					goto err_invalid_state;
				}
				if ((port->info_flags & EV3_UART_INFO_FLAG_REQUIRED)
				    != EV3_UART_INFO_FLAG_REQUIRED)
				{
					port->last_err = "Did not receive all required INFO.";
					goto err_invalid_state;
				}
				schedule_delayed_work(&port->send_ack_work,
						      msecs_to_jiffies(EV3_UART_SEND_ACK_DELAY));
				port->info_done = 1;
				return;
			}
			break;
		case EV3_UART_MSG_TYPE_CMD:
			debug_pr("CMD:%d\n", cmd);
			switch (cmd) {
			case EV3_UART_CMD_MODES:
				if (test_and_set_bit(EV3_UART_INFO_BIT_CMD_MODES,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate modes INFO.";
					goto err_invalid_state;
				}
				if (!cmd2 || cmd2 > EV3_UART_MODE_MAX) {
					port->last_err = "Number of modes is out of range.";
					goto err_invalid_state;
				}
				port->sensor.num_modes = cmd2 + 1;
				if (msg_size > 3)
					port->sensor.num_view_modes = message[2] + 1;
				else
					port->sensor.num_view_modes = port->sensor.num_modes;
				debug_pr("num_modes:%d, num_view_modes:%d\n",
					 port->sensor.num_modes, port->sensor.num_view_modes);
				break;
			case EV3_UART_CMD_SPEED:
				if (test_and_set_bit(EV3_UART_INFO_BIT_CMD_SPEED,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate speed INFO.";
					goto err_invalid_state;
				}
				speed = *(int*)(message + 1);
				if (speed < EV3_UART_SPEED_MIN
				    || speed > EV3_UART_SPEED_MAX)
				{
					port->last_err = "Speed is out of range.";
					goto err_invalid_state;
				}
				port->new_baud_rate = speed;
				debug_pr("speed:%d\n", speed);
				break;
			default:
				port->last_err = "Unknown command.";
				goto err_invalid_state;
			}
			break;
		case EV3_UART_MSG_TYPE_INFO:
			debug_pr("INFO:%d, mode:%d\n", cmd2, mode);
			switch (cmd2) {
			case EV3_UART_INFO_NAME:
				port->info_flags &= ~EV3_UART_INFO_FLAG_ALL_INFO;
				if (message[2] < 'A' || message[2] > 'z') {
					port->last_err = "Invalid name INFO.";
					goto err_invalid_state;
				}
				/*
				 * Name may not have null terminator and we
				 * are done with the checksum at this point
				 * so we are writing 0 over the checksum to
				 * ensure a null terminator for the string
				 * functions.
				 */
				message[msg_size - 1] = 0;
				if (strlen(message + 2) > EV3_UART_MODE_NAME_SIZE) {
					port->last_err = "Name is too long.";
					goto err_invalid_state;
				}
				snprintf(port->mode_info[mode].name,
				         EV3_UART_MODE_NAME_SIZE + 1, "%s",
				         message + 2);
				if (port->sensor.mode != mode) {
					port->sensor.mode = mode;
					kobject_uevent(&port->sensor.dev.kobj,
						       KOBJ_CHANGE);
				}
				port->info_flags |= EV3_UART_INFO_FLAG_INFO_NAME;
				debug_pr("mode %d name:%s\n",
				       mode, port->sensor.address);
				break;
			case EV3_UART_INFO_RAW:
				if (port->sensor.mode != mode) {
					port->last_err = "Received INFO for incorrect mode.";
					goto err_invalid_state;
				}
				if (test_and_set_bit(EV3_UART_INFO_BIT_INFO_RAW,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate raw scaling INFO.";
					goto err_invalid_state;
				}
				port->raw_min = *(u32 *)(message + 2);
				port->raw_max = *(u32 *)(message + 6);
				debug_pr("mode %d raw_min:%08x, raw_max:%08x\n",
				       mode, port->mode_info[mode].raw_min,
				       port->mode_info[mode].raw_max);
				break;
			case EV3_UART_INFO_PCT:
				if (port->sensor.mode != mode) {
					port->last_err = "Received INFO for incorrect mode.";
					goto err_invalid_state;
				}
				if (test_and_set_bit(EV3_UART_INFO_BIT_INFO_PCT,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate percent scaling INFO.";
					goto err_invalid_state;
				}
				port->pct_min = *(u32 *)(message + 2);
				port->pct_max = *(u32 *)(message + 6);
				debug_pr("mode %d pct_min:%08x, pct_max:%08x\n",
				       mode, port->mode_info[mode].pct_min,
				       port->mode_info[mode].pct_max);
				break;
			case EV3_UART_INFO_SI:
				if (port->sensor.mode != mode) {
					port->last_err = "Received INFO for incorrect mode.";
					goto err_invalid_state;
				}
				if (test_and_set_bit(EV3_UART_INFO_BIT_INFO_SI,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate SI scaling INFO.";
					goto err_invalid_state;
				}
				port->si_min = *(u32 *)(message + 2);
				port->si_max = *(u32 *)(message + 6);
				debug_pr("mode %d si_min:%08x, si_max:%08x\n",
				       mode, port->mode_info[mode].si_min,
				       port->mode_info[mode].si_max);
				break;
			case EV3_UART_INFO_UNITS:
				if (port->sensor.mode != mode) {
					port->last_err = "Received INFO for incorrect mode.";
					goto err_invalid_state;
				}
				if (test_and_set_bit(EV3_UART_INFO_BIT_INFO_UNITS,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate SI units INFO.";
					goto err_invalid_state;
				}
				/*
				 * Units may not have null terminator and we
				 * are done with the checksum at this point
				 * so we are writing 0 over the checksum to
				 * ensure a null terminator for the string
				 * functions.
				 */
				message[msg_size - 1] = 0;
				snprintf(port->mode_info[mode].units,
					 EV3_UART_UNITS_SIZE + 1, "%s",
					 message + 2);
				debug_pr("mode %d units:%s\n",
				       mode, port->mode_info[mode].units);
				break;
			case EV3_UART_INFO_FORMAT:
				if (port->sensor.mode != mode) {
					port->last_err = "Received INFO for incorrect mode.";
					goto err_invalid_state;
				}
				if (test_and_set_bit(EV3_UART_INFO_BIT_INFO_FORMAT,
						     &port->info_flags))
				{
					port->last_err = "Received duplicate format INFO.";
					goto err_invalid_state;
				}
				port->mode_info[mode].data_sets = message[2];
				if (!port->mode_info[mode].data_sets) {
					port->last_err = "Invalid number of data sets.";
					goto err_invalid_state;
				}
				if (msg_size < 7) {
					port->last_err = "Invalid format message size.";
					goto err_invalid_state;
				}
				if ((port->info_flags & EV3_UART_INFO_FLAG_REQUIRED)
						!= EV3_UART_INFO_FLAG_REQUIRED) {
					port->last_err = "Did not receive all required INFO.";
					goto err_invalid_state;
				}
				switch (message[3]) {
				case EV3_UART_DATA_8:
					port->mode_info[mode].data_type = LEGO_SENSOR_DATA_S8;
					break;
				case EV3_UART_DATA_16:
					port->mode_info[mode].data_type = LEGO_SENSOR_DATA_S16;
					break;
				case EV3_UART_DATA_32:
					port->mode_info[mode].data_type = LEGO_SENSOR_DATA_S32;
					break;
				case EV3_UART_DATA_FLOAT:
					port->mode_info[mode].data_type = LEGO_SENSOR_DATA_FLOAT;
					break;
				default:
					port->last_err = "Invalid data type.";
					goto err_invalid_state;
				}
				port->mode_info[mode].figures = message[4];
				port->mode_info[mode].decimals = message[5];
				if (port->info_flags & EV3_UART_INFO_FLAG_INFO_RAW) {
					port->mode_info[mode].raw_min =
						lego_sensor_ftoi(port->raw_min, 0);
					port->mode_info[mode].raw_max =
						lego_sensor_ftoi(port->raw_max, 0);
				}
				if (port->info_flags & EV3_UART_INFO_FLAG_INFO_PCT) {
					port->mode_info[mode].pct_min =
						lego_sensor_ftoi(port->pct_min, 0);
					port->mode_info[mode].pct_max =
						lego_sensor_ftoi(port->pct_max, 0);
				}
				if (port->info_flags & EV3_UART_INFO_FLAG_INFO_SI) {
					port->mode_info[mode].si_min =
						lego_sensor_ftoi(port->si_min,
							port->mode_info[mode].decimals);
					port->mode_info[mode].si_max =
						lego_sensor_ftoi(port->si_max,
							port->mode_info[mode].decimals);
				}
				if (port->sensor.mode)
					port->sensor.mode--;
				debug_pr("mode %d - data_sets:%d, data_type:%d, figures:%d, decimals:%d\n",
					 mode, port->mode_info[mode].data_sets,
					 port->mode_info[mode].data_type,
					 port->mode_info[mode].figures,
					 port->mode_info[mode].decimals);
				debug_pr("raw_min: %d, raw_max: %d\n",
					 port->mode_info[mode].raw_min,
					 port->mode_info[mode].raw_max);
				debug_pr("pct_min: %d, pct_max: %d\n",
					 port->mode_info[mode].pct_min,
					 port->mode_info[mode].pct_max);
				debug_pr("si_min: %d, si_max: %d\n",
					 port->mode_info[mode].si_min,
					 port->mode_info[mode].si_max);
				break;
			}
			break;
		case EV3_UART_MSG_TYPE_DATA:
			debug_pr("DATA:%d\n", message[0] & EV3_UART_MSG_CMD_MASK);
			if (!port->info_done) {
				port->last_err = "Received DATA before INFO was complete.";
				goto err_invalid_state;
			}
			if (mode > EV3_UART_MODE_MAX) {
				port->last_err = "Invalid mode received.";
				goto err_invalid_state;
			}
			if (mode != port->sensor.mode) {
				if (mode == port->new_mode) {
					port->sensor.mode = mode;
					kobject_uevent(&port->sensor.dev.kobj,
						       KOBJ_CHANGE);
				} else {
					port->last_err = "Unexpected mode.";
					goto err_invalid_state;
				}
			}
			if (!completion_done(&port->set_mode_completion)
			    && mode == port->new_mode)
				complete(&port->set_mode_completion);
			memcpy(port->mode_info[mode].raw_data, message + 1, msg_size - 2);
			port->data_rec = 1;
			if (port->num_data_err)
				port->num_data_err--;
			break;
		}
err_bad_data_msg_checksum:
		count = CIRC_CNT(cb->head, cb->tail, EV3_UART_BUFFER_SIZE);
	}
	return;

err_invalid_state:
	port->synced = 0;
	port->new_baud_rate = EV3_UART_SPEED_MIN;
	schedule_work(&port->change_bitrate_work);
}