/*	$OpenBSD: musyccvar.h,v 1.9 2006/02/06 17:29:11 jmc Exp $ */

/*
 * Copyright (c) 2004,2005  Internet Business Solutions AG, Zurich, Switzerland
 * Written by: Claudio Jeker <jeker@accoom.net>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */
#ifndef __MUSYCCVAR_H__
#define __MUSYCCVAR_H__

#include <sys/queue.h>

#define PPP_HEADER_LEN 4		/* should be globaly defined by sppp */

/* some defaults */
#define MUSYCC_NUMCHAN		32	/* 32 channels per group */
#define MUSYCC_NUMPORT		8	/* max 8 ports per controller */
#define MUSYCC_SREQNUM		16	/* pending SREQ */
#define MUSYCC_SREQMASK		(MUSYCC_SREQNUM - 1)
#define MUSYCC_SREQTIMEOUT	2

/* dma ring sizes */
#define MUSYCC_DMA_CNT		256
#define MUSYCC_DMA_MAPSIZE	(MUSYCC_DMA_CNT * sizeof(struct dma_desc))
#define MUSYCC_DMA_SIZE		32

struct musycc_softc;
struct ebus_softc;

/* DMA descriptor for data */
struct dma_desc {
	u_int32_t		 status;
	u_int32_t		 data;
	u_int32_t		 next;
	/* Software only */
	struct mbuf		*mbuf;
	struct dma_desc		*nextdesc;
	bus_dmamap_t		 map;
};

#define MUSYCC_INTLEN		512	/* 512 pending interrupts is enough */
struct musycc_intdesc {
	u_int32_t		 md_intrq[MUSYCC_INTLEN];
};

struct musycc_dma_data {
	/*
	 * received dma ring. rx_prod points to the frist descriptors that
	 * is under musycc control (first empty).
	 */
	struct dma_desc		*rx_prod;
	int			 rx_cnt;

	struct dma_desc		*tx_pend;	/* finished pointer */
	struct dma_desc		*tx_cur;	/* current insertion pointer */
	int			 tx_cnt;	/* number of descriptors */
	int			 tx_use;	/* number of used descriptors */
	int			 tx_pkts;	/* number of packets in queue */
};

enum musycc_state {
	CHAN_FLOAT,	/* unconnected channel */
	CHAN_IDLE,
	CHAN_RUNNING,
	CHAN_FAULT,
	CHAN_TRANSIENT	/* dummy state to protect ongoing state changes */
};

enum musycc_event {
	EV_NULL,	/* null event, ignore */
	EV_ACTIVATE,	/* activate channel go to running state */
	EV_STOP,	/* stop dma engine */
	EV_IDLE,	/* free timeslots et al. and go to idle state */
	EV_WATCHDOG	/* watchdog event, stop dma engine */
};

/* group structure */
struct musycc_group {
	struct musycc_softc	*mg_hdlc;	/* main controller */
	struct musycc_grpdesc	*mg_group;	/* group descriptor */
	u_int8_t		 mg_gnum;	/* group number */
	u_int8_t		 mg_port;	/* port number */
	u_int8_t		 mg_loaded;	/* sreq(5) done? */
	u_int64_t		 mg_fifomask;	/* fifo allocation mask */

	struct channel_softc	*mg_channels[MUSYCC_NUMCHAN];
	struct musycc_dma_data	 mg_dma_d[MUSYCC_NUMCHAN];
	struct dma_desc		*mg_freelist;
	int			 mg_freecnt;

	struct {
		long			timeout;
		u_int32_t		sreq;
		enum musycc_event	event;
	}			 mg_sreq[MUSYCC_SREQNUM];
	int			 mg_sreqpend;
	int			 mg_sreqprod;

	struct dma_desc		*mg_dma_pool;
	bus_dma_tag_t		 mg_dmat;	/* bus dma tag */
	caddr_t			 mg_listkva;
	bus_dmamap_t		 mg_listmap;
	bus_dma_segment_t	 mg_listseg[1];
	int			 mg_listnseg;
	bus_dmamap_t		 mg_tx_sparemap;
	bus_dmamap_t		 mg_rx_sparemap;
};

/* attach arguments for framer devices */
struct musycc_attach_args {
	char				ma_product[64];
	bus_size_t			ma_base;
	bus_size_t			ma_size;
	u_int32_t			ma_type;
	u_int8_t			ma_gnum;
	u_int8_t			ma_port;
	u_int8_t			ma_flags;
	char				ma_slot;
};

/* generic ebus device handle */
struct ebus_dev {
	bus_size_t			base;
	bus_size_t			size;
	bus_space_tag_t			st;
	bus_space_handle_t		sh;
};

/* Softc for each HDLC channel config */
struct channel_softc {
	struct sppp		 cc_ppp;	/* sppp network attachement */
	struct ifnet		*cc_ifp;	/* pointer to the active ifp */
	struct musycc_group	*cc_group;
	struct device		*cc_parent;	/* parent framer */

	u_int32_t		 cc_tslots;	/* timeslot map */
	int			 cc_unit;
	enum musycc_state	 cc_state;	/* state machine info */
	u_int8_t		 cc_channel;	/* HDLC channel */
	u_int8_t		 cc_locked;
};

/* Softc for the HDLC Controller (function 0) */
struct musycc_softc {
	struct device		 mc_dev;	/* generic device structures */
	void			*mc_ih;		/* interrupt handler cookie */
	bus_space_tag_t		 mc_st;		/* bus space tag */
	bus_space_handle_t	 mc_sh;		/* bus space handle */
	bus_dma_tag_t		 mc_dmat;	/* bus dma tag */
	bus_size_t		 mc_iosize;	/* size of bus space */

	caddr_t			 mc_groupkva;	/* group configuration mem */
	bus_dmamap_t		 mc_cfgmap;
	bus_dma_segment_t	 mc_cfgseg[1];
	bus_dmamap_t		 mc_intrmap;
	bus_dma_segment_t	 mc_intrseg[1];
	int			 mc_cfgnseg;
	int			 mc_intrnseg;

	struct musycc_group	*mc_groups;	/* mc_ngroups groups */
	struct musycc_intdesc	*mc_intrd;
	u_int32_t		 mc_global_conf; /* global config descriptor */
	u_int32_t		 mc_intrqptr;	 /* interrupt queue pointer */
	int			 mc_ngroups;
	int			 mc_nports;

	struct musycc_softc	*mc_other;	/* the other EBUS/HDLC dev */
	bus_size_t		 mc_ledbase;
	u_int8_t		 mc_ledmask;
	u_int8_t		 mc_ledstate;	/* current state of the LEDs */
	int			 bus, device;	/* location of card */
	SLIST_ENTRY(musycc_softc) list;		/* list of all hdlc ctrls */
};

int	musycc_attach_common(struct musycc_softc *, u_int32_t, u_int32_t);
void	musycc_set_port(struct musycc_group *, int);
int	musycc_init_channel(struct channel_softc *, char);
void	musycc_stop_channel(struct channel_softc *);
void	musycc_free_channel(struct musycc_group *, int);
void	musycc_start(struct ifnet *);
void	musycc_watchdog(struct ifnet *);
void	musycc_tick(struct channel_softc *);

int	musycc_intr(void *);
int	ebus_intr(void *);

/* EBUS API */
int		ebus_attach_device(struct ebus_dev *, struct musycc_softc *,
		    bus_size_t, bus_size_t);
u_int8_t	ebus_read(struct ebus_dev *, bus_size_t);
void		ebus_write(struct ebus_dev *, bus_size_t, u_int8_t);
void		ebus_read_buf(struct ebus_dev *, bus_size_t, void *, size_t);
void		ebus_set_led(struct channel_softc *, int, u_int8_t);

#define MUSYCC_LED_GREEN	0x1
#define MUSYCC_LED_RED		0x2
#define MUSYCC_LED_MASK		0x3

/* channel API */
struct channel_softc	*musycc_channel_create(const char *, u_int8_t);
void		musycc_attach_sppp(struct channel_softc *,
		    int (*)(struct ifnet *, u_long, caddr_t));
int		musycc_channel_attach(struct musycc_softc *,
		    struct channel_softc *, struct device *, u_int8_t);
void		musycc_channel_detach(struct ifnet *);


#ifndef ACCOOM_DEBUG
#define ACCOOM_PRINTF(n, x)
#else
extern int accoom_debug;

#define ACCOOM_PRINTF(n, x)					\
	do {							\
		if (accoom_debug >= n)				\
			printf x;				\
	} while (0)
#endif

#endif