/*-
 * Copyright (c) 2001 Brian Somers <brian@Awfulhak.org>
 *   based on work by Slawa Olhovchenkov
 *                    John Prince <johnp@knight-trosoft.com>
 *                    Eric Hernes
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * $FreeBSD: src/sys/dev/digi/digi.h,v 1.19 2004/10/14 18:37:59 phk Exp $
 */

#define	W(p)				(*(u_int16_t *)(p))
#define	vW(p)				(*(u_int16_t volatile *)(p))
#define	D(p)				(*(u_int32_t *)(p))
#define	vD(p)				(*(u_int32_t volatile *)(p))

#define	CE_OVERRUN			0
#define	CE_INTERRUPT_BUF_OVERFLOW	1
#define	CE_TTY_BUF_OVERFLOW		2
#define	CE_NTYPES			3
#define	CE_RECORD(com, errnum)		(++(com)->delta_error_counts[errnum])

/*#define DIGI_INTERRUPT*/

#ifndef DEBUG
#define	DEBUG
#endif

#ifdef DEBUG
extern unsigned digi_debug;
#define	DLOG(level, args)	if (digi_debug & (level)) device_printf args
#else
#define	DLOG(level, args)
#endif


struct digi_softc;

/* digiboard port structure */
struct digi_p {
	struct digi_softc *sc;

	int status;
#define ENABLED 1
#define DIGI_DTR_OFF 2
#define PAUSE_TX 8
#define PAUSE_RX 16

	int opencnt;
	u_short txbufsize;
	u_short rxbufsize;
	volatile struct board_chan *bc;
	struct tty *tp;

	u_char *txbuf;
	u_char *rxbuf;
	u_char txwin;
	u_char rxwin;

	u_char pnum;		/* port number */

	u_char modemfake;	/* Modem values to be forced */
	u_char mstat;
	u_char modem;		/* Force values */

	/*
	 * The high level of the driver never reads status registers directly
	 * because there would be too many side effects to handle conveniently.
	 * Instead, it reads copies of the registers stored here by the
	 * interrupt handler.
	 */
	u_char last_modem_status;	/* last MSR read by intr handler */
	u_char prev_modem_status;	/* last MSR handled by high level */

	u_long bytes_in, bytes_out;
	u_int delta_error_counts[CE_NTYPES];
	u_long error_counts;

	tcflag_t c_iflag;		/* hold true IXON/IXOFF/IXANY */
	int lcc, lostcc, lbuf;
	u_char send_ring;

	unsigned laltpin : 1;		/* Alternate pin settings locked */
	unsigned ialtpin : 1;		/* Initial alternate pin settings */

	int cd;				/* Depends on the altpin setting */
	int dsr;
};

/*
 * Map TIOCM_* values to digiboard values
 */
struct digi_control_signals {
	int rts;
	int cd;
	int dsr;
	int cts;
	int ri;
	int dtr;
};

enum digi_board_status {
	DIGI_STATUS_NOTINIT,
	DIGI_STATUS_ENABLED,
	DIGI_STATUS_DISABLED
};

/* Digiboard per-board structure */
struct digi_softc {
	/* struct board_info */
	device_t dev;

	const char *name;
	enum digi_board_status status;
	u_short numports;		/* number of ports on card */
	u_int port;			/* I/O port */
	u_int wport;			/* window select I/O port */

	struct {
		struct resource *mem;
		int mrid;
		struct resource *irq;
		int irqrid;
		struct resource *io;
		int iorid;
		void *irqHandler;
		int unit;
		struct cdev *ctldev;
	} res;

	u_char *vmem;			/* virtual memory address */
	u_char *memcmd;
	volatile u_char *memevent;
	long pmem;			/* physical memory address */

	struct {
		u_char *data;
		size_t size;
	} bios, fep, link;

#ifdef DIGI_INTERRUPT
	struct timeval intr_timestamp;
#endif

	struct digi_p *ports;	/* pointer to array of port descriptors */
	volatile struct global_data *gdata;
	u_char window;		/* saved window */
	int win_size;
	int win_bits;
	int mem_size;
	int mem_seg;
	enum digi_model model;
	const struct digi_control_signals *csigs;
	int opencnt;
	unsigned pcibus : 1;		/* On a PCI bus ? */

	struct callout_handle callout;	/* poll timeout handle */
	struct callout_handle inttest;	/* int test timeout handle */
	const char *module;
	
	u_char *(*setwin)(struct digi_softc *_sc, unsigned _addr);
	void	(*hidewin)(struct digi_softc *_sc);
	void	(*towin)(struct digi_softc *_sc, int _win);
#ifdef DEBUG
	int	intr_count;
#endif
};

extern devclass_t digi_devclass;

extern const struct digi_control_signals digi_xixe_signals;
extern const struct digi_control_signals digi_normal_signals;

const char	*digi_errortxt(int _id);
int		 digi_attach(struct digi_softc *);
int		 digi_detach(device_t _dev);
int		 digi_shutdown(device_t _dev);
void		 digi_delay(struct digi_softc *_sc, const char *_txt,
		     u_long _timo);
