/*
  Copyright 2004, 2005 Jean-Baptiste Note
  Copyright (C) 2003 Conexant Americas Inc.

  This file is part of prism54usb.

  prism54usb is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  prism54usb is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with prism54usb; if not, write to the Free Software Foundation,
  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

*/

#ifndef _HAVE_ISL_UART_H_
#define _HAVE_ISL_UART_H_

#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/wait.h>

struct islsm;

/* queue note :

   on the uart rx queue,

   - the p (producer end) is manipulated by the irq handler, and write
   access must be under spinlock, taking care that the data write
   happens *before* the pointer update. Under those conditions, read
   from userspace should be coherent.

   - the c (consumer) end is manipulated by the user-space interface
   functions. Access should be done under a lightweight semaphore, as
   concurrency only exists within userspace.

   on the uart tx queue, the reverse happens :

   - the p (producer) end is written by user-space under semaphore, and
   read by the irq handler => use atomic value.

   - the c (consumer) end is written by irq handlers, under spinlock,
   taking care that the data write happens *before* the pointer update,
   and read by userspace.

   There's a problem whereby a process goes to sleep waiting for some
   data to be available : we want to ensure this process will not "miss"
   a "data available" signal from the DR irq.

*/

struct queue_s {
	uint32_t                s;
	uint32_t                p;
	uint32_t                c;
	uint8_t                *q;
};

/* this structure describes an uart instance */
/* it is used as reference to the uart device
   in the sm device */

typedef struct {
	struct cdev             dev;
	int                     is_open;

	uint32_t                cts;	/* CTS pending */
	wait_queue_head_t       wait;	/* read wait queue */
	spinlock_t              lock;
	uint32_t                major;

	struct queue_s          txq;
	struct queue_s          rxq;
} uart_instance_t;

/* queue management exported and used in the irq handler */
#define UARTPCI_TXQSIZE     (4 * 1024)
#define UARTPCI_RXQSIZE     (4 * 1024)

/* interface functions */
void                    uart_release_dev(struct islsm *islsm);
int                     uart_init_dev(struct islsm *islsm);

/* low-level queue access functions */
static inline int uart_inq(uart_instance_t *uart, struct queue_s *queue)
{
	uint32_t                inq;

	inq = queue->p - queue->c;
	return inq;
}

static inline uint8_t
uart_qconsume(uart_instance_t *uart, struct queue_s *queue)
{
	uint8_t                 ret;

	ret = queue->q[queue->c % queue->s];
	(queue->c)++;

	return ret;
}

static inline void
uart_qproduce(uart_instance_t *uart, struct queue_s *queue, uint8_t val)
{
	queue->q[queue->p % queue->s] = val;
	(queue->p)++;
}

#endif				/* _HAVE_ISL_UART_H_ */
