/*
 * DAHDI Telephony Interface
 *
 * Written by Mark Spencer <markster@digium.com>
 * Based on previous works, designs, and architectures conceived and
 * written by Jim Dixon <jim@lambdatel.com>.
 *
 * Copyright (C) 2001 Jim Dixon / Zapata Telephony.
 * Copyright (C) 2001 - 2012 Digium, Inc.
 *
 * All rights reserved.
 *
 */

/*
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2 as published by the
 * Free Software Foundation. See the LICENSE file included with
 * this program for more details.
 */

/*!
 * \file
 * \brief DAHDI kernel interface definitions
 */

#ifndef _DAHDI_KERNEL_H
#define _DAHDI_KERNEL_H

#include <dahdi/user.h>
#include <dahdi/fasthdlc.h>

#include <dahdi/dahdi_config.h>
#include <linux/version.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/ioctl.h>

#ifdef CONFIG_DAHDI_NET	
#include <linux/hdlc.h>
#endif

#ifdef CONFIG_DAHDI_PPP
#include <linux/ppp_channel.h>
#include <linux/skbuff.h>
#include <linux/interrupt.h>
#endif
#include <linux/device.h>
#include <linux/sysfs.h>

#include <linux/poll.h>

#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
#include <linux/compiler_attributes.h>
#endif
#ifndef fallthrough
#define fallthrough do {} while (0)  /* fallthrough */
#endif

#ifdef CONFIG_PCI
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 4, 0)
#include <linux/pci.h>
#else
#include <linux/pci-aspm.h>
#endif
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 17, 0)
#define PDE_DATA(i)	pde_data(i)
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
#define from_timer timer_container_of
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,15,0)
#define del_timer timer_delete
#define del_timer_sync timer_delete_sync
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 18, 0)
#include <linux/dma-mapping.h>
static inline void *
pci_alloc_consistent(struct pci_dev *hwdev, size_t size,
		     dma_addr_t *dma_handle)
{
	return dma_alloc_coherent(&hwdev->dev, size, dma_handle, GFP_ATOMIC);
}

static inline void
pci_free_consistent(struct pci_dev *hwdev, size_t size,
		    void *vaddr, dma_addr_t dma_handle)
{
	dma_free_coherent(&hwdev->dev, size, vaddr, dma_handle);
}
static inline dma_addr_t
pci_map_single(struct pci_dev *hwdev, void *ptr, size_t size, int direction)
{
	return dma_map_single(&hwdev->dev, ptr, size, (enum dma_data_direction)direction);
}

static inline void
pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
		 size_t size, int direction)
{
	dma_unmap_single(&hwdev->dev, dma_addr, size, (enum dma_data_direction)direction);
}
static inline int pci_set_dma_mask(struct pci_dev *dev, u64 mask)
{
	return dma_set_mask(&dev->dev, mask);
}
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29)
#define HAVE_NET_DEVICE_OPS
#endif

/* __dev* were removed in 3.8. They still have effect in 2.6.18. */
#ifndef __devinit
#  define __devinit
#  define __devinitdata
#  define __devexit
#  define __devexit_p(x) x
#endif

/*! Default chunk size for conferences and such -- static right now, might make
   variable sometime.  8 samples = 1 ms = most frequent service interval possible
   for a USB device */
#define DAHDI_CHUNKSIZE		 8
#define DAHDI_MIN_CHUNKSIZE	 DAHDI_CHUNKSIZE
#define DAHDI_DEFAULT_CHUNKSIZE	 DAHDI_CHUNKSIZE
#define DAHDI_MAX_CHUNKSIZE 	 DAHDI_CHUNKSIZE
#define DAHDI_CB_SIZE		 (1 << 3)

/* DAHDI operates at 8Khz by default */
#define DAHDI_MS_TO_SAMPLES(ms) ((ms) * 8)

#define DAHDI_MSECS_PER_CHUNK	(DAHDI_CHUNKSIZE/DAHDI_MS_TO_SAMPLES(1))

#define RING_DEBOUNCE_TIME	2000	/*!< 2000 ms ring debounce time */

typedef struct
{
    int32_t gain;
    int32_t a1;
    int32_t a2;
    int32_t b1;
    int32_t b2;

    int32_t z1;
    int32_t z2;
} biquad2_state_t;

typedef struct
{
    biquad2_state_t notch;
    int notch_level;
    int channel_level;
    int tone_present;
    int tone_cycle_duration;
    int good_cycles;
    int hit;
} echo_can_disable_detector_state_t;

struct sf_detect_state {
	long	x1;
	long	x2;
	long	y1;
	long	y2;
	long	e1;
	long	e2;
	int	samps;
	int	lastdetect;
};

struct dahdi_tone_state {
	int v1_1;
	int v2_1;
	int v3_1;
	int v1_2;
	int v2_2;
	int v3_2;
	int modulate;
};

/*! \brief Conference queue structure */
struct confq {
	u_char buffer[DAHDI_CHUNKSIZE * DAHDI_CB_SIZE];
	u_char *buf[DAHDI_CB_SIZE];
	int inbuf;
	int outbuf;
};

struct dahdi_chan;
struct dahdi_echocan_state;

/*! Features a DAHDI echo canceler (software or hardware) can provide to the DAHDI core. */
struct dahdi_echocan_features {

	/*! Able to detect CED tone (2100 Hz with phase reversals) in the transmit direction.
	 * If the echocan can detect this tone, it may report it it as an event (see
	 * the events.CED_tx_detected field of dahdi_echocan_state), and if it will automatically
	 * disable itself or its non-linear processor, then the NLP_automatic feature flag should also
	 * be set so that the DAHDI core doesn't bother trying to do so.
	*/
	u32 CED_tx_detect:1;

	/*! Able to detect CED tone (2100 Hz with phase reversals) in the receive direction.
	 * If the echocan can detect this tone, it may report it it as an event (see
	 * the events.CED_rx_detected field of dahdi_echocan_state), and if it will automatically
	 * disable itself or its non-linear processor, then the NLP_automatic flag feature should also
	 * be set so that the DAHDI core doesn't bother trying to do so.
	*/
	u32 CED_rx_detect:1;

	/*! Able to detect CNG tone (1100 Hz) in the transmit direction. */
	u32 CNG_tx_detect:1;

	/*! Able to detect CNG tone (1100 Hz) in the receive direction. */
	u32 CNG_rx_detect:1;

	/*! If the echocan's NLP can be enabled and disabled without requiring destruction
	 * and recreation of the state structure, this feature flag should be set and the
	 * echocan_NLP_toggle field of the dahdi_echocan_ops structure should be filled with a
	 * pointer to the function to perform that operation.
	 */
	u32 NLP_toggle:1;

	/*! If the echocan will automatically disable itself (or even just its NLP) based on
	 * detection of a CED tone in either direction, this feature flag should be set (along
	 * with the tone detection feature flags).
	 */
	u32 NLP_automatic:1;
};

/*! Operations (methods) that can be performed on a DAHDI echo canceler instance (state
 * structure) after it has been created, by either a software or hardware echo canceller.
 * The echo canceler must populate the owner field of the dahdi_echocan_state structure
 * with a pointer to the relevant operations structure for that instance.
 */
struct dahdi_echocan_ops {

	/*! \brief Free an echocan state structure.
	 * \param[in,out] ec Pointer to the state structure to free.
	 *
	 * \return Nothing.
	 */
	void (*echocan_free)(struct dahdi_chan *chan, struct dahdi_echocan_state *ec);

	/*! \brief Process an array of audio samples through the echocan.
	 * \param[in,out] ec Pointer to the state structure.
	 * \param[in,out] isig The receive direction data (will be modified).
	 * \param[in] iref The transmit direction data.
	 * \param[in] size The number of elements in the isig and iref arrays.
	 *
	 * Note: This function can also return events in the events field of the
	 * dahdi_echocan_state structure. If it can do so, then the echocan does
	 * not need to provide the echocan_events function.
	 *
	 * \return Nothing.
	 */
	void (*echocan_process)(struct dahdi_echocan_state *ec, short *isig, const short *iref, u32 size);

	/*! \brief Retrieve events from the echocan.
	 * \param[in,out] ec Pointer to the state structure.
	 *
	 *
	 * If any events have occurred, the events field of the dahdi_echocan_state
	 * structure should be updated to include them.
	 *
	 * \return Nothing.
	 */
	void (*echocan_events)(struct dahdi_echocan_state *ec);

	/*! \brief Feed a sample (and its position) for echocan training.
	 * \param[in,out] ec Pointer to the state structure.
	 * \param[in] pos The tap position to be 'trained'.
	 * \param[in] val The receive direction sample for the specified tap position.
	 *
	 * \retval Zero if training should continue.
	 * \retval Non-zero if training is complete.
	 */
	int (*echocan_traintap)(struct dahdi_echocan_state *ec, int pos, short val);

	/*! \brief Enable or disable non-linear processing (NLP) in the echocan.
	 * \param[in,out] ec Pointer to the state structure.
	 * \param[in] enable Zero to disable, non-zero to enable.
	 *
	 * \return Nothing.
	 */
	void (*echocan_NLP_toggle)(struct dahdi_echocan_state *ec, unsigned int enable);

#ifdef CONFIG_DAHDI_ECHOCAN_PROCESS_TX
	/*! \brief Process an array of TX audio samples.
	 *
	 * \return Nothing.
	 */
	void (*echocan_process_tx)(struct dahdi_echocan_state *ec,
				   short *tx, u32 size);
#endif
};

/*! A factory for creating instances of software echo cancelers to be used on DAHDI channels. */
struct dahdi_echocan_factory {

	/*! Get the name of the factory. */
	const char *(*get_name)(const struct dahdi_chan *chan);

	/*! Pointer to the module that owns this factory; the module's reference count will be
	 * incremented/decremented by the DAHDI core as needed.
	 */
	struct module *owner;

	/*! \brief Function to create an instance of the echocan.
	 * \param[in] ecp Structure defining parameters to be used for the instance creation.
	 * \param[in] p Pointer to the beginning of an (optional) array of user-defined parameters.
	 * \param[out] ec Pointer to the state structure that is created, if any.
	 *
	 * \retval Zero on success.
	 * \retval Non-zero on failure (return value will be returned to userspace so it should be a
	 * standard error number).
	 */
	int (*echocan_create)(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
			      struct dahdi_echocanparam *p, struct dahdi_echocan_state **ec);
};

/*! \brief Register an echo canceler factory with the DAHDI core.
 * \param[in] ec Pointer to the dahdi_echocan_factory structure to be registered.
 *
 * \retval Zero on success.
 * \retval Non-zero on failure (return value will be a standard error number).
 */
int dahdi_register_echocan_factory(const struct dahdi_echocan_factory *ec);

/*! \brief Unregister a previously-registered echo canceler factory from the DAHDI core.
 * \param[in] ec Pointer to the dahdi_echocan_factory structure to be unregistered.
 *
 * \return Nothing.
 */
void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec);

enum dahdi_echocan_mode {
	__ECHO_MODE_MUTE = 1 << 8,
	ECHO_MODE_IDLE = 0,
	ECHO_MODE_PRETRAINING = 1 | __ECHO_MODE_MUTE,
	ECHO_MODE_STARTTRAINING = 2 | __ECHO_MODE_MUTE,
	ECHO_MODE_AWAITINGECHO = 3 | __ECHO_MODE_MUTE,
	ECHO_MODE_TRAINING = 4 | __ECHO_MODE_MUTE,
	ECHO_MODE_ACTIVE = 5,
	ECHO_MODE_FAX = 6,
};

/*! An instance of a DAHDI echo canceler (software or hardware). */
struct dahdi_echocan_state {

	/*! Pointer to a dahdi_echocan_ops structure of operations that can be
	 * performed on this instance.
	 */
	const struct dahdi_echocan_ops *ops;

	/*! State data used by the DAHDI core's CED detector for the transmit
	 * direction, if needed.
	 */
	echo_can_disable_detector_state_t txecdis;

	/*! State data used by the DAHDI core's CED detector for the receive
	 * direction, if needed.
	 */
	echo_can_disable_detector_state_t rxecdis;

	/*! Features offered by the echo canceler that provided this instance. */
	struct dahdi_echocan_features features;

	struct {
		/*! The mode the echocan is currently in. */
		enum dahdi_echocan_mode mode;

		/*! The last tap position that was fed to the echocan's training function. */
		u32 last_train_tap;

		/*! How many samples to wait before beginning the training operation. */
		u32 pretrain_timer;
	} status;

	/*! This structure contains event flags, allowing the echocan to report
	 * events that occurred as it processed the transmit and receive streams
	 * of samples. Each call to the echocan_process operation for this
	 * instance may report events, so the structure should be cleared before
	 * calling that operation.
	 */
	union dahdi_echocan_events {
		u32 all;
		struct {
			/*! CED tone was detected in the transmit direction. If the
			 * echocan automatically disables its NLP when this occurs,
			 * it must also signal the NLP_auto_disabled event during the *same*
			 * call to echocan_process that reports the CED detection.
			 */
			u32 CED_tx_detected:1;

			/*! CED tone was detected in the receive direction. If the
			 * echocan automatically disables its NLP when this occurs,
			 * it must also signal the NLP_auto_disabled event during the *same*
			 * call to echocan_process that reports the CED detection.
			 */
			u32 CED_rx_detected:1;

			/*! CNG tone was detected in the transmit direction. */
			u32 CNG_tx_detected:1;

			/*! CNG tone was detected in the receive direction. */
			u32 CNG_rx_detected:1;

			/*! The echocan disabled its NLP automatically.
			 */
			u32 NLP_auto_disabled:1;

			/*! The echocan enabled its NLP automatically.
			 */
			u32 NLP_auto_enabled:1;
		} bit;
	} events;
};

struct dahdi_chan {
#ifdef CONFIG_DAHDI_NET
	/*! \note Must be first */
	struct dahdi_hdlc *hdlcnetdev;
#endif
#ifdef CONFIG_DAHDI_PPP
	struct ppp_channel *ppp;
	struct tasklet_struct ppp_calls;
	int do_ppp_wakeup;
	int do_ppp_error;
	struct sk_buff_head ppp_rq;
#endif
#ifdef BUFFER_DEBUG
	int statcount;
	int lastnumbufs;
#endif
	spinlock_t lock;
	struct mutex mutex;
	char name[40];
	/* Specified by DAHDI */
	/*! \brief DAHDI channel number */
	int channo;
	int chanpos;
	unsigned long flags;
	long rxp1;
	long rxp2;
	long rxp3;
	int txtone;
	int tx_v2;
	int tx_v3;
	int v1_1;
	int v2_1;
	int v3_1;
	int toneflags;
	struct sf_detect_state rd;

	struct dahdi_chan *master;	/*!< Our Master channel (could be us) */
	/*! \brief Next slave (if appropriate) */
	struct dahdi_chan *nextslave;

	u_char *writechunk;						/*!< Actual place to write to */
	u_char swritechunk[DAHDI_MAX_CHUNKSIZE];	/*!< Buffer to be written */
	u_char *readchunk;						/*!< Actual place to read from */
	u_char sreadchunk[DAHDI_MAX_CHUNKSIZE];	/*!< Preallocated static area */
	short *readchunkpreec;

	/* Channel from which to read when DACSed. */
	struct dahdi_chan *dacs_chan;

	/*! Pointer to tx and rx gain tables */
	const u_char *rxgain;
	const u_char *txgain;
	
	/* Specified by driver, readable by DAHDI */
	void *pvt;			/*!< Private channel data */
	struct file *file;	/*!< File structure */
	
	
#ifdef CONFIG_DAHDI_MIRROR
	struct dahdi_chan	*rxmirror;  /*!< channel we mirror reads to */
	struct dahdi_chan	*txmirror;  /*!< channel we mirror writes to */
	struct dahdi_chan	*srcmirror; /*!< channel we mirror from */
#endif /* CONFIG_DAHDI_MIRROR */
	struct dahdi_span	*span;			/*!< Span we're a member of */
	int		sig;			/*!< Signalling */
	int		sigcap;			/*!< Capability for signalling */
	__u32		chan_alarms;		/*!< alarms status */

	wait_queue_head_t waitq;

	/* Used only by DAHDI -- NO DRIVER SERVICEABLE PARTS BELOW */
	/* Buffer declarations */
	u_char		*readbuf[DAHDI_MAX_NUM_BUFS];	/*!< read buffer */
	int		inreadbuf;
	int		outreadbuf;

	u_char		*writebuf[DAHDI_MAX_NUM_BUFS]; /*!< write buffers */
	int		inwritebuf;
	int		outwritebuf;
	
	int		blocksize;	/*!< Block size */

	int		eventinidx;  /*!< out index in event buf (circular) */
	int		eventoutidx;  /*!< in index in event buf (circular) */
	unsigned int	eventbuf[DAHDI_MAX_EVENTSIZE];  /*!< event circ. buffer */
	
	int		readn[DAHDI_MAX_NUM_BUFS];  /*!< # of bytes ready in read buf */
	int		readidx[DAHDI_MAX_NUM_BUFS];  /*!< current read pointer */
	int		writen[DAHDI_MAX_NUM_BUFS];  /*!< # of bytes ready in write buf */
	int		writeidx[DAHDI_MAX_NUM_BUFS];  /*!< current write pointer */
	
	int		numbufs;			/*!< How many buffers in channel */
	int		txbufpolicy;			/*!< Buffer policy */
	int		txdisable;				/*!< Disable transmitter */
	
	/* Tone zone stuff */
	struct dahdi_zone *curzone;		/*!< Zone for selecting tones */
	struct dahdi_tone *curtone;		/*!< Current tone we're playing (if any) */
	int		tonep;					/*!< Current position in tone */
	struct dahdi_tone_state ts;		/*!< Tone state */

	/* Pulse dial stuff */
	int	pdialcount;			/*!< pulse dial count */

	/*! Ring cadence */
	int ringcadence[DAHDI_MAX_CADENCE];
	int firstcadencepos;				/*!< Where to restart ring cadence */

	/* Digit string dialing stuff */
	int		digitmode;			/*!< What kind of tones are we sending? */
	char	txdialbuf[DAHDI_MAX_DTMF_BUF];
	int 	dialing;
	int	afterdialingtimer;
	int		cadencepos;				/*!< Where in the cadence we are */

	/* I/O Mask */	
	unsigned int iomask;  /*! I/O Mux signal mask */
	
	/* HDLC state machines */
	struct fasthdlc_state txhdlc;
	struct fasthdlc_state rxhdlc;
	int infcs;

	/* Conferencing stuff */
	int		confna;	/*! conference number (alias) */
	int		_confn;	/*! Actual conference number */
	int		confmode;  /*! conference mode */
	int		confmute; /*! conference mute mode */
	struct dahdi_chan *conf_chan;

	/* Incoming and outgoing conference chunk queues for
	   communicating between DAHDI master time and
	   other boards */
	struct confq confin;
	struct confq confout;

	short	getlin[DAHDI_MAX_CHUNKSIZE];			/*!< Last transmitted samples */
	unsigned char getraw[DAHDI_MAX_CHUNKSIZE];		/*!< Last received raw data */
	short	putlin[DAHDI_MAX_CHUNKSIZE];			/*!< Last received samples */
	unsigned char putraw[DAHDI_MAX_CHUNKSIZE];		/*!< Last received raw data */
	short	conflast[DAHDI_MAX_CHUNKSIZE];			/*!< Last conference sample -- base part of channel */
	short	conflast1[DAHDI_MAX_CHUNKSIZE];		/*!< Last conference sample  -- pseudo part of channel */
	short	conflast2[DAHDI_MAX_CHUNKSIZE];		/*!< Previous last conference sample -- pseudo part of channel */


	/*! The echo canceler module that should be used to create an
	   instance when this channel needs one */
	const struct dahdi_echocan_factory *ec_factory;
	/*! The echo canceler module that owns the instance currently
	   on this channel, if one is present */
	const struct dahdi_echocan_factory *ec_current;
	/*! The state data of the echo canceler instance in use */
	struct dahdi_echocan_state *ec_state;

	/* RBS timings  */
	int		prewinktime;  /*!< pre-wink time (ms) */
	int		preflashtime;	/*!< pre-flash time (ms) */
	int		winktime;  /*!< wink time (ms) */
	int		flashtime;  /*!< flash time (ms) */
	int		starttime;  /*!< start time (ms) */
	int		rxwinktime;  /*!< rx wink time (ms) */
	int		rxflashtime; /*!< rx flash time (ms) */
	int		debouncetime;  /*!< FXS GS sig debounce time (ms) */
	int		pulsebreaktime; /*!< pulse line open time (ms) */
	int		pulsemaketime;  /*!< pulse line closed time (ms) */
	int		pulseaftertime; /*!< pulse time between digits (ms) */

	/*! RING debounce timer */
	int	ringdebtimer;
	
	/*! RING trailing detector to make sure a RING is really over */
	int ringtrailer;

	/* PULSE digit receiver stuff */
	int	pulsecount;
	int	pulsetimer;

	/* RBS timers */
	int 	itimerset;		/*!< what the itimer was set to last */
	int 	itimer;
	int 	otimer;
	
	/* RBS state */
	int gotgs;
	int txstate;
	int rxsig;
	int txsig;
	int rxsigstate;

	/* non-RBS rx state */
	int rxhooksig;
	int txhooksig;
	int kewlonhook;

	/*! Idle signalling if CAS signalling */
	int idlebits;

	int deflaw;		/*! 1 = mulaw, 2=alaw, 0=undefined */
	short *xlaw;
#ifdef	OPTIMIZE_CHANMUTE
	int chanmute;		/*!< no need for PCM data */
#endif
#ifdef CONFIG_CALC_XLAW
	unsigned char (*lineartoxlaw)(short a);
#else
	unsigned char *lin2x;
#endif
	struct device chan_device;	/*!< Kernel object for this chan */
#define dev_to_chan(dev)    container_of(dev, struct dahdi_chan, chan_device)
};

#ifdef CONFIG_DAHDI_NET
struct dahdi_hdlc {
	struct net_device *netdev;
	struct dahdi_chan *chan;
};
#endif

/*! Define the maximum block size */
#define DAHDI_MAX_BLOCKSIZE	8192


#define DAHDI_DEFAULT_WINKTIME	150	/*!< 150 ms default wink time */
#define DAHDI_DEFAULT_FLASHTIME	750	/*!< 750 ms default flash time */

#define DAHDI_DEFAULT_PREWINKTIME	50	/*!< 50 ms before wink */
#define DAHDI_DEFAULT_PREFLASHTIME 50	/*!< 50 ms before flash */
#define DAHDI_DEFAULT_STARTTIME 1500	/*!< 1500 ms of start */
#define DAHDI_DEFAULT_RINGTIME 2000	/*!< 2000 ms of ring on (start, FXO) */
#if 0
#define DAHDI_DEFAULT_RXWINKTIME 250	/*!< 250ms longest rx wink */
#endif
#define DAHDI_DEFAULT_RXWINKTIME 300	/*!< 300ms longest rx wink (to work with the Atlas) */
#define DAHDI_DEFAULT_RXFLASHTIME 1250	/*!< 1250ms longest rx flash */
#define DAHDI_DEFAULT_DEBOUNCETIME 600	/*!< 600ms of FXS GS signalling debounce */
#define DAHDI_DEFAULT_PULSEMAKETIME 50	/*!< 50 ms of line closed when dial pulsing */
#define DAHDI_DEFAULT_PULSEBREAKTIME 50	/*!< 50 ms of line open when dial pulsing */
#define DAHDI_DEFAULT_PULSEAFTERTIME 750	/*!< 750ms between dial pulse digits */

#define DAHDI_MINPULSETIME (15 * 8)	/*!< 15 ms minimum */

#ifdef SHORT_FLASH_TIME
#define DAHDI_MAXPULSETIME (80 * 8)	/*!< we need 80 ms, not 200ms, as we have a short flash */
#else
#define DAHDI_MAXPULSETIME (200 * 8)	/*!< 200 ms maximum */
#endif

#define DAHDI_PULSETIMEOUT ((DAHDI_MAXPULSETIME / 8) + 50)

#define DAHDI_RINGTRAILER (50 * 8)	/*!< Don't consider a ring "over" until it's been gone at least this
									   much time */

#define DAHDI_LOOPCODE_TIME 10000		/*!< send loop codes for 10 secs */
#define DAHDI_ALARMSETTLE_TIME	5000	/*!< allow alarms to settle for 5 secs */
#define DAHDI_AFTERSTART_TIME 500		/*!< 500ms after start */

#define DAHDI_RINGOFFTIME 4000		/*!< Turn off ringer for 4000 ms */
#define DAHDI_KEWLTIME 500		/*!< 500ms for kewl pulse */
#define DAHDI_AFTERKEWLTIME 300    /*!< 300ms after kewl pulse */

#define DAHDI_MAX_PRETRAINING   1000	/*!< 1000ms max pretraining time */

#ifdef	FXSFLASH
#define DAHDI_FXSFLASHMINTIME	450	/*!< min 450ms */
#define DAHDI_FXSFLASHMAXTIME	550	/*!< max 550ms */
#endif


struct dahdi_chardev {
	const char *name;
	__u8 minor;
};

int dahdi_register_chardev(struct dahdi_chardev *dev);
int dahdi_unregister_chardev(struct dahdi_chardev *dev);

/*! \brief defines for transmit signalling */
enum dahdi_txsig {
	DAHDI_TXSIG_ONHOOK,  /*!< On hook */
	DAHDI_TXSIG_OFFHOOK, /*!< Off hook */
	DAHDI_TXSIG_START,   /*!< Start / Ring */
	DAHDI_TXSIG_KEWL,     /*!< Drop battery if possible */
	/*! Leave this as the last entry */
	DAHDI_TXSIG_TOTAL,
};

enum dahdi_rxsig {
	DAHDI_RXSIG_ONHOOK,
	DAHDI_RXSIG_OFFHOOK,
	DAHDI_RXSIG_START,
	DAHDI_RXSIG_RING,
	DAHDI_RXSIG_INITIAL
};
	
enum {
	/* Span flags */
	DAHDI_FLAGBIT_REGISTERED= 0,
	DAHDI_FLAGBIT_RUNNING	= 1,
	DAHDI_FLAGBIT_RBS	= 12,	/*!< Span uses RBS signalling */

	/* Channel flags */
	DAHDI_FLAGBIT_DTMFDECODE= 2,	/*!< Channel supports native DTMF decode */
	DAHDI_FLAGBIT_MFDECODE	= 3,	/*!< Channel supports native MFr2 decode */
	DAHDI_FLAGBIT_ECHOCANCEL= 4,	/*!< Channel supports native echo cancellation */
	DAHDI_FLAGBIT_HDLC	= 5,	/*!< Perform HDLC */
#ifdef CONFIG_DAHDI_NET
	DAHDI_FLAGBIT_NETDEV	= 6,	/*!< Send to network */
#endif
	DAHDI_FLAGBIT_CLEAR	= 8,	/*!< Clear channel */
	DAHDI_FLAGBIT_AUDIO	= 9,	/*!< Audio mode channel */
	DAHDI_FLAGBIT_OPEN	= 10,	/*!< Channel is open */
	DAHDI_FLAGBIT_FCS	= 11,	/*!< Calculate FCS */
	/* Reserve 12 for uniqueness with span flags */
	DAHDI_FLAGBIT_LINEAR	= 13,	/*!< Talk to user space in linear */
	DAHDI_FLAGBIT_PPP	= 14,	/*!< PPP is available */
	DAHDI_FLAGBIT_T1PPP	= 15,
	DAHDI_FLAGBIT_SIGFREEZE	= 16,	/*!< Freeze signalling */
	DAHDI_FLAGBIT_NOSTDTXRX	= 17,	/*!< Do NOT do standard transmit and receive on every interrupt */
	DAHDI_FLAGBIT_LOOPED	= 18,	/*!< Loopback the receive data from the channel to the transmit */
	DAHDI_FLAGBIT_MTP2	= 19,	/*!< Repeats last message in buffer and also discards repeating messages sent to us */
	DAHDI_FLAGBIT_HDLC56	= 20,	/*!< Sets the given channel (if in HDLC mode) to use 56K HDLC instead of 64K  */
	DAHDI_FLAGBIT_BUFEVENTS	= 21,	/*!< Report buffer events */
	DAHDI_FLAGBIT_TXUNDERRUN = 22,	/*!< Transmit underrun condition */
	DAHDI_FLAGBIT_RXOVERRUN = 23,	/*!< Receive overrun condition */
	DAHDI_FLAGBIT_DEVFILE	= 25,	/*!< Channel has a sysfs dev file */
};

#ifdef CONFIG_DAHDI_NET
/**
 * have_netdev() - Return true if a channel has an associated network device.
 * @chan:	   Then channel to check.
 *
 */
static inline int dahdi_have_netdev(const struct dahdi_chan *chan)
{
	return test_bit(DAHDI_FLAGBIT_NETDEV, &chan->flags);
}
#else
static inline int dahdi_have_netdev(const struct dahdi_chan *chan) { return 0; }
#endif

struct dahdi_count {
	u32 fe;			/*!< Framing error counter */
	u32 cv;			/*!< Coding violations counter */
	u32 bpv;		/*!< Bipolar Violation counter */
	u32 crc4;		/*!< CRC4 error counter */
	u32 ebit;		/*!< current E-bit error count */
	u32 fas;		/*!< current FAS error count */
	u32 be;			/*!< current bit error count */
	u32 prbs;		/*!< current PRBS detected pattern */
	u32 errsec;		/*!< errored seconds */
	u32 timingslips;	/*!< Clock slips */
};

/* map flagbits to flag masks */
#define	DAHDI_FLAG(x)	(1 << (DAHDI_FLAGBIT_ ## x))

/*! This is a redefinition of the flags from above to allow use of the 
 * legacy drivers that do not use the kernel atomic bit testing and 
 * changing routines.
 * 
 * See the above descriptions for DAHDI_FLAGBIT_....  for documentation 
 * about function. */
/* Span flags */
#define DAHDI_FLAG_REGISTERED	DAHDI_FLAG(REGISTERED)
#define DAHDI_FLAG_RUNNING	DAHDI_FLAG(RUNNING)
#define DAHDI_FLAG_RBS		DAHDI_FLAG(RBS)

/* Channel flags */
#define DAHDI_FLAG_DTMFDECODE	DAHDI_FLAG(DTMFDECODE)
#define DAHDI_FLAG_MFDECODE	DAHDI_FLAG(MFDECODE)
#define DAHDI_FLAG_ECHOCANCEL	DAHDI_FLAG(ECHOCANCEL)

#define DAHDI_FLAG_HDLC		DAHDI_FLAG(HDLC)
/* #define DAHDI_FLAG_NETDEV	DAHDI_FLAG(NETDEV) */
#define DAHDI_FLAG_CLEAR	DAHDI_FLAG(CLEAR)
#define DAHDI_FLAG_AUDIO	DAHDI_FLAG(AUDIO)

#define DAHDI_FLAG_OPEN		DAHDI_FLAG(OPEN)
#define DAHDI_FLAG_FCS		DAHDI_FLAG(FCS)
/* Reserve 12 for uniqueness with span flags */
#define DAHDI_FLAG_LINEAR	DAHDI_FLAG(LINEAR)
#define DAHDI_FLAG_PPP		DAHDI_FLAG(PPP)
#define DAHDI_FLAG_T1PPP	DAHDI_FLAG(T1PPP)
#define DAHDI_FLAG_SIGFREEZE	DAHDI_FLAG(SIGFREEZE)
#define DAHDI_FLAG_NOSTDTXRX	DAHDI_FLAG(NOSTDTXRX)
#define DAHDI_FLAG_LOOPED	DAHDI_FLAG(LOOPED)
#define DAHDI_FLAG_MTP2		DAHDI_FLAG(MTP2)
#define DAHDI_FLAG_HDLC56	DAHDI_FLAG(HDLC56)
#define DAHDI_FLAG_BUFEVENTS	DAHDI_FLAG(BUFEVENTS)
#define DAHDI_FLAG_TXUNDERRUN	DAHDI_FLAG(TXUNDERRUN)
#define DAHDI_FLAG_RXOVERRUN	DAHDI_FLAG(RXOVERRUN)

enum spantypes {
	SPANTYPE_INVALID	= 0,
	SPANTYPE_ANALOG_FXS,
	SPANTYPE_ANALOG_FXO,
	SPANTYPE_ANALOG_MIXED,
	SPANTYPE_DIGITAL_E1,
	SPANTYPE_DIGITAL_T1,
	SPANTYPE_DIGITAL_J1,
	SPANTYPE_DIGITAL_BRI_NT,
	SPANTYPE_DIGITAL_BRI_TE,
	SPANTYPE_DIGITAL_BRI_SOFT,
	SPANTYPE_DIGITAL_DYNAMIC,
};
const char *dahdi_spantype2str(enum spantypes st);
enum spantypes dahdi_str2spantype(const char *name);
const char *dahdi_lineconfig_bit_name(int lineconfig_bit);
ssize_t lineconfig_str(int lineconfig, char buf[], size_t size);

struct file;

struct dahdi_span_ops {
	struct module *owner;		/*!< Which module is exporting this span. */

	/*   ==== Span Callback Operations ====   */
	/*! Req: Set the requested chunk size.  This is the unit in which you must
	   report results for conferencing, etc */
	int (*setchunksize)(struct dahdi_span *span, int chunksize);

	/*! Opt: Configure the span (if appropriate) */
	int (*spanconfig)(struct file *file, struct dahdi_span *span,
			  struct dahdi_lineconfig *lc);
	
	/*! Opt: Start the span */
	int (*startup)(struct file *file, struct dahdi_span *span);
	
	/*! Opt: Shutdown the span */
	int (*shutdown)(struct dahdi_span *span);
	
	/*! Opt: Enable maintenance modes */
	int (*maint)(struct dahdi_span *span, int mode);

#ifdef	DAHDI_SYNC_TICK
	/*! Opt: send sync to spans. Called in hard_irq context with chan_lock
	 *       held.*/
	void (*sync_tick)(struct dahdi_span *span, int is_master);
#endif
	/* ====  Channel Callback Operations ==== */
	/*! Opt: Set signalling type (if appropriate) */
	int (*chanconfig)(struct file *file, struct dahdi_chan *chan,
			  int sigtype);

	/*! Opt: Prepare a channel for I/O */
	int (*open)(struct dahdi_chan *chan);

	/*! Opt: Close channel for I/O */
	int (*close)(struct dahdi_chan *chan);
	
	/*! Opt: IOCTL */
	int (*ioctl)(struct dahdi_chan *chan, unsigned int cmd, unsigned long data);
	
	/* Okay, now we get to the signalling.  You have several options: */

	/* Option 1: If you're a T1 like interface, you can just provide a
	   rbsbits function and we'll assert robbed bits for you.  Be sure to 
	   set the DAHDI_FLAG_RBS in this case.  */

	/*! Opt: If the span uses A/B bits, set them here */
	int (*rbsbits)(struct dahdi_chan *chan, int bits);
	
	/*! Option 2: If you don't know about sig bits, but do have their
	   equivalents (i.e. you can disconnect battery, detect off hook,
	   generate ring, etc directly) then you can just specify a
	   sethook function, and we'll call you with appropriate hook states
	   to set.  Still set the DAHDI_FLAG_RBS in this case as well */
	int (*hooksig)(struct dahdi_chan *chan, enum dahdi_txsig hookstate);
	
	/*! Option 3: If you can't use sig bits, you can write a function
	   which handles the individual hook states  */
	int (*sethook)(struct dahdi_chan *chan, int hookstate);
	
	/*! Opt: Used to tell an onboard HDLC controller that there is data ready to transmit */
	void (*hdlc_hard_xmit)(struct dahdi_chan *chan);

	/*! If the watchdog detects no received data, it will call the
	   watchdog routine */
	int (*watchdog)(struct dahdi_span *span, int cause);

#ifdef	DAHDI_AUDIO_NOTIFY
	/*! Opt: audio is used, don't optimize out */
	int (*audio_notify)(struct dahdi_chan *chan, int yes);
#endif

	/*! Opt: Enable preechocan stream from inline HW echocanceler. */
	int (*enable_hw_preechocan)(struct dahdi_chan *chan);

	/*! Opt: Disable preechocan stream from inline HW echocanceler. */
	void (*disable_hw_preechocan)(struct dahdi_chan *chan);

	/*! Opt: Dacs the contents of chan2 into chan1 if possible */
	int (*dacs)(struct dahdi_chan *chan1, struct dahdi_chan *chan2);

	/*! Opt: Provide echo cancellation on a channel */
	int (*echocan_create)(struct dahdi_chan *chan,
			      struct dahdi_echocanparams *ecp,
			      struct dahdi_echocanparam *p,
			      struct dahdi_echocan_state **ec);

	/*! Opt: Provide the name of the echo canceller on a channel */
	const char *(*echocan_name)(const struct dahdi_chan *chan);

	/*! When using "assigned spans", this function is called back when this
	 * span has been assigned with the system. */
	void (*assigned)(struct dahdi_span *span);

	/*! Called when the spantype / linemode is changed before the span is
	 * assigned a number. */
	int (*set_spantype)(struct dahdi_span *span, enum spantypes st);
};

/**
 * dahdi_device - Represents a device that can contain one or more spans.
 *
 * @spans:        List of child spans.
 * @manufacturer: Device manufacturer.
 * @location:     The location of this device. This should not change if
 *                the device is replaced (e.g: in the same PCI slot)
 * @hardware_id:  The hardware_id of this device (NULL for devices without
 *                a hardware_id). This should not change if the device is
 *                relocated to a different location (e.g: different PCI slot)
 * @devicetype:   What type of device this is.
 * @irqmisses:    Count of "interrupt misses" for this device.
 *
 */
struct dahdi_device {
	struct list_head spans;
	const char *manufacturer;
	const char *location;
	const char *hardware_id;
	const char *devicetype;
	struct device dev;
	unsigned int irqmisses;
	ktime_t registration_time;
};

struct dahdi_span {
	spinlock_t lock;
	char name[40];			/*!< Span name */
	char desc[80];			/*!< Span description */
	enum spantypes spantype;	/*!< span type */
	int deflaw;			/*!< Default law (DAHDI_MULAW or DAHDI_ALAW) */
	int alarms;			/*!< Pending alarms on span */
	unsigned long flags;
	u8 cannot_provide_timing:1;
	int lbo;			/*!< Span Line-Buildout */
	int lineconfig;			/*!< Span line configuration */
	int linecompat;			/*!< Span line compatibility (0 for
					     analog spans)*/
	int channels;			/*!< Number of channels in span */
	int txlevel;			/*!< Tx level */
	int rxlevel;			/*!< Rx level */
	int syncsrc;			/*!< current sync src (gets copied here) */
	struct dahdi_count count;	/*!< Performance and Error counters */

	int maintstat;			/*!< Maintenance state */
	int mainttimer;			/*!< Maintenance timer */

	struct dahdi_chan **chans;	/*!< Member channel structures */

	const struct dahdi_span_ops *ops;	/*!< span callbacks. */

	/* Used by DAHDI only -- no user servicable parts inside */
	int spanno;			/*!< Span number for DAHDI */
	int offset;			/*!< Offset within a given card */
	int lastalarms;			/*!< Previous alarms */

#ifdef CONFIG_DAHDI_WATCHDOG
	int watchcounter;
	int watchstate;
#endif	

#ifdef CONFIG_PROC_FS
	struct proc_dir_entry *proc_entry;
#endif
	struct list_head spans_node;

	struct dahdi_device *parent;
	struct list_head device_node;
	struct device *span_device;
};

struct dahdi_transcoder_channel {
	void *pvt;
	struct dahdi_transcoder *parent;
	wait_queue_head_t ready;
	__u32 built_fmts;
#define DAHDI_TC_FLAG_BUSY		1
#define DAHDI_TC_FLAG_CHAN_BUILT	2
#define DAHDI_TC_FLAG_NONBLOCK		3
#define DAHDI_TC_FLAG_DATA_WAITING	4
	unsigned long flags;
	u32 dstfmt;
	u32 srcfmt;
};

int dahdi_is_sync_master(const struct dahdi_span *span);
struct dahdi_span *get_master_span(void);
void set_master_span(int spanno);

static inline int 
dahdi_tc_is_built(struct dahdi_transcoder_channel *dtc) {
	return test_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags);
}
static inline void
dahdi_tc_set_built(struct dahdi_transcoder_channel *dtc) {
	set_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags);
}
static inline void 
dahdi_tc_clear_built(struct dahdi_transcoder_channel *dtc) {
	clear_bit(DAHDI_TC_FLAG_CHAN_BUILT, &dtc->flags);
}
static inline int 
dahdi_tc_is_nonblock(struct dahdi_transcoder_channel *dtc) {
	return test_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags);
}
static inline void 
dahdi_tc_set_nonblock(struct dahdi_transcoder_channel *dtc) {
	set_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags);
}
static inline void 
dahdi_tc_clear_nonblock(struct dahdi_transcoder_channel *dtc) {
	clear_bit(DAHDI_TC_FLAG_NONBLOCK, &dtc->flags);
}
static inline int 
dahdi_tc_is_data_waiting(struct dahdi_transcoder_channel *dtc) {
	return test_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags);
}
static inline int 
dahdi_tc_is_busy(struct dahdi_transcoder_channel *dtc) {
	return test_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags);
}
static inline void 
dahdi_tc_set_busy(struct dahdi_transcoder_channel *dtc) {
	set_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags);
}
static inline void 
dahdi_tc_clear_busy(struct dahdi_transcoder_channel *dtc) {
	clear_bit(DAHDI_TC_FLAG_BUSY, &dtc->flags);
}
static inline void 
dahdi_tc_set_data_waiting(struct dahdi_transcoder_channel *dtc) {
	set_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags);
}
static inline void 
dahdi_tc_clear_data_waiting(struct dahdi_transcoder_channel *dtc) {
	clear_bit(DAHDI_TC_FLAG_DATA_WAITING, &dtc->flags);
}

struct dahdi_transcoder {
	struct list_head active_list_node;
	struct list_head registration_list_node;
	char name[80];
	int numchannels;
	unsigned int srcfmts;
	unsigned int dstfmts;
	struct file_operations fops;
	int (*allocate)(struct dahdi_transcoder_channel *channel);
	int (*release)(struct dahdi_transcoder_channel *channel);
	/* Transcoder channels */
	struct dahdi_transcoder_channel channels[0];
};

#define DAHDI_WATCHDOG_NOINTS		(1 << 0)

#define DAHDI_WATCHDOG_INIT			1000

#define DAHDI_WATCHSTATE_UNKNOWN		0
#define DAHDI_WATCHSTATE_OK			1
#define DAHDI_WATCHSTATE_RECOVERING	2
#define DAHDI_WATCHSTATE_FAILED		3


struct dahdi_dynamic {
	char addr[40];
	char dname[20];
	int err;
	struct kref kref;
	long rxjif;
	unsigned short txcnt;
	unsigned short rxcnt;
	struct dahdi_device *ddev;
	struct dahdi_span span;
	struct dahdi_chan *chans[256];
	struct dahdi_dynamic_driver *driver;
	void *pvt;
	int timing;
	int master;
	unsigned char *msgbuf;
	struct device *dev;
	int simulated_alarms;

	struct list_head list;
};

struct dahdi_dynamic_driver {
	/*! Driver name (e.g. Eth) */
	const char *name;

	/*! Driver description */
	const char *desc;

	/*! Create a new transmission pipe */
	int (*create)(struct dahdi_dynamic *d, const char *address);

	/*! Destroy a created transmission pipe */
	void (*destroy)(struct dahdi_dynamic *d);

	/*! Transmit a given message */
	void (*transmit)(struct dahdi_dynamic *d, u8 *msg, size_t msglen);

	/*! Flush any pending messages */
	int (*flush)(void);

	struct list_head list;
	struct module *owner;

	/*! Numberic id of next device created by this driver. */
	unsigned int id;
};

/*! \brief Receive a dynamic span message */
void dahdi_dynamic_receive(struct dahdi_span *span, unsigned char *msg, int msglen);

/*! \brief Register a dynamic driver */
int dahdi_dynamic_register_driver(struct dahdi_dynamic_driver *driver);

/*! \brief Unregister a dynamic driver */
void dahdi_dynamic_unregister_driver(struct dahdi_dynamic_driver *driver);

int _dahdi_receive(struct dahdi_span *span);

/*! Receive on a span.  The DAHDI interface will handle all the calculations for
   all member channels of the span, pulling the data from the readchunk buffer */
static inline int dahdi_receive(struct dahdi_span *span)
{
	unsigned long flags;
	int ret;
	local_irq_save(flags);
	ret = _dahdi_receive(span);
	local_irq_restore(flags);
	return ret;
}

int _dahdi_transmit(struct dahdi_span *span);

/*! Prepare writechunk buffers on all channels for this span */
static inline int dahdi_transmit(struct dahdi_span *span)
{
	unsigned long flags;
	int ret;
	local_irq_save(flags);
	ret = _dahdi_transmit(span);
	local_irq_restore(flags);
	return ret;
}

static inline int dahdi_is_digital_span(const struct dahdi_span *s)
{
	return (s->linecompat > 0);
}

static inline int dahdi_is_t1_span(const struct dahdi_span *s)
{
	return (s->linecompat & (DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF |
				 DAHDI_CONFIG_B8ZS)) > 0;
}

static inline int dahdi_is_e1_span(const struct dahdi_span *s)
{
	return dahdi_is_digital_span(s) && !dahdi_is_t1_span(s);
}

/*! Abort the buffer currently being receive with event "event" */
void dahdi_hdlc_abort(struct dahdi_chan *ss, int event);

/*! Indicate to DAHDI that the end of frame was received and rotate buffers */
void dahdi_hdlc_finish(struct dahdi_chan *ss);

/*! Put a chunk of data into the current receive buffer */
void dahdi_hdlc_putbuf(struct dahdi_chan *ss, unsigned char *rxb, int bytes);

/*! Get a chunk of data from the current transmit buffer.  Returns -1 if no data
 * is left to send, 0 if there is data remaining in the current message to be sent
 * and 1 if the currently transmitted message is now done */
int dahdi_hdlc_getbuf(struct dahdi_chan *ss, unsigned char *bufptr, unsigned int *size);

/*! Register a device.  Returns 0 on success, -1 on failure. */
struct dahdi_device *dahdi_create_device(void);
int dahdi_register_device(struct dahdi_device *ddev, struct device *parent);
void dahdi_unregister_device(struct dahdi_device *ddev);
void dahdi_free_device(struct dahdi_device *ddev);
void dahdi_init_span(struct dahdi_span *span);

/*! Find a span by its name and get a reference */
struct dahdi_span *dahdi_span_find_by_name_and_get(const char *name);

/*! Allocate / free memory for a transcoder */
struct dahdi_transcoder *dahdi_transcoder_alloc(int numchans);
void dahdi_transcoder_free(struct dahdi_transcoder *ztc);

/*! \brief Register a transcoder */
int dahdi_transcoder_register(struct dahdi_transcoder *tc);

/*! \brief Unregister a transcoder */
int dahdi_transcoder_unregister(struct dahdi_transcoder *tc);

/*! \brief Alert a transcoder */
int dahdi_transcoder_alert(struct dahdi_transcoder_channel *ztc);

/*! \brief Gives a name to an LBO */
const char *dahdi_lboname(int lbo);

/*! \brief Tell DAHDI about changes in received rbs bits */
void dahdi_rbsbits(struct dahdi_chan *chan, int bits);

/*! \brief Tell DAHDI abou changes in received signalling */
void dahdi_hooksig(struct dahdi_chan *chan, enum dahdi_rxsig rxsig);

/*! \brief Queue an event on a channel */
void dahdi_qevent_nolock(struct dahdi_chan *chan, int event);

/*! \brief Queue an event on a channel, locking it first */
void dahdi_qevent_lock(struct dahdi_chan *chan, int event);

/*! \brief Notify a change possible change in alarm status on a channel */
void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms);

/*! \brief Notify a change possible change in alarm status on a span */
void dahdi_alarm_notify(struct dahdi_span *span);

/*! \brief Initialize a tone state */
void dahdi_init_tone_state(struct dahdi_tone_state *ts, struct dahdi_tone *zt);

/*! \brief Get a given MF tone struct, suitable for dahdi_tone_nextsample. */
struct dahdi_tone *dahdi_mf_tone(const struct dahdi_chan *chan, char digit, int digitmode);

/*! \brief Convert signalling bits to human readable string */
const char *sigstr(int sig);

/*! \brief Convert alarm bits to human readable string */
int fill_alarm_string(char *buf, int count, int alarms);

/* Echo cancel a receive and transmit chunk for a given channel.  This
   should be called by the low-level driver as close to the interface
   as possible.  ECHO CANCELLATION IS NO LONGER AUTOMATICALLY DONE
   AT THE DAHDI LEVEL.  dahdi_ec_chunk will not echo cancel if it should
   not be doing so.  rxchunk is modified in-place */
void __dahdi_ec_chunk(struct dahdi_chan *ss, u8 *rxchunk,
		      const u8 *preecchunk, const u8 *txchunk);

static inline void _dahdi_ec_chunk(struct dahdi_chan *chan,
				   u8 *rxchunk, const u8 *txchunk)
{
	__dahdi_ec_chunk(chan, rxchunk, rxchunk, txchunk);
}

static inline void dahdi_ec_chunk(struct dahdi_chan *ss, unsigned char *rxchunk,
				  const unsigned char *txchunk)
{
	unsigned long flags;
	local_irq_save(flags);
	_dahdi_ec_chunk(ss, rxchunk, txchunk);
	local_irq_restore(flags);
}

void _dahdi_ec_span(struct dahdi_span *span);
static inline void dahdi_ec_span(struct dahdi_span *span)
{
	unsigned long flags;
	local_irq_save(flags);
	_dahdi_ec_span(span);
	local_irq_restore(flags);
}

extern struct file_operations *dahdi_transcode_fops;
extern struct file_operations *dahdi_trunkdev_fops;

int dahdi_get_auto_assign_spans(void);

/* Don't use these directly -- they're not guaranteed to
   be there. */
extern short __dahdi_mulaw[256];
extern short __dahdi_alaw[256];
#ifdef CONFIG_CALC_XLAW
u_char __dahdi_lineartoulaw(short a);
u_char __dahdi_lineartoalaw(short a);
#else
extern u_char __dahdi_lin2mu[16384];
extern u_char __dahdi_lin2a[16384];
#endif

struct dahdi_dynamic_ops {
	struct module *owner;
	int (*ioctl)(unsigned int cmd, unsigned long data);
};

/*! \brief Used by dynamic DAHDI -- don't use directly */
void dahdi_set_dynamic_ops(const struct dahdi_dynamic_ops *ops);

/*! \brief Used by DAHDI HPEC module -- don't use directly */
void dahdi_set_hpec_ioctl(int (*func)(unsigned int cmd, unsigned long data));

/*! \brief Used privately by DAHDI.  Avoid touching directly */
struct dahdi_tone {
	int fac1;
	int init_v2_1;
	int init_v3_1;

	int fac2;
	int init_v2_2;
	int init_v3_2;

	int tonesamples;		/*!< How long to play this tone before 
					   going to the next (in samples) */
	struct dahdi_tone *next;		/* Next tone in this sequence */

	int modulate;
};

static inline short dahdi_tone_nextsample(struct dahdi_tone_state *ts, struct dahdi_tone *zt)
{
	/* follow the curves, return the sum */

	int p;

	ts->v1_1 = ts->v2_1;
	ts->v2_1 = ts->v3_1;
	ts->v3_1 = (zt->fac1 * ts->v2_1 >> 15) - ts->v1_1;

	ts->v1_2 = ts->v2_2;
	ts->v2_2 = ts->v3_2;
	ts->v3_2 = (zt->fac2 * ts->v2_2 >> 15) - ts->v1_2;

	/* Return top 16 bits */
	if (!ts->modulate) return ts->v3_1 + ts->v3_2;
	/* we are modulating */
	p = ts->v3_2 - 32768;
	if (p < 0) p = -p;
	p = ((p * 9) / 10) + 1;
	return (ts->v3_1 * p) >> 15;

}

static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss)
{
	/* follow the curves, return the sum */

	ss->v1_1 = ss->v2_1;
	ss->v2_1 = ss->v3_1;
	ss->v3_1 = (ss->txtone * ss->v2_1 >> 15) - ss->v1_1;
	return ss->v3_1;
}

/* These are the right functions to use.  */

#define DAHDI_MULAW(a) (__dahdi_mulaw[(a)])
#define DAHDI_ALAW(a) (__dahdi_alaw[(a)])
#define DAHDI_XLAW(a,c) (c->xlaw[(a)])

#ifdef CONFIG_CALC_XLAW
#define DAHDI_LIN2MU(a) (__dahdi_lineartoulaw((a)))
#define DAHDI_LIN2A(a) (__dahdi_lineartoalaw((a)))

#define DAHDI_LIN2X(a,c) ((c)->lineartoxlaw((a)))

#else
/* Use tables */
#define DAHDI_LIN2MU(a) (__dahdi_lin2mu[((unsigned short)(a)) >> 2])
#define DAHDI_LIN2A(a) (__dahdi_lin2a[((unsigned short)(a)) >> 2])

/* Manipulate as appropriate for x-law */
#define DAHDI_LIN2X(a,c) ((c)->lin2x[((unsigned short)(a)) >> 2])

#endif /* CONFIG_CALC_XLAW */

/* Data formats for capabilities and frames alike (from Asterisk) */
/*! G.723.1 compression */
#define DAHDI_FORMAT_G723_1	(1 << 0)
/*! GSM compression */
#define DAHDI_FORMAT_GSM		(1 << 1)
/*! Raw mu-law data (G.711) */
#define DAHDI_FORMAT_ULAW		(1 << 2)
/*! Raw A-law data (G.711) */
#define DAHDI_FORMAT_ALAW		(1 << 3)
/*! ADPCM (G.726, 32kbps) */
#define DAHDI_FORMAT_G726		(1 << 4)
/*! ADPCM (IMA) */
#define DAHDI_FORMAT_ADPCM		(1 << 5)
/*! Raw 16-bit Signed Linear (8000 Hz) PCM */
#define DAHDI_FORMAT_SLINEAR	(1 << 6)
/*! LPC10, 180 samples/frame */
#define DAHDI_FORMAT_LPC10		(1 << 7)
/*! G.729A audio */
#define DAHDI_FORMAT_G729A		(1 << 8)
/*! SpeeX Free Compression */
#define DAHDI_FORMAT_SPEEX		(1 << 9)
/*! iLBC Free Compression */
#define DAHDI_FORMAT_ILBC		(1 << 10)
/*! Maximum audio format */
#define DAHDI_FORMAT_MAX_AUDIO	(1 << 15)
/*! Maximum audio mask */
#define DAHDI_FORMAT_AUDIO_MASK	((1 << 16) - 1)

#if LINUX_VERSION_CODE > KERNEL_VERSION(6,5,12)
#undef flush_scheduled_work
#define flush_scheduled_work()				\
({							\
	if (0)						\
		__warn_flushing_systemwide_wq();	\
	__flush_workqueue(system_wq);			\
})
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 15, 0)

#ifndef TIMER_DATA_TYPE
#define TIMER_DATA_TYPE unsigned long
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 13, 0)

#ifdef RHEL_RELEASE_VERSION
#if RHEL_RELEASE_CODE > RHEL_RELEASE_VERSION(7, 5)
#define DAHDI_HAVE_TIMER_SETUP
#undef TIMER_DATA_TYPE
#define TIMER_DATA_TYPE struct timer_list *
#endif
#endif

#ifndef DAHDI_HAVE_TIMER_SETUP
/**
 * timer_setup - Added in 4.13.0.  We can make a direct translation to the
 * setup_timer interface since DAHDI does not pass any flags to any of the
 * timer_setup functions.
 *
 */
static inline void
timer_setup(struct timer_list *timer,
	    void (*timer_callback)(TIMER_DATA_TYPE data),
	    unsigned long flags)
{
	WARN_ON(flags != 0);
	setup_timer(timer, timer_callback, (TIMER_DATA_TYPE)timer);
}

#define from_timer(var, callback_timer, timer_fieldname) \
	container_of((struct timer_list *)(callback_timer), \
		     typeof(*var), timer_fieldname)

#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
#define refcount_read atomic_read

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0)
#define dahdi_ktime_equal ktime_equal

#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)

#ifdef RHEL_RELEASE_VERSION
#if RHEL_RELEASE_CODE >= RHEL_RELEASE_VERSION(6, 8)
#define DAHDI_HAVE_KTIME_MS_DELTA
#endif
#endif

#ifndef DAHDI_HAVE_KTIME_MS_DELTA
static inline s64 dahdi_ktime_to_ms(const ktime_t kt)
{
	struct timeval tv = ktime_to_timeval(kt);

	return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
}

static inline s64 ktime_ms_delta(const ktime_t later, const ktime_t earlier)
{
	return dahdi_ktime_to_ms(ktime_sub(later, earlier));
}
#else
#undef DAHDI_HAVE_KTIME_MS_DELTA
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 16, 0)

/* DAHDI only was using the xxx_clear_bit variants. */
#ifndef smp_mb__before_atomic
#define smp_mb__before_atomic smp_mb__before_clear_bit
#endif

#ifndef smp_mb__after_atomic
#define smp_mb__after_atomic smp_mb__after_clear_bit
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
#ifdef RHEL_RELEASE_VERSION
#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6, 5)
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static inline void *PDE_DATA(const struct inode *inode)
{
	return PDE(inode)->data;
}
#endif
#endif
#else
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
static inline void *PDE_DATA(const struct inode *inode)
{
	return PDE(inode)->data;
}
#endif
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)

#define KERN_CONT ""

#endif /* 2.6.31 */
#endif /* 3.10.0 */
#endif /* 3.16.0 */
#endif /* 4.0.0 */
#endif /* 4.10.0 */
#endif /* 4.11.0 */
#endif /* 4.13.0 */
#else /* >= 4.15.0 */

#ifndef TIMER_DATA_TYPE
#define TIMER_DATA_TYPE struct timer_list *
#endif

#endif /* 4.15.0 */

#ifndef dahdi_ktime_equal
static inline int dahdi_ktime_equal(const ktime_t cmp1, const ktime_t cmp2)
{
	return cmp1 == cmp2;
}
#endif

#ifndef DEFINE_SPINLOCK
#define DEFINE_SPINLOCK(x)      spinlock_t x = SPIN_LOCK_UNLOCKED
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0)
#ifndef DEFINE_SEMAPHORE
#define DEFINE_SEMAPHORE(name) \
	struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
#endif
#else /* 6.4.0, speficcally 48380368dec14859723b9e3fbd43e042638d9a76 */
#undef DEFINE_SEMAPHORE
#define DEFINE_SEMAPHORE(name) \
	struct semaphore name = __SEMAPHORE_INITIALIZER(name, 1)
#endif

#ifndef DEFINE_MUTEX
struct mutex {
	struct semaphore sem;
};
#define DEFINE_MUTEX(name)					\
	struct mutex name = {					\
		.sem = __SEMAPHORE_INITIALIZER((name).sem, 1),	\
	}
#define mutex_lock(_x) down(&(_x)->sem)
#define mutex_unlock(_x) up(&(_x)->sem)
#define mutex_init(_x) sema_init(&(_x)->sem, 1)
#endif

#ifndef DEFINE_PCI_DEVICE_TABLE
#define DEFINE_PCI_DEVICE_TABLE(_x) \
	const struct pci_device_id _x[] __devinitdata
#endif

#ifndef DMA_BIT_MASK
#define DMA_BIT_MASK(n)	(((n) == 64) ? ~0ULL : ((1ULL<<(n))-1))
#endif

/* WARN_ONCE first showed up in the kernel in 2.6.27 but it may have been
 * backported. */
#ifndef WARN_ONCE
#define WARN_ONCE(condition, format...) WARN_ON_ONCE(condition)
#endif

#define	DAHDI_CTL	0
#define	DAHDI_TRANSCODE	250
#define	DAHDI_TRUNKDEV	252
#define	DAHDI_TIMER	253
#define	DAHDI_CHANNEL	254
#define	DAHDI_PSEUDO	255

/* prink-wrapper macros */

#define module_printk(level, fmt, args...) \
		printk(level "%s: " fmt, THIS_MODULE->name, ## args)

#define	DAHDI_PRINTK(level, category, fmt, ...)	\
	printk(KERN_ ## level "%s%s-%s: " fmt, #level, category, \
			THIS_MODULE->name, ## __VA_ARGS__)
#define	span_printk(level, category, span, fmt, ...)	\
	printk(KERN_ ## level "%s%s-%s: span-%d: " fmt, #level,	\
		category, THIS_MODULE->name, (span)->spanno, ## __VA_ARGS__)
#define	chan_printk(level, category, chan, fmt, ...)	\
	printk(KERN_ ## level "%s%s-%s: chan-%d: " fmt, #level,	\
		category, THIS_MODULE->name, (chan)->channo, ## __VA_ARGS__)
#define	dahdi_err(fmt, ...)	DAHDI_PRINTK(ERR, "", fmt, ## __VA_ARGS__)
#define	span_info(span, fmt, ...)	span_printk(INFO, "", span, fmt, \
						## __VA_ARGS__)
#define	span_notice(span, fmt, ...)	span_printk(NOTICE, "", span, fmt, \
						## __VA_ARGS__)
#define	span_err(span, fmt, ...)	span_printk(ERR, "", span, fmt, \
						## __VA_ARGS__)
#define	chan_notice(chan, fmt, ...)	chan_printk(NOTICE, "", chan, fmt, \
						## __VA_ARGS__)
#define	chan_err(chan, fmt, ...)	chan_printk(ERR, "", chan, fmt, \
						## __VA_ARGS__)

#ifndef pr_fmt
#define pr_fmt(fmt)             KBUILD_MODNAME ": " fmt
#endif

#ifndef pr_err
#define pr_err(fmt, ...) \
	printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__)
#endif
#ifndef pr_warning
#define pr_warning(fmt, ...) \
	printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__)
#endif
#ifndef pr_warn
#define pr_warn pr_warning
#endif
#ifndef pr_notice
#define pr_notice(fmt, ...) \
	printk(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__)
#endif
#ifndef pr_info
#define pr_info(fmt, ...) \
	printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
#endif

/* If KBUILD_MODNAME is not defined in a compilation unit, then the dev_dbg
 * macro will not work properly. */
#ifndef KBUILD_MODNAME
  #undef dev_dbg
  #ifdef DEBUG
    #define dev_dbg dev_info
  #else
    #define dev_dbg(...) do { } while (0)
  #endif
#endif

/* The dbg_* ones use a magical variable 'debug' and the user should be
 * aware of that.
*/
#ifdef DAHDI_PRINK_MACROS_USE_debug
#ifndef	BIT	/* added in 2.6.24 */
#define	BIT(i)		(1UL << (i))
#endif
/* Standard debug bit values. Any module may define others. They must
 * be of the form DAHDI_DBG_*
 */
#define	DAHDI_DBG_GENERAL	BIT(0)
#define	DAHDI_DBG_ASSIGN	BIT(1)
#define	DAHDI_DBG_DEVICES	BIT(7)	/* instantiation/destruction etc. */
#define	dahdi_dbg(bits, fmt, ...)	\
	((void)((debug & (DAHDI_DBG_ ## bits)) && DAHDI_PRINTK(DEBUG, \
			"-" #bits, "%s: " fmt, __func__, ## __VA_ARGS__)))
#define	span_dbg(bits, span, fmt, ...)	\
			((void)((debug & (DAHDI_DBG_ ## bits)) && \
				span_printk(DEBUG, "-" #bits, span, "%s: " \
					fmt, __func__, ## __VA_ARGS__)))
#define	chan_dbg(bits, chan, fmt, ...)	\
			((void)((debug & (DAHDI_DBG_ ## bits)) && \
				chan_printk(DEBUG, "-" #bits, chan, \
					"%s: " fmt, __func__, ## __VA_ARGS__)))
#define dahdi_dev_dbg(bits, dev, fmt, ...)         \
		do { if (debug & (DAHDI_DBG_ ## bits)) { \
			dev_printk(KERN_DEBUG, dev, \
			"DBG-%s(%s): " fmt, #bits, __func__, ## __VA_ARGS__); \
		} } while (0)

#endif /* DAHDI_PRINK_MACROS_USE_debug */


/* work-around kernel API change from "struct device *dev" to "const struct device *dev"
 * as implemented in 2a81ada32f0e584fc0c943e0d3a8c9f4fae411d6 */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 3, 0)
#define UEVENT_CONST const
#else
#define UEVENT_CONST
#endif

#endif /* _DAHDI_KERNEL_H */
