summaryrefslogtreecommitdiff
path: root/packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch')
-rw-r--r--packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch5396
1 files changed, 5396 insertions, 0 deletions
diff --git a/packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch b/packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch
new file mode 100644
index 0000000000..3e8e3e2604
--- /dev/null
+++ b/packages/linux/linux-ezx-2.6.24/patches/mux_cli.patch
@@ -0,0 +1,5396 @@
+Index: linux-2.6.24/drivers/char/Kconfig
+===================================================================
+--- linux-2.6.24.orig/drivers/char/Kconfig
++++ linux-2.6.24/drivers/char/Kconfig
+@@ -1040,5 +1040,18 @@
+
+ source "drivers/s390/char/Kconfig"
+
++config TS0710_MUX
++ tristate "GSM TS 07.10 Multiplex driver"
++ depends on EZX_BP
++ help
++ This implements the GSM 07.10 multiplex.
++
++config TS0710_MUX_USB
++ tristate "Motorola USB support for TS 07.10 Multiplex driver"
++ depends on TS0710_MUX
++ help
++ This ads support for TS 07.10 over USB, as found in motorola
++ Smartphones.
++
+ endmenu
+
+Index: linux-2.6.24/drivers/char/Makefile
+===================================================================
+--- linux-2.6.24.orig/drivers/char/Makefile
++++ linux-2.6.24/drivers/char/Makefile
+@@ -111,6 +111,9 @@
+ obj-$(CONFIG_JS_RTC) += js-rtc.o
+ js-rtc-y = rtc.o
+
++obj-$(CONFIG_TS0710_MUX) += ts0710_mux.o ts0710_mux_usb.o
++
++
+ # Files generated that shall be removed upon make clean
+ clean-files := consolemap_deftbl.c defkeymap.c
+
+Index: linux-2.6.24/drivers/char/ts0710.h
+===================================================================
+--- /dev/null
++++ linux-2.6.24/drivers/char/ts0710.h
+@@ -0,0 +1,368 @@
++/*
++ * File: ts0710.h
++ *
++ * Portions derived from rfcomm.c, original header as follows:
++ *
++ * Copyright (C) 2000, 2001 Axis Communications AB
++ *
++ * Author: Mats Friden <mats.friden@axis.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Exceptionally, Axis Communications AB grants discretionary and
++ * conditional permissions for additional use of the text contained
++ * in the company's release of the AXIS OpenBT Stack under the
++ * provisions set forth hereunder.
++ *
++ * Provided that, if you use the AXIS OpenBT Stack with other files,
++ * that do not implement functionality as specified in the Bluetooth
++ * System specification, to produce an executable, this does not by
++ * itself cause the resulting executable to be covered by the GNU
++ * General Public License. Your use of that executable is in no way
++ * restricted on account of using the AXIS OpenBT Stack code with it.
++ *
++ * This exception does not however invalidate any other reasons why
++ * the executable file might be covered by the provisions of the GNU
++ * General Public License.
++ *
++ */
++/*
++ * Copyright (C) 2002 Motorola
++ *
++ * 07/28/2002 Initial version based on rfcomm.c
++ * 11/18/2002 Modified
++ */
++
++#include <linux/config.h>
++#include <linux/module.h>
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/fcntl.h>
++#include <linux/string.h>
++#include <linux/major.h>
++#include <linux/mm.h>
++#include <linux/init.h>
++#include <linux/devfs_fs_kernel.h>
++
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++
++#include <asm/byteorder.h>
++#include <asm/types.h>
++
++#define TS0710_MAX_CHN 14
++
++#define SET_PF(ctr) ((ctr) | (1 << 4))
++#define CLR_PF(ctr) ((ctr) & 0xef)
++#define GET_PF(ctr) (((ctr) >> 4) & 0x1)
++
++#define GET_PN_MSG_FRAME_SIZE(pn) ( ((pn)->frame_sizeh << 8) | ((pn)->frame_sizel))
++#define SET_PN_MSG_FRAME_SIZE(pn, size) ({ (pn)->frame_sizel = (size) & 0xff; \
++ (pn)->frame_sizeh = (size) >> 8; })
++
++#define GET_LONG_LENGTH(a) ( ((a).h_len << 7) | ((a).l_len) )
++#define SET_LONG_LENGTH(a, length) ({ (a).ea = 0; \
++ (a).l_len = length & 0x7F; \
++ (a).h_len = (length >> 7) & 0xFF; })
++
++#define SHORT_CRC_CHECK 3
++#define LONG_CRC_CHECK 4
++
++/* FIXME: Should thsi one be define here? */
++#define SHORT_PAYLOAD_SIZE 127
++
++#define EA 1
++#define FCS_SIZE 1
++#define FLAG_SIZE 2
++
++#define TS0710_MAX_HDR_SIZE 5
++#define DEF_TS0710_MTU 256
++
++#define TS0710_BASIC_FLAG 0xF9
++/* the control field */
++#define SABM 0x2f
++#define SABM_SIZE 4
++#define UA 0x63
++#define UA_SIZE 4
++#define DM 0x0f
++#define DISC 0x43
++#define UIH 0xef
++
++/* the type field in a multiplexer command packet */
++#define TEST 0x8
++#define FCON 0x28
++#define FCOFF 0x18
++#define MSC 0x38
++#define RPN 0x24
++#define RLS 0x14
++#define PN 0x20
++#define NSC 0x4
++
++/* V.24 modem control signals */
++#define FC 0x2
++#define RTC 0x4
++#define RTR 0x8
++#define IC 0x40
++#define DV 0x80
++
++#define CTRL_CHAN 0 /* The control channel is defined as DLCI 0 */
++#define MCC_CMD 1 /* Multiplexer command cr */
++#define MCC_RSP 0 /* Multiplexer response cr */
++
++#ifdef __LITTLE_ENDIAN_BITFIELD
++
++typedef struct {
++ __u8 ea:1;
++ __u8 cr:1;
++ __u8 d:1;
++ __u8 server_chn:5;
++} __attribute__ ((packed)) address_field;
++
++typedef struct {
++ __u8 ea:1;
++ __u8 len:7;
++} __attribute__ ((packed)) short_length;
++
++typedef struct {
++ __u8 ea:1;
++ __u8 l_len:7;
++ __u8 h_len;
++} __attribute__ ((packed)) long_length;
++
++typedef struct {
++ address_field addr;
++ __u8 control;
++ short_length length;
++} __attribute__ ((packed)) short_frame_head;
++
++typedef struct {
++ short_frame_head h;
++ __u8 data[0];
++} __attribute__ ((packed)) short_frame;
++
++typedef struct {
++ address_field addr;
++ __u8 control;
++ long_length length;
++ __u8 data[0];
++} __attribute__ ((packed)) long_frame_head;
++
++typedef struct {
++ long_frame_head h;
++ __u8 data[0];
++} __attribute__ ((packed)) long_frame;
++
++/* Typedefinitions for structures used for the multiplexer commands */
++typedef struct {
++ __u8 ea:1;
++ __u8 cr:1;
++ __u8 type:6;
++} __attribute__ ((packed)) mcc_type;
++
++typedef struct {
++ mcc_type type;
++ short_length length;
++ __u8 value[0];
++} __attribute__ ((packed)) mcc_short_frame_head;
++
++typedef struct {
++ mcc_short_frame_head h;
++ __u8 value[0];
++} __attribute__ ((packed)) mcc_short_frame;
++
++typedef struct {
++ mcc_type type;
++ long_length length;
++ __u8 value[0];
++} __attribute__ ((packed)) mcc_long_frame_head;
++
++typedef struct {
++ mcc_long_frame_head h;
++ __u8 value[0];
++} __attribute__ ((packed)) mcc_long_frame;
++
++/* MSC-command */
++typedef struct {
++ __u8 ea:1;
++ __u8 fc:1;
++ __u8 rtc:1;
++ __u8 rtr:1;
++ __u8 reserved:2;
++ __u8 ic:1;
++ __u8 dv:1;
++} __attribute__ ((packed)) v24_sigs;
++
++typedef struct {
++ __u8 ea:1;
++ __u8 b1:1;
++ __u8 b2:1;
++ __u8 b3:1;
++ __u8 len:4;
++} __attribute__ ((packed)) brk_sigs;
++
++typedef struct {
++ short_frame_head s_head;
++ mcc_short_frame_head mcc_s_head;
++ address_field dlci;
++ __u8 v24_sigs;
++ //brk_sigs break_signals;
++ __u8 fcs;
++} __attribute__ ((packed)) msc_msg;
++
++#if 0
++/* conflict with termios.h */
++/* RPN command */
++#define B2400 0
++#define B4800 1
++#define B7200 2
++#define B9600 3
++#define B19200 4
++#define B38400 5
++#define B57600 6
++#define B115200 7
++#define D230400 8
++#endif
++
++/*
++typedef struct{
++ __u8 bit_rate:1;
++ __u8 data_bits:1;
++ __u8 stop_bit:1;
++ __u8 parity:1;
++ __u8 parity_type:1;
++ __u8 xon_u8:1;
++ __u8 xoff_u8:1;
++ __u8 res1:1;
++ __u8 xon_input:1;
++ __u8 xon_output:1;
++ __u8 rtr_input:1;
++ __u8 rtr_output:1;
++ __u8 rtc_input:1;
++ __u8 rtc_output:1;
++ __u8 res2:2;
++} __attribute__((packed)) parameter_mask;
++
++typedef struct{
++ __u8 bit_rate;
++ __u8 data_bits:2;
++ __u8 stop_bit:1;
++ __u8 parity:1;
++ __u8 parity_type:2;
++ __u8 res1:2;
++ __u8 xon_input:1;
++ __u8 xon_output:1;
++ __u8 rtr_input:1;
++ __u8 rtr_output:1;
++ __u8 rtc_input:1;
++ __u8 rtc_output:1;
++ __u8 res2:2;
++ __u8 xon_u8;
++ __u8 xoff_u8;
++ parameter_mask pm;
++} __attribute__((packed)) rpn_values;
++
++typedef struct{
++ short_frame_head s_head;
++ mcc_short_frame_head mcc_s_head;
++ address_field dlci;
++ rpn_values rpn_val;
++ __u8 fcs;
++} __attribute__((packed)) rpn_msg;
++*/
++
++/* RLS-command */
++/*
++typedef struct{
++ short_frame_head s_head;
++ mcc_short_frame_head mcc_s_head;
++ address_field dlci;
++ __u8 error:4;
++ __u8 res:4;
++ __u8 fcs;
++} __attribute__((packed)) rls_msg;
++*/
++
++/* PN-command */
++typedef struct {
++ short_frame_head s_head;
++ mcc_short_frame_head mcc_s_head;
++ __u8 dlci:6;
++ __u8 res1:2;
++ __u8 frame_type:4;
++ __u8 credit_flow:4;
++ __u8 prior:6;
++ __u8 res2:2;
++ __u8 ack_timer;
++ __u8 frame_sizel;
++ __u8 frame_sizeh;
++ __u8 max_nbrof_retrans;
++ __u8 credits;
++ __u8 fcs;
++} __attribute__ ((packed)) pn_msg;
++
++/* NSC-command */
++typedef struct {
++ short_frame_head s_head;
++ mcc_short_frame_head mcc_s_head;
++ mcc_type command_type;
++ __u8 fcs;
++} __attribute__ ((packed)) nsc_msg;
++
++#else
++#error Only littel-endianess supported now!
++#endif
++
++enum {
++ REJECTED = 0,
++ DISCONNECTED,
++ CONNECTING,
++ NEGOTIATING,
++ CONNECTED,
++ DISCONNECTING,
++ FLOW_STOPPED
++};
++
++enum ts0710_events {
++ CONNECT_IND,
++ CONNECT_CFM,
++ DISCONN_CFM
++};
++
++typedef struct {
++ volatile __u8 state;
++ volatile __u8 flow_control;
++ volatile __u8 initiated;
++ volatile __u8 initiator;
++ volatile __u16 mtu;
++ wait_queue_head_t open_wait;
++ wait_queue_head_t close_wait;
++} dlci_struct;
++
++/* user space interfaces */
++typedef struct {
++ volatile __u8 initiator;
++ volatile __u8 c_dlci;
++ volatile __u16 mtu;
++ volatile __u8 be_testing;
++ volatile __u32 test_errs;
++ wait_queue_head_t test_wait;
++
++ dlci_struct dlci[TS0710_MAX_CHN];
++} ts0710_con;
+Index: linux-2.6.24/drivers/char/ts0710_mux.c
+===================================================================
+--- /dev/null
++++ linux-2.6.24/drivers/char/ts0710_mux.c
+@@ -0,0 +1,3966 @@
++/*
++ * File: mux_driver.c
++ *
++ * Portions derived from rfcomm.c, original header as follows:
++ *
++ * Copyright (C) 2000, 2001 Axis Communications AB
++ *
++ * Author: Mats Friden <mats.friden@axis.com>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * as published by the Free Software Foundation; either version 2
++ * of the License, or (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
++ *
++ * Exceptionally, Axis Communications AB grants discretionary and
++ * conditional permissions for additional use of the text contained
++ * in the company's release of the AXIS OpenBT Stack under the
++ * provisions set forth hereunder.
++ *
++ * Provided that, if you use the AXIS OpenBT Stack with other files,
++ * that do not implement functionality as specified in the Bluetooth
++ * System specification, to produce an executable, this does not by
++ * itself cause the resulting executable to be covered by the GNU
++ * General Public License. Your use of that executable is in no way
++ * restricted on account of using the AXIS OpenBT Stack code with it.
++ *
++ * This exception does not however invalidate any other reasons why
++ * the executable file might be covered by the provisions of the GNU
++ * General Public License.
++ *
++ */
++/*
++ * Copyright (C) 2002-2004 Motorola
++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org>
++ *
++ * 07/28/2002 Initial version
++ * 11/18/2002 Second version
++ * 04/21/2004 Add GPRS PROC
++ */
++#include <linux/config.h>
++#include <linux/module.h>
++#include <linux/types.h>
++
++#include <linux/kernel.h>
++#include <linux/proc_fs.h>
++
++#define USB_FOR_MUX
++
++#ifndef USB_FOR_MUX
++#include <linux/serial.h>
++#endif
++
++#include <linux/errno.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/fcntl.h>
++#include <linux/string.h>
++#include <linux/major.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/devfs_fs_kernel.h>
++//#include <syslog.h>
++
++#include <asm/uaccess.h>
++#include <asm/system.h>
++#include <asm/bitops.h>
++
++#ifdef USB_FOR_MUX
++//#include <linux/usb.h>
++#include "ts0710_mux_usb.h"
++#endif
++
++#include "ts0710.h"
++#include "ts0710_mux.h"
++
++#define TS0710MUX_GPRS_SESSION_MAX 2
++#define TS0710MUX_MAJOR 250
++#define TS0710MUX_MINOR_START 0
++#define NR_MUXS 16
++
++ /*#define TS0710MUX_TIME_OUT 30 *//* 300ms */
++#define TS0710MUX_TIME_OUT 250 /* 2500ms, for BP UART hardware flow control AP UART */
++
++#define TS0710MUX_IO_DLCI_FC_ON 0x54F2
++#define TS0710MUX_IO_DLCI_FC_OFF 0x54F3
++#define TS0710MUX_IO_FC_ON 0x54F4
++#define TS0710MUX_IO_FC_OFF 0x54F5
++
++#define TS0710MUX_MAX_BUF_SIZE 2048
++
++#define TS0710MUX_SEND_BUF_OFFSET 10
++#define TS0710MUX_SEND_BUF_SIZE (DEF_TS0710_MTU + TS0710MUX_SEND_BUF_OFFSET + 34)
++#define TS0710MUX_RECV_BUF_SIZE TS0710MUX_SEND_BUF_SIZE
++
++/*For BP UART problem Begin*/
++#ifdef TS0710SEQ2
++#define ACK_SPACE 66 /* 6 * 11(ACK frame size) */
++#else
++#define ACK_SPACE 42 /* 6 * 7(ACK frame size) */
++#endif
++/*For BP UART problem End*/
++
++ /*#define TS0710MUX_SERIAL_BUF_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE)*//* For BP UART problem */
++#define TS0710MUX_SERIAL_BUF_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE + ACK_SPACE) /* For BP UART problem: ACK_SPACE */
++
++#define TS0710MUX_MAX_TOTAL_FRAME_SIZE (DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE + FLAG_SIZE)
++#define TS0710MUX_MAX_CHARS_IN_BUF 65535
++#define TS0710MUX_THROTTLE_THRESHOLD DEF_TS0710_MTU
++
++#define TEST_PATTERN_SIZE 250
++
++#define CMDTAG 0x55
++#define DATATAG 0xAA
++
++#define ACK 0x4F /*For BP UART problem */
++
++/*For BP UART problem Begin*/
++#ifdef TS0710SEQ2
++#define FIRST_BP_SEQ_OFFSET 1 /*offset from start flag */
++#define SECOND_BP_SEQ_OFFSET 2 /*offset from start flag */
++#define FIRST_AP_SEQ_OFFSET 3 /*offset from start flag */
++#define SECOND_AP_SEQ_OFFSET 4 /*offset from start flag */
++#define SLIDE_BP_SEQ_OFFSET 5 /*offset from start flag */
++#define SEQ_FIELD_SIZE 5
++#else
++#define SLIDE_BP_SEQ_OFFSET 1 /*offset from start flag */
++#define SEQ_FIELD_SIZE 1
++#endif
++
++#define ADDRESS_FIELD_OFFSET (1 + SEQ_FIELD_SIZE) /*offset from start flag */
++/*For BP UART problem End*/
++
++#ifndef UNUSED_PARAM
++#define UNUSED_PARAM(v) (void)(v)
++#endif
++
++#define TS0710MUX_GPRS1_DLCI 7
++#define TS0710MUX_GPRS2_DLCI 8
++
++#define TS0710MUX_GPRS1_RECV_COUNT_IDX 0
++#define TS0710MUX_GPRS1_SEND_COUNT_IDX 1
++#define TS0710MUX_GPRS2_RECV_COUNT_IDX 2
++#define TS0710MUX_GPRS2_SEND_COUNT_IDX 3
++#define TS0710MUX_COUNT_MAX_IDX 3
++#define TS0710MUX_COUNT_IDX_NUM (TS0710MUX_COUNT_MAX_IDX + 1)
++
++static volatile int mux_data_count[TS0710MUX_COUNT_IDX_NUM] = { 0, 0, 0, 0 };
++static volatile int mux_data_count2[TS0710MUX_COUNT_IDX_NUM] = { 0, 0, 0, 0 };
++static struct semaphore mux_data_count_mutex[TS0710MUX_COUNT_IDX_NUM];
++static volatile __u8 post_recv_count_flag = 0;
++
++/*PROC file*/
++struct proc_dir_entry *gprs_proc_file = NULL;
++ssize_t file_proc_read(struct file *file, char *buf, size_t size,
++ loff_t * ppos);
++ssize_t file_proc_write(struct file *file, const char *buf, size_t count,
++ loff_t * ppos);
++struct file_operations file_proc_operations = {
++ read:file_proc_read,
++ write:file_proc_write,
++};
++typedef struct {
++ int recvBytes;
++ int sentBytes;
++} gprs_bytes;
++
++static __u8 tty2dlci[NR_MUXS] =
++ { 1, 2, 3, 4, 5, 6, 7, 8, 6, 7, 8, 9, 10, 11, 12, 13 };
++static __u8 iscmdtty[NR_MUXS] =
++ { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0 };
++typedef struct {
++ __u8 cmdtty;
++ __u8 datatty;
++} dlci_tty;
++static dlci_tty dlci2tty[] = { {0, 0}, /* DLCI 0 */
++{0, 0}, /* DLCI 1 */
++{1, 1}, /* DLCI 2 */
++{2, 2}, /* DLCI 3 */
++{3, 3}, /* DLCI 4 */
++{4, 4}, /* DLCI 5 */
++{5, 8}, /* DLCI 6 */
++{6, 9}, /* DLCI 7 */
++{7, 10}, /* DLCI 8 */
++{11, 11}, /* DLCI 9 */
++{12, 12}, /* DLCI 10 */
++{13, 13}, /* DLCI 11 */
++{14, 14}, /* DLCI 12 */
++{15, 15}
++}; /* DLCI 13 */
++
++typedef struct {
++ volatile __u8 buf[TS0710MUX_SEND_BUF_SIZE];
++ volatile __u8 *frame;
++ unsigned long flags;
++ volatile __u16 length;
++ volatile __u8 filled;
++ volatile __u8 dummy; /* Allignment to 4*n bytes */
++} mux_send_struct;
++
++/* Bit number in flags of mux_send_struct */
++#define BUF_BUSY 0
++
++struct mux_recv_packet_tag {
++ __u8 *data;
++ __u32 length;
++ struct mux_recv_packet_tag *next;
++};
++typedef struct mux_recv_packet_tag mux_recv_packet;
++
++struct mux_recv_struct_tag {
++ __u8 data[TS0710MUX_RECV_BUF_SIZE];
++ __u32 length;
++ __u32 total;
++ mux_recv_packet *mux_packet;
++ struct mux_recv_struct_tag *next;
++ int no_tty;
++ volatile __u8 post_unthrottle;
++};
++typedef struct mux_recv_struct_tag mux_recv_struct;
++
++#define RECV_RUNNING 0
++static unsigned long mux_recv_flags = 0;
++
++static mux_send_struct *mux_send_info[NR_MUXS];
++static volatile __u8 mux_send_info_flags[NR_MUXS];
++static volatile __u8 mux_send_info_idx = NR_MUXS;
++
++static mux_recv_struct *mux_recv_info[NR_MUXS];
++static volatile __u8 mux_recv_info_flags[NR_MUXS];
++static mux_recv_struct *mux_recv_queue = NULL;
++
++static struct tty_driver mux_driver;
++
++#ifdef USB_FOR_MUX
++#define COMM_FOR_MUX_DRIVER usb_for_mux_driver
++#define COMM_FOR_MUX_TTY usb_for_mux_tty
++#define COMM_MUX_DISPATCHER usb_mux_dispatcher
++#define COMM_MUX_SENDER usb_mux_sender
++#else
++#define COMM_FOR_MUX_DRIVER serial_for_mux_driver
++#define COMM_FOR_MUX_TTY serial_for_mux_tty
++#define COMM_MUX_DISPATCHER serial_mux_dispatcher
++#define COMM_MUX_SENDER serial_mux_sender
++
++extern struct list_head *tq_serial_for_mux;
++#endif
++
++extern struct tty_driver *COMM_FOR_MUX_DRIVER;
++extern struct tty_struct *COMM_FOR_MUX_TTY;
++extern void (*COMM_MUX_DISPATCHER) (struct tty_struct * tty);
++extern void (*COMM_MUX_SENDER) (void);
++
++static struct work_struct send_tqueue;
++static struct work_struct receive_tqueue;
++static struct work_struct post_recv_tqueue;
++
++static struct tty_struct *mux_table[NR_MUXS];
++static struct termios *mux_termios[NR_MUXS];
++static struct termios *mux_termios_locked[NR_MUXS];
++static volatile short int mux_tty[NR_MUXS];
++
++#ifdef min
++#undef min
++#define min(a,b) ( (a)<(b) ? (a):(b) )
++#endif
++
++static int get_count(__u8 idx);
++static int set_count(__u8 idx, int count);
++static int add_count(__u8 idx, int count);
++
++static int send_ua(ts0710_con * ts0710, __u8 dlci);
++static int send_dm(ts0710_con * ts0710, __u8 dlci);
++static int send_sabm(ts0710_con * ts0710, __u8 dlci);
++static int send_disc(ts0710_con * ts0710, __u8 dlci);
++static void queue_uih(mux_send_struct * send_info, __u16 len,
++ ts0710_con * ts0710, __u8 dlci);
++static int send_pn_msg(ts0710_con * ts0710, __u8 prior, __u32 frame_size,
++ __u8 credit_flow, __u8 credits, __u8 dlci, __u8 cr);
++static int send_nsc_msg(ts0710_con * ts0710, mcc_type cmd, __u8 cr);
++static void set_uih_hdr(short_frame * uih_pkt, __u8 dlci, __u32 len, __u8 cr);
++
++static __u32 crc_check(__u8 * data, __u32 length, __u8 check_sum);
++static __u8 crc_calc(__u8 * data, __u32 length);
++static void create_crctable(__u8 table[]);
++
++static void mux_sched_send(void);
++
++static __u8 crctable[256];
++
++static ts0710_con ts0710_connection;
++/*
++static rpn_values rpn_val;
++*/
++
++static int valid_dlci(__u8 dlci)
++{
++ if ((dlci < TS0710_MAX_CHN) && (dlci > 0))
++ return 1;
++ else
++ return 0;
++}
++
++#ifdef TS0710DEBUG
++
++#ifdef PRINT_OUTPUT_PRINTK
++#define TS0710_DEBUG(fmt, arg...) printk(KERN_INFO "MUX " __FUNCTION__ ": " fmt "\n" , ## arg)
++#else
++#include "ezxlog.h"
++static __u8 strDebug[256];
++#define TS0710_DEBUG(fmt, arg...) ({ snprintf(strDebug, sizeof(strDebug), "MUX " __FUNCTION__ ": " fmt "\n" , ## arg); \
++ /*printk("%s", strDebug)*/ezxlogk("MX", strDebug, strlen(strDebug)); })
++#endif /* End #ifdef PRINT_OUTPUT_PRINTK */
++
++#else
++#define TS0710_DEBUG(fmt...)
++#endif /* End #ifdef TS0710DEBUG */
++
++#ifdef TS0710LOG
++static unsigned char g_tbuf[TS0710MUX_MAX_BUF_SIZE];
++#ifdef PRINT_OUTPUT_PRINTK
++#define TS0710_LOG(fmt, arg...) printk(fmt, ## arg)
++#define TS0710_PRINTK(fmt, arg...) printk(fmt, ## arg)
++#else
++#include "ezxlog.h"
++static __u8 strLog[256];
++#define TS0710_LOG(fmt, arg...) ({ snprintf(strLog, sizeof(strLog), fmt, ## arg); \
++ /*printk("%s", strLog)*/ezxlogk("MX", strLog, strlen(strLog)); })
++#define TS0710_PRINTK(fmt, arg...) ({ printk(fmt, ## arg); \
++ TS0710_LOG(fmt, ## arg); })
++#endif /* End #ifdef PRINT_OUTPUT_PRINTK */
++
++#else
++#define TS0710_LOG(fmt...)
++#define TS0710_PRINTK(fmt, arg...) printk(fmt, ## arg)
++#endif /* End #ifdef TS0710LOG */
++
++#ifdef TS0710DEBUG
++static void TS0710_DEBUGHEX(__u8 * buf, int len)
++{
++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE];
++
++ int i;
++ int c;
++
++ if (len <= 0) {
++ return;
++ }
++
++ c = 0;
++ for (i = 0; (i < len) && (c < (TS0710MUX_MAX_BUF_SIZE - 3)); i++) {
++ sprintf(&tbuf[c], "%02x ", buf[i]);
++ c += 3;
++ }
++ tbuf[c] = 0;
++
++#ifdef PRINT_OUTPUT_PRINTK
++ TS0710_DEBUG("%s", tbuf);
++#else
++ /*printk("%s\n", tbuf) */ ezxlogk("MX", tbuf, c);
++#endif
++}
++static void TS0710_DEBUGSTR(__u8 * buf, int len)
++{
++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE];
++
++ if (len <= 0) {
++ return;
++ }
++
++ if (len > (TS0710MUX_MAX_BUF_SIZE - 1)) {
++ len = (TS0710MUX_MAX_BUF_SIZE - 1);
++ }
++
++ memcpy(tbuf, buf, len);
++ tbuf[len] = 0;
++
++#ifdef PRINT_OUTPUT_PRINTK
++ /* 0x00 byte in the string pointed by tbuf may truncate the print result */
++ TS0710_DEBUG("%s", tbuf);
++#else
++ /*printk("%s\n", tbuf) */ ezxlogk("MX", tbuf, len);
++#endif
++}
++#else
++#define TS0710_DEBUGHEX(buf, len)
++#define TS0710_DEBUGSTR(buf, len)
++#endif /* End #ifdef TS0710DEBUG */
++
++#ifdef TS0710LOG
++static void TS0710_LOGSTR_FRAME(__u8 send, __u8 * data, int len)
++{
++ short_frame *short_pkt;
++ long_frame *long_pkt;
++ __u8 *uih_data_start;
++ __u32 uih_len;
++ __u8 dlci;
++ int pos;
++
++ if (len <= 0) {
++ return;
++ }
++
++ pos = 0;
++ if (send) {
++ pos += sprintf(&g_tbuf[pos], "<");
++ short_pkt = (short_frame *) (data + 1); /*For BP UART problem */
++ } else {
++ /*For BP UART problem */
++ /*pos += sprintf(&g_tbuf[pos], ">"); */
++ pos += sprintf(&g_tbuf[pos], ">%d ", *(data + SLIDE_BP_SEQ_OFFSET)); /*For BP UART problem */
++
++#ifdef TS0710SEQ2
++ pos += sprintf(&g_tbuf[pos], "%02x %02x %02x %02x ", *(data + FIRST_BP_SEQ_OFFSET), *(data + SECOND_BP_SEQ_OFFSET), *(data + FIRST_AP_SEQ_OFFSET), *(data + SECOND_AP_SEQ_OFFSET)); /*For BP UART problem */
++#endif
++
++ short_pkt = (short_frame *) (data + ADDRESS_FIELD_OFFSET); /*For BP UART problem */
++ }
++
++ /*For BP UART problem */
++ /*short_pkt = (short_frame *)(data + 1); */
++
++ dlci = short_pkt->h.addr.server_chn << 1 | short_pkt->h.addr.d;
++ switch (CLR_PF(short_pkt->h.control)) {
++ case SABM:
++ pos += sprintf(&g_tbuf[pos], "C SABM %d ::", dlci);
++ break;
++ case UA:
++ pos += sprintf(&g_tbuf[pos], "C UA %d ::", dlci);
++ break;
++ case DM:
++ pos += sprintf(&g_tbuf[pos], "C DM %d ::", dlci);
++ break;
++ case DISC:
++ pos += sprintf(&g_tbuf[pos], "C DISC %d ::", dlci);
++ break;
++
++ /*For BP UART problem Begin */
++ case ACK:
++ pos += sprintf(&g_tbuf[pos], "C ACK %d ", short_pkt->data[0]);
++
++#ifdef TS0710SEQ2
++ pos += sprintf(&g_tbuf[pos], "%02x %02x %02x %02x ", short_pkt->data[1], short_pkt->data[2], short_pkt->data[3], short_pkt->data[4]); /*For BP UART problem */
++#endif
++
++ pos += sprintf(&g_tbuf[pos], "::");
++ break;
++ /*For BP UART problem End */
++
++ case UIH:
++ if (!dlci) {
++ pos += sprintf(&g_tbuf[pos], "C MCC %d ::", dlci);
++ } else {
++
++ if ((short_pkt->h.length.ea) == 0) {
++ long_pkt = (long_frame *) short_pkt;
++ uih_len = GET_LONG_LENGTH(long_pkt->h.length);
++ uih_data_start = long_pkt->h.data;
++ } else {
++ uih_len = short_pkt->h.length.len;
++ uih_data_start = short_pkt->data;
++ }
++ switch (*uih_data_start) {
++ case CMDTAG:
++ pos +=
++ sprintf(&g_tbuf[pos], "I %d A %d ::", dlci,
++ uih_len);
++ break;
++ case DATATAG:
++ default:
++ pos +=
++ sprintf(&g_tbuf[pos], "I %d D %d ::", dlci,
++ uih_len);
++ break;
++ }
++
++ }
++ break;
++ default:
++ pos += sprintf(&g_tbuf[pos], "N!!! %d ::", dlci);
++ break;
++ }
++
++ if (len > (sizeof(g_tbuf) - pos - 1)) {
++ len = (sizeof(g_tbuf) - pos - 1);
++ }
++
++ memcpy(&g_tbuf[pos], data, len);
++ pos += len;
++ g_tbuf[pos] = 0;
++
++#ifdef PRINT_OUTPUT_PRINTK
++ /* 0x00 byte in the string pointed by g_tbuf may truncate the print result */
++ TS0710_LOG("%s\n", g_tbuf);
++#else
++ /*printk("%s\n", g_tbuf) */ ezxlogk("MX", g_tbuf, pos);
++#endif
++}
++#else
++#define TS0710_LOGSTR_FRAME(send, data, len)
++#endif
++
++#ifdef TS0710SIG
++#define my_for_each_task(p) \
++ for ((p) = current; ((p) = (p)->next_task) != current; )
++
++static void TS0710_SIG2APLOGD(void)
++{
++ struct task_struct *p;
++ static __u8 sig = 0;
++
++ if (sig) {
++ return;
++ }
++
++ read_lock(&tasklist_lock);
++ my_for_each_task(p) {
++ if (strncmp(p->comm, "aplogd", 6) == 0) {
++ sig = 1;
++ if (send_sig(SIGUSR2, p, 1) == 0) {
++ TS0710_PRINTK
++ ("MUX: success to send SIGUSR2 to aplogd!\n");
++ } else {
++ TS0710_PRINTK
++ ("MUX: failure to send SIGUSR2 to aplogd!\n");
++ }
++ break;
++ }
++ }
++ read_unlock(&tasklist_lock);
++
++ if (!sig) {
++ TS0710_PRINTK("MUX: not found aplogd!\n");
++ }
++}
++#else
++#define TS0710_SIG2APLOGD()
++#endif
++
++static int basic_write(ts0710_con * ts0710, __u8 * buf, int len)
++{
++ int res;
++
++ UNUSED_PARAM(ts0710);
++
++ buf[0] = TS0710_BASIC_FLAG;
++ buf[len + 1] = TS0710_BASIC_FLAG;
++
++ if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) {
++ TS0710_PRINTK
++ ("MUX basic_write: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n");
++
++#ifndef USB_FOR_MUX
++ TS0710_PRINTK
++ ("MUX basic_write: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n");
++ TS0710_SIG2APLOGD();
++#endif
++
++ return -1;
++ }
++
++ TS0710_LOGSTR_FRAME(1, buf, len + 2);
++ TS0710_DEBUGHEX(buf, len + 2);
++
++ res = COMM_FOR_MUX_DRIVER->write(COMM_FOR_MUX_TTY, buf, len + 2);
++
++ if (res != len + 2) {
++ TS0710_PRINTK("MUX basic_write: Write Error!\n");
++ return -1;
++ }
++
++ return len + 2;
++}
++
++/* Functions for the crc-check and calculation */
++
++#define CRC_VALID 0xcf
++
++static __u32 crc_check(__u8 * data, __u32 length, __u8 check_sum)
++{
++ __u8 fcs = 0xff;
++
++ while (length--) {
++ fcs = crctable[fcs ^ *data++];
++ }
++ fcs = crctable[fcs ^ check_sum];
++ TS0710_DEBUG("fcs : %d\n", fcs);
++ if (fcs == (uint) 0xcf) { /*CRC_VALID) */
++ TS0710_DEBUG("crc_check: CRC check OK\n");
++ return 0;
++ } else {
++ TS0710_PRINTK("MUX crc_check: CRC check failed\n");
++ return 1;
++ }
++}
++
++/* Calculates the checksum according to the ts0710 specification */
++
++static __u8 crc_calc(__u8 * data, __u32 length)
++{
++ __u8 fcs = 0xff;
++
++ while (length--) {
++ fcs = crctable[fcs ^ *data++];
++ }
++
++ return 0xff - fcs;
++}
++
++/* Calulates a reversed CRC table for the FCS check */
++
++static void create_crctable(__u8 table[])
++{
++ int i, j;
++
++ __u8 data;
++ __u8 code_word = (__u8) 0xe0;
++ __u8 sr = (__u8) 0;
++
++ for (j = 0; j < 256; j++) {
++ data = (__u8) j;
++
++ for (i = 0; i < 8; i++) {
++ if ((data & 0x1) ^ (sr & 0x1)) {
++ sr >>= 1;
++ sr ^= code_word;
++ } else {
++ sr >>= 1;
++ }
++
++ data >>= 1;
++ sr &= 0xff;
++ }
++
++ table[j] = sr;
++ sr = 0;
++ }
++}
++
++static void ts0710_reset_dlci(__u8 j)
++{
++ if (j >= TS0710_MAX_CHN)
++ return;
++
++ ts0710_connection.dlci[j].state = DISCONNECTED;
++ ts0710_connection.dlci[j].flow_control = 0;
++ ts0710_connection.dlci[j].mtu = DEF_TS0710_MTU;
++ ts0710_connection.dlci[j].initiated = 0;
++ ts0710_connection.dlci[j].initiator = 0;
++ init_waitqueue_head(&ts0710_connection.dlci[j].open_wait);
++ init_waitqueue_head(&ts0710_connection.dlci[j].close_wait);
++}
++
++static void ts0710_reset_con(void)
++{
++ __u8 j;
++
++ ts0710_connection.initiator = 0;
++ ts0710_connection.mtu = DEF_TS0710_MTU + TS0710_MAX_HDR_SIZE;
++ ts0710_connection.be_testing = 0;
++ ts0710_connection.test_errs = 0;
++ init_waitqueue_head(&ts0710_connection.test_wait);
++
++ for (j = 0; j < TS0710_MAX_CHN; j++) {
++ ts0710_reset_dlci(j);
++ }
++}
++
++static void ts0710_init(void)
++{
++ create_crctable(crctable);
++
++ ts0710_reset_con();
++
++ /* Set the values in the rpn octets */
++/*
++ rpn_val.bit_rate = 7;
++ rpn_val.data_bits = 3;
++ rpn_val.stop_bit = 0;
++ rpn_val.parity = 0;
++ rpn_val.parity_type = 0;
++ rpn_val.res1 = 0;
++ rpn_val.xon_input = 0;
++ rpn_val.xon_output = 0;
++ rpn_val.rtr_input = 0;
++ rpn_val.rtr_output = 0;
++ rpn_val.rtc_input = 0;
++ rpn_val.rtc_output = 0;
++ rpn_val.res2 = 0;
++ rpn_val.xon_u8 = 0x11;
++ rpn_val.xoff_u8 = 0x13;
++ memset(&rpn_val.pm, 0 , 2); *//* Set the mask to zero */
++}
++
++static void ts0710_upon_disconnect(void)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ __u8 j;
++
++ for (j = 0; j < TS0710_MAX_CHN; j++) {
++ ts0710->dlci[j].state = DISCONNECTED;
++ wake_up_interruptible(&ts0710->dlci[j].open_wait);
++ wake_up_interruptible(&ts0710->dlci[j].close_wait);
++ }
++ ts0710->be_testing = 0;
++ wake_up_interruptible(&ts0710->test_wait);
++ ts0710_reset_con();
++}
++
++/* Sending packet functions */
++
++/* Creates a UA packet and puts it at the beginning of the pkt pointer */
++
++static int send_ua(ts0710_con * ts0710, __u8 dlci)
++{
++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE];
++ short_frame *ua;
++
++ TS0710_DEBUG("send_ua: Creating UA packet to DLCI %d\n", dlci);
++
++ ua = (short_frame *) (buf + 1);
++ ua->h.addr.ea = 1;
++ ua->h.addr.cr = ((~(ts0710->initiator)) & 0x1);
++ ua->h.addr.d = (dlci) & 0x1;
++ ua->h.addr.server_chn = (dlci) >> 0x1;
++ ua->h.control = SET_PF(UA);
++ ua->h.length.ea = 1;
++ ua->h.length.len = 0;
++ ua->data[0] = crc_calc((__u8 *) ua, SHORT_CRC_CHECK);
++
++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE);
++}
++
++/* Creates a DM packet and puts it at the beginning of the pkt pointer */
++
++static int send_dm(ts0710_con * ts0710, __u8 dlci)
++{
++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE];
++ short_frame *dm;
++
++ TS0710_DEBUG("send_dm: Creating DM packet to DLCI %d\n", dlci);
++
++ dm = (short_frame *) (buf + 1);
++ dm->h.addr.ea = 1;
++ dm->h.addr.cr = ((~(ts0710->initiator)) & 0x1);
++ dm->h.addr.d = dlci & 0x1;
++ dm->h.addr.server_chn = dlci >> 0x1;
++ dm->h.control = SET_PF(DM);
++ dm->h.length.ea = 1;
++ dm->h.length.len = 0;
++ dm->data[0] = crc_calc((__u8 *) dm, SHORT_CRC_CHECK);
++
++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE);
++}
++
++static int send_sabm(ts0710_con * ts0710, __u8 dlci)
++{
++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE];
++ short_frame *sabm;
++
++ TS0710_DEBUG("send_sabm: Creating SABM packet to DLCI %d\n", dlci);
++
++ sabm = (short_frame *) (buf + 1);
++ sabm->h.addr.ea = 1;
++ sabm->h.addr.cr = ((ts0710->initiator) & 0x1);
++ sabm->h.addr.d = dlci & 0x1;
++ sabm->h.addr.server_chn = dlci >> 0x1;
++ sabm->h.control = SET_PF(SABM);
++ sabm->h.length.ea = 1;
++ sabm->h.length.len = 0;
++ sabm->data[0] = crc_calc((__u8 *) sabm, SHORT_CRC_CHECK);
++
++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE);
++}
++
++static int send_disc(ts0710_con * ts0710, __u8 dlci)
++{
++ __u8 buf[sizeof(short_frame) + FCS_SIZE + FLAG_SIZE];
++ short_frame *disc;
++
++ TS0710_DEBUG("send_disc: Creating DISC packet to DLCI %d\n", dlci);
++
++ disc = (short_frame *) (buf + 1);
++ disc->h.addr.ea = 1;
++ disc->h.addr.cr = ((ts0710->initiator) & 0x1);
++ disc->h.addr.d = dlci & 0x1;
++ disc->h.addr.server_chn = dlci >> 0x1;
++ disc->h.control = SET_PF(DISC);
++ disc->h.length.ea = 1;
++ disc->h.length.len = 0;
++ disc->data[0] = crc_calc((__u8 *) disc, SHORT_CRC_CHECK);
++
++ return basic_write(ts0710, buf, sizeof(short_frame) + FCS_SIZE);
++}
++
++static void queue_uih(mux_send_struct * send_info, __u16 len,
++ ts0710_con * ts0710, __u8 dlci)
++{
++ __u32 size;
++
++ TS0710_DEBUG
++ ("queue_uih: Creating UIH packet with %d bytes data to DLCI %d\n",
++ len, dlci);
++
++ if (len > SHORT_PAYLOAD_SIZE) {
++ long_frame *l_pkt;
++
++ size = sizeof(long_frame) + len + FCS_SIZE;
++ l_pkt = (long_frame *) (send_info->frame - sizeof(long_frame));
++ set_uih_hdr((void *)l_pkt, dlci, len, ts0710->initiator);
++ l_pkt->data[len] = crc_calc((__u8 *) l_pkt, LONG_CRC_CHECK);
++ send_info->frame = ((__u8 *) l_pkt) - 1;
++ } else {
++ short_frame *s_pkt;
++
++ size = sizeof(short_frame) + len + FCS_SIZE;
++ s_pkt =
++ (short_frame *) (send_info->frame - sizeof(short_frame));
++ set_uih_hdr((void *)s_pkt, dlci, len, ts0710->initiator);
++ s_pkt->data[len] = crc_calc((__u8 *) s_pkt, SHORT_CRC_CHECK);
++ send_info->frame = ((__u8 *) s_pkt) - 1;
++ }
++ send_info->length = size;
++}
++
++/* Multiplexer command packets functions */
++
++/* Turns on the ts0710 flow control */
++
++static int ts0710_fcon_msg(ts0710_con * ts0710, __u8 cr)
++{
++ __u8 buf[30];
++ mcc_short_frame *mcc_pkt;
++ short_frame *uih_pkt;
++ __u32 size;
++
++ size = sizeof(short_frame) + sizeof(mcc_short_frame) + FCS_SIZE;
++ uih_pkt = (short_frame *) (buf + 1);
++ set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame),
++ ts0710->initiator);
++ uih_pkt->data[sizeof(mcc_short_frame)] =
++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK);
++ mcc_pkt = (mcc_short_frame *) (uih_pkt->data);
++
++ mcc_pkt->h.type.ea = EA;
++ mcc_pkt->h.type.cr = cr;
++ mcc_pkt->h.type.type = FCON;
++ mcc_pkt->h.length.ea = EA;
++ mcc_pkt->h.length.len = 0;
++
++ return basic_write(ts0710, buf, size);
++}
++
++/* Turns off the ts0710 flow control */
++
++static int ts0710_fcoff_msg(ts0710_con * ts0710, __u8 cr)
++{
++ __u8 buf[30];
++ mcc_short_frame *mcc_pkt;
++ short_frame *uih_pkt;
++ __u32 size;
++
++ size = (sizeof(short_frame) + sizeof(mcc_short_frame) + FCS_SIZE);
++ uih_pkt = (short_frame *) (buf + 1);
++ set_uih_hdr(uih_pkt, CTRL_CHAN, sizeof(mcc_short_frame),
++ ts0710->initiator);
++ uih_pkt->data[sizeof(mcc_short_frame)] =
++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK);
++ mcc_pkt = (mcc_short_frame *) (uih_pkt->data);
++
++ mcc_pkt->h.type.ea = 1;
++ mcc_pkt->h.type.cr = cr;
++ mcc_pkt->h.type.type = FCOFF;
++ mcc_pkt->h.length.ea = 1;
++ mcc_pkt->h.length.len = 0;
++
++ return basic_write(ts0710, buf, size);
++}
++
++/*
++static int ts0710_rpn_msg(ts0710_con *ts0710, __u8 cr, __u8 dlci, __u8 req)
++{
++ char buf[100];
++ rpn_msg* rpn_pkt;
++ __u32 fsize;
++ __u32 psize;
++
++ fsize = sizeof(rpn_msg);
++
++ if (req) {
++ fsize -= sizeof(rpn_values);
++ }
++
++ psize = (fsize - sizeof(short_frame) - FCS_SIZE);
++
++ rpn_pkt = (rpn_msg *) buf;
++
++ set_uih_hdr((short_frame *) rpn_pkt, CTRL_CHAN, psize, ts0710->initiator);
++
++ rpn_pkt->fcs = crc_calc((__u8*) rpn_pkt, SHORT_CRC_CHECK);
++
++ rpn_pkt->mcc_s_head.type.ea = EA;
++ rpn_pkt->mcc_s_head.type.cr = cr;
++ rpn_pkt->mcc_s_head.type.type = RPN;
++ rpn_pkt->mcc_s_head.length.ea = EA;
++
++ rpn_pkt->dlci.ea = EA;
++ rpn_pkt->dlci.cr = 1;
++ rpn_pkt->dlci.d = dlci & 1;
++ rpn_pkt->dlci.server_chn = (dlci >> 1);
++
++ if (req) {
++ rpn_pkt->mcc_s_head.length.len = 1;
++ rpn_pkt->rpn_val.bit_rate = rpn_pkt->fcs;
++ } else {
++ rpn_pkt->mcc_s_head.length.len = 8;
++ memcpy(&(rpn_pkt->rpn_val), &rpn_val, sizeof(rpn_values));
++ }
++ return basic_write(ts0710, buf, fsize);
++}
++*/
++/*
++static int ts0710_rls_msg(ts0710_con *ts0710, __u8 cr, __u8 dlci, __u8 err_code)
++{
++ char buf[100];
++ rls_msg *rls_pkt;
++ __u32 fsize;
++ __u32 psize;
++
++ fsize = sizeof(rls_msg);
++ psize = fsize - sizeof(short_frame) - FCS_SIZE;
++ rls_pkt = (rls_msg *) buf;
++
++ set_uih_hdr((short_frame *) rls_pkt, CTRL_CHAN, psize, ts0710->initiator);
++ rls_pkt->fcs = crc_calc((__u8*) rls_pkt, SHORT_CRC_CHECK);
++
++ rls_pkt->mcc_s_head.type.ea = EA;
++ rls_pkt->mcc_s_head.type.cr = cr;
++ rls_pkt->mcc_s_head.type.type = RLS;
++ rls_pkt->mcc_s_head.length.ea = EA;
++ rls_pkt->mcc_s_head.length.len = 2;
++
++ rls_pkt->dlci.ea = EA;
++ rls_pkt->dlci.cr = 1;
++ rls_pkt->dlci.d = dlci & 1;
++ rls_pkt->dlci.server_chn = dlci >> 1;
++ rls_pkt->error = err_code;
++ rls_pkt->res = 0;
++
++ return basic_write(ts0710, buf, fsize);
++}
++*/
++
++/* Sends an PN-messages and sets the not negotiable parameters to their
++ default values in ts0710 */
++
++static int send_pn_msg(ts0710_con * ts0710, __u8 prior, __u32 frame_size,
++ __u8 credit_flow, __u8 credits, __u8 dlci, __u8 cr)
++{
++ __u8 buf[30];
++ pn_msg *pn_pkt;
++ __u32 size;
++ TS0710_DEBUG
++ ("send_pn_msg: DLCI 0x%02x, prior:0x%02x, frame_size:%d, credit_flow:%x, credits:%d, cr:%x\n",
++ dlci, prior, frame_size, credit_flow, credits, cr);
++
++ size = sizeof(pn_msg);
++ pn_pkt = (pn_msg *) (buf + 1);
++
++ set_uih_hdr((void *)pn_pkt, CTRL_CHAN,
++ size - (sizeof(short_frame) + FCS_SIZE), ts0710->initiator);
++ pn_pkt->fcs = crc_calc((__u8 *) pn_pkt, SHORT_CRC_CHECK);
++
++ pn_pkt->mcc_s_head.type.ea = 1;
++ pn_pkt->mcc_s_head.type.cr = cr;
++ pn_pkt->mcc_s_head.type.type = PN;
++ pn_pkt->mcc_s_head.length.ea = 1;
++ pn_pkt->mcc_s_head.length.len = 8;
++
++ pn_pkt->res1 = 0;
++ pn_pkt->res2 = 0;
++ pn_pkt->dlci = dlci;
++ pn_pkt->frame_type = 0;
++ pn_pkt->credit_flow = credit_flow;
++ pn_pkt->prior = prior;
++ pn_pkt->ack_timer = 0;
++ SET_PN_MSG_FRAME_SIZE(pn_pkt, frame_size);
++ pn_pkt->credits = credits;
++ pn_pkt->max_nbrof_retrans = 0;
++
++ return basic_write(ts0710, buf, size);
++}
++
++/* Send a Not supported command - command, which needs 3 bytes */
++
++static int send_nsc_msg(ts0710_con * ts0710, mcc_type cmd, __u8 cr)
++{
++ __u8 buf[30];
++ nsc_msg *nsc_pkt;
++ __u32 size;
++
++ size = sizeof(nsc_msg);
++ nsc_pkt = (nsc_msg *) (buf + 1);
++
++ set_uih_hdr((void *)nsc_pkt, CTRL_CHAN,
++ sizeof(nsc_msg) - sizeof(short_frame) - FCS_SIZE,
++ ts0710->initiator);
++
++ nsc_pkt->fcs = crc_calc((__u8 *) nsc_pkt, SHORT_CRC_CHECK);
++
++ nsc_pkt->mcc_s_head.type.ea = 1;
++ nsc_pkt->mcc_s_head.type.cr = cr;
++ nsc_pkt->mcc_s_head.type.type = NSC;
++ nsc_pkt->mcc_s_head.length.ea = 1;
++ nsc_pkt->mcc_s_head.length.len = 1;
++
++ nsc_pkt->command_type.ea = 1;
++ nsc_pkt->command_type.cr = cmd.cr;
++ nsc_pkt->command_type.type = cmd.type;
++
++ return basic_write(ts0710, buf, size);
++}
++
++static int ts0710_msc_msg(ts0710_con * ts0710, __u8 value, __u8 cr, __u8 dlci)
++{
++ __u8 buf[30];
++ msc_msg *msc_pkt;
++ __u32 size;
++
++ size = sizeof(msc_msg);
++ msc_pkt = (msc_msg *) (buf + 1);
++
++ set_uih_hdr((void *)msc_pkt, CTRL_CHAN,
++ sizeof(msc_msg) - sizeof(short_frame) - FCS_SIZE,
++ ts0710->initiator);
++
++ msc_pkt->fcs = crc_calc((__u8 *) msc_pkt, SHORT_CRC_CHECK);
++
++ msc_pkt->mcc_s_head.type.ea = 1;
++ msc_pkt->mcc_s_head.type.cr = cr;
++ msc_pkt->mcc_s_head.type.type = MSC;
++ msc_pkt->mcc_s_head.length.ea = 1;
++ msc_pkt->mcc_s_head.length.len = 2;
++
++ msc_pkt->dlci.ea = 1;
++ msc_pkt->dlci.cr = 1;
++ msc_pkt->dlci.d = dlci & 1;
++ msc_pkt->dlci.server_chn = (dlci >> 1) & 0x1f;
++
++ msc_pkt->v24_sigs = value;
++
++ return basic_write(ts0710, buf, size);
++}
++
++static int ts0710_test_msg(ts0710_con * ts0710, __u8 * test_pattern, __u32 len,
++ __u8 cr, __u8 * f_buf /*Frame buf */ )
++{
++ __u32 size;
++
++ if (len > SHORT_PAYLOAD_SIZE) {
++ long_frame *uih_pkt;
++ mcc_long_frame *mcc_pkt;
++
++ size =
++ (sizeof(long_frame) + sizeof(mcc_long_frame) + len +
++ FCS_SIZE);
++ uih_pkt = (long_frame *) (f_buf + 1);
++
++ set_uih_hdr((short_frame *) uih_pkt, CTRL_CHAN, len +
++ sizeof(mcc_long_frame), ts0710->initiator);
++ uih_pkt->data[GET_LONG_LENGTH(uih_pkt->h.length)] =
++ crc_calc((__u8 *) uih_pkt, LONG_CRC_CHECK);
++ mcc_pkt = (mcc_long_frame *) uih_pkt->data;
++
++ mcc_pkt->h.type.ea = EA;
++ /* cr tells whether it is a commmand (1) or a response (0) */
++ mcc_pkt->h.type.cr = cr;
++ mcc_pkt->h.type.type = TEST;
++ SET_LONG_LENGTH(mcc_pkt->h.length, len);
++ memcpy(mcc_pkt->value, test_pattern, len);
++ } else if (len > (SHORT_PAYLOAD_SIZE - sizeof(mcc_short_frame))) {
++ long_frame *uih_pkt;
++ mcc_short_frame *mcc_pkt;
++
++ /* Create long uih packet and short mcc packet */
++ size =
++ (sizeof(long_frame) + sizeof(mcc_short_frame) + len +
++ FCS_SIZE);
++ uih_pkt = (long_frame *) (f_buf + 1);
++
++ set_uih_hdr((short_frame *) uih_pkt, CTRL_CHAN,
++ len + sizeof(mcc_short_frame), ts0710->initiator);
++ uih_pkt->data[GET_LONG_LENGTH(uih_pkt->h.length)] =
++ crc_calc((__u8 *) uih_pkt, LONG_CRC_CHECK);
++ mcc_pkt = (mcc_short_frame *) uih_pkt->data;
++
++ mcc_pkt->h.type.ea = EA;
++ mcc_pkt->h.type.cr = cr;
++ mcc_pkt->h.type.type = TEST;
++ mcc_pkt->h.length.ea = EA;
++ mcc_pkt->h.length.len = len;
++ memcpy(mcc_pkt->value, test_pattern, len);
++ } else {
++ short_frame *uih_pkt;
++ mcc_short_frame *mcc_pkt;
++
++ size =
++ (sizeof(short_frame) + sizeof(mcc_short_frame) + len +
++ FCS_SIZE);
++ uih_pkt = (short_frame *) (f_buf + 1);
++
++ set_uih_hdr((void *)uih_pkt, CTRL_CHAN, len
++ + sizeof(mcc_short_frame), ts0710->initiator);
++ uih_pkt->data[uih_pkt->h.length.len] =
++ crc_calc((__u8 *) uih_pkt, SHORT_CRC_CHECK);
++ mcc_pkt = (mcc_short_frame *) uih_pkt->data;
++
++ mcc_pkt->h.type.ea = EA;
++ mcc_pkt->h.type.cr = cr;
++ mcc_pkt->h.type.type = TEST;
++ mcc_pkt->h.length.ea = EA;
++ mcc_pkt->h.length.len = len;
++ memcpy(mcc_pkt->value, test_pattern, len);
++
++ }
++ return basic_write(ts0710, f_buf, size);
++}
++
++static void set_uih_hdr(short_frame * uih_pkt, __u8 dlci, __u32 len, __u8 cr)
++{
++ uih_pkt->h.addr.ea = 1;
++ uih_pkt->h.addr.cr = cr;
++ uih_pkt->h.addr.d = dlci & 0x1;
++ uih_pkt->h.addr.server_chn = dlci >> 1;
++ uih_pkt->h.control = CLR_PF(UIH);
++
++ if (len > SHORT_PAYLOAD_SIZE) {
++ SET_LONG_LENGTH(((long_frame *) uih_pkt)->h.length, len);
++ } else {
++ uih_pkt->h.length.ea = 1;
++ uih_pkt->h.length.len = len;
++ }
++}
++
++/* Parses a multiplexer control channel packet */
++
++void process_mcc(__u8 * data, __u32 len, ts0710_con * ts0710, int longpkt)
++{
++ __u8 *tbuf = NULL;
++ mcc_short_frame *mcc_short_pkt;
++ int j;
++
++ if (longpkt) {
++ mcc_short_pkt =
++ (mcc_short_frame *) (((long_frame *) data)->data);
++ } else {
++ mcc_short_pkt =
++ (mcc_short_frame *) (((short_frame *) data)->data);
++ }
++
++ switch (mcc_short_pkt->h.type.type) {
++ case TEST:
++ if (mcc_short_pkt->h.type.cr == MCC_RSP) {
++ TS0710_DEBUG("Received test command response\n");
++
++ if (ts0710->be_testing) {
++ if ((mcc_short_pkt->h.length.ea) == 0) {
++ mcc_long_frame *mcc_long_pkt;
++ mcc_long_pkt =
++ (mcc_long_frame *) mcc_short_pkt;
++ if (GET_LONG_LENGTH
++ (mcc_long_pkt->h.length) !=
++ TEST_PATTERN_SIZE) {
++ ts0710->test_errs =
++ TEST_PATTERN_SIZE;
++ TS0710_DEBUG
++ ("Err: received test pattern is %d bytes long, not expected %d\n",
++ GET_LONG_LENGTH
++ (mcc_long_pkt->h.length),
++ TEST_PATTERN_SIZE);
++ } else {
++ ts0710->test_errs = 0;
++ for (j = 0;
++ j < TEST_PATTERN_SIZE;
++ j++) {
++ if (mcc_long_pkt->
++ value[j] !=
++ (j & 0xFF)) {
++ (ts0710->
++ test_errs)++;
++ }
++ }
++ }
++
++ } else {
++
++#if TEST_PATTERN_SIZE < 128
++ if (mcc_short_pkt->h.length.len !=
++ TEST_PATTERN_SIZE) {
++#endif
++
++ ts0710->test_errs =
++ TEST_PATTERN_SIZE;
++ TS0710_DEBUG
++ ("Err: received test pattern is %d bytes long, not expected %d\n",
++ mcc_short_pkt->h.length.
++ len, TEST_PATTERN_SIZE);
++
++#if TEST_PATTERN_SIZE < 128
++ } else {
++ ts0710->test_errs = 0;
++ for (j = 0;
++ j < TEST_PATTERN_SIZE;
++ j++) {
++ if (mcc_short_pkt->
++ value[j] !=
++ (j & 0xFF)) {
++ (ts0710->
++ test_errs)++;
++ }
++ }
++ }
++#endif
++
++ }
++
++ ts0710->be_testing = 0; /* Clear the flag */
++ wake_up_interruptible(&ts0710->test_wait);
++ } else {
++ TS0710_DEBUG
++ ("Err: shouldn't or late to get test cmd response\n");
++ }
++ } else {
++ tbuf = (__u8 *) kmalloc(len + 32, GFP_ATOMIC);
++ if (!tbuf) {
++ break;
++ }
++
++ if ((mcc_short_pkt->h.length.ea) == 0) {
++ mcc_long_frame *mcc_long_pkt;
++ mcc_long_pkt = (mcc_long_frame *) mcc_short_pkt;
++ ts0710_test_msg(ts0710, mcc_long_pkt->value,
++ GET_LONG_LENGTH(mcc_long_pkt->h.
++ length),
++ MCC_RSP, tbuf);
++ } else {
++ ts0710_test_msg(ts0710, mcc_short_pkt->value,
++ mcc_short_pkt->h.length.len,
++ MCC_RSP, tbuf);
++ }
++
++ kfree(tbuf);
++ }
++ break;
++
++ case FCON: /*Flow control on command */
++ TS0710_PRINTK
++ ("MUX Received Flow control(all channels) on command\n");
++ if (mcc_short_pkt->h.type.cr == MCC_CMD) {
++ ts0710->dlci[0].state = CONNECTED;
++ ts0710_fcon_msg(ts0710, MCC_RSP);
++ mux_sched_send();
++ }
++ break;
++
++ case FCOFF: /*Flow control off command */
++ TS0710_PRINTK
++ ("MUX Received Flow control(all channels) off command\n");
++ if (mcc_short_pkt->h.type.cr == MCC_CMD) {
++ for (j = 0; j < TS0710_MAX_CHN; j++) {
++ ts0710->dlci[j].state = FLOW_STOPPED;
++ }
++ ts0710_fcoff_msg(ts0710, MCC_RSP);
++ }
++ break;
++
++ case MSC: /*Modem status command */
++ {
++ __u8 dlci;
++ __u8 v24_sigs;
++
++ dlci = (mcc_short_pkt->value[0]) >> 2;
++ v24_sigs = mcc_short_pkt->value[1];
++
++ if ((ts0710->dlci[dlci].state != CONNECTED)
++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) {
++ send_dm(ts0710, dlci);
++ break;
++ }
++ if (mcc_short_pkt->h.type.cr == MCC_CMD) {
++ TS0710_DEBUG("Received Modem status command\n");
++ if (v24_sigs & 2) {
++ if (ts0710->dlci[dlci].state ==
++ CONNECTED) {
++ TS0710_LOG
++ ("MUX Received Flow off on dlci %d\n",
++ dlci);
++ ts0710->dlci[dlci].state =
++ FLOW_STOPPED;
++ }
++ } else {
++ if (ts0710->dlci[dlci].state ==
++ FLOW_STOPPED) {
++ ts0710->dlci[dlci].state =
++ CONNECTED;
++ TS0710_LOG
++ ("MUX Received Flow on on dlci %d\n",
++ dlci);
++ mux_sched_send();
++ }
++ }
++
++ ts0710_msc_msg(ts0710, v24_sigs, MCC_RSP, dlci);
++/*
++ if (!(ts0710->dlci[dlci].initiated) && !(ts0710->dlci[dlci].initiator)) {
++ ts0710_msc_msg(ts0710, EA | RTR | RTC | DV, MCC_CMD, dlci);
++ ts0710->dlci[dlci].initiated = 1;
++ }
++*/
++ } else {
++ TS0710_DEBUG
++ ("Received Modem status response\n");
++
++ if (v24_sigs & 2) {
++ TS0710_DEBUG("Flow stop accepted\n");
++ }
++ }
++ break;
++ }
++
++ /* case RPN: *//*Remote port negotiation command */
++
++/* {
++ __u8 dlci;
++
++ dlci = (mcc_short_pkt->value[0]) >> 2;
++
++ if (mcc_short_pkt->h.type.cr == MCC_CMD) {
++ if (mcc_short_pkt->h.length.len == 1) {
++ TS0710_DEBUG("Received Remote port negotiation command\n");
++ ts0710_rpn_msg(ts0710, MCC_RSP, dlci, 0);
++ } else {
++*/
++ /* Accept the other sides settings (accept all for now) */
++/* TS0710_DEBUG("Received Remote port negotiation respons\n");
++ memcpy(&rpn_val, &mcc_short_pkt->value[1], 8);
++ ts0710_rpn_msg(ts0710, MCC_RSP, dlci, 0);
++*/
++ /* Zero the parametermask after response */
++/* memset(&rpn_val.pm, 0, 2);
++ }
++ }
++ break;
++ }
++*/
++/*
++ case RLS: *//*Remote line status */
++/* {
++ __u8 dlci;
++ __u8 err_code;
++
++ TS0710_DEBUG("Received Remote line status\n");
++ if (mcc_short_pkt->h.type.cr == MCC_CMD) {
++ dlci = mcc_short_pkt->value[0] >> 2;
++ err_code = mcc_short_pkt->value[1];
++
++ ts0710_rls_msg(ts0710, MCC_RSP, dlci, err_code);
++ }
++ break;
++ }
++*/
++ case PN: /*DLC parameter negotiation */
++ {
++ __u8 dlci;
++ __u16 frame_size;
++ pn_msg *pn_pkt;
++
++ pn_pkt = (pn_msg *) data;
++ dlci = pn_pkt->dlci;
++ frame_size = GET_PN_MSG_FRAME_SIZE(pn_pkt);
++ TS0710_DEBUG
++ ("Received DLC parameter negotiation, PN\n");
++ if (pn_pkt->mcc_s_head.type.cr == MCC_CMD) {
++ TS0710_DEBUG("received PN command with:\n");
++ TS0710_DEBUG("Frame size:%d\n", frame_size);
++
++ frame_size =
++ min(frame_size, ts0710->dlci[dlci].mtu);
++ send_pn_msg(ts0710, pn_pkt->prior, frame_size,
++ 0, 0, dlci, MCC_RSP);
++ ts0710->dlci[dlci].mtu = frame_size;
++ TS0710_DEBUG("process_mcc : mtu set to %d\n",
++ ts0710->dlci[dlci].mtu);
++ } else {
++ TS0710_DEBUG("received PN response with:\n");
++ TS0710_DEBUG("Frame size:%d\n", frame_size);
++
++ frame_size =
++ min(frame_size, ts0710->dlci[dlci].mtu);
++ ts0710->dlci[dlci].mtu = frame_size;
++
++ TS0710_DEBUG
++ ("process_mcc : mtu set on dlci:%d to %d\n",
++ dlci, ts0710->dlci[dlci].mtu);
++
++ if (ts0710->dlci[dlci].state == NEGOTIATING) {
++ ts0710->dlci[dlci].state = CONNECTING;
++ wake_up_interruptible(&ts0710->
++ dlci[dlci].
++ open_wait);
++ }
++ }
++ break;
++ }
++
++ case NSC: /*Non supported command resonse */
++ TS0710_LOG("MUX Received Non supported command response\n");
++ break;
++
++ default: /*Non supported command received */
++ TS0710_LOG("MUX Received a non supported command\n");
++ send_nsc_msg(ts0710, mcc_short_pkt->h.type, MCC_RSP);
++ break;
++ }
++}
++
++static mux_recv_packet *get_mux_recv_packet(__u32 size)
++{
++ mux_recv_packet *recv_packet;
++
++ TS0710_DEBUG("Enter into get_mux_recv_packet");
++
++ recv_packet =
++ (mux_recv_packet *) kmalloc(sizeof(mux_recv_packet), GFP_ATOMIC);
++ if (!recv_packet) {
++ return 0;
++ }
++
++ recv_packet->data = (__u8 *) kmalloc(size, GFP_ATOMIC);
++ if (!(recv_packet->data)) {
++ kfree(recv_packet);
++ return 0;
++ }
++ recv_packet->length = 0;
++ recv_packet->next = 0;
++ return recv_packet;
++}
++
++static void free_mux_recv_packet(mux_recv_packet * recv_packet)
++{
++ TS0710_DEBUG("Enter into free_mux_recv_packet");
++
++ if (!recv_packet) {
++ return;
++ }
++
++ if (recv_packet->data) {
++ kfree(recv_packet->data);
++ }
++ kfree(recv_packet);
++}
++
++static void free_mux_recv_struct(mux_recv_struct * recv_info)
++{
++ mux_recv_packet *recv_packet1, *recv_packet2;
++
++ if (!recv_info) {
++ return;
++ }
++
++ recv_packet1 = recv_info->mux_packet;
++ while (recv_packet1) {
++ recv_packet2 = recv_packet1->next;
++ free_mux_recv_packet(recv_packet1);
++ recv_packet1 = recv_packet2;
++ }
++
++ kfree(recv_info);
++}
++
++static inline void add_post_recv_queue(mux_recv_struct ** head,
++ mux_recv_struct * new_item)
++{
++ new_item->next = *head;
++ *head = new_item;
++}
++
++static void ts0710_flow_on(__u8 dlci, ts0710_con * ts0710)
++{
++ int i;
++ __u8 cmdtty;
++ __u8 datatty;
++ struct tty_struct *tty;
++ mux_recv_struct *recv_info;
++
++ if ((ts0710->dlci[0].state != CONNECTED)
++ && (ts0710->dlci[0].state != FLOW_STOPPED)) {
++ return;
++ } else if ((ts0710->dlci[dlci].state != CONNECTED)
++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) {
++ return;
++ }
++
++ if (!(ts0710->dlci[dlci].flow_control)) {
++ return;
++ }
++
++ cmdtty = dlci2tty[dlci].cmdtty;
++ datatty = dlci2tty[dlci].datatty;
++
++ if (cmdtty != datatty) {
++ /* Check AT cmd tty */
++ tty = mux_table[cmdtty];
++ if (mux_tty[cmdtty] && tty) {
++ if (test_bit(TTY_THROTTLED, &tty->flags)) {
++ return;
++ }
++ }
++ recv_info = mux_recv_info[cmdtty];
++ if (mux_recv_info_flags[cmdtty] && recv_info) {
++ if (recv_info->total) {
++ return;
++ }
++ }
++
++ /* Check data tty */
++ tty = mux_table[datatty];
++ if (mux_tty[datatty] && tty) {
++ if (test_bit(TTY_THROTTLED, &tty->flags)) {
++ return;
++ }
++ }
++ recv_info = mux_recv_info[datatty];
++ if (mux_recv_info_flags[datatty] && recv_info) {
++ if (recv_info->total) {
++ return;
++ }
++ }
++ }
++
++ for (i = 0; i < 3; i++) {
++ if (ts0710_msc_msg(ts0710, EA | RTC | RTR | DV, MCC_CMD, dlci) <
++ 0) {
++ continue;
++ } else {
++ TS0710_LOG("MUX send Flow on on dlci %d\n", dlci);
++ ts0710->dlci[dlci].flow_control = 0;
++ break;
++ }
++ }
++}
++
++static void ts0710_flow_off(struct tty_struct *tty, __u8 dlci,
++ ts0710_con * ts0710)
++{
++ int i;
++
++ if (test_and_set_bit(TTY_THROTTLED, &tty->flags)) {
++ return;
++ }
++
++ if ((ts0710->dlci[0].state != CONNECTED)
++ && (ts0710->dlci[0].state != FLOW_STOPPED)) {
++ return;
++ } else if ((ts0710->dlci[dlci].state != CONNECTED)
++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) {
++ return;
++ }
++
++ if (ts0710->dlci[dlci].flow_control) {
++ return;
++ }
++
++ for (i = 0; i < 3; i++) {
++ if (ts0710_msc_msg
++ (ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, dlci) < 0) {
++ continue;
++ } else {
++ TS0710_LOG("MUX send Flow off on dlci %d\n", dlci);
++ ts0710->dlci[dlci].flow_control = 1;
++ break;
++ }
++ }
++}
++
++int ts0710_recv_data(ts0710_con * ts0710, char *data, int len)
++{
++ short_frame *short_pkt;
++ long_frame *long_pkt;
++ __u8 *uih_data_start;
++ __u32 uih_len;
++ __u8 dlci;
++ __u8 be_connecting;
++#ifdef TS0710DEBUG
++ unsigned long t;
++#endif
++
++ short_pkt = (short_frame *) data;
++
++ dlci = short_pkt->h.addr.server_chn << 1 | short_pkt->h.addr.d;
++ switch (CLR_PF(short_pkt->h.control)) {
++ case SABM:
++ TS0710_DEBUG("SABM-packet received\n");
++
++/*For BP UART problem
++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) )
++ break;
++*/
++
++ if (!dlci) {
++ TS0710_DEBUG("server channel == 0\n");
++ ts0710->dlci[0].state = CONNECTED;
++
++ TS0710_DEBUG("sending back UA - control channel\n");
++ send_ua(ts0710, dlci);
++ wake_up_interruptible(&ts0710->dlci[0].open_wait);
++
++ } else if (valid_dlci(dlci)) {
++
++ TS0710_DEBUG("Incomming connect on channel %d\n", dlci);
++
++ TS0710_DEBUG("sending UA, dlci %d\n", dlci);
++ send_ua(ts0710, dlci);
++
++ ts0710->dlci[dlci].state = CONNECTED;
++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait);
++
++ } else {
++ TS0710_DEBUG("invalid dlci %d, sending DM\n", dlci);
++ send_dm(ts0710, dlci);
++ }
++
++ break;
++
++ case UA:
++ TS0710_DEBUG("UA packet received\n");
++
++/*For BP UART problem
++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) )
++ break;
++*/
++
++ if (!dlci) {
++ TS0710_DEBUG("server channel == 0\n");
++
++ if (ts0710->dlci[0].state == CONNECTING) {
++ ts0710->dlci[0].state = CONNECTED;
++ wake_up_interruptible(&ts0710->dlci[0].
++ open_wait);
++ } else if (ts0710->dlci[0].state == DISCONNECTING) {
++ ts0710_upon_disconnect();
++ } else {
++ TS0710_DEBUG
++ (" Something wrong receiving UA packet\n");
++ }
++ } else if (valid_dlci(dlci)) {
++ TS0710_DEBUG("Incomming UA on channel %d\n", dlci);
++
++ if (ts0710->dlci[dlci].state == CONNECTING) {
++ ts0710->dlci[dlci].state = CONNECTED;
++ wake_up_interruptible(&ts0710->dlci[dlci].
++ open_wait);
++ } else if (ts0710->dlci[dlci].state == DISCONNECTING) {
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ wake_up_interruptible(&ts0710->dlci[dlci].
++ open_wait);
++ wake_up_interruptible(&ts0710->dlci[dlci].
++ close_wait);
++ ts0710_reset_dlci(dlci);
++ } else {
++ TS0710_DEBUG
++ (" Something wrong receiving UA packet\n");
++ }
++ } else {
++ TS0710_DEBUG("invalid dlci %d\n", dlci);
++ }
++
++ break;
++
++ case DM:
++ TS0710_DEBUG("DM packet received\n");
++
++/*For BP UART problem
++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) )
++ break;
++*/
++
++ if (!dlci) {
++ TS0710_DEBUG("server channel == 0\n");
++
++ if (ts0710->dlci[0].state == CONNECTING) {
++ be_connecting = 1;
++ } else {
++ be_connecting = 0;
++ }
++ ts0710_upon_disconnect();
++ if (be_connecting) {
++ ts0710->dlci[0].state = REJECTED;
++ }
++ } else if (valid_dlci(dlci)) {
++ TS0710_DEBUG("Incomming DM on channel %d\n", dlci);
++
++ if (ts0710->dlci[dlci].state == CONNECTING) {
++ ts0710->dlci[dlci].state = REJECTED;
++ } else {
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ }
++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait);
++ wake_up_interruptible(&ts0710->dlci[dlci].close_wait);
++ ts0710_reset_dlci(dlci);
++ } else {
++ TS0710_DEBUG("invalid dlci %d\n", dlci);
++ }
++
++ break;
++
++ case DISC:
++ TS0710_DEBUG("DISC packet received\n");
++
++/*For BP UART problem
++ if( crc_check((__u8*) short_pkt, SHORT_CRC_CHECK, short_pkt->data[0]) )
++ break;
++*/
++
++ if (!dlci) {
++ TS0710_DEBUG("server channel == 0\n");
++
++ send_ua(ts0710, dlci);
++ TS0710_DEBUG("DISC, sending back UA\n");
++
++ ts0710_upon_disconnect();
++ } else if (valid_dlci(dlci)) {
++ TS0710_DEBUG("Incomming DISC on channel %d\n", dlci);
++
++ send_ua(ts0710, dlci);
++ TS0710_DEBUG("DISC, sending back UA\n");
++
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait);
++ wake_up_interruptible(&ts0710->dlci[dlci].close_wait);
++ ts0710_reset_dlci(dlci);
++ } else {
++ TS0710_DEBUG("invalid dlci %d\n", dlci);
++ }
++
++ break;
++
++ case UIH:
++ TS0710_DEBUG("UIH packet received\n");
++
++ if ((dlci >= TS0710_MAX_CHN)) {
++ TS0710_DEBUG("invalid dlci %d\n", dlci);
++ send_dm(ts0710, dlci);
++ break;
++ }
++
++ if (GET_PF(short_pkt->h.control)) {
++ TS0710_LOG
++ ("MUX Error %s: UIH packet with P/F set, discard it!\n",
++ __FUNCTION__);
++ break;
++ }
++
++ if ((ts0710->dlci[dlci].state != CONNECTED)
++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) {
++ TS0710_LOG
++ ("MUX Error %s: DLCI %d not connected, discard it!\n",
++ __FUNCTION__, dlci);
++ send_dm(ts0710, dlci);
++ break;
++ }
++
++ if ((short_pkt->h.length.ea) == 0) {
++ TS0710_DEBUG("Long UIH packet received\n");
++ long_pkt = (long_frame *) data;
++ uih_len = GET_LONG_LENGTH(long_pkt->h.length);
++ uih_data_start = long_pkt->h.data;
++ TS0710_DEBUG("long packet length %d\n", uih_len);
++
++/*For BP UART problem
++ if (crc_check(data, LONG_CRC_CHECK, *(uih_data_start + uih_len)))
++ break;
++*/
++ } else {
++ TS0710_DEBUG("Short UIH pkt received\n");
++ uih_len = short_pkt->h.length.len;
++ uih_data_start = short_pkt->data;
++
++/*For BP UART problem
++ if (crc_check(data, SHORT_CRC_CHECK, *(uih_data_start + uih_len)))
++ break;
++*/
++ }
++
++ if (dlci == 0) {
++ TS0710_DEBUG("UIH on serv_channel 0\n");
++ process_mcc(data, len, ts0710,
++ !(short_pkt->h.length.ea));
++ } else if (valid_dlci(dlci)) {
++ /* do tty dispatch */
++ __u8 tag;
++ __u8 tty_idx;
++ struct tty_struct *tty;
++ __u8 queue_data;
++ __u8 post_recv;
++ __u8 flow_control;
++ mux_recv_struct *recv_info;
++ int recv_room;
++ mux_recv_packet *recv_packet, *recv_packet2;
++
++ TS0710_DEBUG("UIH on channel %d\n", dlci);
++
++ if (uih_len > ts0710->dlci[dlci].mtu) {
++ TS0710_PRINTK
++ ("MUX Error: DLCI:%d, uih_len:%d is bigger than mtu:%d, discard data!\n",
++ dlci, uih_len, ts0710->dlci[dlci].mtu);
++ break;
++ }
++
++ tag = *uih_data_start;
++ uih_data_start++;
++ uih_len--;
++
++ if (!uih_len) {
++ break;
++ }
++
++ switch (tag) {
++ case CMDTAG:
++ tty_idx = dlci2tty[dlci].cmdtty;
++ TS0710_DEBUG("CMDTAG on DLCI:%d, /dev/mux%d\n",
++ dlci, tty_idx);
++ TS0710_DEBUGSTR(uih_data_start, uih_len);
++ if (!(iscmdtty[tty_idx])) {
++ TS0710_PRINTK
++ ("MUX Error: %s: Wrong CMDTAG on DLCI:%d, /dev/mux%d\n",
++ __FUNCTION__, dlci, tty_idx);
++ }
++ break;
++ case DATATAG:
++ default:
++ tty_idx = dlci2tty[dlci].datatty;
++ TS0710_DEBUG
++ ("NON-CMDTAG on DLCI:%d, /dev/mux%d\n",
++ dlci, tty_idx);
++ if (iscmdtty[tty_idx]) {
++ TS0710_PRINTK
++ ("MUX Error: %s: Wrong NON-CMDTAG on DLCI:%d, /dev/mux%d\n",
++ __FUNCTION__, dlci, tty_idx);
++ }
++ break;
++ }
++ tty = mux_table[tty_idx];
++ if ((!mux_tty[tty_idx]) || (!tty)) {
++ TS0710_PRINTK
++ ("MUX: No application waiting for, discard it! /dev/mux%d\n",
++ tty_idx);
++ } else { /* Begin processing received data */
++ if ((!mux_recv_info_flags[tty_idx])
++ || (!mux_recv_info[tty_idx])) {
++ TS0710_PRINTK
++ ("MUX Error: No mux_recv_info, discard it! /dev/mux%d\n",
++ tty_idx);
++ break;
++ }
++
++ recv_info = mux_recv_info[tty_idx];
++ if (recv_info->total > 8192) {
++ TS0710_PRINTK
++ ("MUX : discard data for tty_idx:%d, recv_info->total > 8192 \n",
++ tty_idx);
++ break;
++ }
++
++ queue_data = 0;
++ post_recv = 0;
++ flow_control = 0;
++ recv_room = 65535;
++ if (tty->receive_room)
++ recv_room = tty->receive_room;
++
++ if (test_bit(TTY_THROTTLED, &tty->flags)) {
++ queue_data = 1;
++ } else {
++ if (test_bit
++ (TTY_DONT_FLIP, &tty->flags)) {
++ queue_data = 1;
++ post_recv = 1;
++ } else if (recv_info->total) {
++ queue_data = 1;
++ post_recv = 1;
++ } else if (recv_room < uih_len) {
++ queue_data = 1;
++ flow_control = 1;
++ }
++
++ if ((recv_room -
++ (uih_len + recv_info->total)) <
++ ts0710->dlci[dlci].mtu) {
++ flow_control = 1;
++ }
++ }
++
++ if (!queue_data) {
++ /* Put received data into read buffer of tty */
++ TS0710_DEBUG
++ ("Put received data into read buffer of /dev/mux%d",
++ tty_idx);
++
++#ifdef TS0710DEBUG
++ t = jiffies;
++#endif
++
++ (tty->ldisc.receive_buf) (tty,
++ uih_data_start,
++ NULL,
++ uih_len);
++
++#ifdef TS0710DEBUG
++ TS0710_DEBUG
++ ("tty->ldisc.receive_buf take ticks: %lu",
++ (jiffies - t));
++#endif
++
++ } else { /* Queue data */
++
++ TS0710_DEBUG
++ ("Put received data into recv queue of /dev/mux%d",
++ tty_idx);
++ if (recv_info->total) {
++ /* recv_info is already linked into mux_recv_queue */
++
++ recv_packet =
++ get_mux_recv_packet
++ (uih_len);
++ if (!recv_packet) {
++ TS0710_PRINTK
++ ("MUX %s: no memory\n",
++ __FUNCTION__);
++ break;
++ }
++
++ memcpy(recv_packet->data,
++ uih_data_start, uih_len);
++ recv_packet->length = uih_len;
++ recv_info->total += uih_len;
++ recv_packet->next = NULL;
++
++ if (!(recv_info->mux_packet)) {
++ recv_info->mux_packet =
++ recv_packet;
++ } else {
++ recv_packet2 =
++ recv_info->
++ mux_packet;
++ while (recv_packet2->
++ next) {
++ recv_packet2 =
++ recv_packet2->
++ next;
++ }
++ recv_packet2->next =
++ recv_packet;
++ } /* End if( !(recv_info->mux_packet) ) */
++ } else { /* recv_info->total == 0 */
++ if (uih_len >
++ TS0710MUX_RECV_BUF_SIZE) {
++ TS0710_PRINTK
++ ("MUX Error: tty_idx:%d, uih_len == %d is too big\n",
++ tty_idx, uih_len);
++ uih_len =
++ TS0710MUX_RECV_BUF_SIZE;
++ }
++ memcpy(recv_info->data,
++ uih_data_start, uih_len);
++ recv_info->length = uih_len;
++ recv_info->total = uih_len;
++
++ add_post_recv_queue
++ (&mux_recv_queue,
++ recv_info);
++ } /* End recv_info->total == 0 */
++ } /* End Queue data */
++
++ if (flow_control) {
++ /* Do something for flow control */
++ ts0710_flow_off(tty, dlci, ts0710);
++ }
++
++ if (tty_idx ==
++ dlci2tty[TS0710MUX_GPRS1_DLCI].datatty) {
++ if (add_count
++ (TS0710MUX_GPRS1_RECV_COUNT_IDX,
++ uih_len) < 0) {
++ post_recv_count_flag = 1;
++ post_recv = 1;
++ mux_data_count2
++ [TS0710MUX_GPRS1_RECV_COUNT_IDX]
++ += uih_len;
++ }
++ } else if (tty_idx ==
++ dlci2tty[TS0710MUX_GPRS2_DLCI].
++ datatty) {
++ if (add_count
++ (TS0710MUX_GPRS2_RECV_COUNT_IDX,
++ uih_len) < 0) {
++ post_recv_count_flag = 1;
++ post_recv = 1;
++ mux_data_count2
++ [TS0710MUX_GPRS2_RECV_COUNT_IDX]
++ += uih_len;
++ }
++ }
++
++ if (post_recv)
++ schedule_work(&post_recv_tqueue);
++ } /* End processing received data */
++ } else {
++ TS0710_DEBUG("invalid dlci %d\n", dlci);
++ }
++
++ break;
++
++ default:
++ TS0710_DEBUG("illegal packet\n");
++ break;
++ }
++ return 0;
++}
++
++/*
++int ts0710_send_data(ts0710_con *ts0710, __u8 dlci, __u8 *data, __u32 count)
++{
++ __u32 c, total = 0;
++ __u8 tag, first;
++
++ if( ts0710->dlci[0].state == FLOW_STOPPED ){
++ TS0710_DEBUG("Flow stopped on all channels, returning zero\n");
++*/
++/*
++ return -EFLOWSTOPPED;
++ } else if( ts0710->dlci[dlci].state == FLOW_STOPPED ){
++ TS0710_DEBUG("Flow stopped, returning zero\n");
++*/
++/*
++ return -EFLOWSTOPPED;
++ } else if( ts0710->dlci[dlci].state == CONNECTED ){
++
++ TS0710_DEBUG("trying to send %d bytes\n", count);
++ tag = *data;
++ first = 1;
++*/
++ /* The first byte is always a Cmd/Data tag */
++/*
++ while( count > 1 ){
++
++ c = min(count, ts0710->dlci[dlci].mtu);
++ if( queue_uih(data, c, ts0710, dlci) <= 0 ) {
++ break;
++ }
++
++ total += (c - 1);
++ data += (c - 1);
++ *data = tag;
++ count -= (c - 1);
++
++ if( first ) {
++ first = 0;
++ total++;
++ }
++ }
++ TS0710_DEBUG("sent %d bytes\n", total);
++ return total;
++ } else {
++ TS0710_DEBUG("DLCI %d not connected\n", dlci);
++ return -EDISCONNECTED;
++ }
++}
++*/
++
++/* Close ts0710 channel */
++static void ts0710_close_channel(__u8 dlci)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int try;
++ unsigned long t;
++
++ TS0710_DEBUG("ts0710_disc_command on channel %d\n", dlci);
++
++ if ((ts0710->dlci[dlci].state == DISCONNECTED)
++ || (ts0710->dlci[dlci].state == REJECTED)) {
++ return;
++ } else if (ts0710->dlci[dlci].state == DISCONNECTING) {
++ /* Reentry */
++ return;
++ } else {
++ ts0710->dlci[dlci].state = DISCONNECTING;
++ try = 3;
++ while (try--) {
++ t = jiffies;
++ send_disc(ts0710, dlci);
++ interruptible_sleep_on_timeout(&ts0710->dlci[dlci].
++ close_wait,
++ TS0710MUX_TIME_OUT);
++ if (ts0710->dlci[dlci].state == DISCONNECTED) {
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI %d Send DISC got signal!\n",
++ dlci);
++ break;
++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI %d Send DISC timeout!\n", dlci);
++ continue;
++ }
++ }
++
++ if (ts0710->dlci[dlci].state != DISCONNECTED) {
++ if (dlci == 0) { /* Control Channel */
++ ts0710_upon_disconnect();
++ } else { /* Other Channel */
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ wake_up_interruptible(&ts0710->dlci[dlci].
++ close_wait);
++ ts0710_reset_dlci(dlci);
++ }
++ }
++ }
++}
++
++int ts0710_open_channel(__u8 dlci)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int try;
++ int retval;
++ unsigned long t;
++
++ retval = -ENODEV;
++ if (dlci == 0) { // control channel
++ if ((ts0710->dlci[0].state == CONNECTED)
++ || (ts0710->dlci[0].state == FLOW_STOPPED)) {
++ return 0;
++ } else if (ts0710->dlci[0].state == CONNECTING) {
++ /* Reentry */
++ TS0710_PRINTK
++ ("MUX DLCI: 0, reentry to open DLCI 0, pid: %d, %s !\n",
++ current->pid, current->comm);
++ try = 11;
++ while (try--) {
++ t = jiffies;
++ interruptible_sleep_on_timeout(&ts0710->dlci[0].
++ open_wait,
++ TS0710MUX_TIME_OUT);
++ if ((ts0710->dlci[0].state == CONNECTED)
++ || (ts0710->dlci[0].state ==
++ FLOW_STOPPED)) {
++ retval = 0;
++ break;
++ } else if (ts0710->dlci[0].state == REJECTED) {
++ retval = -EREJECTED;
++ break;
++ } else if (ts0710->dlci[0].state ==
++ DISCONNECTED) {
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Wait for connecting got signal!\n",
++ dlci);
++ retval = -EAGAIN;
++ break;
++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Wait for connecting timeout!\n",
++ dlci);
++ continue;
++ } else if (ts0710->dlci[0].state == CONNECTING) {
++ continue;
++ }
++ }
++
++ if (ts0710->dlci[0].state == CONNECTING) {
++ ts0710->dlci[0].state = DISCONNECTED;
++ }
++ } else if ((ts0710->dlci[0].state != DISCONNECTED)
++ && (ts0710->dlci[0].state != REJECTED)) {
++ TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci);
++ return retval;
++ } else {
++ ts0710->initiator = 1;
++ ts0710->dlci[0].state = CONNECTING;
++ ts0710->dlci[0].initiator = 1;
++ try = 10;
++ while (try--) {
++ t = jiffies;
++ send_sabm(ts0710, 0);
++ interruptible_sleep_on_timeout(&ts0710->dlci[0].
++ open_wait,
++ TS0710MUX_TIME_OUT);
++ if ((ts0710->dlci[0].state == CONNECTED)
++ || (ts0710->dlci[0].state ==
++ FLOW_STOPPED)) {
++ retval = 0;
++ break;
++ } else if (ts0710->dlci[0].state == REJECTED) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM got rejected!\n",
++ dlci);
++ retval = -EREJECTED;
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM got signal!\n",
++ dlci);
++ retval = -EAGAIN;
++ break;
++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM timeout!\n",
++ dlci);
++ continue;
++ }
++ }
++
++ if (ts0710->dlci[0].state == CONNECTING) {
++ ts0710->dlci[0].state = DISCONNECTED;
++ }
++ wake_up_interruptible(&ts0710->dlci[0].open_wait);
++ }
++ } else { // other channel
++ if ((ts0710->dlci[0].state != CONNECTED)
++ && (ts0710->dlci[0].state != FLOW_STOPPED)) {
++ return retval;
++ } else if ((ts0710->dlci[dlci].state == CONNECTED)
++ || (ts0710->dlci[dlci].state == FLOW_STOPPED)) {
++ return 0;
++ } else if ((ts0710->dlci[dlci].state == NEGOTIATING)
++ || (ts0710->dlci[dlci].state == CONNECTING)) {
++ /* Reentry */
++ try = 8;
++ while (try--) {
++ t = jiffies;
++ interruptible_sleep_on_timeout(&ts0710->
++ dlci[dlci].
++ open_wait,
++ TS0710MUX_TIME_OUT);
++ if ((ts0710->dlci[dlci].state == CONNECTED)
++ || (ts0710->dlci[dlci].state ==
++ FLOW_STOPPED)) {
++ retval = 0;
++ break;
++ } else if (ts0710->dlci[dlci].state == REJECTED) {
++ retval = -EREJECTED;
++ break;
++ } else if (ts0710->dlci[dlci].state ==
++ DISCONNECTED) {
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Wait for connecting got signal!\n",
++ dlci);
++ retval = -EAGAIN;
++ break;
++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Wait for connecting timeout!\n",
++ dlci);
++ continue;
++ } else
++ if ((ts0710->dlci[dlci].state ==
++ NEGOTIATING)
++ || (ts0710->dlci[dlci].state ==
++ CONNECTING)) {
++ continue;
++ }
++ }
++
++ if ((ts0710->dlci[dlci].state == NEGOTIATING)
++ || (ts0710->dlci[dlci].state == CONNECTING)) {
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ }
++ } else if ((ts0710->dlci[dlci].state != DISCONNECTED)
++ && (ts0710->dlci[dlci].state != REJECTED)) {
++ TS0710_PRINTK("MUX DLCI:%d state is invalid!\n", dlci);
++ return retval;
++ } else {
++ ts0710->dlci[dlci].state = NEGOTIATING;
++ ts0710->dlci[dlci].initiator = 1;
++ try = 3;
++ while (try--) {
++ t = jiffies;
++ send_pn_msg(ts0710, 7, ts0710->dlci[dlci].mtu,
++ 0, 0, dlci, 1);
++ interruptible_sleep_on_timeout(&ts0710->
++ dlci[dlci].
++ open_wait,
++ TS0710MUX_TIME_OUT);
++ if (ts0710->dlci[dlci].state == CONNECTING) {
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send pn_msg got signal!\n",
++ dlci);
++ retval = -EAGAIN;
++ break;
++ } else if ((jiffies - t) >= TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send pn_msg timeout!\n",
++ dlci);
++ continue;
++ }
++ }
++
++ if (ts0710->dlci[dlci].state == CONNECTING) {
++ try = 3;
++ while (try--) {
++ t = jiffies;
++ send_sabm(ts0710, dlci);
++ interruptible_sleep_on_timeout(&ts0710->
++ dlci
++ [dlci].
++ open_wait,
++ TS0710MUX_TIME_OUT);
++ if ((ts0710->dlci[dlci].state ==
++ CONNECTED)
++ || (ts0710->dlci[dlci].state ==
++ FLOW_STOPPED)) {
++ retval = 0;
++ break;
++ } else if (ts0710->dlci[dlci].state ==
++ REJECTED) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM got rejected!\n",
++ dlci);
++ retval = -EREJECTED;
++ break;
++ } else if (signal_pending(current)) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM got signal!\n",
++ dlci);
++ retval = -EAGAIN;
++ break;
++ } else if ((jiffies - t) >=
++ TS0710MUX_TIME_OUT) {
++ TS0710_PRINTK
++ ("MUX DLCI:%d Send SABM timeout!\n",
++ dlci);
++ continue;
++ }
++ }
++ }
++
++ if ((ts0710->dlci[dlci].state == NEGOTIATING)
++ || (ts0710->dlci[dlci].state == CONNECTING)) {
++ ts0710->dlci[dlci].state = DISCONNECTED;
++ }
++ wake_up_interruptible(&ts0710->dlci[dlci].open_wait);
++ }
++ }
++ return retval;
++}
++
++static int ts0710_exec_test_cmd(void)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ __u8 *f_buf; /* Frame buffer */
++ __u8 *d_buf; /* Data buffer */
++ int retval = -EFAULT;
++ int j;
++ unsigned long t;
++
++ if (ts0710->be_testing) {
++ /* Reentry */
++ t = jiffies;
++ interruptible_sleep_on_timeout(&ts0710->test_wait,
++ 3 * TS0710MUX_TIME_OUT);
++ if (ts0710->be_testing == 0) {
++ if (ts0710->test_errs == 0) {
++ retval = 0;
++ } else {
++ retval = -EFAULT;
++ }
++ } else if (signal_pending(current)) {
++ TS0710_DEBUG
++ ("Wait for Test_cmd response got signal!\n");
++ retval = -EAGAIN;
++ } else if ((jiffies - t) >= 3 * TS0710MUX_TIME_OUT) {
++ TS0710_DEBUG("Wait for Test_cmd response timeout!\n");
++ retval = -EFAULT;
++ }
++ } else {
++ ts0710->be_testing = 1; /* Set the flag */
++
++ f_buf = (__u8 *) kmalloc(TEST_PATTERN_SIZE + 32, GFP_KERNEL);
++ d_buf = (__u8 *) kmalloc(TEST_PATTERN_SIZE + 32, GFP_KERNEL);
++ if ((!f_buf) || (!d_buf)) {
++ if (f_buf) {
++ kfree(f_buf);
++ }
++ if (d_buf) {
++ kfree(d_buf);
++ }
++
++ ts0710->be_testing = 0; /* Clear the flag */
++ ts0710->test_errs = TEST_PATTERN_SIZE;
++ wake_up_interruptible(&ts0710->test_wait);
++ return -ENOMEM;
++ }
++
++ for (j = 0; j < TEST_PATTERN_SIZE; j++) {
++ d_buf[j] = j & 0xFF;
++ }
++
++ t = jiffies;
++ ts0710_test_msg(ts0710, d_buf, TEST_PATTERN_SIZE, MCC_CMD,
++ f_buf);
++ interruptible_sleep_on_timeout(&ts0710->test_wait,
++ 2 * TS0710MUX_TIME_OUT);
++ if (ts0710->be_testing == 0) {
++ if (ts0710->test_errs == 0) {
++ retval = 0;
++ } else {
++ retval = -EFAULT;
++ }
++ } else if (signal_pending(current)) {
++ TS0710_DEBUG("Send Test_cmd got signal!\n");
++ retval = -EAGAIN;
++ } else if ((jiffies - t) >= 2 * TS0710MUX_TIME_OUT) {
++ TS0710_DEBUG("Send Test_cmd timeout!\n");
++ ts0710->test_errs = TEST_PATTERN_SIZE;
++ retval = -EFAULT;
++ }
++
++ ts0710->be_testing = 0; /* Clear the flag */
++ wake_up_interruptible(&ts0710->test_wait);
++
++ /* Release buffer */
++ if (f_buf) {
++ kfree(f_buf);
++ }
++ if (d_buf) {
++ kfree(d_buf);
++ }
++ }
++
++ return retval;
++}
++
++static void mux_sched_send(void)
++{
++
++#ifdef USB_FOR_MUX
++ schedule_work(&send_tqueue);
++#else
++ if (!tq_serial_for_mux) {
++ TS0710_PRINTK("MUX Error: %s: tq_serial_for_mux == 0\n",
++ __FUNCTION__);
++ return;
++ }
++ schedule_work(&send_tqueue);
++ mark_bh(SERIAL_BH);
++#endif
++
++}
++
++/****************************
++ * TTY driver routines
++*****************************/
++
++static void mux_close(struct tty_struct *tty, struct file *filp)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int line;
++ __u8 dlci;
++ __u8 cmdtty;
++ __u8 datatty;
++
++ UNUSED_PARAM(filp);
++
++ if (!tty) {
++ return;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ return;
++ }
++ if (mux_tty[line] > 0)
++ mux_tty[line]--;
++
++ dlci = tty2dlci[line];
++ cmdtty = dlci2tty[dlci].cmdtty;
++ datatty = dlci2tty[dlci].datatty;
++ if ((mux_tty[cmdtty] == 0) && (mux_tty[datatty] == 0)) {
++ if (dlci == 1) {
++ ts0710_close_channel(0);
++ TS0710_PRINTK
++ ("MUX mux_close: tapisrv might be down!!! Close DLCI 1\n");
++ TS0710_SIG2APLOGD();
++ }
++ ts0710_close_channel(dlci);
++ }
++
++ if (mux_tty[line] == 0) {
++ if ((mux_send_info_flags[line])
++ && (mux_send_info[line])
++ /*&& (mux_send_info[line]->filled == 0) */
++ ) {
++ mux_send_info_flags[line] = 0;
++ kfree(mux_send_info[line]);
++ mux_send_info[line] = 0;
++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line);
++ }
++
++ if ((mux_recv_info_flags[line])
++ && (mux_recv_info[line])
++ && (mux_recv_info[line]->total == 0)) {
++ mux_recv_info_flags[line] = 0;
++ free_mux_recv_struct(mux_recv_info[line]);
++ mux_recv_info[line] = 0;
++ TS0710_DEBUG("Free mux_recv_info for /dev/mux%d", line);
++ }
++
++ ts0710_flow_on(dlci, ts0710);
++ schedule_work(&post_recv_tqueue);
++
++ wake_up_interruptible(&tty->read_wait);
++ wake_up_interruptible(&tty->write_wait);
++ tty->packet = 0;
++ }
++}
++
++static void mux_throttle(struct tty_struct *tty)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int line;
++ int i;
++ __u8 dlci;
++
++ if (!tty) {
++ return;
++ }
++
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ return;
++ }
++
++ TS0710_DEBUG("Enter into %s, minor number is: %d\n", __FUNCTION__,
++ line);
++
++ dlci = tty2dlci[line];
++ if ((ts0710->dlci[0].state != CONNECTED)
++ && (ts0710->dlci[0].state != FLOW_STOPPED)) {
++ return;
++ } else if ((ts0710->dlci[dlci].state != CONNECTED)
++ && (ts0710->dlci[dlci].state != FLOW_STOPPED)) {
++ return;
++ }
++
++ if (ts0710->dlci[dlci].flow_control) {
++ return;
++ }
++
++ for (i = 0; i < 3; i++) {
++ if (ts0710_msc_msg
++ (ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, dlci) < 0) {
++ continue;
++ } else {
++ TS0710_LOG("MUX Send Flow off on dlci %d\n", dlci);
++ ts0710->dlci[dlci].flow_control = 1;
++ break;
++ }
++ }
++}
++
++static void mux_unthrottle(struct tty_struct *tty)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int line;
++ __u8 dlci;
++ mux_recv_struct *recv_info;
++
++ if (!tty) {
++ return;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ return;
++ }
++
++ if ((!mux_recv_info_flags[line]) || (!mux_recv_info[line])) {
++ return;
++ }
++
++ TS0710_DEBUG("Enter into %s, minor number is: %d\n", __FUNCTION__,
++ line);
++
++ recv_info = mux_recv_info[line];
++ dlci = tty2dlci[line];
++
++ if (recv_info->total) {
++ recv_info->post_unthrottle = 1;
++ schedule_work(&post_recv_tqueue);
++ } else {
++ ts0710_flow_on(dlci, ts0710);
++ }
++}
++
++static int mux_chars_in_buffer(struct tty_struct *tty)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int retval;
++ int line;
++ __u8 dlci;
++ mux_send_struct *send_info;
++
++ retval = TS0710MUX_MAX_CHARS_IN_BUF;
++ if (!tty) {
++ goto out;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ goto out;
++ }
++
++ dlci = tty2dlci[line];
++ if (ts0710->dlci[0].state == FLOW_STOPPED) {
++ TS0710_DEBUG
++ ("Flow stopped on all channels, returning MAX chars in buffer\n");
++ goto out;
++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped, returning MAX chars in buffer\n");
++ goto out;
++ } else if (ts0710->dlci[dlci].state != CONNECTED) {
++ TS0710_DEBUG("DLCI %d not connected\n", dlci);
++ goto out;
++ }
++
++ if (!(mux_send_info_flags[line])) {
++ goto out;
++ }
++ send_info = mux_send_info[line];
++ if (!send_info) {
++ goto out;
++ }
++ if (send_info->filled) {
++ goto out;
++ }
++
++ retval = 0;
++
++ out:
++ return retval;
++}
++
++static int mux_chars_in_serial_buffer(struct tty_struct *tty)
++{
++ UNUSED_PARAM(tty);
++
++ if ((COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)) {
++ TS0710_PRINTK
++ ("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n",
++ __FUNCTION__);
++
++#ifndef USB_FOR_MUX
++ TS0710_PRINTK
++ ("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n",
++ __FUNCTION__);
++ TS0710_SIG2APLOGD();
++#endif
++
++ return 0;
++ }
++ return COMM_FOR_MUX_DRIVER->chars_in_buffer(COMM_FOR_MUX_TTY);
++}
++
++static int mux_write(struct tty_struct *tty,
++ const unsigned char *buf, int count)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int line;
++ __u8 dlci;
++ mux_send_struct *send_info;
++ __u8 *d_buf;
++ __u16 c;
++ __u8 post_recv;
++
++ if (count <= 0) {
++ return 0;
++ }
++
++ if (!tty) {
++ return 0;
++ }
++
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS))
++ return -ENODEV;
++
++ dlci = tty2dlci[line];
++ if (ts0710->dlci[0].state == FLOW_STOPPED) {
++ TS0710_DEBUG
++ ("Flow stopped on all channels, returning zero /dev/mux%d\n",
++ line);
++ return 0;
++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped, returning zero /dev/mux%d\n", line);
++ return 0;
++ } else if (ts0710->dlci[dlci].state == CONNECTED) {
++
++ if (!(mux_send_info_flags[line])) {
++ TS0710_PRINTK
++ ("MUX Error: mux_write: mux_send_info_flags[%d] == 0\n",
++ line);
++ return -ENODEV;
++ }
++ send_info = mux_send_info[line];
++ if (!send_info) {
++ TS0710_PRINTK
++ ("MUX Error: mux_write: mux_send_info[%d] == 0\n",
++ line);
++ return -ENODEV;
++ }
++
++ c = min(count, (ts0710->dlci[dlci].mtu - 1));
++ if (c <= 0) {
++ return 0;
++ }
++
++ if (test_and_set_bit(BUF_BUSY, &send_info->flags))
++ return 0;
++
++ if (send_info->filled) {
++ clear_bit(BUF_BUSY, &send_info->flags);
++ return 0;
++ }
++
++ d_buf = ((__u8 *) send_info->buf) + TS0710MUX_SEND_BUF_OFFSET;
++ memcpy(&d_buf[1], buf, c);
++
++ TS0710_DEBUG("Prepare to send %d bytes from /dev/mux%d", c,
++ line);
++ if (iscmdtty[line]) {
++ TS0710_DEBUGSTR(&d_buf[1], c);
++ TS0710_DEBUG("CMDTAG");
++ d_buf[0] = CMDTAG;
++ } else {
++ TS0710_DEBUG("DATATAG");
++ d_buf[0] = DATATAG;
++ }
++
++ TS0710_DEBUGHEX(d_buf, c + 1);
++
++ send_info->frame = d_buf;
++ queue_uih(send_info, c + 1, ts0710, dlci);
++ send_info->filled = 1;
++ clear_bit(BUF_BUSY, &send_info->flags);
++
++ post_recv = 0;
++ if (dlci == TS0710MUX_GPRS1_DLCI) {
++ if (add_count
++ (TS0710MUX_GPRS1_SEND_COUNT_IDX, c) < 0) {
++ post_recv_count_flag = 1;
++ post_recv = 1;
++ mux_data_count2[TS0710MUX_GPRS1_SEND_COUNT_IDX]
++ += c;
++ }
++ } else if (dlci == TS0710MUX_GPRS2_DLCI) {
++ if (add_count
++ (TS0710MUX_GPRS2_SEND_COUNT_IDX, c) < 0) {
++ post_recv_count_flag = 1;
++ post_recv = 1;
++ mux_data_count2[TS0710MUX_GPRS2_SEND_COUNT_IDX]
++ += c;
++ }
++ }
++
++ if (post_recv)
++ schedule_work(&post_recv_tqueue);
++
++ if (mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY) == 0) {
++ /* Sending bottom half should be
++ run after return from this function */
++ mux_sched_send();
++ }
++ return c;
++ } else {
++ TS0710_PRINTK("MUX mux_write: DLCI %d not connected\n", dlci);
++ return -EDISCONNECTED;
++ }
++}
++
++static int mux_write_room(struct tty_struct *tty)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int retval;
++ int line;
++ __u8 dlci;
++ mux_send_struct *send_info;
++
++ retval = 0;
++ if (!tty) {
++ goto out;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ goto out;
++ }
++
++ dlci = tty2dlci[line];
++ if (ts0710->dlci[0].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped on all channels, returning ZERO\n");
++ goto out;
++ } else if (ts0710->dlci[dlci].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped, returning ZERO\n");
++ goto out;
++ } else if (ts0710->dlci[dlci].state != CONNECTED) {
++ TS0710_DEBUG("DLCI %d not connected\n", dlci);
++ goto out;
++ }
++
++ if (!(mux_send_info_flags[line])) {
++ goto out;
++ }
++ send_info = mux_send_info[line];
++ if (!send_info) {
++ goto out;
++ }
++ if (send_info->filled) {
++ goto out;
++ }
++
++ retval = ts0710->dlci[dlci].mtu - 1;
++
++ out:
++ return retval;
++}
++
++static int mux_ioctl(struct tty_struct *tty, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int line;
++ __u8 dlci;
++
++ UNUSED_PARAM(file);
++ UNUSED_PARAM(arg);
++
++ if (!tty) {
++ return -EIO;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ return -ENODEV;
++ }
++
++ dlci = tty2dlci[line];
++ switch (cmd) {
++ case TS0710MUX_IO_MSC_HANGUP:
++ if (ts0710_msc_msg(ts0710, EA | RTR | DV, MCC_CMD, dlci) < 0) {
++ return -EAGAIN;
++ } else {
++ return 0;
++ }
++
++ case TS0710MUX_IO_TEST_CMD:
++ return ts0710_exec_test_cmd();
++/*
++ case TS0710MUX_IO_DLCI_FC_ON:
++ if( line == 0 ) {
++ break;
++ }
++ if( ts0710_msc_msg(ts0710, EA | RTC | RTR | DV, MCC_CMD, (__u8)line) < 0) {
++ return -EAGAIN;
++ } else {
++ return 0;
++ }
++
++ case TS0710MUX_IO_DLCI_FC_OFF:
++ if( line == 0 ) {
++ break;
++ }
++ if( ts0710_msc_msg(ts0710, EA | FC | RTC | RTR | DV, MCC_CMD, (__u8)line) < 0) {
++ return -EAGAIN;
++ } else {
++ return 0;
++ }
++
++ case TS0710MUX_IO_FC_ON:
++ if( line != 0 ) {
++ break;
++ }
++ if( ts0710_fcon_msg(ts0710, MCC_CMD) < 0) {
++ return -EAGAIN;
++ } else {
++ return 0;
++ }
++
++ case TS0710MUX_IO_FC_OFF:
++ if( line != 0 ) {
++ break;
++ }
++ if( ts0710_fcoff_msg(ts0710, MCC_CMD) < 0) {
++ return -EAGAIN;
++ } else {
++ return 0;
++ }
++*/
++ default:
++ break;
++ }
++ return -ENOIOCTLCMD;
++}
++
++static void mux_flush_buffer(struct tty_struct *tty)
++{
++ int line;
++
++ if (!tty) {
++ return;
++ }
++
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ return;
++ }
++
++ TS0710_PRINTK("MUX %s: line is:%d\n", __FUNCTION__, line);
++
++ if ((mux_send_info_flags[line])
++ && (mux_send_info[line])
++ && (mux_send_info[line]->filled)) {
++
++ mux_send_info[line]->filled = 0;
++ }
++
++ wake_up_interruptible(&tty->write_wait);
++#ifdef SERIAL_HAVE_POLL_WAIT
++ wake_up_interruptible(&tty->poll_wait);
++#endif
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++ tty->ldisc.write_wakeup) {
++ (tty->ldisc.write_wakeup) (tty);
++ }
++
++/*
++ if( (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0) ) {
++ TS0710_PRINTK("MUX %s: (COMM_FOR_MUX_DRIVER == 0) || (COMM_FOR_MUX_TTY == 0)\n", __FUNCTION__);
++
++#ifndef USB_FOR_MUX
++ TS0710_PRINTK("MUX %s: tapisrv might be down!!! (serial_for_mux_driver == 0) || (serial_for_mux_tty == 0)\n", __FUNCTION__);
++ TS0710_SIG2APLOGD();
++#endif
++
++ return;
++ }
++ return COMM_FOR_MUX_DRIVER->flush_buffer(COMM_FOR_MUX_TTY);
++*/
++}
++
++static int mux_open(struct tty_struct *tty, struct file *filp)
++{
++ int retval;
++ int line;
++ __u8 dlci;
++ __u8 cmdtty;
++ __u8 datatty;
++ mux_send_struct *send_info;
++ mux_recv_struct *recv_info;
++
++ UNUSED_PARAM(filp);
++
++ retval = -ENODEV;
++ if ((COMM_FOR_MUX_DRIVER == NULL) || (COMM_FOR_MUX_TTY == NULL)) {
++
++#ifdef USB_FOR_MUX
++ TS0710_PRINTK("MUX: please install and open IPC-USB first\n");
++#else
++ TS0710_PRINTK("MUX: please install and open ttyS0 first\n");
++#endif
++
++ goto out;
++ }
++
++ if (!tty) {
++ goto out;
++ }
++ line = tty->index;
++ if ((line < 0) || (line >= NR_MUXS)) {
++ goto out;
++ }
++#ifdef TS0710SERVER
++ /* do nothing as a server */
++ mux_tty[line]++;
++ retval = 0;
++#else
++ mux_tty[line]++;
++ dlci = tty2dlci[line];
++
++/* if( dlci == 1 ) { */
++ /* Open server channel 0 first */
++ if ((retval = ts0710_open_channel(0)) != 0) {
++ TS0710_PRINTK("MUX: Can't connect server channel 0!\n");
++ ts0710_init();
++
++ mux_tty[line]--;
++ goto out;
++ }
++/* } */
++
++ /* Allocate memory first. As soon as connection has been established, MUX may receive */
++ if (mux_send_info_flags[line] == 0) {
++ send_info =
++ (mux_send_struct *) kmalloc(sizeof(mux_send_struct),
++ GFP_KERNEL);
++ if (!send_info) {
++ retval = -ENOMEM;
++
++ mux_tty[line]--;
++ goto out;
++ }
++ send_info->length = 0;
++ send_info->flags = 0;
++ send_info->filled = 0;
++ mux_send_info[line] = send_info;
++ mux_send_info_flags[line] = 1;
++ TS0710_DEBUG("Allocate mux_send_info for /dev/mux%d", line);
++ }
++
++ if (mux_recv_info_flags[line] == 0) {
++ recv_info =
++ (mux_recv_struct *) kmalloc(sizeof(mux_recv_struct),
++ GFP_KERNEL);
++ if (!recv_info) {
++ mux_send_info_flags[line] = 0;
++ kfree(mux_send_info[line]);
++ mux_send_info[line] = 0;
++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line);
++ retval = -ENOMEM;
++
++ mux_tty[line]--;
++ goto out;
++ }
++ recv_info->length = 0;
++ recv_info->total = 0;
++ recv_info->mux_packet = 0;
++ recv_info->next = 0;
++ recv_info->no_tty = line;
++ recv_info->post_unthrottle = 0;
++ mux_recv_info[line] = recv_info;
++ mux_recv_info_flags[line] = 1;
++ TS0710_DEBUG("Allocate mux_recv_info for /dev/mux%d", line);
++ }
++
++ /* Now establish DLCI connection */
++ cmdtty = dlci2tty[dlci].cmdtty;
++ datatty = dlci2tty[dlci].datatty;
++ if ((mux_tty[cmdtty] > 0) || (mux_tty[datatty] > 0)) {
++ if ((retval = ts0710_open_channel(dlci)) != 0) {
++ TS0710_PRINTK("MUX: Can't connected channel %d!\n",
++ dlci);
++ ts0710_reset_dlci(dlci);
++
++ mux_send_info_flags[line] = 0;
++ kfree(mux_send_info[line]);
++ mux_send_info[line] = 0;
++ TS0710_DEBUG("Free mux_send_info for /dev/mux%d", line);
++
++ mux_recv_info_flags[line] = 0;
++ free_mux_recv_struct(mux_recv_info[line]);
++ mux_recv_info[line] = 0;
++ TS0710_DEBUG("Free mux_recv_info for /dev/mux%d", line);
++
++ mux_tty[line]--;
++ goto out;
++ }
++ }
++
++ retval = 0;
++#endif
++ out:
++ return retval;
++}
++
++/* mux dispatcher, call from serial.c receiver_chars() */
++void mux_dispatcher(struct tty_struct *tty)
++{
++ UNUSED_PARAM(tty);
++
++ schedule_work(&receive_tqueue);
++}
++
++/*For BP UART problem Begin*/
++#ifdef TS0710SEQ2
++static int send_ack(ts0710_con * ts0710, __u8 seq_num, __u8 bp_seq1,
++ __u8 bp_seq2)
++#else
++static int send_ack(ts0710_con * ts0710, __u8 seq_num)
++#endif
++{
++ __u8 buf[20];
++ short_frame *ack;
++
++#ifdef TS0710SEQ2
++ static __u16 ack_seq = 0;
++#endif
++
++ ack = (short_frame *) (buf + 1);
++ ack->h.addr.ea = 1;
++ ack->h.addr.cr = ((ts0710->initiator) & 0x1);
++ ack->h.addr.d = 0;
++ ack->h.addr.server_chn = 0;
++ ack->h.control = ACK;
++ ack->h.length.ea = 1;
++
++#ifdef TS0710SEQ2
++ ack->h.length.len = 5;
++ ack->data[0] = seq_num;
++ ack->data[1] = bp_seq1;
++ ack->data[2] = bp_seq2;
++ ack->data[3] = (ack_seq & 0xFF);
++ ack->data[4] = (ack_seq >> 8) & 0xFF;
++ ack_seq++;
++ ack->data[5] = crc_calc((__u8 *) ack, SHORT_CRC_CHECK);
++#else
++ ack->h.length.len = 1;
++ ack->data[0] = seq_num;
++ ack->data[1] = crc_calc((__u8 *) ack, SHORT_CRC_CHECK);
++#endif
++
++ return basic_write(ts0710, buf,
++ (sizeof(short_frame) + FCS_SIZE +
++ ack->h.length.len));
++}
++
++/*For BP UART problem End*/
++
++static void receive_worker(void *private_)
++{
++ struct tty_struct *tty = COMM_FOR_MUX_TTY;
++ int i, count;
++ static unsigned char tbuf[TS0710MUX_MAX_BUF_SIZE];
++ static unsigned char *tbuf_ptr = &tbuf[0];
++ static unsigned char *start_flag = 0;
++ unsigned char *search, *to, *from;
++ short_frame *short_pkt;
++ long_frame *long_pkt;
++ static int framelen = -1;
++
++ /*For BP UART problem Begin */
++ static __u8 expect_seq = 0;
++ __u32 crc_error;
++ __u8 *uih_data_start;
++ __u32 uih_len;
++ /*For BP UART problem End */
++
++ UNUSED_PARAM(private_);
++
++ if (!tty)
++ return;
++
++#ifdef USB_FOR_MUX
++ TS0710_DEBUG("Receive following bytes from IPC-USB");
++#else
++ TS0710_DEBUG("Receive following bytes from UART");
++#endif
++
++ TS0710_DEBUGHEX(cp, count);
++
++ if (count > (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf))) {
++ TS0710_PRINTK
++ ("MUX receive_worker: !!!!! Exceed buffer boundary !!!!!\n");
++ count = (TS0710MUX_MAX_BUF_SIZE - (tbuf_ptr - tbuf));
++ }
++
++ count = tty_buffer_request_room(tty, count);
++
++ for (i = 0; i < count; i++)
++ tty_insert_flip_char(tty, tbuf_ptr[i], TTY_NORMAL);
++
++ tbuf_ptr += count;
++ search = &tbuf[0];
++
++ if (test_and_set_bit(RECV_RUNNING, &mux_recv_flags)) {
++ schedule_work(&receive_tqueue);
++ return;
++ }
++
++ if ((start_flag != 0) && (framelen != -1)) {
++ if ((tbuf_ptr - start_flag) < framelen) {
++ clear_bit(RECV_RUNNING, &mux_recv_flags);
++ return;
++ }
++ }
++
++ while (1) {
++ if (start_flag == 0) { /* Frame Start Flag not found */
++ framelen = -1;
++ while (search < tbuf_ptr) {
++ if (*search == TS0710_BASIC_FLAG) {
++ start_flag = search;
++ break;
++ }
++#ifdef TS0710LOG
++ else {
++ TS0710_LOG(">S %02x %c\n", *search,
++ *search);
++ }
++#endif
++
++ search++;
++ }
++
++ if (start_flag == 0) {
++ tbuf_ptr = &tbuf[0];
++ break;
++ }
++ } else { /* Frame Start Flag found */
++ /* 1 start flag + 1 address + 1 control + 1 or 2 length + lengths data + 1 FCS + 1 end flag */
++ /* For BP UART problem 1 start flag + 1 seq_num + 1 address + ...... */
++ /*if( (framelen == -1) && ((tbuf_ptr - start_flag) > TS0710_MAX_HDR_SIZE) ) */
++ if ((framelen == -1) && ((tbuf_ptr - start_flag) > (TS0710_MAX_HDR_SIZE + SEQ_FIELD_SIZE))) { /*For BP UART problem */
++ /*short_pkt = (short_frame *) (start_flag + 1); */
++ short_pkt = (short_frame *) (start_flag + ADDRESS_FIELD_OFFSET); /*For BP UART problem */
++ if (short_pkt->h.length.ea == 1) { /* short frame */
++ /*framelen = TS0710_MAX_HDR_SIZE + short_pkt->h.length.len + 1; */
++ framelen = TS0710_MAX_HDR_SIZE + short_pkt->h.length.len + 1 + SEQ_FIELD_SIZE; /*For BP UART problem */
++ } else { /* long frame */
++ /*long_pkt = (long_frame *) (start_flag + 1); */
++ long_pkt = (long_frame *) (start_flag + ADDRESS_FIELD_OFFSET); /*For BP UART problem */
++ /*framelen = TS0710_MAX_HDR_SIZE + GET_LONG_LENGTH( long_pkt->h.length ) + 2; */
++ framelen = TS0710_MAX_HDR_SIZE + GET_LONG_LENGTH(long_pkt->h.length) + 2 + SEQ_FIELD_SIZE; /*For BP UART problem */
++ }
++
++ /*if( framelen > TS0710MUX_MAX_TOTAL_FRAME_SIZE ) { */
++ if (framelen > (TS0710MUX_MAX_TOTAL_FRAME_SIZE + SEQ_FIELD_SIZE)) { /*For BP UART problem */
++ TS0710_LOGSTR_FRAME(0, start_flag,
++ (tbuf_ptr -
++ start_flag));
++ TS0710_PRINTK
++ ("MUX Error: %s: frame length:%d is bigger than Max total frame size:%d\n",
++ /*__FUNCTION__, framelen, TS0710MUX_MAX_TOTAL_FRAME_SIZE);*/
++ __FUNCTION__, framelen, (TS0710MUX_MAX_TOTAL_FRAME_SIZE + SEQ_FIELD_SIZE)); /*For BP UART problem */
++ search = start_flag + 1;
++ start_flag = 0;
++ framelen = -1;
++ continue;
++ }
++ }
++
++ if ((framelen != -1)
++ && ((tbuf_ptr - start_flag) >= framelen)) {
++ if (*(start_flag + framelen - 1) == TS0710_BASIC_FLAG) { /* OK, We got one frame */
++
++ /*For BP UART problem Begin */
++ TS0710_LOGSTR_FRAME(0, start_flag,
++ framelen);
++ TS0710_DEBUGHEX(start_flag, framelen);
++
++ short_pkt =
++ (short_frame *) (start_flag +
++ ADDRESS_FIELD_OFFSET);
++ if ((short_pkt->h.length.ea) == 0) {
++ long_pkt =
++ (long_frame *) (start_flag +
++ ADDRESS_FIELD_OFFSET);
++ uih_len =
++ GET_LONG_LENGTH(long_pkt->h.
++ length);
++ uih_data_start =
++ long_pkt->h.data;
++
++ crc_error =
++ crc_check((__u8
++ *) (start_flag +
++ SLIDE_BP_SEQ_OFFSET),
++ LONG_CRC_CHECK +
++ 1,
++ *(uih_data_start +
++ uih_len));
++ } else {
++ uih_len =
++ short_pkt->h.length.len;
++ uih_data_start =
++ short_pkt->data;
++
++ crc_error =
++ crc_check((__u8
++ *) (start_flag +
++ SLIDE_BP_SEQ_OFFSET),
++ SHORT_CRC_CHECK +
++ 1,
++ *(uih_data_start +
++ uih_len));
++ }
++
++ if (!crc_error) {
++ if (expect_seq ==
++ *(start_flag +
++ SLIDE_BP_SEQ_OFFSET)) {
++ expect_seq++;
++ if (expect_seq >= 4) {
++ expect_seq = 0;
++ }
++#ifdef TS0710SEQ2
++ send_ack
++ (&ts0710_connection,
++ expect_seq,
++ *(start_flag +
++ FIRST_BP_SEQ_OFFSET),
++ *(start_flag +
++ SECOND_BP_SEQ_OFFSET));
++#else
++ send_ack
++ (&ts0710_connection,
++ expect_seq);
++#endif
++
++ ts0710_recv_data
++ (&ts0710_connection,
++ start_flag +
++ ADDRESS_FIELD_OFFSET,
++ framelen - 2 -
++ SEQ_FIELD_SIZE);
++ } else {
++
++#ifdef TS0710DEBUG
++ if (*
++ (start_flag +
++ SLIDE_BP_SEQ_OFFSET)
++ != 0x9F) {
++#endif
++
++ TS0710_LOG
++ ("MUX sequence number %d is not expected %d, discard data!\n",
++ *
++ (start_flag
++ +
++ SLIDE_BP_SEQ_OFFSET),
++ expect_seq);
++
++#ifdef TS0710SEQ2
++ send_ack
++ (&ts0710_connection,
++ expect_seq,
++ *
++ (start_flag
++ +
++ FIRST_BP_SEQ_OFFSET),
++ *
++ (start_flag
++ +
++ SECOND_BP_SEQ_OFFSET));
++#else
++ send_ack
++ (&ts0710_connection,
++ expect_seq);
++#endif
++
++#ifdef TS0710DEBUG
++ } else {
++ *(uih_data_start
++ + uih_len) =
++ 0;
++ TS0710_PRINTK
++ ("MUX bp log: %s\n",
++ uih_data_start);
++ }
++#endif
++
++ }
++ } else { /* crc_error */
++ search = start_flag + 1;
++ start_flag = 0;
++ framelen = -1;
++ continue;
++ } /*End if(!crc_error) */
++
++ /*For BP UART problem End */
++
++/*For BP UART problem
++ TS0710_LOGSTR_FRAME(0, start_flag, framelen);
++ TS0710_DEBUGHEX(start_flag, framelen);
++ ts0710_recv_data(&ts0710_connection, start_flag + 1, framelen - 2);
++*/
++ search = start_flag + framelen;
++ } else {
++ TS0710_LOGSTR_FRAME(0, start_flag,
++ framelen);
++ TS0710_DEBUGHEX(start_flag, framelen);
++ TS0710_PRINTK
++ ("MUX: Lost synchronization!\n");
++ search = start_flag + 1;
++ }
++
++ start_flag = 0;
++ framelen = -1;
++ continue;
++ }
++
++ if (start_flag != &tbuf[0]) {
++ to = tbuf;
++ from = start_flag;
++ count = tbuf_ptr - start_flag;
++ while (count--) {
++ *to++ = *from++;
++ }
++
++ tbuf_ptr -= (start_flag - tbuf);
++ start_flag = tbuf;
++ }
++ break;
++ } /* End Frame Start Flag found */
++ } /* End while(1) */
++
++ clear_bit(RECV_RUNNING, &mux_recv_flags);
++}
++
++static void post_recv_worker(void *private_)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ int tty_idx;
++ struct tty_struct *tty;
++ __u8 post_recv;
++ __u8 flow_control;
++ __u8 dlci;
++ mux_recv_struct *recv_info, *recv_info2, *post_recv_q;
++ int recv_room;
++ mux_recv_packet *recv_packet, *recv_packet2;
++ __u8 j;
++
++ UNUSED_PARAM(private_);
++
++ if (test_and_set_bit(RECV_RUNNING, &mux_recv_flags)) {
++ schedule_work(&post_recv_tqueue);
++ return;
++ }
++
++ TS0710_DEBUG("Enter into post_recv_worker");
++
++ post_recv = 0;
++ if (!mux_recv_queue) {
++ goto out;
++ }
++
++ post_recv_q = NULL;
++ recv_info2 = mux_recv_queue;
++ while ((recv_info = recv_info2)) {
++ recv_info2 = recv_info->next;
++
++ if (!(recv_info->total)) {
++ TS0710_PRINTK
++ ("MUX Error: %s: Should not get here, recv_info->total == 0 \n",
++ __FUNCTION__);
++ continue;
++ }
++
++ tty_idx = recv_info->no_tty;
++ dlci = tty2dlci[tty_idx];
++ tty = mux_table[tty_idx];
++ if ((!mux_tty[tty_idx]) || (!tty)) {
++ TS0710_PRINTK
++ ("MUX: No application waiting for, free recv_info! tty_idx:%d\n",
++ tty_idx);
++ mux_recv_info_flags[tty_idx] = 0;
++ free_mux_recv_struct(mux_recv_info[tty_idx]);
++ mux_recv_info[tty_idx] = 0;
++ ts0710_flow_on(dlci, ts0710);
++ continue;
++ }
++
++ TS0710_DEBUG("/dev/mux%d recv_info->total is: %d", tty_idx,
++ recv_info->total);
++
++ if (test_bit(TTY_THROTTLED, &tty->flags)) {
++ add_post_recv_queue(&post_recv_q, recv_info);
++ continue;
++ } else if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
++ post_recv = 1;
++ add_post_recv_queue(&post_recv_q, recv_info);
++ continue;
++ }
++
++ flow_control = 0;
++ recv_packet2 = recv_info->mux_packet;
++ while (recv_info->total) {
++ recv_room = 65535;
++ if (tty->receive_room)
++ recv_room = tty->receive_room;
++
++ if (recv_info->length) {
++ if (recv_room < recv_info->length) {
++ flow_control = 1;
++ break;
++ }
++
++ /* Put queued data into read buffer of tty */
++ TS0710_DEBUG
++ ("Put queued recv data into read buffer of /dev/mux%d",
++ tty_idx);
++ TS0710_DEBUGHEX(recv_info->data,
++ recv_info->length);
++ (tty->ldisc.receive_buf) (tty, recv_info->data,
++ NULL,
++ recv_info->length);
++ recv_info->total -= recv_info->length;
++ recv_info->length = 0;
++ } else { /* recv_info->length == 0 */
++ if ((recv_packet = recv_packet2)) {
++ recv_packet2 = recv_packet->next;
++
++ if (recv_room < recv_packet->length) {
++ flow_control = 1;
++ recv_info->mux_packet =
++ recv_packet;
++ break;
++ }
++
++ /* Put queued data into read buffer of tty */
++ TS0710_DEBUG
++ ("Put queued recv data into read buffer of /dev/mux%d",
++ tty_idx);
++ TS0710_DEBUGHEX(recv_packet->data,
++ recv_packet->length);
++ (tty->ldisc.receive_buf) (tty,
++ recv_packet->
++ data, NULL,
++ recv_packet->
++ length);
++ recv_info->total -= recv_packet->length;
++ free_mux_recv_packet(recv_packet);
++ } else {
++ TS0710_PRINTK
++ ("MUX Error: %s: Should not get here, recv_info->total is:%u \n",
++ __FUNCTION__, recv_info->total);
++ }
++ } /* End recv_info->length == 0 */
++ } /* End while( recv_info->total ) */
++
++ if (!(recv_info->total)) {
++ /* Important clear */
++ recv_info->mux_packet = 0;
++
++ if (recv_info->post_unthrottle) {
++ /* Do something for post_unthrottle */
++ ts0710_flow_on(dlci, ts0710);
++ recv_info->post_unthrottle = 0;
++ }
++ } else {
++ add_post_recv_queue(&post_recv_q, recv_info);
++
++ if (flow_control) {
++ /* Do something for flow control */
++ if (recv_info->post_unthrottle) {
++ set_bit(TTY_THROTTLED, &tty->flags);
++ recv_info->post_unthrottle = 0;
++ } else {
++ ts0710_flow_off(tty, dlci, ts0710);
++ }
++ } /* End if( flow_control ) */
++ }
++ } /* End while( (recv_info = recv_info2) ) */
++
++ mux_recv_queue = post_recv_q;
++
++ out:
++ if (post_recv_count_flag) {
++ post_recv_count_flag = 0;
++ for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) {
++ if (mux_data_count2[j] > 0) {
++ if (add_count(j, mux_data_count2[j]) == 0) {
++ mux_data_count2[j] = 0;
++ } else {
++ post_recv_count_flag = 1;
++ post_recv = 1;
++ }
++ }
++ } /* End for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) */
++ }
++ /* End if( post_recv_count_flag ) */
++ if (post_recv)
++ schedule_work(&post_recv_tqueue);
++ clear_bit(RECV_RUNNING, &mux_recv_flags);
++}
++
++/* mux sender, call from serial.c transmit_chars() */
++void mux_sender(void)
++{
++ mux_send_struct *send_info;
++ int chars;
++ __u8 idx;
++
++ chars = mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY);
++ if (!chars) {
++ /* chars == 0 */
++ TS0710_LOG("<[]\n");
++ mux_sched_send();
++ return;
++ }
++
++ idx = mux_send_info_idx;
++ if ((idx < NR_MUXS) && (mux_send_info_flags[idx])) {
++ send_info = mux_send_info[idx];
++ if ((send_info)
++ && (send_info->filled)
++ && (send_info->length <=
++ (TS0710MUX_SERIAL_BUF_SIZE - chars))) {
++
++ mux_sched_send();
++ }
++ }
++}
++
++static void send_worker(void *private_)
++{
++ ts0710_con *ts0710 = &ts0710_connection;
++ __u8 j;
++ mux_send_struct *send_info;
++ int chars;
++ struct tty_struct *tty;
++ __u8 dlci;
++
++ UNUSED_PARAM(private_);
++
++ TS0710_DEBUG("Enter into send_worker");
++
++ mux_send_info_idx = NR_MUXS;
++
++ if (ts0710->dlci[0].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped on all channels\n");
++ return;
++ }
++
++ for (j = 0; j < NR_MUXS; j++) {
++
++ if (!(mux_send_info_flags[j])) {
++ continue;
++ }
++
++ send_info = mux_send_info[j];
++ if (!send_info) {
++ continue;
++ }
++
++ if (!(send_info->filled)) {
++ continue;
++ }
++
++ dlci = tty2dlci[j];
++ if (ts0710->dlci[dlci].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped on channel DLCI: %d\n",
++ dlci);
++ continue;
++ } else if (ts0710->dlci[dlci].state != CONNECTED) {
++ TS0710_DEBUG("DLCI %d not connected\n", dlci);
++ send_info->filled = 0;
++ continue;
++ }
++
++ chars = mux_chars_in_serial_buffer(COMM_FOR_MUX_TTY);
++ if (send_info->length <= (TS0710MUX_SERIAL_BUF_SIZE - chars)) {
++ TS0710_DEBUG("Send queued UIH for /dev/mux%d", j);
++ basic_write(ts0710, (__u8 *) send_info->frame,
++ send_info->length);
++ send_info->length = 0;
++ send_info->filled = 0;
++ } else {
++ mux_send_info_idx = j;
++ break;
++ }
++ } /* End for() loop */
++
++ /* Queue UIH data to be transmitted */
++ for (j = 0; j < NR_MUXS; j++) {
++
++ if (!(mux_send_info_flags[j])) {
++ continue;
++ }
++
++ send_info = mux_send_info[j];
++ if (!send_info) {
++ continue;
++ }
++
++ if (send_info->filled) {
++ continue;
++ }
++
++ /* Now queue UIH data to send_info->buf */
++
++ if (!mux_tty[j]) {
++ continue;
++ }
++
++ tty = mux_table[j];
++ if (!tty) {
++ continue;
++ }
++
++ dlci = tty2dlci[j];
++ if (ts0710->dlci[dlci].state == FLOW_STOPPED) {
++ TS0710_DEBUG("Flow stopped on channel DLCI: %d\n",
++ dlci);
++ continue;
++ } else if (ts0710->dlci[dlci].state != CONNECTED) {
++ TS0710_DEBUG("DLCI %d not connected\n", dlci);
++ continue;
++ }
++
++ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP))
++ && tty->ldisc.write_wakeup) {
++ (tty->ldisc.write_wakeup) (tty);
++ }
++ wake_up_interruptible(&tty->write_wait);
++
++#ifdef SERIAL_HAVE_POLL_WAIT
++ wake_up_interruptible(&tty->poll_wait);
++#endif
++
++ if (send_info->filled) {
++ if (j < mux_send_info_idx) {
++ mux_send_info_idx = j;
++ }
++ }
++ } /* End for() loop */
++}
++
++static int get_count(__u8 idx)
++{
++ int ret;
++
++ if (idx > TS0710MUX_COUNT_MAX_IDX) {
++ TS0710_PRINTK("MUX get_count: invalid idx: %d!\n", idx);
++ return -1;
++ }
++
++ down(&mux_data_count_mutex[idx]);
++ ret = mux_data_count[idx];
++ up(&mux_data_count_mutex[idx]);
++
++ return ret;
++}
++
++static int set_count(__u8 idx, int count)
++{
++ if (idx > TS0710MUX_COUNT_MAX_IDX) {
++ TS0710_PRINTK("MUX set_count: invalid idx: %d!\n", idx);
++ return -1;
++ }
++ if (count < 0) {
++ TS0710_PRINTK("MUX set_count: invalid count: %d!\n", count);
++ return -1;
++ }
++
++ down(&mux_data_count_mutex[idx]);
++ mux_data_count[idx] = count;
++ up(&mux_data_count_mutex[idx]);
++
++ return 0;
++}
++
++static int add_count(__u8 idx, int count)
++{
++ if (idx > TS0710MUX_COUNT_MAX_IDX) {
++ TS0710_PRINTK("MUX add_count: invalid idx: %d!\n", idx);
++ return -1;
++ }
++ if (count <= 0) {
++ TS0710_PRINTK("MUX add_count: invalid count: %d!\n", count);
++ return -1;
++ }
++
++ if (down_trylock(&mux_data_count_mutex[idx]))
++ return -1;
++ mux_data_count[idx] += count;
++ up(&mux_data_count_mutex[idx]);
++
++ return 0;
++}
++
++ssize_t file_proc_read(struct file * file, char *buf, size_t size,
++ loff_t * ppos)
++{
++ gprs_bytes gprsData[TS0710MUX_GPRS_SESSION_MAX];
++ int bufLen = sizeof(gprs_bytes) * TS0710MUX_GPRS_SESSION_MAX;
++
++ UNUSED_PARAM(file);
++ UNUSED_PARAM(size);
++ UNUSED_PARAM(ppos);
++
++ gprsData[0].recvBytes = get_count(TS0710MUX_GPRS1_RECV_COUNT_IDX);
++ gprsData[0].sentBytes = get_count(TS0710MUX_GPRS1_SEND_COUNT_IDX);
++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].recvBytes =
++ get_count(TS0710MUX_GPRS2_RECV_COUNT_IDX);
++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].sentBytes =
++ get_count(TS0710MUX_GPRS2_SEND_COUNT_IDX);
++
++ copy_to_user(buf, gprsData, bufLen);
++
++ return bufLen;
++}
++
++ssize_t file_proc_write(struct file * file, const char *buf, size_t count,
++ loff_t * ppos)
++{
++ gprs_bytes gprsData[TS0710MUX_GPRS_SESSION_MAX];
++ int bufLen = sizeof(gprs_bytes) * TS0710MUX_GPRS_SESSION_MAX;
++
++ UNUSED_PARAM(file);
++ UNUSED_PARAM(count);
++ UNUSED_PARAM(ppos);
++
++ memset(gprsData, 0, bufLen);
++
++ copy_from_user(gprsData, buf, bufLen);
++
++ set_count(TS0710MUX_GPRS1_RECV_COUNT_IDX, gprsData[0].recvBytes);
++ set_count(TS0710MUX_GPRS1_SEND_COUNT_IDX, gprsData[0].sentBytes);
++ set_count(TS0710MUX_GPRS2_RECV_COUNT_IDX,
++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].recvBytes);
++ set_count(TS0710MUX_GPRS2_SEND_COUNT_IDX,
++ gprsData[TS0710MUX_GPRS_SESSION_MAX - 1].sentBytes);
++
++ return bufLen;
++}
++
++static void gprs_proc_init(void)
++{
++ gprs_proc_file =
++ create_proc_entry("gprsbytes", S_IRUSR | S_IWUSR, NULL);
++ gprs_proc_file->proc_fops = &file_proc_operations;
++}
++
++static void gprs_proc_exit(void)
++{
++ remove_proc_entry("gprsbytes", gprs_proc_file);
++}
++
++static int __init mux_init(void)
++{
++ __u8 j;
++
++ if (COMM_FOR_MUX_DRIVER == NULL) {
++
++#ifdef USB_FOR_MUX
++ panic("please install IPC-USB first\n");
++#else
++ panic("please install ttyS0 first\n");
++#endif
++
++ }
++
++ ts0710_init();
++
++ for (j = 0; j < NR_MUXS; j++) {
++ mux_send_info_flags[j] = 0;
++ mux_send_info[j] = 0;
++ mux_recv_info_flags[j] = 0;
++ mux_recv_info[j] = 0;
++ }
++ mux_send_info_idx = NR_MUXS;
++ mux_recv_queue = NULL;
++ mux_recv_flags = 0;
++
++ for (j = 0; j < TS0710MUX_COUNT_IDX_NUM; j++) {
++ mux_data_count[j] = 0;
++ mux_data_count2[j] = 0;
++ init_MUTEX(&mux_data_count_mutex[j]);
++ }
++ post_recv_count_flag = 0;
++
++ INIT_WORK(&send_tqueue, send_worker, NULL);
++ INIT_WORK(&receive_tqueue, receive_worker, NULL);
++ INIT_WORK(&post_recv_tqueue, post_recv_worker, NULL);
++
++ memset(&mux_driver, 0, sizeof(struct tty_driver));
++ memset(&mux_tty, 0, sizeof(mux_tty));
++ mux_driver.magic = TTY_DRIVER_MAGIC;
++ mux_driver.driver_name = "ts0710mux";
++ mux_driver.name = "ts0710mux";
++ mux_driver.major = TS0710MUX_MAJOR;
++ mux_driver.minor_start = TS0710MUX_MINOR_START;
++ mux_driver.num = NR_MUXS;
++ mux_driver.type = TTY_DRIVER_TYPE_SERIAL;
++ mux_driver.subtype = SERIAL_TYPE_NORMAL;
++ mux_driver.init_termios = tty_std_termios;
++ mux_driver.init_termios.c_iflag = 0;
++ mux_driver.init_termios.c_oflag = 0;
++ mux_driver.init_termios.c_cflag = B38400 | CS8 | CREAD;
++ mux_driver.init_termios.c_lflag = 0;
++ mux_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
++
++ mux_driver.ttys = mux_table;
++ mux_driver.termios = mux_termios;
++ mux_driver.termios_locked = mux_termios_locked;
++// mux_driver.driver_state = mux_state;
++ mux_driver.other = NULL;
++
++ mux_driver.open = mux_open;
++ mux_driver.close = mux_close;
++ mux_driver.write = mux_write;
++ mux_driver.write_room = mux_write_room;
++ mux_driver.flush_buffer = mux_flush_buffer;
++ mux_driver.chars_in_buffer = mux_chars_in_buffer;
++ mux_driver.throttle = mux_throttle;
++ mux_driver.unthrottle = mux_unthrottle;
++ mux_driver.ioctl = mux_ioctl;
++ mux_driver.owner = THIS_MODULE;
++
++ if (tty_register_driver(&mux_driver))
++ panic("Couldn't register mux driver");
++
++ COMM_MUX_DISPATCHER = mux_dispatcher;
++ COMM_MUX_SENDER = mux_sender;
++
++ gprs_proc_init();
++
++ return 0;
++}
++
++static void __exit mux_exit(void)
++{
++ __u8 j;
++
++ COMM_MUX_DISPATCHER = NULL;
++ COMM_MUX_SENDER = NULL;
++
++ gprs_proc_exit();
++
++ mux_send_info_idx = NR_MUXS;
++ mux_recv_queue = NULL;
++ for (j = 0; j < NR_MUXS; j++) {
++ if ((mux_send_info_flags[j]) && (mux_send_info[j])) {
++ kfree(mux_send_info[j]);
++ }
++ mux_send_info_flags[j] = 0;
++ mux_send_info[j] = 0;
++
++ if ((mux_recv_info_flags[j]) && (mux_recv_info[j])) {
++ free_mux_recv_struct(mux_recv_info[j]);
++ }
++ mux_recv_info_flags[j] = 0;
++ mux_recv_info[j] = 0;
++ }
++
++ if (tty_unregister_driver(&mux_driver))
++ panic("Couldn't unregister mux driver");
++}
++
++module_init(mux_init);
++module_exit(mux_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Harald Welte <laforge@openezx.org>");
++MODULE_DESCRIPTION("TS 07.10 Multiplexer");
+Index: linux-2.6.24/drivers/char/ts0710_mux.h
+===================================================================
+--- /dev/null
++++ linux-2.6.24/drivers/char/ts0710_mux.h
+@@ -0,0 +1,103 @@
++/*
++ * mux_macro.h
++ *
++ * Copyright (C) 2002 2005 Motorola
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ *
++ * 11/18/2002 (Motorola) - Initial version
++ *
++ */
++
++/*
++* This header file should be included by both MUX and other applications
++* which access MUX device files. It gives the additional macro definitions
++* shared between MUX and applications.
++*/
++
++/* MUX DLCI(Data Link Connection Identifier) Configuration */
++/*
++* DLCI Service
++* 0 Control Channel
++* 1 Voice Call & Network-related
++* 2 SMS MO
++* 3 SMS MT
++* 4 Phonebook & related
++* 5 MISC
++* 6 CSD/FAX
++* 7 GPRS1
++* 8 GPRS2
++* 9 Logger CMD
++* 10 Logger Data
++* 11 Test CMD
++* 12 AGPS
++* 13 Net Monitor
++*/
++
++/* Mapping between DLCI and MUX device files */
++/*
++* File Name Minor DLCI AT Command/Data
++* /dev/mux0 0 1 AT Command
++* /dev/mux1 1 2 AT Command
++* /dev/mux2 2 3 AT Command
++* /dev/mux3 3 4 AT Command
++* /dev/mux4 4 5 AT Command
++* /dev/mux5 5 6 AT Command
++* /dev/mux6 6 7 AT Command
++* /dev/mux7 7 8 AT Command
++* /dev/mux8 8 6 Data
++* /dev/mux9 9 7 Data
++* /dev/mux10 10 8 Data
++* /dev/mux11 11 9 Data
++* /dev/mux12 12 10 Data
++* /dev/mux13 13 11 Data
++* /dev/mux14 14 12 Data
++* /dev/mux15 15 13 Data
++*/
++
++#define MUX_CMD_FILE_VOICE_CALL "/dev/mux0"
++#define MUX_CMD_FILE_SMS_MO "/dev/mux1"
++#define MUX_CMD_FILE_SMS_MT "/dev/mux2"
++#define MUX_CMD_FILE_PHONEBOOK "/dev/mux3"
++#define MUX_CMD_FILE_MISC "/dev/mux4"
++#define MUX_CMD_FILE_CSD "/dev/mux5"
++#define MUX_CMD_FILE_GPRS1 "/dev/mux6"
++#define MUX_CMD_FILE_GPRS2 "/dev/mux7"
++
++#define MUX_DATA_FILE_CSD "/dev/mux8"
++#define MUX_DATA_FILE_GPRS1 "/dev/mux9"
++#define MUX_DATA_FILE_GPRS2 "/dev/mux10"
++#define MUX_DATA_FILE_LOGGER_CMD "/dev/mux11"
++#define MUX_DATA_FILE_LOGGER_DATA "/dev/mux12"
++#define MUX_DATA_FILE_TEST_CMD "/dev/mux13"
++#define MUX_DATA_FILE_AGPS "/dev/mux14"
++#define MUX_DATA_FILE_NET_MONITOR "/dev/mux15"
++
++#define NUM_MUX_CMD_FILES 8
++#define NUM_MUX_DATA_FILES 8
++#define NUM_MUX_FILES ( NUM_MUX_CMD_FILES + NUM_MUX_DATA_FILES )
++
++/* Special ioctl() upon a MUX device file for hanging up a call */
++#define TS0710MUX_IO_MSC_HANGUP 0x54F0
++
++/* Special ioctl() upon a MUX device file for MUX loopback test */
++#define TS0710MUX_IO_TEST_CMD 0x54F1
++
++/* Special Error code might be return from write() to a MUX device file */
++#define EDISCONNECTED 900 /* Logical data link is disconnected */
++
++/* Special Error code might be return from open() to a MUX device file */
++#define EREJECTED 901 /* Logical data link connection request is rejected */
+Index: linux-2.6.24/drivers/char/ts0710_mux_usb.c
+===================================================================
+--- /dev/null
++++ linux-2.6.24/drivers/char/ts0710_mux_usb.c
+@@ -0,0 +1,868 @@
++/*
++ * linux/drivers/usb/ipcusb.c
++ *
++ * Implementation of a ipc driver based Intel's Bulverde USB Host
++ * Controller.
++ *
++ * Copyright (C) 2003-2005 Motorola
++ * Copyright (C) 2006 Harald Welte <laforge@openezx.org>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * 2003-Nov-03 - (Motorola) created
++ * 2004-Feb-20 - (Motorola) Add Power Manager codes
++ * 2004-Apr-14 - (Motorola) Update Suspend/Resume codes
++ * 2004-May-10 - (Motorola) Add unlink_urbs codes and do some updates of send
++ * out urb sequence
++ * 2006-Jun-22 - (Harald Welte) port to Linux 2.6.x
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/errno.h>
++#include <asm/uaccess.h>
++#include <asm/hardware.h>
++#include <asm/arch/hardware.h>
++#include <asm/arch-pxa/pxa-regs.h>
++#include <asm/arch-pxa/ezx.h>
++#include <linux/slab.h>
++#include <linux/miscdevice.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/delay.h>
++#include <linux/sched.h>
++#include <linux/tty.h>
++#include <linux/tty_driver.h>
++#include <linux/tty_flip.h>
++#include <linux/circ_buf.h>
++#include <linux/usb.h>
++
++#include "ts0710_mux_usb.h"
++
++/*Macro defined for this driver*/
++#define DRIVER_VERSION "1.0alpha1"
++#define DRIVER_AUTHOR "Motorola / Harald Welte <laforge@openezx.org>"
++#define DRIVER_DESC "USB IPC Driver (TS07.10 lowlevel)"
++#define MOTO_IPC_VID 0x22b8
++#define MOTO_IPC_PID 0x3006
++#define IBUF_SIZE 32 /*urb size*/
++#define IPC_USB_XMIT_SIZE 1024
++#define IPC_URB_SIZE 32
++#define IPC_USB_WRITE_INIT 0
++#define IPC_USB_WRITE_XMIT 1
++#define IPC_USB_PROBE_READY 3
++#define IPC_USB_PROBE_NOT_READY 4
++#define DBG_MAX_BUF_SIZE 1024
++#define ICL_EVENT_INTERVAL (HZ)
++#undef BVD_DEBUG
++
++#define IS_EP_BULK(ep) ((ep).bmAttributes == USB_ENDPOINT_XFER_BULK ? 1 : 0)
++#define IS_EP_BULK_IN(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
++#define IS_EP_BULK_OUT(ep) (IS_EP_BULK(ep) && ((ep).bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
++/*End defined macro*/
++
++/*global values defined*/
++static struct usb_driver usb_ipc_driver;
++static struct timer_list ipcusb_timer;
++static struct timer_list suspend_timer;
++static struct timer_list wakeup_timer;
++static struct tty_struct ipcusb_tty; /* the coresponding tty struct, we just use flip buffer here. */
++static struct tty_driver ipcusb_tty_driver; /* the coresponding tty driver, we just use write and chars in buff here*/
++struct tty_driver *usb_for_mux_driver = NULL;
++struct tty_struct *usb_for_mux_tty = NULL;
++void (*usb_mux_dispatcher)(struct tty_struct *tty) = NULL;
++void (*usb_mux_sender)(void) = NULL;
++void (*ipcusb_ap_to_bp)(unsigned char*, int) = NULL;
++void (*ipcusb_bp_to_ap)(unsigned char*, int) = NULL;
++EXPORT_SYMBOL(usb_for_mux_driver);
++EXPORT_SYMBOL(usb_for_mux_tty);
++EXPORT_SYMBOL(usb_mux_dispatcher);
++EXPORT_SYMBOL(usb_mux_sender);
++EXPORT_SYMBOL(ipcusb_ap_to_bp);
++EXPORT_SYMBOL(ipcusb_bp_to_ap);
++static int sumbit_times = 0;
++static int callback_times = 0;
++//static unsigned long last_jiff = 0;
++extern int usbh_finished_resume;
++/*end global values defined*/
++
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++MODULE_LICENSE("GPL");
++
++#ifdef BVD_DEBUG
++#define bvd_dbg(format, arg...) printk(__FILE__ ": " format "\n" , ## arg)
++#else
++#define bvd_dbg(format, arg...) do {} while (0)
++#endif
++
++/* USB device context */
++typedef struct {
++ struct list_head list;
++ int size;
++ char *body;
++} buf_list_t;
++
++struct ipc_usb_data {
++ u_int8_t write_finished_flag;
++ u_int8_t write_flag,
++ ipc_flag,
++ suspend_flag;
++ struct usb_device *ipc_dev;
++ struct urb readurb_mux,
++ writeurb_mux,
++ writeurb_dsplog;
++ char *obuf, *ibuf;
++ int writesize; /* max packet size for the
++ output bulk endpoint *
++ transfer buffers */
++
++ struct circ_buf xmit; /* write cric bufffer */
++ struct list_head in_buf_list;
++ char bulk_in_ep_mux,
++ bulk_out_ep_mux,
++ bulk_in_ep_dsplog;
++ unsigned int ifnum;
++
++ struct tasklet_struct bh,
++ bh_bp;
++
++ spinlock_t lock;
++};
++
++struct ipc_usb_data *bvd_ipc;
++
++#ifdef BVD_DEBUG
++static void bvd_dbg_hex(__u8 *buf, int len)
++{
++ static unsigned char tbuf[DBG_MAX_BUF_SIZE];
++ int i, c;
++
++ if (len <= 0)
++ return;
++
++ c = 0;
++ for (i=0; (i < len) && (c < (DBG_MAX_BUF_SIZE - 3)); i++) {
++ sprintf(&tbuf[c], "%02x ",buf[i]);
++ c += 3;
++ }
++ tbuf[c] = 0;
++
++ printk("%s: %s\n", __FUNCTION__, tbuf);
++}
++#else
++#define bvd_dbg_hex(buf, len)
++#endif
++
++static int unlink_urbs(struct urb *urb)
++{
++ unsigned long flags;
++ int retval;
++
++ spin_lock_irqsave(&bvd_ipc->lock, flags);
++
++ retval = usb_unlink_urb(urb);
++ if (retval != -EINPROGRESS && retval != 0)
++ printk("unlink urb err, %d", retval);
++
++ spin_unlock_irqrestore(&bvd_ipc->lock, flags);
++ return retval;
++}
++
++static void append_to_inbuf_list(struct urb *urb)
++{
++ buf_list_t *inbuf;
++ int count = urb->actual_length;
++
++ inbuf = kmalloc(sizeof(buf_list_t), GFP_KERNEL);
++ if (!inbuf) {
++ printk("append_to_inbuf_list: (%d) out of memory!\n",
++ sizeof(buf_list_t));
++ return;
++ }
++
++ inbuf->size = count;
++ inbuf->body = kmalloc(sizeof(char)*count, GFP_KERNEL);
++ if (!inbuf->body) {
++ kfree(inbuf);
++ printk("append_to_inbuf_list: (%d) out of memory!\n",
++ sizeof(char)*count);
++ return;
++ }
++ memcpy(inbuf->body, (unsigned char*)urb->transfer_buffer, count);
++ list_add_tail(&inbuf->list, &bvd_ipc->in_buf_list);
++}
++
++static void ipcusb_timeout(unsigned long data)
++{
++ struct tty_struct *tty = &ipcusb_tty;
++ struct urb *urb = (struct urb *)data;
++
++ bvd_dbg("ipcusb_timeout***");
++
++ while (!(list_empty(&bvd_ipc->in_buf_list))) {
++ int count;
++ buf_list_t *inbuf;
++ struct list_head *ptr = NULL;
++
++ ptr = bvd_ipc->in_buf_list.next;
++ inbuf = list_entry (ptr, buf_list_t, list);
++ count = inbuf->size;
++ if (tty_insert_flip_string(tty, inbuf->body, count) >= count) {
++ list_del(ptr);
++ kfree(inbuf->body);
++ inbuf->body = NULL;
++ kfree(inbuf);
++ } else {
++ bvd_dbg("ipcusb_timeout: bvd_ipc->in_buf_list empty!");
++ break;
++ }
++ }
++
++ if (usb_mux_dispatcher)
++ usb_mux_dispatcher(tty); /**call Liu changhui's func.**/
++
++ if (list_empty(&bvd_ipc->in_buf_list)) {
++ urb->actual_length = 0;
++ urb->dev = bvd_ipc->ipc_dev;
++ if (usb_submit_urb(urb, GFP_ATOMIC))
++ bvd_dbg("ipcusb_timeout: failed resubmitting read urb");
++ bvd_dbg("ipcusb_timeout: resubmited read urb");
++ } else {
++ ipcusb_timer.data = (unsigned long)urb;
++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000));
++ }
++}
++
++static void usb_ipc_read_bulk(struct urb *urb, struct pt_regs *regs)
++{
++ buf_list_t *inbuf;
++ int count = urb->actual_length;
++ struct tty_struct *tty = &ipcusb_tty;
++
++ bvd_dbg("usb_ipc_read_bulk: begining!");
++ if (urb->status)
++ printk("nonzero read bulk status received: %d\n", urb->status);
++
++ bvd_dbg("usb_ipc_read_bulk: urb->actual_length=%d", urb->actual_length);
++ bvd_dbg("usb_ipc_read_bulk: urb->transfer_buffer:");
++
++ bvd_dbg_hex((unsigned char*)urb->transfer_buffer, urb->actual_length);
++
++ if (count > 0 && ((*ipcusb_bp_to_ap) != NULL))
++ (*ipcusb_bp_to_ap)(urb->transfer_buffer, urb->actual_length);
++
++ if (!(list_empty(&bvd_ipc->in_buf_list))) {
++ int need_mux = 0;
++
++ bvd_dbg("usb_ipc_read_bulk: some urbs in_buf_list");
++ if (count > 0) {
++ bvd_ipc->suspend_flag = 1;
++ append_to_inbuf_list(urb); /* append the current received urb */
++#if 0
++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL)
++ {
++ last_jiff = jiffies;
++ queue_apm_event(KRNL_ICL, NULL);
++ }
++#endif
++ }
++
++ while (!(list_empty(&bvd_ipc->in_buf_list))) {
++ struct list_head* ptr = NULL;
++ ptr = bvd_ipc->in_buf_list.next;
++ inbuf = list_entry(ptr, buf_list_t, list);
++ count = inbuf->size;
++ need_mux = 1;
++
++ tty_insert_flip_string(tty, inbuf->body, count);
++
++ list_del(ptr);
++ kfree(inbuf->body);
++ inbuf->body = NULL;
++ kfree(inbuf);
++ }
++
++ if (usb_mux_dispatcher && need_mux)
++ usb_mux_dispatcher(tty); /* call Liu changhui's func. */
++
++ if (list_empty(&bvd_ipc->in_buf_list)) {
++ urb->actual_length = 0;
++ urb->dev = bvd_ipc->ipc_dev;
++ if (usb_submit_urb(urb, GFP_ATOMIC))
++ bvd_dbg("usb_ipc_read_bulk: "
++ "failed resubmitting read urb");
++ bvd_dbg("usb_ipc_read_bulk: resubmited read urb");
++ } else {
++ ipcusb_timer.data = (unsigned long)urb;
++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000));
++ }
++ } else if (count > 0) {
++ bvd_dbg("usb_ipc_read_bulk: no urbs in_buf_list");
++ bvd_ipc->suspend_flag = 1;
++
++ if (tty_insert_flip_string(tty, urb->transfer_buffer,
++ count) < count) {
++ bvd_ipc->suspend_flag = 1;
++ append_to_inbuf_list(urb);
++ ipcusb_timer.data = (unsigned long)urb;
++ mod_timer(&ipcusb_timer, jiffies+(10*HZ/1000));
++#if 0
++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL)
++ {
++ last_jiff = jiffies;
++ queue_apm_event(KRNL_ICL, NULL);
++ }
++#endif
++ }
++
++ if (usb_mux_dispatcher)
++ usb_mux_dispatcher(tty); /* call Liu changhui's func. */
++
++ urb->actual_length = 0;
++ urb->dev = bvd_ipc->ipc_dev;
++ if (usb_submit_urb(urb, GFP_ATOMIC))
++ bvd_dbg("failed resubmitting read urb");
++#if 0
++ if(jiffies - last_jiff > ICL_EVENT_INTERVAL)
++ {
++ last_jiff = jiffies;
++ queue_apm_event(KRNL_ICL, NULL);
++ }
++#endif
++ bvd_dbg("usb_ipc_read_bulk: resubmited read urb");
++ }
++
++ bvd_dbg("usb_ipc_read_bulk: completed!!!");
++}
++
++static void usb_ipc_write_bulk(struct urb *urb, struct pt_regs *regs)
++{
++ callback_times++;
++ bvd_ipc->write_finished_flag = 1;
++
++ bvd_dbg("usb_ipc_write_bulk: begining!");
++ //printk("%s: write_finished_flag=%d\n", __FUNCTION__, bvd_ipc->write_finished_flag);
++
++ if (urb->status)
++ printk("nonzero write bulk status received: %d\n", urb->status);
++
++ if (usb_mux_sender)
++ usb_mux_sender(); /**call Liu changhui's func**/
++
++ //printk("usb_ipc_write_bulk: mark ipcusb_softint!\n");
++ tasklet_schedule(&bvd_ipc->bh);
++
++ bvd_dbg("usb_ipc_write_bulk: finished!");
++}
++
++static void wakeup_timeout(unsigned long data)
++{
++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW);
++ bvd_dbg("wakup_timeout: send GPIO_MCU_INT_SW signal!");
++}
++
++static void suspend_timeout(unsigned long data)
++{
++ if (bvd_ipc->suspend_flag == 1) {
++ bvd_ipc->suspend_flag = 0;
++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000));
++ bvd_dbg("suspend_timeout: add the suspend timer again");
++ } else {
++ unlink_urbs(&bvd_ipc->readurb_mux);
++ UHCRHPS3 = 0x4;
++ mdelay(40);
++ bvd_dbg("suspend_timeout: send SUSPEND signal! UHCRHPS3=0x%x",
++ UHCRHPS3);
++ }
++}
++
++static void ipcusb_xmit_data(void)
++{
++ int c, count = IPC_URB_SIZE;
++ int result = 0;
++ int buf_flag = 0;
++ int buf_num = 0;
++
++ //printk("%s: sumbit_times=%d, callback_times=%d\n", __FUNCTION__, sumbit_times, callback_times);
++ if (bvd_ipc->write_finished_flag == 0)
++ return;
++
++ while (1) {
++ c = CIRC_CNT_TO_END(bvd_ipc->xmit.head, bvd_ipc->xmit.tail,
++ IPC_USB_XMIT_SIZE);
++ if (count < c)
++ c = count;
++ if (c <= 0)
++ break;
++
++ memcpy(bvd_ipc->obuf+buf_num,
++ bvd_ipc->xmit.buf + bvd_ipc->xmit.tail, c);
++ buf_flag = 1;
++ bvd_ipc->xmit.tail = ((bvd_ipc->xmit.tail + c)
++ & (IPC_USB_XMIT_SIZE-1));
++ count -= c;
++ buf_num += c;
++ }
++
++ if (buf_num == 0) {
++ bvd_dbg("ipcusb_xmit_data: buf_num=%d, add suspend_timer",
++ buf_num);
++ bvd_ipc->suspend_flag = 0;
++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000));
++ }
++
++ bvd_dbg("ipcusb_xmit_data: buf_num=%d", buf_num);
++ bvd_dbg("ipcusb_xmit_data: bvd_ipc->obuf: ");
++
++ bvd_dbg_hex((bvd_ipc->obuf)-buf_num, buf_num);
++
++ if (buf_flag) {
++ bvd_ipc->writeurb_mux.transfer_buffer_length = buf_num;
++ bvd_dbg("ipcusb_xmit_data: copy data to write urb finished! ");
++
++ if ((UHCRHPS3 & 0x4) == 0x4) {
++ static int ret;
++ int time = 0;
++
++ /* if BP sleep, wake up BP first */
++ pxa_gpio_mode(GPIO_IN | 41);
++ if (GPIO_is_high(41)) {
++ if (GPIO_is_high(GPIO_MCU_INT_SW))
++ GPCR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW);
++ else
++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW);
++
++ time = jiffies;
++ while (GPIO_is_high(41) && (jiffies < (time+HZ)));
++
++ if (GPIO_is_high(41)) {
++ printk("%s: Wakeup BP timeout! BP state is %d\n",
++ __FUNCTION__, GPIO_is_high(41));
++ }
++ if (GPIO_is_high(GPIO_MCU_INT_SW))
++ GPCR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW);
++ else
++ GPSR(GPIO_MCU_INT_SW) = GPIO_bit(GPIO_MCU_INT_SW);
++ }
++
++ /* Resume BP */
++ UHCRHPS3 = 0x8;
++ mdelay(40);
++ bvd_dbg("ipcusb_xmit_data: Send RESUME signal! UHCRHPS3=0x%x",
++ UHCRHPS3);
++ /*send IN token*/
++ bvd_ipc->readurb_mux.actual_length = 0;
++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev;
++ if (ret = usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC))
++ printk("ipcusb_xmit_data: usb_submit_urb(read mux bulk)"
++ "failed! status=%d\n", ret);
++ bvd_dbg("ipcusb_xmit_data: Send a IN token successfully!");
++ }
++
++ sumbit_times++;
++ bvd_ipc->write_finished_flag = 0;
++ //printk("%s: clear write_finished_flag:%d\n", __FUNCTION__, bvd_ipc->write_finished_flag);
++ bvd_ipc->writeurb_mux.dev = bvd_ipc->ipc_dev;
++ if (result = usb_submit_urb(&bvd_ipc->writeurb_mux, GFP_ATOMIC))
++ warn("ipcusb_xmit_data: funky result! result=%d\n", result);
++
++ bvd_dbg("ipcusb_xmit_data: usb_submit_urb finished! result:%d", result);
++
++ }
++}
++
++static void usbipc_bh_func(unsigned long param)
++{
++ ipcusb_xmit_data();
++}
++
++extern void get_halted_bit(void);
++
++static void usbipc_bh_bp_func(unsigned long param)
++{
++ if ((UHCRHPS3 & 0x4) == 0x4) {
++ UHCRHPS3 = 0x8;
++ mdelay(40);
++ bvd_dbg("ipcusb_softint_send_readurb: Send RESUME signal! "
++ "UHCRHPS3=0x%x", UHCRHPS3);
++ }
++ if (bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) {
++ get_halted_bit();
++
++ /*send a IN token*/
++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev;
++ if (usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC)) {
++ bvd_dbg("ipcusb_softint_send_readurb: "
++ "usb_submit_urb(read mux bulk) failed!");
++ }
++ bvd_dbg("ipcusb_softint_send_readurb: Send a IN token successfully!");
++ bvd_ipc->suspend_flag = 0;
++ bvd_dbg("ipcusb_softint_send_readurb: add suspend_timer");
++ mod_timer(&suspend_timer, jiffies+(5000*HZ/1000));
++ }
++}
++
++static int usb_ipc_write(struct tty_struct *tty,
++ const unsigned char *buf, int count)
++{
++ int c, ret = 0;
++
++ bvd_dbg("usb_ipc_write: count=%d, buf: ", count);
++ bvd_dbg_hex(buf, count);
++
++ if (count <= 0)
++ return 0;
++
++ if (*ipcusb_ap_to_bp != NULL)
++ (*ipcusb_ap_to_bp)(buf, count);
++
++ bvd_ipc->suspend_flag = 1;
++
++ if ((bvd_ipc->ipc_flag == IPC_USB_PROBE_READY) &&
++ (bvd_ipc->xmit.head == bvd_ipc->xmit.tail)) {
++ bvd_dbg("usb_ipc_write: set write_flag");
++ bvd_ipc->write_flag = IPC_USB_WRITE_XMIT;
++ }
++
++ while (1) {
++ c = CIRC_SPACE_TO_END(bvd_ipc->xmit.head,
++ bvd_ipc->xmit.tail, IPC_USB_XMIT_SIZE);
++ if (count < c)
++ c = count;
++ if (c <= 0)
++ break;
++
++ memcpy(bvd_ipc->xmit.buf + bvd_ipc->xmit.head, buf, c);
++ bvd_ipc->xmit.head = ((bvd_ipc->xmit.head + c)
++ & (IPC_USB_XMIT_SIZE-1));
++ buf += c;
++ count -= c;
++ ret += c;
++ }
++ bvd_dbg("usb_ipc_write: ret=%d, bvd_ipc->xmit.buf: ", ret);
++
++ bvd_dbg_hex(bvd_ipc->xmit.buf, ret);
++
++ if (bvd_ipc->write_flag == IPC_USB_WRITE_XMIT) {
++ bvd_ipc->write_flag = IPC_USB_WRITE_INIT;
++ bvd_dbg("usb_ipc_write: mark ipcusb_softint");
++ tasklet_schedule(&bvd_ipc->bh);
++ }
++
++ bvd_dbg("usb_ipc_write: ret=%d\n", ret);
++ return ret;
++}
++
++static int usb_ipc_chars_in_buffer(struct tty_struct *tty)
++{
++ return CIRC_CNT(bvd_ipc->xmit.head, bvd_ipc->xmit.tail, IPC_USB_XMIT_SIZE);
++}
++
++void usb_send_readurb(void)
++{
++ //printk("usb_send_readurb: begining!UHCRHPS3=0x%x, usbh_finished_resume=%d\n", UHCRHPS3, usbh_finished_resume);
++
++ if (usbh_finished_resume == 0)
++ return;
++
++ tasklet_schedule(&bvd_ipc->bh_bp);
++}
++
++static int usb_ipc_probe(struct usb_interface *intf,
++ const struct usb_device_id *id)
++{
++ struct usb_device *usbdev = interface_to_usbdev(intf);
++ struct usb_config_descriptor *ipccfg;
++ struct usb_interface_descriptor *interface;
++ struct usb_endpoint_descriptor *endpoint;
++ int ep_cnt, readsize, writesize;
++ char have_bulk_in_mux, have_bulk_out_mux;
++
++ bvd_dbg("usb_ipc_probe: vendor id 0x%x, device id 0x%x",
++ usbdev->descriptor.idVendor, usbdev->descriptor.idProduct);
++
++ if ((usbdev->descriptor.idVendor != MOTO_IPC_VID) ||
++ (usbdev->descriptor.idProduct != MOTO_IPC_PID))
++ return -ENODEV;
++
++ /* a2590c : dsplog interface is not supported by this driver */
++ if (intf->minor == 2) /* dsplog interface number is 2 */
++ return -1;
++
++ bvd_dbg("usb_ipc_probe: USB dev address:%p", usbdev);
++ bvd_dbg("usb_ipc_probe: ifnum:%u", intf->minor);
++
++ ipccfg = &usbdev->actconfig->desc;
++ bvd_dbg("usb_ipc_prob: config%d", ipccfg->bConfigurationValue);
++ bvd_dbg("usb_ipc_prob: bNumInterfaces = %d", ipccfg->bNumInterfaces);
++
++ /* After this point we can be a little noisy about what we are trying
++ * to configure, hehe. */
++ if (usbdev->descriptor.bNumConfigurations != 1) {
++ info("usb_ipc_probe: Only one device configuration "
++ "is supported.");
++ return -1;
++ }
++
++ if (usbdev->config[0].desc.bNumInterfaces != 3) {
++ info("usb_ipc_probe: Only three device interfaces are "
++ "supported.");
++ return -1;
++ }
++
++ interface = &intf->cur_altsetting->desc;
++ endpoint = &intf->cur_altsetting->endpoint[0].desc;
++ /* Start checking for two bulk endpoints or ... FIXME: This is a future
++ * enhancement...*/
++ bvd_dbg("usb_ipc_probe: Number of Endpoints:%d",
++ (int) interface->bNumEndpoints);
++ if (interface->bNumEndpoints != 2) {
++ info("usb_ipc_probe: Only two endpoints supported.");
++ return -1;
++ }
++
++ ep_cnt = have_bulk_in_mux = have_bulk_out_mux = 0;
++
++ bvd_dbg("usb_ipc_probe: endpoint[0] is:%x",
++ (&endpoint[0])->bEndpointAddress);
++ bvd_dbg("usb_ipc_probe: endpoint[1] is:%x ",
++ (&endpoint[1])->bEndpointAddress);
++
++ while (ep_cnt < interface->bNumEndpoints) {
++
++ if (!have_bulk_in_mux && IS_EP_BULK_IN(endpoint[ep_cnt])) {
++ bvd_dbg("usb_ipc_probe: bEndpointAddress(IN) is:%x ",
++ (&endpoint[ep_cnt])->bEndpointAddress);
++ have_bulk_in_mux =
++ (&endpoint[ep_cnt])->bEndpointAddress;
++ readsize = (&endpoint[ep_cnt])->wMaxPacketSize;
++ bvd_dbg("usb_ipc_probe: readsize=%d", readsize);
++ ep_cnt++;
++ continue;
++ }
++
++ if (!have_bulk_out_mux && IS_EP_BULK_OUT(endpoint[ep_cnt])) {
++ bvd_dbg("usb_ipc_probe: bEndpointAddress(OUT) is:%x ",
++ (&endpoint[ep_cnt])->bEndpointAddress);
++ have_bulk_out_mux =
++ (&endpoint[ep_cnt])->bEndpointAddress;
++ writesize = (&endpoint[ep_cnt])->wMaxPacketSize;
++ bvd_dbg("usb_ipc_probe: writesize=%d", writesize);
++ ep_cnt++;
++ continue;
++ }
++
++ info("usb_ipc_probe: Undetected endpoint ^_^ ");
++ /* Shouldn't ever get here unless we have something weird */
++ return -1;
++ }
++
++ /* Perform a quick check to make sure that everything worked as it
++ * should have. */
++
++ switch (interface->bNumEndpoints) {
++ case 2:
++ if (!have_bulk_in_mux || !have_bulk_out_mux) {
++ info("usb_ipc_probe: Two bulk endpoints required.");
++ return -1;
++ }
++ break;
++ default:
++ info("usb_ipc_probe: Endpoint determination failed ^_^ ");
++ return -1;
++ }
++
++ /* Ok, now initialize all the relevant values */
++ if (!(bvd_ipc->obuf = (char *)kmalloc(writesize, GFP_KERNEL))) {
++ err("usb_ipc_probe: Not enough memory for the output buffer.");
++ kfree(bvd_ipc);
++ return -1;
++ }
++ bvd_dbg("usb_ipc_probe: obuf address:%p", bvd_ipc->obuf);
++
++ if (!(bvd_ipc->ibuf = (char *)kmalloc(readsize, GFP_KERNEL))) {
++ err("usb_ipc_probe: Not enough memory for the input buffer.");
++ kfree(bvd_ipc->obuf);
++ kfree(bvd_ipc);
++ return -1;
++ }
++ bvd_dbg("usb_ipc_probe: ibuf address:%p", bvd_ipc->ibuf);
++
++ bvd_ipc->ipc_flag = IPC_USB_PROBE_READY;
++ bvd_ipc->write_finished_flag = 1;
++ bvd_ipc->suspend_flag = 1;
++ bvd_ipc->bulk_in_ep_mux= have_bulk_in_mux;
++ bvd_ipc->bulk_out_ep_mux= have_bulk_out_mux;
++ bvd_ipc->ipc_dev = usbdev;
++ bvd_ipc->writesize = writesize;
++ INIT_LIST_HEAD (&bvd_ipc->in_buf_list);
++
++ bvd_ipc->bh.func = usbipc_bh_func;
++ bvd_ipc->bh.data = (unsigned long) bvd_ipc;
++
++ bvd_ipc->bh_bp.func = usbipc_bh_bp_func;
++ bvd_ipc->bh_bp.data = (unsigned long) bvd_ipc;
++
++ /*Build a write urb*/
++ usb_fill_bulk_urb(&bvd_ipc->writeurb_mux, usbdev,
++ usb_sndbulkpipe(bvd_ipc->ipc_dev,
++ bvd_ipc->bulk_out_ep_mux),
++ bvd_ipc->obuf, writesize, usb_ipc_write_bulk,
++ bvd_ipc);
++ //bvd_ipc->writeurb_mux.transfer_flags |= USB_ASYNC_UNLINK;
++
++ /*Build a read urb and send a IN token first time*/
++ usb_fill_bulk_urb(&bvd_ipc->readurb_mux, usbdev,
++ usb_rcvbulkpipe(usbdev, bvd_ipc->bulk_in_ep_mux),
++ bvd_ipc->ibuf, readsize, usb_ipc_read_bulk, bvd_ipc);
++ //bvd_ipc->readurb_mux.transfer_flags |= USB_ASYNC_UNLINK;
++
++ usb_driver_claim_interface(&usb_ipc_driver, intf, bvd_ipc);
++ //usb_driver_claim_interface(&usb_ipc_driver, &ipccfg->interface[1], bvd_ipc);
++
++ // a2590c: dsplog is not supported by this driver
++ // usb_driver_claim_interface(&usb_ipc_driver,
++ // &ipccfg->interface[2], bvd_ipc);
++ /*send a IN token first time*/
++ bvd_ipc->readurb_mux.dev = bvd_ipc->ipc_dev;
++ if (usb_submit_urb(&bvd_ipc->readurb_mux, GFP_ATOMIC))
++ printk("usb_ipc_prob: usb_submit_urb(read mux bulk) failed!\n");
++
++ bvd_dbg("usb_ipc_prob: Send a IN token successfully!");
++
++ if (bvd_ipc->xmit.head != bvd_ipc->xmit.tail) {
++ printk("usb_ipc_probe: mark ipcusb_softint!\n");
++ tasklet_schedule(&bvd_ipc->bh);
++ }
++
++ printk("usb_ipc_probe: completed probe!");
++ usb_set_intfdata(intf, &bvd_ipc);
++ return 0;
++}
++
++static void usb_ipc_disconnect(struct usb_interface *intf)
++{
++ //struct usb_device *usbdev = interface_to_usbdev(intf);
++ struct ipc_usb_data *bvd_ipc_disconnect = usb_get_intfdata(intf);
++
++ printk("usb_ipc_disconnect:*** \n");
++
++ if ((UHCRHPS3 & 0x4) == 0)
++ usb_unlink_urb(&bvd_ipc_disconnect->readurb_mux);
++
++ usb_unlink_urb(&bvd_ipc_disconnect->writeurb_mux);
++
++ bvd_ipc_disconnect->ipc_flag = IPC_USB_PROBE_NOT_READY;
++ kfree(bvd_ipc_disconnect->ibuf);
++ kfree(bvd_ipc_disconnect->obuf);
++
++ usb_driver_release_interface(&usb_ipc_driver,
++ bvd_ipc_disconnect->ipc_dev->actconfig->interface[0]);
++ usb_driver_release_interface(&usb_ipc_driver,
++ bvd_ipc_disconnect->ipc_dev->actconfig->interface[1]);
++
++ //a2590c: dsplog interface is not supported by this driver
++ //usb_driver_release_interface(&usb_ipc_driver, &bvd_ipc_disconnect->ipc_dev->actconfig->interface[2]);
++
++ bvd_ipc_disconnect->ipc_dev = NULL;
++
++ usb_set_intfdata(intf, NULL);
++
++ printk("usb_ipc_disconnect completed!\n");
++}
++
++static struct usb_device_id usb_ipc_id_table[] = {
++ { USB_DEVICE(MOTO_IPC_VID, MOTO_IPC_PID) },
++ { } /* Terminating entry */
++};
++
++static struct usb_driver usb_ipc_driver = {
++ .name = "usb ipc",
++ .probe = usb_ipc_probe,
++ .disconnect = usb_ipc_disconnect,
++ .id_table = usb_ipc_id_table,
++};
++
++static int __init usb_ipc_init(void)
++{
++ int result;
++
++ bvd_dbg("init usb_ipc");
++ /* register driver at the USB subsystem */
++ result = usb_register(&usb_ipc_driver);
++ if (result < 0) {
++ err ("usb ipc driver could not be registered");
++ return result;
++ }
++
++ /*init the related mux interface*/
++ if (!(bvd_ipc = kzalloc(sizeof(struct ipc_usb_data), GFP_KERNEL))) {
++ err("usb_ipc_init: Out of memory.");
++ usb_deregister(&usb_ipc_driver);
++ return -ENOMEM;
++ }
++ bvd_dbg("usb_ipc_init: Address of bvd_ipc:%p", bvd_ipc);
++
++ if (!(bvd_ipc->xmit.buf = kmalloc(IPC_USB_XMIT_SIZE, GFP_KERNEL))) {
++ err("usb_ipc_init: Not enough memory for the input buffer.");
++ kfree(bvd_ipc);
++ usb_deregister(&usb_ipc_driver);
++ return -ENOMEM;
++ }
++ bvd_dbg("usb_ipc_init: bvd_ipc->xmit.buf address:%p",
++ bvd_ipc->xmit.buf);
++ bvd_ipc->ipc_dev = NULL;
++ bvd_ipc->xmit.head = bvd_ipc->xmit.tail = 0;
++ bvd_ipc->write_flag = IPC_USB_WRITE_INIT;
++
++ ipcusb_tty_driver.write = usb_ipc_write;
++ ipcusb_tty_driver.chars_in_buffer = usb_ipc_chars_in_buffer;
++
++ usb_for_mux_driver = &ipcusb_tty_driver;
++ usb_for_mux_tty = &ipcusb_tty;
++
++ /* init timers for ipcusb read process and usb suspend */
++ init_timer(&ipcusb_timer);
++ ipcusb_timer.function = ipcusb_timeout;
++
++ init_timer(&suspend_timer);
++ suspend_timer.function = suspend_timeout;
++
++ init_timer(&wakeup_timer);
++ wakeup_timer.function = wakeup_timeout;
++
++ info("USB Host(Bulverde) IPC driver registered.");
++ info(DRIVER_VERSION ":" DRIVER_DESC);
++
++ return 0;
++}
++
++static void __exit usb_ipc_exit(void)
++{
++ bvd_dbg("cleanup bvd_ipc");
++
++ kfree(bvd_ipc->xmit.buf);
++ kfree(bvd_ipc);
++ usb_deregister(&usb_ipc_driver);
++
++ info("USB Host(Bulverde) IPC driver deregistered.");
++}
++
++module_init(usb_ipc_init);
++module_exit(usb_ipc_exit);
++EXPORT_SYMBOL(usb_send_readurb);
+Index: linux-2.6.24/drivers/char/ts0710_mux_usb.h
+===================================================================
+--- /dev/null
++++ linux-2.6.24/drivers/char/ts0710_mux_usb.h
+@@ -0,0 +1,29 @@
++/*
++ * linux/drivers/usb/ipcusb.h
++ *
++ * Implementation of a ipc driver based Intel's Bulverde USB Host
++ * Controller.
++ *
++ * Copyright (C) 2003-2005 Motorola
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ *
++ * 2003-Nov-18 - (Motorola) created
++ *
++ */
++extern struct tty_driver *usb_for_mux_driver;
++extern struct tty_struct *usb_for_mux_tty;
++extern void (*usb_mux_dispatcher)(struct tty_struct *tty);
++extern void (*usb_mux_sender)(void);