diff options
Diffstat (limited to 'packages/linux/linux-ezx-2.6.21/mux_cli.patch')
-rw-r--r-- | packages/linux/linux-ezx-2.6.21/mux_cli.patch | 5395 |
1 files changed, 5395 insertions, 0 deletions
diff --git a/packages/linux/linux-ezx-2.6.21/mux_cli.patch b/packages/linux/linux-ezx-2.6.21/mux_cli.patch new file mode 100644 index 0000000000..2964f24fd2 --- /dev/null +++ b/packages/linux/linux-ezx-2.6.21/mux_cli.patch @@ -0,0 +1,5395 @@ +Index: linux-2.6.21/drivers/char/Kconfig +=================================================================== +--- linux-2.6.21.orig/drivers/char/Kconfig 2007-04-26 20:07:19.000000000 +0200 ++++ linux-2.6.21/drivers/char/Kconfig 2007-04-26 20:09:29.000000000 +0200 +@@ -1071,5 +1071,17 @@ + /sys/devices/platform/telco_clock, with a number of files for + controlling the behavior of this hardware. + ++config TS0710_MUX ++ tristate "GSM TS 07.10 Multiplex driver" ++ 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.21/drivers/char/Makefile +=================================================================== +--- linux-2.6.21.orig/drivers/char/Makefile 2007-04-26 20:07:19.000000000 +0200 ++++ linux-2.6.21/drivers/char/Makefile 2007-04-26 20:09:29.000000000 +0200 +@@ -104,6 +104,9 @@ + obj-$(CONFIG_HANGCHECK_TIMER) += hangcheck-timer.o + obj-$(CONFIG_TCG_TPM) += tpm/ + ++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.21/drivers/char/ts0710.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/char/ts0710.h 2007-04-26 20:09:29.000000000 +0200 +@@ -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.21/drivers/char/ts0710_mux.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/char/ts0710_mux.c 2007-04-26 20:09:29.000000000 +0200 +@@ -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.21/drivers/char/ts0710_mux.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/char/ts0710_mux.h 2007-04-26 20:09:29.000000000 +0200 +@@ -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.21/drivers/char/ts0710_mux_usb.c +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/char/ts0710_mux_usb.c 2007-04-26 20:09:29.000000000 +0200 +@@ -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.21/drivers/char/ts0710_mux_usb.h +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ linux-2.6.21/drivers/char/ts0710_mux_usb.h 2007-04-26 20:09:29.000000000 +0200 +@@ -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); |