tty: n_smux: Add SMUX TTY Line Discipline Driver

Add new Serial Multiplexer (SMUX) driver.

This driver multiplexes multiple logical channels over a single
physical HSUART channel using the TTY Line Discipline framework.
This driver will be used in Fusion 4 for control plane, data plane
and DIAG traffic between Application processor and QSC modem.

Change-Id: Ibecf6cea872f5baf11fb93ded6124243a37a2085
Signed-off-by: Eric Holmberg <eholmber@codeaurora.org>
Signed-off-by: Angshuman Sarkar <angshuman@codeaurora.org>
Signed-off-by: Karthikeyan Ramasubramanian <kramasub@codeaurora.org>
Signed-off-by: David Brown <davidb@codeaurora.org>
This commit is contained in:
Eric Holmberg
2012-05-10 19:16:51 -06:00
committed by Stephen Boyd
parent 6944ad25e1
commit d68384d72e
9 changed files with 4914 additions and 0 deletions

View File

@@ -323,6 +323,19 @@ config N_GSM
This line discipline provides support for the GSM MUX protocol and
presents the mux as a set of 61 individual tty devices.
config N_SMUX
tristate "SMUX line discipline support"
depends on NET && SERIAL_MSM_HS
help
This line discipline provides support for the Serial MUX protocol
and provides a TTY and kernel API for multiple logical channels.
config N_SMUX_LOOPBACK
tristate "SMUX line discipline loopback support"
depends on N_SMUX
help
Provides loopback and unit testing support for the Serial MUX Protocol.
config TRACE_ROUTER
tristate "Trace data router for MIPI P1149.7 cJTAG standard"
depends on TRACE_SINK

View File

@@ -6,6 +6,8 @@ obj-$(CONFIG_AUDIT) += tty_audit.o
obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o
obj-$(CONFIG_N_HDLC) += n_hdlc.o
obj-$(CONFIG_N_GSM) += n_gsm.o
obj-$(CONFIG_N_SMUX) += n_smux.o
obj-$(CONFIG_N_SMUX_LOOPBACK) += smux_test.o smux_loopback.o
obj-$(CONFIG_TRACE_ROUTER) += n_tracerouter.o
obj-$(CONFIG_TRACE_SINK) += n_tracesink.o
obj-$(CONFIG_R3964) += n_r3964.o

2938
drivers/tty/n_smux.c Normal file

File diff suppressed because it is too large Load Diff

289
drivers/tty/smux_loopback.c Normal file
View File

@@ -0,0 +1,289 @@
/* drivers/tty/smux_loopback.c
*
* Copyright (c) 2012, Code Aurora Forum. 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.
*
*/
#include <linux/types.h>
#include <linux/err.h>
#include <linux/workqueue.h>
#include <linux/kfifo.h>
#include <linux/slab.h>
#include <linux/smux.h>
#include "smux_private.h"
#define SMUX_LOOP_FIFO_SIZE 128
static void smux_loopback_rx_worker(struct work_struct *work);
static struct workqueue_struct *smux_loopback_wq;
static DECLARE_WORK(smux_loopback_work, smux_loopback_rx_worker);
static struct kfifo smux_loop_pkt_fifo;
static DEFINE_SPINLOCK(hw_fn_lock);
/**
* Initialize loopback framework (called by n_smux.c).
*/
int smux_loopback_init(void)
{
int ret = 0;
spin_lock_init(&hw_fn_lock);
smux_loopback_wq = create_singlethread_workqueue("smux_loopback_wq");
if (IS_ERR(smux_loopback_wq)) {
pr_err("%s: failed to create workqueue\n", __func__);
return -ENOMEM;
}
ret |= kfifo_alloc(&smux_loop_pkt_fifo,
SMUX_LOOP_FIFO_SIZE * sizeof(struct smux_pkt_t *),
GFP_KERNEL);
return ret;
}
/**
* Simulate a write to the TTY hardware by duplicating
* the TX packet and putting it into the RX queue.
*
* @pkt Packet to write
*
* @returns 0 on success
*/
int smux_tx_loopback(struct smux_pkt_t *pkt_ptr)
{
struct smux_pkt_t *send_pkt;
unsigned long flags;
int i;
int ret;
/* duplicate packet */
send_pkt = smux_alloc_pkt();
send_pkt->hdr = pkt_ptr->hdr;
if (pkt_ptr->hdr.payload_len) {
ret = smux_alloc_pkt_payload(send_pkt);
if (ret) {
ret = -ENOMEM;
goto out;
}
memcpy(send_pkt->payload, pkt_ptr->payload,
pkt_ptr->hdr.payload_len);
}
/* queue duplicate as pseudo-RX data */
spin_lock_irqsave(&hw_fn_lock, flags);
i = kfifo_avail(&smux_loop_pkt_fifo);
if (i < sizeof(struct smux_pkt_t *)) {
pr_err("%s: no space in fifo\n", __func__);
ret = -ENOMEM;
goto unlock;
}
i = kfifo_in(&smux_loop_pkt_fifo,
&send_pkt,
sizeof(struct smux_pkt_t *));
if (i < 0) {
pr_err("%s: fifo error\n", __func__);
ret = -ENOMEM;
goto unlock;
}
queue_work(smux_loopback_wq, &smux_loopback_work);
ret = 0;
unlock:
spin_unlock_irqrestore(&hw_fn_lock, flags);
out:
return ret;
}
/**
* Receive loopback byte processor.
*
* @pkt Incoming packet
*/
static void smux_loopback_rx_byte(struct smux_pkt_t *pkt)
{
static int simulated_retry_cnt;
const char ack = SMUX_WAKEUP_ACK;
switch (pkt->hdr.flags) {
case SMUX_WAKEUP_REQ:
/* reply with ACK after appropriate delays */
++simulated_retry_cnt;
if (simulated_retry_cnt >= smux_simulate_wakeup_delay) {
pr_err("%s: completed %d of %d\n",
__func__, simulated_retry_cnt,
smux_simulate_wakeup_delay);
pr_err("%s: simulated wakeup\n", __func__);
simulated_retry_cnt = 0;
smux_rx_state_machine(&ack, 1, 0);
} else {
/* force retry */
pr_err("%s: dropping wakeup request %d of %d\n",
__func__, simulated_retry_cnt,
smux_simulate_wakeup_delay);
}
break;
case SMUX_WAKEUP_ACK:
/* this shouldn't happen since we don't send requests */
pr_err("%s: wakeup ACK unexpected\n", __func__);
break;
default:
/* invalid character */
pr_err("%s: invalid character 0x%x\n",
__func__, (unsigned)pkt->hdr.flags);
break;
}
}
/**
* Simulated remote hardware used for local loopback testing.
*
* @work Not used
*/
static void smux_loopback_rx_worker(struct work_struct *work)
{
struct smux_pkt_t *pkt;
struct smux_pkt_t reply_pkt;
char *data;
int len;
int lcid;
int i;
unsigned long flags;
data = kzalloc(SMUX_MAX_PKT_SIZE, GFP_ATOMIC);
spin_lock_irqsave(&hw_fn_lock, flags);
while (kfifo_len(&smux_loop_pkt_fifo) >= sizeof(struct smux_pkt_t *)) {
i = kfifo_out(&smux_loop_pkt_fifo, &pkt,
sizeof(struct smux_pkt_t *));
spin_unlock_irqrestore(&hw_fn_lock, flags);
if (pkt->hdr.magic != SMUX_MAGIC) {
pr_err("%s: invalid magic %x\n", __func__,
pkt->hdr.magic);
return;
}
lcid = pkt->hdr.lcid;
if (smux_assert_lch_id(lcid)) {
pr_err("%s: invalid channel id %d\n", __func__, lcid);
return;
}
switch (pkt->hdr.cmd) {
case SMUX_CMD_OPEN_LCH:
if (pkt->hdr.flags & SMUX_CMD_OPEN_ACK)
break;
/* Reply with Open ACK */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_OPEN_LCH;
reply_pkt.hdr.flags = SMUX_CMD_OPEN_ACK
| SMUX_CMD_OPEN_POWER_COLLAPSE;
reply_pkt.hdr.payload_len = 0;
reply_pkt.hdr.pad_len = 0;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
/* Send Remote Open */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_OPEN_LCH;
reply_pkt.hdr.flags = SMUX_CMD_OPEN_POWER_COLLAPSE;
reply_pkt.hdr.payload_len = 0;
reply_pkt.hdr.pad_len = 0;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
break;
case SMUX_CMD_CLOSE_LCH:
if (pkt->hdr.flags == SMUX_CMD_CLOSE_ACK)
break;
/* Reply with Close ACK */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_CLOSE_LCH;
reply_pkt.hdr.flags = SMUX_CMD_CLOSE_ACK;
reply_pkt.hdr.payload_len = 0;
reply_pkt.hdr.pad_len = 0;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
/* Send Remote Close */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_CLOSE_LCH;
reply_pkt.hdr.flags = 0;
reply_pkt.hdr.payload_len = 0;
reply_pkt.hdr.pad_len = 0;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
break;
case SMUX_CMD_DATA:
/* Echo back received data */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_DATA;
reply_pkt.hdr.flags = 0;
reply_pkt.hdr.payload_len = pkt->hdr.payload_len;
reply_pkt.payload = pkt->payload;
reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
break;
case SMUX_CMD_STATUS:
/* Echo back received status */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_STATUS;
reply_pkt.hdr.flags = pkt->hdr.flags;
reply_pkt.hdr.payload_len = 0;
reply_pkt.payload = NULL;
reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
break;
case SMUX_CMD_PWR_CTL:
/* reply with ack */
smux_init_pkt(&reply_pkt);
reply_pkt.hdr.lcid = lcid;
reply_pkt.hdr.cmd = SMUX_CMD_PWR_CTL;
reply_pkt.hdr.flags = SMUX_CMD_PWR_CTL_SLEEP_REQ
| SMUX_CMD_PWR_CTL_ACK;
reply_pkt.hdr.payload_len = 0;
reply_pkt.payload = NULL;
reply_pkt.hdr.pad_len = pkt->hdr.pad_len;
smux_serialize(&reply_pkt, data, &len);
smux_rx_state_machine(data, len, 0);
break;
case SMUX_CMD_BYTE:
smux_loopback_rx_byte(pkt);
break;
default:
pr_err("%s: unknown command %d\n",
__func__, pkt->hdr.cmd);
break;
};
smux_free_pkt(pkt);
spin_lock_irqsave(&hw_fn_lock, flags);
}
spin_unlock_irqrestore(&hw_fn_lock, flags);
kfree(data);
}

View File

@@ -0,0 +1,39 @@
/* drivers/tty/smux_loopback.h
*
* Copyright (c) 2012, Code Aurora Forum. 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_LOOPBACK_H
#define SMUX_LOOPBACK_H
#include "smux_private.h"
#ifdef CONFIG_N_SMUX_LOOPBACK
int smux_loopback_init(void);
int smux_tx_loopback(struct smux_pkt_t *pkt_ptr);
#else
static inline int smux_loopback_init(void)
{
return 0;
}
static inline int smux_tx_loopback(struct smux_pkt_t *pkt_ptr)
{
return -ENODEV;
}
#endif /* CONFIG_N_SMUX_LOOPBACK */
#endif /* SMUX_LOOPBACK_H */

115
drivers/tty/smux_private.h Normal file
View File

@@ -0,0 +1,115 @@
/* drivers/tty/smux_private.h
*
* Copyright (c) 2012, Code Aurora Forum. 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_PRIVATE_H
#define SMUX_PRIVATE_H
#define SMUX_MAX_PKT_SIZE 8192
/* SMUX Protocol Characters */
#define SMUX_MAGIC 0x33FC
#define SMUX_MAGIC_WORD1 0xFC
#define SMUX_MAGIC_WORD2 0x33
#define SMUX_WAKEUP_REQ 0xFD
#define SMUX_WAKEUP_ACK 0xFE
/* Unit testing characters */
#define SMUX_UT_ECHO_REQ 0xF0
#define SMUX_UT_ECHO_ACK_OK 0xF1
#define SMUX_UT_ECHO_ACK_FAIL 0xF2
struct tty_struct;
/* Packet header. */
struct smux_hdr_t {
uint16_t magic;
uint8_t flags;
uint8_t cmd;
uint8_t pad_len;
uint8_t lcid;
uint16_t payload_len;
};
/* Internal packet structure. */
struct smux_pkt_t {
struct smux_hdr_t hdr;
int allocated;
unsigned char *payload;
int free_payload;
struct list_head list;
void *priv;
};
/* SMUX Packet Commands */
enum {
SMUX_CMD_DATA = 0x0,
SMUX_CMD_OPEN_LCH = 0x1,
SMUX_CMD_CLOSE_LCH = 0x2,
SMUX_CMD_STATUS = 0x3,
SMUX_CMD_PWR_CTL = 0x4,
SMUX_CMD_BYTE, /* for internal usage */
SMUX_NUM_COMMANDS
};
/* Open command flags */
enum {
SMUX_CMD_OPEN_ACK = 1 << 0,
SMUX_CMD_OPEN_POWER_COLLAPSE = 1 << 1,
SMUX_CMD_OPEN_REMOTE_LOOPBACK = 1 << 2,
};
/* Close command flags */
enum {
SMUX_CMD_CLOSE_ACK = 1 << 0,
};
/* Power command flags */
enum {
SMUX_CMD_PWR_CTL_ACK = 1 << 0,
SMUX_CMD_PWR_CTL_SLEEP_REQ = 1 << 1,
};
/* Local logical channel states */
enum {
SMUX_LCH_LOCAL_CLOSED,
SMUX_LCH_LOCAL_OPENING,
SMUX_LCH_LOCAL_OPENED,
SMUX_LCH_LOCAL_CLOSING,
};
/* Remote logical channel states */
enum {
SMUX_LCH_REMOTE_CLOSED,
SMUX_LCH_REMOTE_OPENED,
};
int smux_assert_lch_id(uint32_t lcid);
void smux_init_pkt(struct smux_pkt_t *pkt);
struct smux_pkt_t *smux_alloc_pkt(void);
int smux_alloc_pkt_payload(struct smux_pkt_t *pkt);
void smux_free_pkt(struct smux_pkt_t *pkt);
int smux_serialize(struct smux_pkt_t *pkt, char *out,
unsigned int *out_len);
void smux_rx_state_machine(const unsigned char *data, int len, int flag);
void smuxld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count);
/* testing parameters */
extern int smux_byte_loopback;
extern int smux_simulate_wakeup_delay;
#endif /* SMUX_PRIVATE_H */

1222
drivers/tty/smux_test.c Normal file

File diff suppressed because it is too large Load Diff

295
include/linux/smux.h Normal file
View File

@@ -0,0 +1,295 @@
/* include/linux/smux.h
*
* Copyright (c) 2012, Code Aurora Forum. 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 */
};
/**
* 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,
};
/**
* 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
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;
}
int msm_smux_close(uint8_t lcid)
{
return -ENODEV;
}
int msm_smux_write(uint8_t lcid, void *pkt_priv, const void *data, int len)
{
return -ENODEV;
}
int msm_smux_is_ch_full(uint8_t lcid);
{
return -ENODEV;
}
int msm_smux_is_ch_low(uint8_t lcid);
{
return -ENODEV;
}
long msm_smux_tiocm_get(uint8_t lcid)
{
return 0;
}
int msm_smux_tiocm_set(uint8_t lcid, uint32_t set, uint32_t clear)
{
return -ENODEV;
}
int msm_smux_set_ch_option(uint8_t lcid, uint32_t set, uint32_t clear)
{
return -ENODEV;
}
#endif /* CONFIG_N_SMUX */
#endif /* SMUX_H */

View File

@@ -34,6 +34,7 @@
#define N_TI_WL 22 /* for TI's WL BT, FM, GPS combo chips */
#define N_TRACESINK 23 /* Trace data routing for MIPI P1149.7 */
#define N_TRACEROUTER 24 /* Trace data routing for MIPI P1149.7 */
#define N_SMUX 25 /* Serial MUX */
#ifdef __KERNEL__
#include <linux/fs.h>