/* include/linux/smux.h
 *
 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
 *
 * This software is licensed under the terms of the GNU General Public
 * License version 2, as published by the Free Software Foundation, and
 * may be copied, distributed, and modified under those terms.
 *
 * This program 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.
 *
 */
#ifndef SMUX_H
#define SMUX_H

/**
 * Logical Channel IDs
 *
 * This must be identical between local and remote clients.
 */
enum {
	/* Data Ports */
	SMUX_DATA_0,
	SMUX_DATA_1,
	SMUX_DATA_2,
	SMUX_DATA_3,
	SMUX_DATA_4,
	SMUX_DATA_5,
	SMUX_DATA_6,
	SMUX_DATA_7,
	SMUX_DATA_8,
	SMUX_DATA_9,
	SMUX_USB_RMNET_DATA_0,
	SMUX_USB_DUN_0,
	SMUX_USB_DIAG_0,
	SMUX_SYS_MONITOR_0,
	SMUX_CSVT_0,
	/* add new data ports here */

	/* Control Ports */
	SMUX_DATA_CTL_0 = 32,
	SMUX_DATA_CTL_1,
	SMUX_DATA_CTL_2,
	SMUX_DATA_CTL_3,
	SMUX_DATA_CTL_4,
	SMUX_DATA_CTL_5,
	SMUX_DATA_CTL_6,
	SMUX_DATA_CTL_7,
	SMUX_DATA_CTL_8,
	SMUX_DATA_CTL_9,
	SMUX_USB_RMNET_CTL_0,
	SMUX_USB_DUN_CTL_0_UNUSED,
	SMUX_USB_DIAG_CTL_0,
	SMUX_SYS_MONITOR_CTL_0,
	SMUX_CSVT_CTL_0,
	/* add new control ports here */

	SMUX_TEST_LCID,
	SMUX_NUM_LOGICAL_CHANNELS,
};

/**
 * Notification events that are passed to the notify() function.
 *
 * If the @metadata argument in the notifier is non-null, then it will
 * point to the associated struct smux_meta_* structure.
 */
enum {
	SMUX_CONNECTED,       /* @metadata is null */
	SMUX_DISCONNECTED,
	SMUX_READ_DONE,
	SMUX_READ_FAIL,
	SMUX_WRITE_DONE,
	SMUX_WRITE_FAIL,
	SMUX_TIOCM_UPDATE,
	SMUX_LOW_WM_HIT,      /* @metadata is NULL */
	SMUX_HIGH_WM_HIT,     /* @metadata is NULL */
	SMUX_RX_RETRY_HIGH_WM_HIT,  /* @metadata is NULL */
	SMUX_RX_RETRY_LOW_WM_HIT,   /* @metadata is NULL */
	SMUX_LOCAL_CLOSED,
	SMUX_REMOTE_CLOSED,
};

/**
 * Channel options used to modify channel behavior.
 */
enum {
	SMUX_CH_OPTION_LOCAL_LOOPBACK = 1 << 0,
	SMUX_CH_OPTION_REMOTE_LOOPBACK = 1 << 1,
	SMUX_CH_OPTION_REMOTE_TX_STOP = 1 << 2,
	SMUX_CH_OPTION_AUTO_REMOTE_TX_STOP = 1 << 3,
};

/**
 * Metadata for SMUX_DISCONNECTED notification
 *
 * @is_ssr:  Disconnect caused by subsystem restart
 */
struct smux_meta_disconnected {
	int is_ssr;
};

/**
 * Metadata for SMUX_READ_DONE/SMUX_READ_FAIL notification
 *
 * @pkt_priv: Packet-specific private data
 * @buffer:   Buffer pointer passed into msm_smux_write
 * @len:      Buffer length passed into  msm_smux_write
 */
struct smux_meta_read {
	void *pkt_priv;
	void *buffer;
	int len;
};

/**
 * Metadata for SMUX_WRITE_DONE/SMUX_WRITE_FAIL notification
 *
 * @pkt_priv: Packet-specific private data
 * @buffer:  Buffer pointer returned by get_rx_buffer()
 * @len:     Buffer length returned by get_rx_buffer()
 */
struct smux_meta_write {
	void *pkt_priv;
	void *buffer;
	int len;
};

/**
 * Metadata for SMUX_TIOCM_UPDATE notification
 *
 * @tiocm_old:  Previous TIOCM state
 * @tiocm_new:   Current TIOCM state
 */
struct smux_meta_tiocm {
	uint32_t tiocm_old;
	uint32_t tiocm_new;
};


#ifdef CONFIG_N_SMUX
/**
 * Starts the opening sequence for a logical channel.
 *
 * @lcid          Logical channel ID
 * @priv          Free for client usage
 * @notify        Event notification function
 * @get_rx_buffer Function used to provide a receive buffer to SMUX
 *
 * @returns 0 for success, <0 otherwise
 *
 * A channel must be fully closed (either not previously opened or
 * msm_smux_close() has been called and the SMUX_DISCONNECTED has been
 * recevied.
 *
 * One the remote side is opened, the client will receive a SMUX_CONNECTED
 * event.
 */
int msm_smux_open(uint8_t lcid, void *priv,
	void (*notify)(void *priv, int event_type, const void *metadata),
	int (*get_rx_buffer)(void *priv, void **pkt_priv,
					void **buffer, int size));

/**
 * Starts the closing sequence for a logical channel.
 *
 * @lcid    Logical channel ID
 * @returns 0 for success, <0 otherwise
 *
 * Once the close event has been acknowledge by the remote side, the client
 * will receive a SMUX_DISCONNECTED notification.
 */
int msm_smux_close(uint8_t lcid);

/**
 * Write data to a logical channel.
 *
 * @lcid      Logical channel ID
 * @pkt_priv  Client data that will be returned with the SMUX_WRITE_DONE or
 *            SMUX_WRITE_FAIL notification.
 * @data      Data to write
 * @len       Length of @data
 *
 * @returns   0 for success, <0 otherwise
 *
 * Data may be written immediately after msm_smux_open() is called, but
 * the data will wait in the transmit queue until the channel has been
 * fully opened.
 *
 * Once the data has been written, the client will receive either a completion
 * (SMUX_WRITE_DONE) or a failure notice (SMUX_WRITE_FAIL).
 */
int msm_smux_write(uint8_t lcid, void *pkt_priv, const void *data, int len);

/**
 * Returns true if the TX queue is currently full (high water mark).
 *
 * @lcid      Logical channel ID
 *
 * @returns   0 if channel is not full; 1 if it is full; < 0 for error
 */
int msm_smux_is_ch_full(uint8_t lcid);

/**
 * Returns true if the TX queue has space for more packets it is at or
 * below the low water mark).
 *
 * @lcid      Logical channel ID
 *
 * @returns   0 if channel is above low watermark
 *            1 if it's at or below the low watermark
 *            < 0 for error
 */
int msm_smux_is_ch_low(uint8_t lcid);

/**
 * Get the TIOCM status bits.
 *
 * @lcid      Logical channel ID
 *
 * @returns   >= 0 TIOCM status bits
 *            < 0  Error condition
 */
long msm_smux_tiocm_get(uint8_t lcid);

/**
 * Set/clear the TIOCM status bits.
 *
 * @lcid      Logical channel ID
 * @set       Bits to set
 * @clear     Bits to clear
 *
 * @returns   0 for success; < 0 for failure
 *
 * If a bit is specified in both the @set and @clear masks, then the clear bit
 * definition will dominate and the bit will be cleared.
 */
int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear);

/**
 * Set or clear channel option using the SMUX_CH_OPTION_* channel
 * flags.
 *
 * @lcid   Logical channel ID
 * @set    Options to set
 * @clear  Options to clear
 *
 * @returns 0 for success, < 0 for failure
 */
int msm_smux_set_ch_option(uint8_t lcid, uint32_t set, uint32_t clear);

#else
static inline int msm_smux_open(uint8_t lcid, void *priv,
	void (*notify)(void *priv, int event_type, const void *metadata),
	int (*get_rx_buffer)(void *priv, void **pkt_priv,
					void **buffer, int size))
{
	return -ENODEV;
}

static inline int msm_smux_close(uint8_t lcid)
{
	return -ENODEV;
}

static inline int msm_smux_write(uint8_t lcid, void *pkt_priv,
				const void *data, int len)
{
	return -ENODEV;
}

static inline int msm_smux_is_ch_full(uint8_t lcid)
{
	return -ENODEV;
}

static inline int msm_smux_is_ch_low(uint8_t lcid)
{
	return -ENODEV;
}

static inline long msm_smux_tiocm_get(uint8_t lcid)
{
	return 0;
}

static inline int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear)
{
	return -ENODEV;
}

static inline int msm_smux_set_ch_option(uint8_t lcid, uint32_t set,
					uint32_t clear)
{
	return -ENODEV;
}

#endif /* CONFIG_N_SMUX */

#endif /* SMUX_H */
