zte's code,first commit

Change-Id: I9a04da59e459a9bc0d67f101f700d9d7dc8d681b
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Kconfig b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Kconfig
new file mode 100644
index 0000000..e9b2dd8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Kconfig
@@ -0,0 +1,10 @@
+config ISDN_DRV_PCBIT
+	tristate "PCBIT-D support"
+	depends on ISA && (BROKEN || X86)
+	help
+	  This enables support for the PCBIT ISDN-card.  This card is
+	  manufactured in Portugal by Octal.  For running this card,
+	  additional firmware is necessary, which has to be downloaded into
+	  the card using a utility which is distributed separately.  See
+	  <file:Documentation/isdn/README> and
+	  <file:Documentation/isdn/README.pcbit> for more information.
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Makefile b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Makefile
new file mode 100644
index 0000000..2d026c3
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/Makefile
@@ -0,0 +1,9 @@
+# Makefile for the pcbit ISDN device driver
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ISDN_DRV_PCBIT)	+= pcbit.o
+
+# Multipart objects.
+
+pcbit-y				:= module.o edss1.o drv.o layer2.o capi.o callbacks.o
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.c
new file mode 100644
index 0000000..efb6d6a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.c
@@ -0,0 +1,345 @@
+/*
+ * Callbacks for the FSM
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * Fix: 19981230 - Carlos Morgado <chbm@techie.com>
+ * Port of Nelson Escravana's <nelson.escravana@usa.net> fix to CalledPN
+ * NULL pointer dereference in cb_in_1 (originally fixed in 2.0)
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "layer2.h"
+#include "edss1.h"
+#include "callbacks.h"
+#include "capi.h"
+
+ushort last_ref_num = 1;
+
+/*
+ *  send_conn_req
+ *
+ */
+
+void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	      struct callb_data *cbdata)
+{
+	struct sk_buff *skb;
+	int len;
+	ushort refnum;
+
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Called Party Number: %s\n",
+	       cbdata->data.setup.CalledPN);
+#endif
+	/*
+	 * hdr - kmalloc in capi_conn_req
+	 *     - kfree   when msg has been sent
+	 */
+
+	if ((len = capi_conn_req(cbdata->data.setup.CalledPN, &skb,
+				 chan->proto)) < 0)
+	{
+		printk("capi_conn_req failed\n");
+		return;
+	}
+
+
+	refnum = last_ref_num++ & 0x7fffU;
+
+	chan->callref = 0;
+	chan->layer2link = 0;
+	chan->snum = 0;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_CONN_REQ, refnum, skb, len);
+}
+
+/*
+ *  rcv CONNECT
+ *  will go into ACTIVE state
+ *  send CONN_ACTIVE_RESP
+ *  send Select protocol request
+ */
+
+void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	      struct callb_data *data)
+{
+	isdn_ctrl ictl;
+	struct sk_buff *skb;
+	int len;
+	ushort refnum;
+
+	if ((len = capi_conn_active_resp(chan, &skb)) < 0)
+	{
+		printk("capi_conn_active_req failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_CONN_ACTV_RESP, refnum, skb, len);
+
+
+	ictl.command = ISDN_STAT_DCONN;
+	ictl.driver = dev->id;
+	ictl.arg = chan->id;
+	dev->dev_if->statcallb(&ictl);
+
+	/* ACTIVE D-channel */
+
+	/* Select protocol  */
+
+	if ((len = capi_select_proto_req(chan, &skb, 1 /*outgoing*/)) < 0) {
+		printk("capi_select_proto_req failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
+}
+
+
+/*
+ * Incoming call received
+ * inform user
+ */
+
+void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	     struct callb_data *cbdata)
+{
+	isdn_ctrl ictl;
+	unsigned short refnum;
+	struct sk_buff *skb;
+	int len;
+
+
+	ictl.command = ISDN_STAT_ICALL;
+	ictl.driver = dev->id;
+	ictl.arg = chan->id;
+
+	/*
+	 *  ictl.num >= strlen() + strlen() + 5
+	 */
+
+	if (cbdata->data.setup.CallingPN == NULL) {
+		printk(KERN_DEBUG "NULL CallingPN to phone; using 0\n");
+		strcpy(ictl.parm.setup.phone, "0");
+	}
+	else {
+		strcpy(ictl.parm.setup.phone, cbdata->data.setup.CallingPN);
+	}
+	if (cbdata->data.setup.CalledPN == NULL) {
+		printk(KERN_DEBUG "NULL CalledPN to eazmsn; using 0\n");
+		strcpy(ictl.parm.setup.eazmsn, "0");
+	}
+	else {
+		strcpy(ictl.parm.setup.eazmsn, cbdata->data.setup.CalledPN);
+	}
+	ictl.parm.setup.si1 = 7;
+	ictl.parm.setup.si2 = 0;
+	ictl.parm.setup.plan = 0;
+	ictl.parm.setup.screen = 0;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "statstr: %s\n", ictl.num);
+#endif
+
+	dev->dev_if->statcallb(&ictl);
+
+
+	if ((len = capi_conn_resp(chan, &skb)) < 0) {
+		printk(KERN_DEBUG "capi_conn_resp failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_CONN_RESP, refnum, skb, len);
+}
+
+/*
+ * user has replied
+ * open the channel
+ * send CONNECT message CONNECT_ACTIVE_REQ in CAPI
+ */
+
+void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	     struct callb_data *data)
+{
+	unsigned short refnum;
+	struct sk_buff *skb;
+	int len;
+
+	if ((len = capi_conn_active_req(chan, &skb)) < 0) {
+		printk(KERN_DEBUG "capi_conn_active_req failed\n");
+		return;
+	}
+
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	printk(KERN_DEBUG "sending MSG_CONN_ACTV_REQ\n");
+	pcbit_l2_write(dev, MSG_CONN_ACTV_REQ, refnum, skb, len);
+}
+
+/*
+ * CONN_ACK arrived
+ * start b-proto selection
+ *
+ */
+
+void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	     struct callb_data *data)
+{
+	unsigned short refnum;
+	struct sk_buff *skb;
+	int len;
+
+	if ((len = capi_select_proto_req(chan, &skb, 0 /*incoming*/)) < 0)
+	{
+		printk("capi_select_proto_req failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_SELP_REQ, refnum, skb, len);
+
+}
+
+
+/*
+ * Received disconnect ind on active state
+ * send disconnect resp
+ * send msg to user
+ */
+void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	       struct callb_data *data)
+{
+	struct sk_buff *skb;
+	int len;
+	ushort refnum;
+	isdn_ctrl ictl;
+
+	if ((len = capi_disc_resp(chan, &skb)) < 0) {
+		printk("capi_disc_resp failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_DISC_RESP, refnum, skb, len);
+
+	ictl.command = ISDN_STAT_BHUP;
+	ictl.driver = dev->id;
+	ictl.arg = chan->id;
+	dev->dev_if->statcallb(&ictl);
+}
+
+
+/*
+ *  User HANGUP on active/call proceeding state
+ *  send disc.req
+ */
+void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	       struct callb_data *data)
+{
+	struct sk_buff *skb;
+	int len;
+	ushort refnum;
+
+	if ((len = capi_disc_req(chan->callref, &skb, CAUSE_NORMAL)) < 0)
+	{
+		printk("capi_disc_req failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb, len);
+}
+
+/*
+ *  Disc confirm received send BHUP
+ *  Problem: when the HL driver sends the disc req itself
+ *           LL receives BHUP
+ */
+void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	       struct callb_data *data)
+{
+	isdn_ctrl ictl;
+
+	ictl.command = ISDN_STAT_BHUP;
+	ictl.driver = dev->id;
+	ictl.arg = chan->id;
+	dev->dev_if->statcallb(&ictl);
+}
+
+void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		struct callb_data *data)
+{
+}
+
+/*
+ * send activate b-chan protocol
+ */
+void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	       struct callb_data *data)
+{
+	struct sk_buff *skb;
+	int len;
+	ushort refnum;
+
+	if ((len = capi_activate_transp_req(chan, &skb)) < 0)
+	{
+		printk("capi_conn_activate_transp_req failed\n");
+		return;
+	}
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_ACT_TRANSP_REQ, refnum, skb, len);
+}
+
+/*
+ *  Inform User that the B-channel is available
+ */
+void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
+	     struct callb_data *data)
+{
+	isdn_ctrl ictl;
+
+	ictl.command = ISDN_STAT_BCONN;
+	ictl.driver = dev->id;
+	ictl.arg = chan->id;
+	dev->dev_if->statcallb(&ictl);
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.h b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.h
new file mode 100644
index 0000000..a036b4a
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/callbacks.h
@@ -0,0 +1,44 @@
+/*
+ * Callbacks prototypes for FSM
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef CALLBACKS_H
+#define CALLBACKS_H
+
+
+extern void cb_out_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		     struct callb_data *data);
+
+extern void cb_out_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		     struct callb_data *data);
+
+extern void cb_in_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		    struct callb_data *data);
+extern void cb_in_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		    struct callb_data *data);
+extern void cb_in_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		    struct callb_data *data);
+
+extern void cb_disc_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		      struct callb_data *data);
+extern void cb_disc_2(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		      struct callb_data *data);
+extern void cb_disc_3(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		      struct callb_data *data);
+
+extern void cb_notdone(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		       struct callb_data *data);
+
+extern void cb_selp_1(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		      struct callb_data *data);
+extern void cb_open(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		    struct callb_data *data);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.c
new file mode 100644
index 0000000..4e3cbf8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.c
@@ -0,0 +1,649 @@
+/*
+ * CAPI encoder/decoder for
+ * Portugal Telecom CAPI 2.0
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ *
+ * Not compatible with the AVM Gmbh. CAPI 2.0
+ *
+ */
+
+/*
+ *        Documentation:
+ *        - "Common ISDN API - Perfil Português - Versão 2.1",
+ *           Telecom Portugal, Fev 1992.
+ *        - "Common ISDN API - Especificação de protocolos para
+ *           acesso aos canais B", Inesc, Jan 1994.
+ */
+
+/*
+ *        TODO: better decoding of Information Elements
+ *              for debug purposes mainly
+ *              encode our number in CallerPN and ConnectedPN
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <linux/skbuff.h>
+
+#include <asm/io.h>
+#include <asm/string.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "capi.h"
+
+
+/*
+ *  Encoding of CAPI messages
+ *
+ */
+
+int capi_conn_req(const char *calledPN, struct sk_buff **skb, int proto)
+{
+	ushort len;
+
+	/*
+	 * length
+	 *   AppInfoMask - 2
+	 *   BC0         - 3
+	 *   BC1         - 1
+	 *   Chan        - 2
+	 *   Keypad      - 1
+	 *   CPN         - 1
+	 *   CPSA        - 1
+	 *   CalledPN    - 2 + strlen
+	 *   CalledPSA   - 1
+	 *   rest...     - 4
+	 *   ----------------
+	 *   Total        18 + strlen
+	 */
+
+	len = 18 + strlen(calledPN);
+
+	if (proto == ISDN_PROTO_L2_TRANS)
+		len++;
+
+	if ((*skb = dev_alloc_skb(len)) == NULL) {
+
+		printk(KERN_WARNING "capi_conn_req: alloc_skb failed\n");
+		return -1;
+	}
+
+	/* InfoElmMask */
+	*((ushort *)skb_put(*skb, 2)) = AppInfoMask;
+
+	if (proto == ISDN_PROTO_L2_TRANS)
+	{
+		/* Bearer Capability - Mandatory*/
+		*(skb_put(*skb, 1)) = 3;        /* BC0.Length		*/
+		*(skb_put(*skb, 1)) = 0x80;     /* Speech		*/
+		*(skb_put(*skb, 1)) = 0x10;     /* Circuit Mode		*/
+		*(skb_put(*skb, 1)) = 0x23;     /* A-law		*/
+	}
+	else
+	{
+		/* Bearer Capability - Mandatory*/
+		*(skb_put(*skb, 1)) = 2;        /* BC0.Length		*/
+		*(skb_put(*skb, 1)) = 0x88;     /* Digital Information	*/
+		*(skb_put(*skb, 1)) = 0x90;     /* BC0.Octect4		*/
+	}
+
+	/* Bearer Capability - Optional*/
+	*(skb_put(*skb, 1)) = 0;        /* BC1.Length = 0                    */
+
+	*(skb_put(*skb, 1)) = 1;        /* ChannelID.Length = 1              */
+	*(skb_put(*skb, 1)) = 0x83;     /* Basic Interface - Any Channel     */
+
+	*(skb_put(*skb, 1)) = 0;        /* Keypad.Length = 0                 */
+
+
+	*(skb_put(*skb, 1)) = 0;        /* CallingPN.Length = 0              */
+	*(skb_put(*skb, 1)) = 0;        /* CallingPSA.Length = 0             */
+
+	/* Called Party Number */
+	*(skb_put(*skb, 1)) = strlen(calledPN) + 1;
+	*(skb_put(*skb, 1)) = 0x81;
+	memcpy(skb_put(*skb, strlen(calledPN)), calledPN, strlen(calledPN));
+
+	/* '#' */
+
+	*(skb_put(*skb, 1)) = 0;       /* CalledPSA.Length = 0     */
+
+	/* LLC.Length  = 0; */
+	/* HLC0.Length = 0; */
+	/* HLC1.Length = 0; */
+	/* UTUS.Length = 0; */
+	memset(skb_put(*skb, 4), 0, 4);
+
+	return len;
+}
+
+int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+
+	if ((*skb = dev_alloc_skb(5)) == NULL) {
+
+		printk(KERN_WARNING "capi_conn_resp: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+	*(skb_put(*skb, 1)) = 0x01;  /* ACCEPT_CALL */
+	*(skb_put(*skb, 1)) = 0;
+	*(skb_put(*skb, 1)) = 0;
+
+	return 5;
+}
+
+int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+	/*
+	 * 8 bytes
+	 */
+
+	if ((*skb = dev_alloc_skb(8)) == NULL) {
+
+		printk(KERN_WARNING "capi_conn_active_req: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
+#endif
+
+	*(skb_put(*skb, 1)) = 0;       /*  BC.Length = 0;          */
+	*(skb_put(*skb, 1)) = 0;       /*  ConnectedPN.Length = 0  */
+	*(skb_put(*skb, 1)) = 0;       /*  PSA.Length              */
+	*(skb_put(*skb, 1)) = 0;       /*  LLC.Length = 0;         */
+	*(skb_put(*skb, 1)) = 0;       /*  HLC.Length = 0;         */
+	*(skb_put(*skb, 1)) = 0;       /*  UTUS.Length = 0;        */
+
+	return 8;
+}
+
+int capi_conn_active_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+	/*
+	 * 2 bytes
+	 */
+
+	if ((*skb = dev_alloc_skb(2)) == NULL) {
+
+		printk(KERN_WARNING "capi_conn_active_resp: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+	return 2;
+}
+
+
+int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
+			  int outgoing)
+{
+
+	/*
+	 * 18 bytes
+	 */
+
+	if ((*skb = dev_alloc_skb(18)) == NULL) {
+
+		printk(KERN_WARNING "capi_select_proto_req: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+	/* Layer2 protocol */
+
+	switch (chan->proto) {
+	case ISDN_PROTO_L2_X75I:
+		*(skb_put(*skb, 1)) = 0x05;            /* LAPB */
+		break;
+	case ISDN_PROTO_L2_HDLC:
+		*(skb_put(*skb, 1)) = 0x02;
+		break;
+	case ISDN_PROTO_L2_TRANS:
+		/*
+		 *	Voice (a-law)
+		 */
+		*(skb_put(*skb, 1)) = 0x06;
+		break;
+	default:
+#ifdef DEBUG
+		printk(KERN_DEBUG "Transparent\n");
+#endif
+		*(skb_put(*skb, 1)) = 0x03;
+		break;
+	}
+
+	*(skb_put(*skb, 1)) = (outgoing ? 0x02 : 0x42);    /* Don't ask */
+	*(skb_put(*skb, 1)) = 0x00;
+
+	*((ushort *) skb_put(*skb, 2)) = MRU;
+
+
+	*(skb_put(*skb, 1)) = 0x08;           /* Modulo */
+	*(skb_put(*skb, 1)) = 0x07;           /* Max Window */
+
+	*(skb_put(*skb, 1)) = 0x01;           /* No Layer3 Protocol */
+
+	/*
+	 * 2 - layer3 MTU       [10]
+	 *   - Modulo           [12]
+	 *   - Window
+	 *   - layer1 proto     [14]
+	 *   - bitrate
+	 *   - sub-channel      [16]
+	 *   - layer1dataformat [17]
+	 */
+
+	memset(skb_put(*skb, 8), 0, 8);
+
+	return 18;
+}
+
+
+int capi_activate_transp_req(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+
+	if ((*skb = dev_alloc_skb(7)) == NULL) {
+
+		printk(KERN_WARNING "capi_activate_transp_req: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+
+	*(skb_put(*skb, 1)) = chan->layer2link; /* Layer2 id */
+	*(skb_put(*skb, 1)) = 0x00;             /* Transmit by default */
+
+	*((ushort *) skb_put(*skb, 2)) = MRU;
+
+	*(skb_put(*skb, 1)) = 0x01;             /* Enables reception*/
+
+	return 7;
+}
+
+int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort data_len;
+
+
+	/*
+	 * callref      - 2
+	 * layer2link   - 1
+	 * wBlockLength - 2
+	 * data         - 4
+	 * sernum       - 1
+	 */
+
+	data_len = skb->len;
+
+	if (skb_headroom(skb) < 10)
+	{
+		printk(KERN_CRIT "No headspace (%u) on headroom %p for capi header\n", skb_headroom(skb), skb);
+	}
+	else
+	{
+		skb_push(skb, 10);
+	}
+
+	*((u16 *) (skb->data)) = chan->callref;
+	skb->data[2] = chan->layer2link;
+	*((u16 *) (skb->data + 3)) = data_len;
+
+	chan->s_refnum = (chan->s_refnum + 1) % 8;
+	*((u32 *) (skb->data + 5)) = chan->s_refnum;
+
+	skb->data[9] = 0;                           /* HDLC frame number */
+
+	return 10;
+}
+
+int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+
+{
+	if ((*skb = dev_alloc_skb(4)) == NULL) {
+
+		printk(KERN_WARNING "capi_tdata_resp: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+	*(skb_put(*skb, 1)) = chan->layer2link;
+	*(skb_put(*skb, 1)) = chan->r_refnum;
+
+	return (*skb)->len;
+}
+
+int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause)
+{
+
+	if ((*skb = dev_alloc_skb(6)) == NULL) {
+
+		printk(KERN_WARNING "capi_disc_req: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = callref;
+
+	*(skb_put(*skb, 1)) = 2;                  /* Cause.Length = 2; */
+	*(skb_put(*skb, 1)) = 0x80;
+	*(skb_put(*skb, 1)) = 0x80 | cause;
+
+	/*
+	 * Change it: we should send 'Sic transit gloria Mundi' here ;-)
+	 */
+
+	*(skb_put(*skb, 1)) = 0;                   /* UTUS.Length = 0;  */
+
+	return 6;
+}
+
+int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb)
+{
+	if ((*skb = dev_alloc_skb(2)) == NULL) {
+
+		printk(KERN_WARNING "capi_disc_resp: alloc_skb failed\n");
+		return -1;
+	}
+
+	*((ushort *)skb_put(*skb, 2)) = chan->callref;
+
+	return 2;
+}
+
+
+/*
+ *  Decoding of CAPI messages
+ *
+ */
+
+int capi_decode_conn_ind(struct pcbit_chan *chan,
+			 struct sk_buff *skb,
+			 struct callb_data *info)
+{
+	int CIlen, len;
+
+	/* Call Reference [CAPI] */
+	chan->callref = *((ushort *)skb->data);
+	skb_pull(skb, 2);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Call Reference: %04x\n", chan->callref);
+#endif
+
+	/* Channel Identification */
+
+	/* Expect
+	   Len = 1
+	   Octect 3 = 0100 10CC - [ 7 Basic, 4 , 2-1 chan ]
+	*/
+
+	CIlen = skb->data[0];
+#ifdef DEBUG
+	if (CIlen == 1) {
+
+		if (((skb->data[1]) & 0xFC) == 0x48)
+			printk(KERN_DEBUG "decode_conn_ind: chan ok\n");
+		printk(KERN_DEBUG "phyChan = %d\n", skb->data[1] & 0x03);
+	}
+	else
+		printk(KERN_DEBUG "conn_ind: CIlen = %d\n", CIlen);
+#endif
+	skb_pull(skb, CIlen + 1);
+
+	/* Calling Party Number */
+	/* An "additional service" as far as Portugal Telecom is concerned */
+
+	len = skb->data[0];
+
+	if (len > 0) {
+		int count = 1;
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "CPN: Octect 3 %02x\n", skb->data[1]);
+#endif
+		if ((skb->data[1] & 0x80) == 0)
+			count = 2;
+
+		if (!(info->data.setup.CallingPN = kmalloc(len - count + 1, GFP_ATOMIC)))
+			return -1;
+
+		skb_copy_from_linear_data_offset(skb, count + 1,
+						 info->data.setup.CallingPN,
+						 len - count);
+		info->data.setup.CallingPN[len - count] = 0;
+
+	}
+	else {
+		info->data.setup.CallingPN = NULL;
+		printk(KERN_DEBUG "NULL CallingPN\n");
+	}
+
+	skb_pull(skb, len + 1);
+
+	/* Calling Party Subaddress */
+	skb_pull(skb, skb->data[0] + 1);
+
+	/* Called Party Number */
+
+	len = skb->data[0];
+
+	if (len > 0) {
+		int count = 1;
+
+		if ((skb->data[1] & 0x80) == 0)
+			count = 2;
+
+		if (!(info->data.setup.CalledPN = kmalloc(len - count + 1, GFP_ATOMIC)))
+			return -1;
+
+		skb_copy_from_linear_data_offset(skb, count + 1,
+						 info->data.setup.CalledPN,
+						 len - count);
+		info->data.setup.CalledPN[len - count] = 0;
+
+	}
+	else {
+		info->data.setup.CalledPN = NULL;
+		printk(KERN_DEBUG "NULL CalledPN\n");
+	}
+
+	skb_pull(skb, len + 1);
+
+	/* Called Party Subaddress */
+	skb_pull(skb, skb->data[0] + 1);
+
+	/* LLC */
+	skb_pull(skb, skb->data[0] + 1);
+
+	/* HLC */
+	skb_pull(skb, skb->data[0] + 1);
+
+	/* U2U */
+	skb_pull(skb, skb->data[0] + 1);
+
+	return 0;
+}
+
+/*
+ *  returns errcode
+ */
+
+int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
+			  int *complete)
+{
+	int errcode;
+
+	chan->callref = *((ushort *)skb->data);     /* Update CallReference */
+	skb_pull(skb, 2);
+
+	errcode = *((ushort *) skb->data);   /* read errcode */
+	skb_pull(skb, 2);
+
+	*complete = *(skb->data);
+	skb_pull(skb, 1);
+
+	/* FIX ME */
+	/* This is actually a firmware bug */
+	if (!*complete)
+	{
+		printk(KERN_DEBUG "complete=%02x\n", *complete);
+		*complete = 1;
+	}
+
+
+	/* Optional Bearer Capability */
+	skb_pull(skb, *(skb->data) + 1);
+
+	/* Channel Identification */
+	skb_pull(skb, *(skb->data) + 1);
+
+	/* High Layer Compatibility follows */
+	skb_pull(skb, *(skb->data) + 1);
+
+	return errcode;
+}
+
+int capi_decode_conn_actv_ind(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort len;
+#ifdef DEBUG
+	char str[32];
+#endif
+
+	/* Yet Another Bearer Capability */
+	skb_pull(skb, *(skb->data) + 1);
+
+
+	/* Connected Party Number */
+	len = *(skb->data);
+
+#ifdef DEBUG
+	if (len > 1 && len < 31) {
+		skb_copy_from_linear_data_offset(skb, 2, str, len - 1);
+		str[len] = 0;
+		printk(KERN_DEBUG "Connected Party Number: %s\n", str);
+	}
+	else
+		printk(KERN_DEBUG "actv_ind CPN len = %d\n", len);
+#endif
+
+	skb_pull(skb, len + 1);
+
+	/* Connected Subaddress */
+	skb_pull(skb, *(skb->data) + 1);
+
+	/* Low Layer Capability */
+	skb_pull(skb, *(skb->data) + 1);
+
+	/* High Layer Capability */
+	skb_pull(skb, *(skb->data) + 1);
+
+	return 0;
+}
+
+int capi_decode_conn_actv_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort errcode;
+
+	errcode = *((ushort *)skb->data);
+	skb_pull(skb, 2);
+
+	/* Channel Identification
+	   skb_pull(skb, skb->data[0] + 1);
+	*/
+	return errcode;
+}
+
+
+int capi_decode_sel_proto_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort errcode;
+
+	chan->layer2link = *(skb->data);
+	skb_pull(skb, 1);
+
+	errcode = *((ushort *)skb->data);
+	skb_pull(skb, 2);
+
+	return errcode;
+}
+
+int capi_decode_actv_trans_conf(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort errcode;
+
+	if (chan->layer2link != *(skb->data))
+		printk("capi_decode_actv_trans_conf: layer2link doesn't match\n");
+
+	skb_pull(skb, 1);
+
+	errcode = *((ushort *)skb->data);
+	skb_pull(skb, 2);
+
+	return errcode;
+}
+
+int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb)
+{
+	ushort len;
+#ifdef DEBUG
+	int i;
+#endif
+	/* Cause */
+
+	len = *(skb->data);
+	skb_pull(skb, 1);
+
+#ifdef DEBUG
+
+	for (i = 0; i < len; i++)
+		printk(KERN_DEBUG "Cause Octect %d: %02x\n", i + 3,
+		       *(skb->data + i));
+#endif
+
+	skb_pull(skb, len);
+
+	return 0;
+}
+
+#ifdef DEBUG
+int capi_decode_debug_188(u_char *hdr, ushort hdrlen)
+{
+	char str[64];
+	int len;
+
+	len = hdr[0];
+
+	if (len < 64 && len == hdrlen - 1) {
+		memcpy(str, hdr + 1, hdrlen - 1);
+		str[hdrlen - 1] = 0;
+		printk("%s\n", str);
+	}
+	else
+		printk("debug message incorrect\n");
+
+	return 0;
+}
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.h b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.h
new file mode 100644
index 0000000..635f634
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/capi.h
@@ -0,0 +1,81 @@
+/*
+ * CAPI encode/decode prototypes and defines
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef CAPI_H
+#define CAPI_H
+
+
+#define REQ_CAUSE         0x01
+#define REQ_DISPLAY       0x04
+#define REQ_USER_TO_USER  0x08
+
+#define AppInfoMask  REQ_CAUSE | REQ_DISPLAY | REQ_USER_TO_USER
+
+/* Connection Setup */
+extern int capi_conn_req(const char *calledPN, struct sk_buff **buf,
+			 int proto);
+extern int capi_decode_conn_conf(struct pcbit_chan *chan, struct sk_buff *skb,
+				 int *complete);
+
+extern int capi_decode_conn_ind(struct pcbit_chan *chan, struct sk_buff *skb,
+				struct callb_data *info);
+extern int capi_conn_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+extern int capi_conn_active_req(struct pcbit_chan *chan, struct sk_buff **skb);
+extern int capi_decode_conn_actv_conf(struct pcbit_chan *chan,
+				      struct sk_buff *skb);
+
+extern int capi_decode_conn_actv_ind(struct pcbit_chan *chan,
+				     struct sk_buff *skb);
+extern int capi_conn_active_resp(struct pcbit_chan *chan,
+				 struct sk_buff **skb);
+
+/* Data */
+extern int capi_select_proto_req(struct pcbit_chan *chan, struct sk_buff **skb,
+				 int outgoing);
+extern int capi_decode_sel_proto_conf(struct pcbit_chan *chan,
+				      struct sk_buff *skb);
+
+extern int capi_activate_transp_req(struct pcbit_chan *chan,
+				    struct sk_buff **skb);
+extern int capi_decode_actv_trans_conf(struct pcbit_chan *chan,
+				       struct sk_buff *skb);
+
+extern int capi_tdata_req(struct pcbit_chan *chan, struct sk_buff *skb);
+extern int capi_tdata_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+/* Connection Termination */
+extern int capi_disc_req(ushort callref, struct sk_buff **skb, u_char cause);
+
+extern int capi_decode_disc_ind(struct pcbit_chan *chan, struct sk_buff *skb);
+extern int capi_disc_resp(struct pcbit_chan *chan, struct sk_buff **skb);
+
+#ifdef DEBUG
+extern int capi_decode_debug_188(u_char *hdr, ushort hdrlen);
+#endif
+
+static inline struct pcbit_chan *
+capi_channel(struct pcbit_dev *dev, struct sk_buff *skb)
+{
+	ushort callref;
+
+	callref = *((ushort *)skb->data);
+	skb_pull(skb, 2);
+
+	if (dev->b1->callref == callref)
+		return dev->b1;
+	else if (dev->b2->callref == callref)
+		return dev->b2;
+
+	return NULL;
+}
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/drv.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/drv.c
new file mode 100644
index 0000000..1eaf622
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/drv.c
@@ -0,0 +1,1077 @@
+/*
+ * PCBIT-D interface with isdn4linux
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ *	Fixes:
+ *
+ *	Nuno Grilo	<l38486@alfa.ist.utl.pt>
+ *      fixed msn_list NULL pointer dereference.
+ *
+ */
+
+#include <linux/module.h>
+
+
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#include <asm/string.h>
+#include <asm/io.h>
+#include <linux/ioport.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "layer2.h"
+#include "capi.h"
+
+
+extern ushort last_ref_num;
+
+static int pcbit_ioctl(isdn_ctrl *ctl);
+
+static char *pcbit_devname[MAX_PCBIT_CARDS] = {
+	"pcbit0",
+	"pcbit1",
+	"pcbit2",
+	"pcbit3"
+};
+
+/*
+ * prototypes
+ */
+
+static int pcbit_command(isdn_ctrl *ctl);
+static int pcbit_stat(u_char __user *buf, int len, int, int);
+static int pcbit_xmit(int driver, int chan, int ack, struct sk_buff *skb);
+static int pcbit_writecmd(const u_char __user *, int, int, int);
+
+static int set_protocol_running(struct pcbit_dev *dev);
+
+static void pcbit_clear_msn(struct pcbit_dev *dev);
+static void pcbit_set_msn(struct pcbit_dev *dev, char *list);
+static int pcbit_check_msn(struct pcbit_dev *dev, char *msn);
+
+
+int pcbit_init_dev(int board, int mem_base, int irq)
+{
+	struct pcbit_dev *dev;
+	isdn_if *dev_if;
+
+	if ((dev = kzalloc(sizeof(struct pcbit_dev), GFP_KERNEL)) == NULL)
+	{
+		printk("pcbit_init: couldn't malloc pcbit_dev struct\n");
+		return -ENOMEM;
+	}
+
+	dev_pcbit[board] = dev;
+	init_waitqueue_head(&dev->set_running_wq);
+	spin_lock_init(&dev->lock);
+
+	if (mem_base >= 0xA0000 && mem_base <= 0xFFFFF) {
+		dev->ph_mem = mem_base;
+		if (!request_mem_region(dev->ph_mem, 4096, "PCBIT mem")) {
+			printk(KERN_WARNING
+			       "PCBIT: memory region %lx-%lx already in use\n",
+			       dev->ph_mem, dev->ph_mem + 4096);
+			kfree(dev);
+			dev_pcbit[board] = NULL;
+			return -EACCES;
+		}
+		dev->sh_mem = ioremap(dev->ph_mem, 4096);
+	}
+	else
+	{
+		printk("memory address invalid");
+		kfree(dev);
+		dev_pcbit[board] = NULL;
+		return -EACCES;
+	}
+
+	dev->b1 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+	if (!dev->b1) {
+		printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	dev->b2 = kzalloc(sizeof(struct pcbit_chan), GFP_KERNEL);
+	if (!dev->b2) {
+		printk("pcbit_init: couldn't malloc pcbit_chan struct\n");
+		kfree(dev->b1);
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+		return -ENOMEM;
+	}
+
+	dev->b2->id = 1;
+
+	INIT_WORK(&dev->qdelivery, pcbit_deliver);
+
+	/*
+	 *  interrupts
+	 */
+
+	if (request_irq(irq, &pcbit_irq_handler, 0, pcbit_devname[board], dev) != 0)
+	{
+		kfree(dev->b1);
+		kfree(dev->b2);
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+		dev_pcbit[board] = NULL;
+		return -EIO;
+	}
+
+	dev->irq = irq;
+
+	/* next frame to be received */
+	dev->rcv_seq = 0;
+	dev->send_seq = 0;
+	dev->unack_seq = 0;
+
+	dev->hl_hdrlen = 16;
+
+	dev_if = kmalloc(sizeof(isdn_if), GFP_KERNEL);
+
+	if (!dev_if) {
+		free_irq(irq, dev);
+		kfree(dev->b1);
+		kfree(dev->b2);
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+		dev_pcbit[board] = NULL;
+		return -EIO;
+	}
+
+	dev->dev_if = dev_if;
+
+	dev_if->owner = THIS_MODULE;
+
+	dev_if->channels = 2;
+
+	dev_if->features = (ISDN_FEATURE_P_EURO  | ISDN_FEATURE_L3_TRANS |
+			    ISDN_FEATURE_L2_HDLC | ISDN_FEATURE_L2_TRANS);
+
+	dev_if->writebuf_skb = pcbit_xmit;
+	dev_if->hl_hdrlen = 16;
+
+	dev_if->maxbufsize = MAXBUFSIZE;
+	dev_if->command  = pcbit_command;
+
+	dev_if->writecmd = pcbit_writecmd;
+	dev_if->readstat = pcbit_stat;
+
+
+	strcpy(dev_if->id, pcbit_devname[board]);
+
+	if (!register_isdn(dev_if)) {
+		free_irq(irq, dev);
+		kfree(dev->b1);
+		kfree(dev->b2);
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+		dev_pcbit[board] = NULL;
+		return -EIO;
+	}
+
+	dev->id = dev_if->channels;
+
+
+	dev->l2_state = L2_DOWN;
+	dev->free = 511;
+
+	/*
+	 * set_protocol_running(dev);
+	 */
+
+	return 0;
+}
+
+#ifdef MODULE
+void pcbit_terminate(int board)
+{
+	struct pcbit_dev *dev;
+
+	dev = dev_pcbit[board];
+
+	if (dev) {
+		/* unregister_isdn(dev->dev_if); */
+		free_irq(dev->irq, dev);
+		pcbit_clear_msn(dev);
+		kfree(dev->dev_if);
+		if (dev->b1->fsm_timer.function)
+			del_timer(&dev->b1->fsm_timer);
+		if (dev->b2->fsm_timer.function)
+			del_timer(&dev->b2->fsm_timer);
+		kfree(dev->b1);
+		kfree(dev->b2);
+		iounmap(dev->sh_mem);
+		release_mem_region(dev->ph_mem, 4096);
+		kfree(dev);
+	}
+}
+#endif
+
+static int pcbit_command(isdn_ctrl *ctl)
+{
+	struct pcbit_dev *dev;
+	struct pcbit_chan *chan;
+	struct callb_data info;
+
+	dev = finddev(ctl->driver);
+
+	if (!dev)
+	{
+		printk("pcbit_command: unknown device\n");
+		return -1;
+	}
+
+	chan = (ctl->arg & 0x0F) ? dev->b2 : dev->b1;
+
+
+	switch (ctl->command) {
+	case ISDN_CMD_IOCTL:
+		return pcbit_ioctl(ctl);
+		break;
+	case ISDN_CMD_DIAL:
+		info.type = EV_USR_SETUP_REQ;
+		info.data.setup.CalledPN = (char *) &ctl->parm.setup.phone;
+		pcbit_fsm_event(dev, chan, EV_USR_SETUP_REQ, &info);
+		break;
+	case ISDN_CMD_ACCEPTD:
+		pcbit_fsm_event(dev, chan, EV_USR_SETUP_RESP, NULL);
+		break;
+	case ISDN_CMD_ACCEPTB:
+		printk("ISDN_CMD_ACCEPTB - not really needed\n");
+		break;
+	case ISDN_CMD_HANGUP:
+		pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
+		break;
+	case ISDN_CMD_SETL2:
+		chan->proto = (ctl->arg >> 8);
+		break;
+	case ISDN_CMD_CLREAZ:
+		pcbit_clear_msn(dev);
+		break;
+	case ISDN_CMD_SETEAZ:
+		pcbit_set_msn(dev, ctl->parm.num);
+		break;
+	case ISDN_CMD_SETL3:
+		if ((ctl->arg >> 8) != ISDN_PROTO_L3_TRANS)
+			printk(KERN_DEBUG "L3 protocol unknown\n");
+		break;
+	default:
+		printk(KERN_DEBUG "pcbit_command: unknown command\n");
+		break;
+	};
+
+	return 0;
+}
+
+/*
+ * Another Hack :-(
+ * on some conditions the board stops sending TDATA_CONFs
+ * let's see if we can turn around the problem
+ */
+
+#ifdef BLOCK_TIMER
+static void pcbit_block_timer(unsigned long data)
+{
+	struct pcbit_chan *chan;
+	struct pcbit_dev *dev;
+	isdn_ctrl ictl;
+
+	chan = (struct pcbit_chan *)data;
+
+	dev = chan2dev(chan);
+
+	if (dev == NULL) {
+		printk(KERN_DEBUG "pcbit: chan2dev failed\n");
+		return;
+	}
+
+	del_timer(&chan->block_timer);
+	chan->block_timer.function = NULL;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "pcbit_block_timer\n");
+#endif
+	chan->queued = 0;
+	ictl.driver = dev->id;
+	ictl.command = ISDN_STAT_BSENT;
+	ictl.arg = chan->id;
+	dev->dev_if->statcallb(&ictl);
+}
+#endif
+
+static int pcbit_xmit(int driver, int chnum, int ack, struct sk_buff *skb)
+{
+	ushort hdrlen;
+	int refnum, len;
+	struct pcbit_chan *chan;
+	struct pcbit_dev *dev;
+
+	dev = finddev(driver);
+	if (dev == NULL)
+	{
+		printk("finddev returned NULL");
+		return -1;
+	}
+
+	chan = chnum ? dev->b2 : dev->b1;
+
+
+	if (chan->fsm_state != ST_ACTIVE)
+		return -1;
+
+	if (chan->queued >= MAX_QUEUED)
+	{
+#ifdef DEBUG_QUEUE
+		printk(KERN_DEBUG
+		       "pcbit: %d packets already in queue - write fails\n",
+		       chan->queued);
+#endif
+		/*
+		 * packet stays on the head of the device queue
+		 * since dev_start_xmit will fail
+		 * see net/core/dev.c
+		 */
+#ifdef BLOCK_TIMER
+		if (chan->block_timer.function == NULL) {
+			init_timer(&chan->block_timer);
+			chan->block_timer.function =  &pcbit_block_timer;
+			chan->block_timer.data = (long) chan;
+			chan->block_timer.expires = jiffies + 1 * HZ;
+			add_timer(&chan->block_timer);
+		}
+#endif
+		return 0;
+	}
+
+
+	chan->queued++;
+
+	len = skb->len;
+
+	hdrlen = capi_tdata_req(chan, skb);
+
+	refnum = last_ref_num++ & 0x7fffU;
+	chan->s_refnum = refnum;
+
+	pcbit_l2_write(dev, MSG_TDATA_REQ, refnum, skb, hdrlen);
+
+	return len;
+}
+
+static int pcbit_writecmd(const u_char __user *buf, int len, int driver, int channel)
+{
+	struct pcbit_dev *dev;
+	int i, j;
+	const u_char *loadbuf;
+	u_char *ptr = NULL;
+	u_char *cbuf;
+
+	int errstat;
+
+	dev = finddev(driver);
+
+	if (!dev)
+	{
+		printk("pcbit_writecmd: couldn't find device");
+		return -ENODEV;
+	}
+
+	switch (dev->l2_state) {
+	case L2_LWMODE:
+		/* check (size <= rdp_size); write buf into board */
+		if (len < 0 || len > BANK4 + 1 || len > 1024)
+		{
+			printk("pcbit_writecmd: invalid length %d\n", len);
+			return -EINVAL;
+		}
+
+		cbuf = memdup_user(buf, len);
+		if (IS_ERR(cbuf))
+			return PTR_ERR(cbuf);
+
+		memcpy_toio(dev->sh_mem, cbuf, len);
+		kfree(cbuf);
+		return len;
+	case L2_FWMODE:
+		/* this is the hard part */
+		/* dumb board */
+		/* get it into kernel space */
+		if ((ptr = kmalloc(len, GFP_KERNEL)) == NULL)
+			return -ENOMEM;
+		if (copy_from_user(ptr, buf, len)) {
+			kfree(ptr);
+			return -EFAULT;
+		}
+		loadbuf = ptr;
+
+		errstat = 0;
+
+		for (i = 0; i < len; i++)
+		{
+			for (j = 0; j < LOAD_RETRY; j++)
+				if (!(readb(dev->sh_mem + dev->loadptr)))
+					break;
+
+			if (j == LOAD_RETRY)
+			{
+				errstat = -ETIME;
+				printk("TIMEOUT i=%d\n", i);
+				break;
+			}
+			writeb(loadbuf[i], dev->sh_mem + dev->loadptr + 1);
+			writeb(0x01, dev->sh_mem + dev->loadptr);
+
+			dev->loadptr += 2;
+			if (dev->loadptr > LOAD_ZONE_END)
+				dev->loadptr = LOAD_ZONE_START;
+		}
+		kfree(ptr);
+
+		return errstat ? errstat : len;
+	default:
+		return -EBUSY;
+	}
+}
+
+/*
+ *  demultiplexing of messages
+ *
+ */
+
+void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg,
+		      struct sk_buff *skb,
+		      ushort hdr_len, ushort refnum)
+{
+	struct pcbit_chan *chan;
+	struct sk_buff *skb2;
+	unsigned short len;
+	struct callb_data cbdata;
+	int complete, err;
+	isdn_ctrl ictl;
+
+	switch (msg) {
+
+	case MSG_TDATA_IND:
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+		chan->r_refnum = skb->data[7];
+		skb_pull(skb, 8);
+
+		dev->dev_if->rcvcallb_skb(dev->id, chan->id, skb);
+
+		if (capi_tdata_resp(chan, &skb2) > 0)
+			pcbit_l2_write(dev, MSG_TDATA_RESP, refnum,
+				       skb2, skb2->len);
+		return;
+		break;
+	case MSG_TDATA_CONF:
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+#ifdef DEBUG
+		if ((*((ushort *)(skb->data + 2))) != 0) {
+			printk(KERN_DEBUG "TDATA_CONF error\n");
+		}
+#endif
+#ifdef BLOCK_TIMER
+		if (chan->queued == MAX_QUEUED) {
+			del_timer(&chan->block_timer);
+			chan->block_timer.function = NULL;
+		}
+
+#endif
+		chan->queued--;
+
+		ictl.driver = dev->id;
+		ictl.command = ISDN_STAT_BSENT;
+		ictl.arg = chan->id;
+		dev->dev_if->statcallb(&ictl);
+		break;
+
+	case MSG_CONN_IND:
+		/*
+		 *  channel: 1st not used will do
+		 *           if both are used we're in trouble
+		 */
+
+		if (!dev->b1->fsm_state)
+			chan = dev->b1;
+		else if (!dev->b2->fsm_state)
+			chan = dev->b2;
+		else {
+			printk(KERN_INFO
+			       "Incoming connection: no channels available");
+
+			if ((len = capi_disc_req(*(ushort *)(skb->data), &skb2, CAUSE_NOCHAN)) > 0)
+				pcbit_l2_write(dev, MSG_DISC_REQ, refnum, skb2, len);
+			break;
+		}
+
+		cbdata.data.setup.CalledPN = NULL;
+		cbdata.data.setup.CallingPN = NULL;
+
+		capi_decode_conn_ind(chan, skb, &cbdata);
+		cbdata.type = EV_NET_SETUP;
+
+		pcbit_fsm_event(dev, chan, EV_NET_SETUP, NULL);
+
+		if (pcbit_check_msn(dev, cbdata.data.setup.CallingPN))
+			pcbit_fsm_event(dev, chan, EV_USR_PROCED_REQ, &cbdata);
+		else
+			pcbit_fsm_event(dev, chan, EV_USR_RELEASE_REQ, NULL);
+
+		kfree(cbdata.data.setup.CalledPN);
+		kfree(cbdata.data.setup.CallingPN);
+		break;
+
+	case MSG_CONN_CONF:
+		/*
+		 * We should be able to find the channel by the message
+		 * reference number. The current version of the firmware
+		 * doesn't sent the ref number correctly.
+		 */
+#ifdef DEBUG
+		printk(KERN_DEBUG "refnum=%04x b1=%04x b2=%04x\n", refnum,
+		       dev->b1->s_refnum,
+		       dev->b2->s_refnum);
+#endif
+		/* We just try to find a channel in the right state */
+
+		if (dev->b1->fsm_state == ST_CALL_INIT)
+			chan = dev->b1;
+		else {
+			if (dev->b2->s_refnum == ST_CALL_INIT)
+				chan = dev->b2;
+			else {
+				chan = NULL;
+				printk(KERN_WARNING "Connection Confirm - no channel in Call Init state\n");
+				break;
+			}
+		}
+		if (capi_decode_conn_conf(chan, skb, &complete)) {
+			printk(KERN_DEBUG "conn_conf indicates error\n");
+			pcbit_fsm_event(dev, chan, EV_ERROR, NULL);
+		}
+		else
+			if (complete)
+				pcbit_fsm_event(dev, chan, EV_NET_CALL_PROC, NULL);
+			else
+				pcbit_fsm_event(dev, chan, EV_NET_SETUP_ACK, NULL);
+		break;
+	case MSG_CONN_ACTV_IND:
+
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (capi_decode_conn_actv_ind(chan, skb)) {
+			printk("error in capi_decode_conn_actv_ind\n");
+			/* pcbit_fsm_event(dev, chan, EV_ERROR, NULL); */
+			break;
+		}
+		chan->r_refnum = refnum;
+		pcbit_fsm_event(dev, chan, EV_NET_CONN, NULL);
+		break;
+	case MSG_CONN_ACTV_CONF:
+
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (capi_decode_conn_actv_conf(chan, skb) == 0)
+			pcbit_fsm_event(dev, chan, EV_NET_CONN_ACK, NULL);
+
+		else
+			printk(KERN_DEBUG "decode_conn_actv_conf failed\n");
+		break;
+
+	case  MSG_SELP_CONF:
+
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (!(err = capi_decode_sel_proto_conf(chan, skb)))
+			pcbit_fsm_event(dev, chan, EV_NET_SELP_RESP, NULL);
+		else {
+			/* Error */
+			printk("error %d - capi_decode_sel_proto_conf\n", err);
+		}
+		break;
+	case MSG_ACT_TRANSP_CONF:
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (!capi_decode_actv_trans_conf(chan, skb))
+			pcbit_fsm_event(dev, chan, EV_NET_ACTV_RESP, NULL);
+		break;
+
+	case MSG_DISC_IND:
+
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (!capi_decode_disc_ind(chan, skb))
+			pcbit_fsm_event(dev, chan, EV_NET_DISC, NULL);
+		else
+			printk(KERN_WARNING "capi_decode_disc_ind - error\n");
+		break;
+	case MSG_DISC_CONF:
+		if (!(chan = capi_channel(dev, skb))) {
+			printk(KERN_WARNING
+			       "CAPI header: unknown channel id\n");
+			break;
+		}
+
+		if (!capi_decode_disc_ind(chan, skb))
+			pcbit_fsm_event(dev, chan, EV_NET_RELEASE, NULL);
+		else
+			printk(KERN_WARNING "capi_decode_disc_conf - error\n");
+		break;
+	case MSG_INFO_IND:
+#ifdef DEBUG
+		printk(KERN_DEBUG "received Info Indication - discarded\n");
+#endif
+		break;
+#ifdef DEBUG
+	case MSG_DEBUG_188:
+		capi_decode_debug_188(skb->data, skb->len);
+		break;
+
+	default:
+		printk(KERN_DEBUG "pcbit_l3_receive: unknown message %08lx\n",
+		       msg);
+		break;
+#endif
+	}
+
+	kfree_skb(skb);
+
+}
+
+/*
+ *   Single statbuf
+ *   should be a statbuf per device
+ */
+
+static char statbuf[STATBUF_LEN];
+static int stat_st = 0;
+static int stat_end = 0;
+
+static int pcbit_stat(u_char __user *buf, int len, int driver, int channel)
+{
+	int stat_count;
+	stat_count = stat_end - stat_st;
+
+	if (stat_count < 0)
+		stat_count = STATBUF_LEN - stat_st + stat_end;
+
+	/* FIXME: should we sleep and wait for more cookies ? */
+	if (len > stat_count)
+		len = stat_count;
+
+	if (stat_st < stat_end)
+	{
+		if (copy_to_user(buf, statbuf + stat_st, len))
+			return -EFAULT;
+		stat_st += len;
+	}
+	else
+	{
+		if (len > STATBUF_LEN - stat_st)
+		{
+			if (copy_to_user(buf, statbuf + stat_st,
+					 STATBUF_LEN - stat_st))
+				return -EFAULT;
+			if (copy_to_user(buf, statbuf,
+					 len - (STATBUF_LEN - stat_st)))
+				return -EFAULT;
+
+			stat_st = len - (STATBUF_LEN - stat_st);
+		}
+		else
+		{
+			if (copy_to_user(buf, statbuf + stat_st, len))
+				return -EFAULT;
+
+			stat_st += len;
+
+			if (stat_st == STATBUF_LEN)
+				stat_st = 0;
+		}
+	}
+
+	if (stat_st == stat_end)
+		stat_st = stat_end = 0;
+
+	return len;
+}
+
+static void pcbit_logstat(struct pcbit_dev *dev, char *str)
+{
+	int i;
+	isdn_ctrl ictl;
+
+	for (i = stat_end; i < strlen(str); i++)
+	{
+		statbuf[i] = str[i];
+		stat_end = (stat_end + 1) % STATBUF_LEN;
+		if (stat_end == stat_st)
+			stat_st = (stat_st + 1) % STATBUF_LEN;
+	}
+
+	ictl.command = ISDN_STAT_STAVAIL;
+	ictl.driver = dev->id;
+	ictl.arg = strlen(str);
+	dev->dev_if->statcallb(&ictl);
+}
+
+void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
+			unsigned short i, unsigned short ev, unsigned short f)
+{
+	char buf[256];
+
+	sprintf(buf, "change on device: %d channel:%d\n%s -> %s -> %s\n",
+		dev->id, chan->id,
+		isdn_state_table[i], strisdnevent(ev), isdn_state_table[f]
+		);
+
+#ifdef DEBUG
+	printk("%s", buf);
+#endif
+
+	pcbit_logstat(dev, buf);
+}
+
+static void set_running_timeout(unsigned long ptr)
+{
+	struct pcbit_dev *dev;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "set_running_timeout\n");
+#endif
+	dev = (struct pcbit_dev *) ptr;
+
+	wake_up_interruptible(&dev->set_running_wq);
+}
+
+static int set_protocol_running(struct pcbit_dev *dev)
+{
+	isdn_ctrl ctl;
+
+	init_timer(&dev->set_running_timer);
+
+	dev->set_running_timer.function = &set_running_timeout;
+	dev->set_running_timer.data = (ulong) dev;
+	dev->set_running_timer.expires = jiffies + SET_RUN_TIMEOUT;
+
+	/* kick it */
+
+	dev->l2_state = L2_STARTING;
+
+	writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
+	       dev->sh_mem + BANK4);
+
+	add_timer(&dev->set_running_timer);
+
+	interruptible_sleep_on(&dev->set_running_wq);
+
+	del_timer(&dev->set_running_timer);
+
+	if (dev->l2_state == L2_RUNNING)
+	{
+		printk(KERN_DEBUG "pcbit: running\n");
+
+		dev->unack_seq = dev->send_seq;
+
+		dev->writeptr = dev->sh_mem;
+		dev->readptr = dev->sh_mem + BANK2;
+
+		/* tell the good news to the upper layer */
+		ctl.driver = dev->id;
+		ctl.command = ISDN_STAT_RUN;
+
+		dev->dev_if->statcallb(&ctl);
+	}
+	else
+	{
+		printk(KERN_DEBUG "pcbit: initialization failed\n");
+		printk(KERN_DEBUG "pcbit: firmware not loaded\n");
+
+		dev->l2_state = L2_DOWN;
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "Bank3 = %02x\n",
+		       readb(dev->sh_mem + BANK3));
+#endif
+		writeb(0x40, dev->sh_mem + BANK4);
+
+		/* warn the upper layer */
+		ctl.driver = dev->id;
+		ctl.command = ISDN_STAT_STOP;
+
+		dev->dev_if->statcallb(&ctl);
+
+		return -EL2HLT;	/* Level 2 halted */
+	}
+
+	return 0;
+}
+
+static int pcbit_ioctl(isdn_ctrl *ctl)
+{
+	struct pcbit_dev *dev;
+	struct pcbit_ioctl *cmd;
+
+	dev = finddev(ctl->driver);
+
+	if (!dev)
+	{
+		printk(KERN_DEBUG "pcbit_ioctl: unknown device\n");
+		return -ENODEV;
+	}
+
+	cmd = (struct pcbit_ioctl *) ctl->parm.num;
+
+	switch (ctl->arg) {
+	case PCBIT_IOCTL_GETSTAT:
+		cmd->info.l2_status = dev->l2_state;
+		break;
+
+	case PCBIT_IOCTL_STRLOAD:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+
+		dev->unack_seq = dev->send_seq = dev->rcv_seq = 0;
+
+		dev->writeptr = dev->sh_mem;
+		dev->readptr = dev->sh_mem + BANK2;
+
+		dev->l2_state = L2_LOADING;
+		break;
+
+	case PCBIT_IOCTL_LWMODE:
+		if (dev->l2_state != L2_LOADING)
+			return -EINVAL;
+
+		dev->l2_state = L2_LWMODE;
+		break;
+
+	case PCBIT_IOCTL_FWMODE:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+		dev->loadptr = LOAD_ZONE_START;
+		dev->l2_state = L2_FWMODE;
+
+		break;
+	case PCBIT_IOCTL_ENDLOAD:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+		dev->l2_state = L2_DOWN;
+		break;
+
+	case PCBIT_IOCTL_SETBYTE:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+
+		/* check addr */
+		if (cmd->info.rdp_byte.addr > BANK4)
+			return -EFAULT;
+
+		writeb(cmd->info.rdp_byte.value, dev->sh_mem + cmd->info.rdp_byte.addr);
+		break;
+	case PCBIT_IOCTL_GETBYTE:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+
+		/* check addr */
+
+		if (cmd->info.rdp_byte.addr > BANK4)
+		{
+			printk("getbyte: invalid addr %04x\n", cmd->info.rdp_byte.addr);
+			return -EFAULT;
+		}
+
+		cmd->info.rdp_byte.value = readb(dev->sh_mem + cmd->info.rdp_byte.addr);
+		break;
+	case PCBIT_IOCTL_RUNNING:
+		if (dev->l2_state == L2_RUNNING)
+			return -EBUSY;
+		return set_protocol_running(dev);
+		break;
+	case PCBIT_IOCTL_WATCH188:
+		if (dev->l2_state != L2_LOADING)
+			return -EINVAL;
+		pcbit_l2_write(dev, MSG_WATCH188, 0x0001, NULL, 0);
+		break;
+	case PCBIT_IOCTL_PING188:
+		if (dev->l2_state != L2_LOADING)
+			return -EINVAL;
+		pcbit_l2_write(dev, MSG_PING188_REQ, 0x0001, NULL, 0);
+		break;
+	case PCBIT_IOCTL_APION:
+		if (dev->l2_state != L2_LOADING)
+			return -EINVAL;
+		pcbit_l2_write(dev, MSG_API_ON, 0x0001, NULL, 0);
+		break;
+	case PCBIT_IOCTL_STOP:
+		dev->l2_state = L2_DOWN;
+		writeb(0x40, dev->sh_mem + BANK4);
+		dev->rcv_seq = 0;
+		dev->send_seq = 0;
+		dev->unack_seq = 0;
+		break;
+	default:
+		printk("error: unknown ioctl\n");
+		break;
+	};
+	return 0;
+}
+
+/*
+ *        MSN list handling
+ *
+ *        if null reject all calls
+ *        if first entry has null MSN accept all calls
+ */
+
+static void pcbit_clear_msn(struct pcbit_dev *dev)
+{
+	struct msn_entry *ptr, *back;
+
+	for (ptr = dev->msn_list; ptr;)
+	{
+		back = ptr->next;
+		kfree(ptr);
+		ptr = back;
+	}
+
+	dev->msn_list = NULL;
+}
+
+static void pcbit_set_msn(struct pcbit_dev *dev, char *list)
+{
+	struct msn_entry *ptr;
+	struct msn_entry *back = NULL;
+	char *cp, *sp;
+	int len;
+
+	if (strlen(list) == 0) {
+		ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
+		if (!ptr) {
+			printk(KERN_WARNING "kmalloc failed\n");
+			return;
+		}
+
+		ptr->msn = NULL;
+
+		ptr->next = dev->msn_list;
+		dev->msn_list = ptr;
+
+		return;
+	}
+
+	if (dev->msn_list)
+		for (back = dev->msn_list; back->next; back = back->next);
+
+	sp = list;
+
+	do {
+		cp = strchr(sp, ',');
+		if (cp)
+			len = cp - sp;
+		else
+			len = strlen(sp);
+
+		ptr = kmalloc(sizeof(struct msn_entry), GFP_ATOMIC);
+
+		if (!ptr) {
+			printk(KERN_WARNING "kmalloc failed\n");
+			return;
+		}
+		ptr->next = NULL;
+
+		ptr->msn = kmalloc(len, GFP_ATOMIC);
+		if (!ptr->msn) {
+			printk(KERN_WARNING "kmalloc failed\n");
+			kfree(ptr);
+			return;
+		}
+
+		memcpy(ptr->msn, sp, len - 1);
+		ptr->msn[len] = 0;
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "msn: %s\n", ptr->msn);
+#endif
+		if (dev->msn_list == NULL)
+			dev->msn_list = ptr;
+		else
+			back->next = ptr;
+		back = ptr;
+		sp += len;
+	} while (cp);
+}
+
+/*
+ *  check if we do signal or reject an incoming call
+ */
+static int pcbit_check_msn(struct pcbit_dev *dev, char *msn)
+{
+	struct msn_entry *ptr;
+
+	for (ptr = dev->msn_list; ptr; ptr = ptr->next) {
+
+		if (ptr->msn == NULL)
+			return 1;
+
+		if (strcmp(ptr->msn, msn) == 0)
+			return 1;
+	}
+
+	return 0;
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.c
new file mode 100644
index 0000000..b2262ba
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.c
@@ -0,0 +1,313 @@
+/*
+ * DSS.1 Finite State Machine
+ * base: ITU-T Rec Q.931
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ *        TODO: complete the FSM
+ *              move state/event descriptions to a user space logger
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <linux/timer.h>
+#include <asm/io.h>
+
+#include <linux/isdnif.h>
+
+#include "pcbit.h"
+#include "edss1.h"
+#include "layer2.h"
+#include "callbacks.h"
+
+
+const char * const isdn_state_table[] = {
+	"Closed",
+	"Call initiated",
+	"Overlap sending",
+	"Outgoing call proceeding",
+	"NOT DEFINED",
+	"Call delivered",
+	"Call present",
+	"Call received",
+	"Connect request",
+	"Incoming call proceeding",
+	"Active",
+	"Disconnect request",
+	"Disconnect indication",
+	"NOT DEFINED",
+	"NOT DEFINED",
+	"Suspend request",
+	"NOT DEFINED",
+	"Resume request",
+	"NOT DEFINED",
+	"Release Request",
+	"NOT DEFINED",
+	"NOT DEFINED",
+	"NOT DEFINED",
+	"NOT DEFINED",
+	"NOT DEFINED",
+	"Overlap receiving",
+	"Select protocol on B-Channel",
+	"Activate B-channel protocol"
+};
+
+#ifdef DEBUG_ERRS
+static
+struct CauseValue {
+	byte nr;
+	char *descr;
+} cvlist[] = {
+	{0x01, "Unallocated (unassigned) number"},
+	{0x02, "No route to specified transit network"},
+	{0x03, "No route to destination"},
+	{0x04, "Send special information tone"},
+	{0x05, "Misdialled trunk prefix"},
+	{0x06, "Channel unacceptable"},
+	{0x07, "Channel awarded and being delivered in an established channel"},
+	{0x08, "Preemption"},
+	{0x09, "Preemption - circuit reserved for reuse"},
+	{0x10, "Normal call clearing"},
+	{0x11, "User busy"},
+	{0x12, "No user responding"},
+	{0x13, "No answer from user (user alerted)"},
+	{0x14, "Subscriber absent"},
+	{0x15, "Call rejected"},
+	{0x16, "Number changed"},
+	{0x1a, "non-selected user clearing"},
+	{0x1b, "Destination out of order"},
+	{0x1c, "Invalid number format (address incomplete)"},
+	{0x1d, "Facility rejected"},
+	{0x1e, "Response to Status enquiry"},
+	{0x1f, "Normal, unspecified"},
+	{0x22, "No circuit/channel available"},
+	{0x26, "Network out of order"},
+	{0x27, "Permanent frame mode connection out-of-service"},
+	{0x28, "Permanent frame mode connection operational"},
+	{0x29, "Temporary failure"},
+	{0x2a, "Switching equipment congestion"},
+	{0x2b, "Access information discarded"},
+	{0x2c, "Requested circuit/channel not available"},
+	{0x2e, "Precedence call blocked"},
+	{0x2f, "Resource unavailable, unspecified"},
+	{0x31, "Quality of service unavailable"},
+	{0x32, "Requested facility not subscribed"},
+	{0x35, "Outgoing calls barred within CUG"},
+	{0x37, "Incoming calls barred within CUG"},
+	{0x39, "Bearer capability not authorized"},
+	{0x3a, "Bearer capability not presently available"},
+	{0x3e, "Inconsistency in designated outgoing access information and subscriber class"},
+	{0x3f, "Service or option not available, unspecified"},
+	{0x41, "Bearer capability not implemented"},
+	{0x42, "Channel type not implemented"},
+	{0x43, "Requested facility not implemented"},
+	{0x44, "Only restricted digital information bearer capability is available"},
+	{0x4f, "Service or option not implemented"},
+	{0x51, "Invalid call reference value"},
+	{0x52, "Identified channel does not exist"},
+	{0x53, "A suspended call exists, but this call identity does not"},
+	{0x54, "Call identity in use"},
+	{0x55, "No call suspended"},
+	{0x56, "Call having the requested call identity has been cleared"},
+	{0x57, "User not member of CUG"},
+	{0x58, "Incompatible destination"},
+	{0x5a, "Non-existent CUG"},
+	{0x5b, "Invalid transit network selection"},
+	{0x5f, "Invalid message, unspecified"},
+	{0x60, "Mandatory information element is missing"},
+	{0x61, "Message type non-existent or not implemented"},
+	{0x62, "Message not compatible with call state or message type non-existent or not implemented"},
+	{0x63, "Information element/parameter non-existent or not implemented"},
+	{0x64, "Invalid information element contents"},
+	{0x65, "Message not compatible with call state"},
+	{0x66, "Recovery on timer expiry"},
+	{0x67, "Parameter non-existent or not implemented - passed on"},
+	{0x6e, "Message with unrecognized parameter discarded"},
+	{0x6f, "Protocol error, unspecified"},
+	{0x7f, "Interworking, unspecified"}
+};
+
+#endif
+
+static struct isdn_event_desc {
+	unsigned short ev;
+	char *desc;
+} isdn_event_table[] = {
+	{EV_USR_SETUP_REQ,     "CC->L3: Setup Request"},
+	{EV_USR_SETUP_RESP,    "CC->L3: Setup Response"},
+	{EV_USR_PROCED_REQ,    "CC->L3: Proceeding Request"},
+	{EV_USR_RELEASE_REQ,   "CC->L3: Release Request"},
+
+	{EV_NET_SETUP,        "NET->TE: setup "},
+	{EV_NET_CALL_PROC,    "NET->TE: call proceeding"},
+	{EV_NET_SETUP_ACK,    "NET->TE: setup acknowledge (more info needed)"},
+	{EV_NET_CONN,         "NET->TE: connect"},
+	{EV_NET_CONN_ACK,     "NET->TE: connect acknowledge"},
+	{EV_NET_DISC,         "NET->TE: disconnect indication"},
+	{EV_NET_RELEASE,      "NET->TE: release"},
+	{EV_NET_RELEASE_COMP, "NET->TE: release complete"},
+	{EV_NET_SELP_RESP,    "Board: Select B-channel protocol ack"},
+	{EV_NET_ACTV_RESP,    "Board: Activate B-channel protocol ack"},
+	{EV_TIMER,            "Timeout"},
+	{0, "NULL"}
+};
+
+char *strisdnevent(ushort ev)
+{
+	struct isdn_event_desc *entry;
+
+	for (entry = isdn_event_table; entry->ev; entry++)
+		if (entry->ev == ev)
+			break;
+
+	return entry->desc;
+}
+
+/*
+ * Euro ISDN finite state machine
+ */
+
+static struct fsm_timer_entry fsm_timers[] = {
+	{ST_CALL_PROC, 10},
+	{ST_DISC_REQ, 2},
+	{ST_ACTIVE_SELP, 5},
+	{ST_ACTIVE_ACTV, 5},
+	{ST_INCM_PROC, 10},
+	{ST_CONN_REQ, 2},
+	{0xff, 0}
+};
+
+static struct fsm_entry fsm_table[] = {
+/* Connect Phase */
+	/* Outgoing */
+	{ST_NULL, ST_CALL_INIT, EV_USR_SETUP_REQ, cb_out_1},
+
+	{ST_CALL_INIT, ST_OVER_SEND, EV_NET_SETUP_ACK, cb_notdone},
+	{ST_CALL_INIT, ST_CALL_PROC, EV_NET_CALL_PROC, NULL},
+	{ST_CALL_INIT, ST_NULL, EV_NET_DISC, cb_out_2},
+
+	{ST_CALL_PROC, ST_ACTIVE_SELP, EV_NET_CONN, cb_out_2},
+	{ST_CALL_PROC, ST_NULL, EV_NET_DISC, cb_disc_1},
+	{ST_CALL_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+	/* Incoming */
+	{ST_NULL, ST_CALL_PRES, EV_NET_SETUP, NULL},
+
+	{ST_CALL_PRES, ST_INCM_PROC, EV_USR_PROCED_REQ, cb_in_1},
+	{ST_CALL_PRES, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+	{ST_INCM_PROC, ST_CONN_REQ, EV_USR_SETUP_RESP, cb_in_2},
+	{ST_INCM_PROC, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+	{ST_CONN_REQ, ST_ACTIVE_SELP, EV_NET_CONN_ACK, cb_in_3},
+
+	/* Active */
+	{ST_ACTIVE, ST_NULL, EV_NET_DISC, cb_disc_1},
+	{ST_ACTIVE, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+	{ST_ACTIVE, ST_NULL, EV_NET_RELEASE, cb_disc_3},
+
+	/* Disconnect */
+
+	{ST_DISC_REQ, ST_NULL, EV_NET_DISC, cb_disc_1},
+	{ST_DISC_REQ, ST_NULL, EV_NET_RELEASE, cb_disc_3},
+
+	/* protocol selection */
+	{ST_ACTIVE_SELP, ST_ACTIVE_ACTV, EV_NET_SELP_RESP, cb_selp_1},
+	{ST_ACTIVE_SELP, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+	{ST_ACTIVE_ACTV, ST_ACTIVE, EV_NET_ACTV_RESP, cb_open},
+	{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_USR_RELEASE_REQ, cb_disc_2},
+
+	/* Timers */
+	{ST_CALL_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+	{ST_DISC_REQ, ST_NULL, EV_TIMER, cb_disc_3},
+	{ST_ACTIVE_SELP, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+	{ST_ACTIVE_ACTV, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+	{ST_INCM_PROC, ST_DISC_REQ, EV_TIMER, cb_disc_2},
+	{ST_CONN_REQ, ST_CONN_REQ, EV_TIMER, cb_in_2},
+
+	{0xff, 0, 0, NULL}
+};
+
+
+static void pcbit_fsm_timer(unsigned long data)
+{
+	struct pcbit_dev *dev;
+	struct pcbit_chan *chan;
+
+	chan = (struct pcbit_chan *) data;
+
+	del_timer(&chan->fsm_timer);
+	chan->fsm_timer.function = NULL;
+
+	dev = chan2dev(chan);
+
+	if (dev == NULL) {
+		printk(KERN_WARNING "pcbit: timer for unknown device\n");
+		return;
+	}
+
+	pcbit_fsm_event(dev, chan, EV_TIMER, NULL);
+}
+
+
+void pcbit_fsm_event(struct pcbit_dev *dev, struct pcbit_chan *chan,
+		     unsigned short event, struct callb_data *data)
+{
+	struct fsm_entry *action;
+	struct fsm_timer_entry *tentry;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	for (action = fsm_table; action->init != 0xff; action++)
+		if (action->init == chan->fsm_state && action->event == event)
+			break;
+
+	if (action->init == 0xff) {
+
+		spin_unlock_irqrestore(&dev->lock, flags);
+		printk(KERN_DEBUG "fsm error: event %x on state %x\n",
+		       event, chan->fsm_state);
+		return;
+	}
+
+	if (chan->fsm_timer.function) {
+		del_timer(&chan->fsm_timer);
+		chan->fsm_timer.function = NULL;
+	}
+
+	chan->fsm_state = action->final;
+
+	pcbit_state_change(dev, chan, action->init, event, action->final);
+
+	for (tentry = fsm_timers; tentry->init != 0xff; tentry++)
+		if (tentry->init == chan->fsm_state)
+			break;
+
+	if (tentry->init != 0xff) {
+		init_timer(&chan->fsm_timer);
+		chan->fsm_timer.function = &pcbit_fsm_timer;
+		chan->fsm_timer.data = (ulong) chan;
+		chan->fsm_timer.expires = jiffies + tentry->timeout * HZ;
+		add_timer(&chan->fsm_timer);
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	if (action->callb)
+		action->callb(dev, chan, data);
+
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.h b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.h
new file mode 100644
index 0000000..2f6b3a8
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/edss1.h
@@ -0,0 +1,99 @@
+/*
+ * DSS.1 module definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef EDSS1_H
+#define EDSS1_H
+
+/* ISDN states */
+
+#define ST_NULL      0
+#define ST_CALL_INIT 1    /* Call initiated */
+#define ST_OVER_SEND 2    /* Overlap sending - Requests More Info 4 call */
+#define ST_CALL_PROC 3    /* Call Proceeding */
+#define ST_CALL_DELV 4
+#define ST_CALL_PRES 6    /* Call Present - Received CONN.IND */
+#define ST_CALL_RECV 7    /* Alerting sent */
+#define ST_CONN_REQ  8    /* Answered - waiting 4 CONN.CONF */
+#define ST_INCM_PROC 9
+#define ST_ACTIVE    10
+#define ST_DISC_REQ  11
+#define ST_DISC_IND  12
+#define ST_SUSP_REQ  15
+#define ST_RESM_REQ  17
+#define ST_RELS_REQ  19
+#define ST_OVER_RECV 25
+
+#define ST_ACTIVE_SELP 26 /* Select protocol on B-Channel */
+#define ST_ACTIVE_ACTV 27 /* Activate B-channel protocol  */
+
+#define MAX_STATE ST_ACTIVE_ACTV
+
+#define EV_NULL               0
+#define EV_USR_SETUP_REQ      1
+#define EV_USR_SETUP_RESP     2
+#define EV_USR_PROCED_REQ     3
+#define EV_USR_RELEASE_REQ    4
+#define EV_USR_REJECT_REQ     4
+
+#define EV_NET_SETUP          16
+#define EV_NET_CALL_PROC      17
+#define EV_NET_SETUP_ACK      18
+#define EV_NET_CONN           19
+#define EV_NET_CONN_ACK       20
+
+#define EV_NET_SELP_RESP      21
+#define EV_NET_ACTV_RESP      22
+
+#define EV_NET_DISC           23
+#define EV_NET_RELEASE        24
+#define EV_NET_RELEASE_COMP   25
+
+#define EV_TIMER              26
+#define EV_ERROR              32
+
+/*
+ *  Cause values
+ *  only the ones we use
+ */
+
+#define CAUSE_NORMAL          0x10U
+#define CAUSE_NOCHAN          0x22U
+
+struct callb_data {
+	unsigned short type;
+	union {
+		struct ConnInfo {
+			char *CalledPN;
+			char *CallingPN;
+		} setup;
+		unsigned short cause;
+	} data;
+};
+
+struct fsm_entry {
+	unsigned short init;
+	unsigned short final;
+	unsigned short event;
+	void (*callb)(struct pcbit_dev *, struct pcbit_chan *, struct callb_data*);
+};
+
+struct fsm_timer_entry {
+	unsigned short init;
+	unsigned long timeout;          /* in seconds */
+};
+
+extern const char * const isdn_state_table[];
+
+void pcbit_fsm_event(struct pcbit_dev *, struct pcbit_chan *,
+		     unsigned short event, struct callb_data *);
+char *strisdnevent(ushort ev);
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.c
new file mode 100644
index 0000000..a18e639
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.c
@@ -0,0 +1,713 @@
+/*
+ * PCBIT-D low-layer interface
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+ */
+
+/*
+ *        Based on documentation provided by Inesc:
+ *        - "Interface com bus do PC para o PCBIT e PCBIT-D", Inesc, Jan 93
+ */
+
+/*
+ *        TODO: better handling of errors
+ *              re-write/remove debug printks
+ */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/workqueue.h>
+#include <linux/mm.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+
+#include <asm/io.h>
+
+
+#include "pcbit.h"
+#include "layer2.h"
+#include "edss1.h"
+
+#undef DEBUG_FRAG
+
+
+/*
+ *  Prototypes
+ */
+
+static void pcbit_transmit(struct pcbit_dev *dev);
+
+static void pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack);
+
+static void pcbit_l2_error(struct pcbit_dev *dev);
+static void pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info);
+static void pcbit_l2_err_recover(unsigned long data);
+
+static void pcbit_firmware_bug(struct pcbit_dev *dev);
+
+static __inline__ void
+pcbit_sched_delivery(struct pcbit_dev *dev)
+{
+	schedule_work(&dev->qdelivery);
+}
+
+
+/*
+ *  Called from layer3
+ */
+
+int
+pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+	       struct sk_buff *skb, unsigned short hdr_len)
+{
+	struct frame_buf *frame,
+		*ptr;
+	unsigned long flags;
+
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+		dev_kfree_skb(skb);
+		return -1;
+	}
+	if ((frame = kmalloc(sizeof(struct frame_buf),
+			     GFP_ATOMIC)) == NULL) {
+		printk(KERN_WARNING "pcbit_2_write: kmalloc failed\n");
+		dev_kfree_skb(skb);
+		return -1;
+	}
+	frame->msg = msg;
+	frame->refnum = refnum;
+	frame->copied = 0;
+	frame->hdr_len = hdr_len;
+
+	if (skb)
+		frame->dt_len = skb->len - hdr_len;
+	else
+		frame->dt_len = 0;
+
+	frame->skb = skb;
+
+	frame->next = NULL;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->write_queue == NULL) {
+		dev->write_queue = frame;
+		spin_unlock_irqrestore(&dev->lock, flags);
+		pcbit_transmit(dev);
+	} else {
+		for (ptr = dev->write_queue; ptr->next; ptr = ptr->next);
+		ptr->next = frame;
+
+		spin_unlock_irqrestore(&dev->lock, flags);
+	}
+	return 0;
+}
+
+static __inline__ void
+pcbit_tx_update(struct pcbit_dev *dev, ushort len)
+{
+	u_char info;
+
+	dev->send_seq = (dev->send_seq + 1) % 8;
+
+	dev->fsize[dev->send_seq] = len;
+	info = 0;
+	info |= dev->rcv_seq << 3;
+	info |= dev->send_seq;
+
+	writeb(info, dev->sh_mem + BANK4);
+
+}
+
+/*
+ * called by interrupt service routine or by write_2
+ */
+
+static void
+pcbit_transmit(struct pcbit_dev *dev)
+{
+	struct frame_buf *frame = NULL;
+	unsigned char unacked;
+	int flen;               /* fragment frame length including all headers */
+	int free;
+	int count,
+		cp_len;
+	unsigned long flags;
+	unsigned short tt;
+
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+		return;
+
+	unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->free > 16 && dev->write_queue && unacked < 7) {
+
+		if (!dev->w_busy)
+			dev->w_busy = 1;
+		else {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return;
+		}
+
+
+		frame = dev->write_queue;
+		free = dev->free;
+
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		if (frame->copied == 0) {
+
+			/* Type 0 frame */
+
+			ulong	msg;
+
+			if (frame->skb)
+				flen = FRAME_HDR_LEN + PREHDR_LEN + frame->skb->len;
+			else
+				flen = FRAME_HDR_LEN + PREHDR_LEN;
+
+			if (flen > free)
+				flen = free;
+
+			msg = frame->msg;
+
+			/*
+			 *  Board level 2 header
+			 */
+
+			pcbit_writew(dev, flen - FRAME_HDR_LEN);
+
+			pcbit_writeb(dev, GET_MSG_CPU(msg));
+
+			pcbit_writeb(dev, GET_MSG_PROC(msg));
+
+			/* TH */
+			pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
+
+			/* TD */
+			pcbit_writew(dev, frame->dt_len);
+
+
+			/*
+			 *  Board level 3 fixed-header
+			 */
+
+			/* LEN = TH */
+			pcbit_writew(dev, frame->hdr_len + PREHDR_LEN);
+
+			/* XX */
+			pcbit_writew(dev, 0);
+
+			/* C + S */
+			pcbit_writeb(dev, GET_MSG_CMD(msg));
+			pcbit_writeb(dev, GET_MSG_SCMD(msg));
+
+			/* NUM */
+			pcbit_writew(dev, frame->refnum);
+
+			count = FRAME_HDR_LEN + PREHDR_LEN;
+		} else {
+			/* Type 1 frame */
+
+			flen = 2 + (frame->skb->len - frame->copied);
+
+			if (flen > free)
+				flen = free;
+
+			/* TT */
+			tt = ((ushort) (flen - 2)) | 0x8000U;	/* Type 1 */
+			pcbit_writew(dev, tt);
+
+			count = 2;
+		}
+
+		if (frame->skb) {
+			cp_len = frame->skb->len - frame->copied;
+			if (cp_len > flen - count)
+				cp_len = flen - count;
+
+			memcpy_topcbit(dev, frame->skb->data + frame->copied,
+				       cp_len);
+			frame->copied += cp_len;
+		}
+		/* bookkeeping */
+		dev->free -= flen;
+		pcbit_tx_update(dev, flen);
+
+		spin_lock_irqsave(&dev->lock, flags);
+
+		if (frame->skb == NULL || frame->copied == frame->skb->len) {
+
+			dev->write_queue = frame->next;
+
+			if (frame->skb != NULL) {
+				/* free frame */
+				dev_kfree_skb(frame->skb);
+			}
+			kfree(frame);
+		}
+		dev->w_busy = 0;
+		spin_unlock_irqrestore(&dev->lock, flags);
+	} else {
+		spin_unlock_irqrestore(&dev->lock, flags);
+#ifdef DEBUG
+		printk(KERN_DEBUG "unacked %d free %d write_queue %s\n",
+		       unacked, dev->free, dev->write_queue ? "not empty" :
+		       "empty");
+#endif
+	}
+}
+
+
+/*
+ *  deliver a queued frame to the upper layer
+ */
+
+void
+pcbit_deliver(struct work_struct *work)
+{
+	struct frame_buf *frame;
+	unsigned long flags, msg;
+	struct pcbit_dev *dev =
+		container_of(work, struct pcbit_dev, qdelivery);
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	while ((frame = dev->read_queue)) {
+		dev->read_queue = frame->next;
+		spin_unlock_irqrestore(&dev->lock, flags);
+
+		msg = 0;
+		SET_MSG_CPU(msg, 0);
+		SET_MSG_PROC(msg, 0);
+		SET_MSG_CMD(msg, frame->skb->data[2]);
+		SET_MSG_SCMD(msg, frame->skb->data[3]);
+
+		frame->refnum = *((ushort *)frame->skb->data + 4);
+		frame->msg = *((ulong *)&msg);
+
+		skb_pull(frame->skb, 6);
+
+		pcbit_l3_receive(dev, frame->msg, frame->skb, frame->hdr_len,
+				 frame->refnum);
+
+		kfree(frame);
+
+		spin_lock_irqsave(&dev->lock, flags);
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ * Reads BANK 2 & Reassembles
+ */
+
+static void
+pcbit_receive(struct pcbit_dev *dev)
+{
+	unsigned short tt;
+	u_char cpu,
+		proc;
+	struct frame_buf *frame = NULL;
+	unsigned long flags;
+	u_char type1;
+
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING)
+		return;
+
+	tt = pcbit_readw(dev);
+
+	if ((tt & 0x7fffU) > 511) {
+		printk(KERN_INFO "pcbit: invalid frame length -> TT=%04x\n",
+		       tt);
+		pcbit_l2_error(dev);
+		return;
+	}
+	if (!(tt & 0x8000U)) {  /* Type 0 */
+		type1 = 0;
+
+		if (dev->read_frame) {
+			printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
+			/* discard previous queued frame */
+			kfree_skb(dev->read_frame->skb);
+			kfree(dev->read_frame);
+			dev->read_frame = NULL;
+		}
+		frame = kzalloc(sizeof(struct frame_buf), GFP_ATOMIC);
+
+		if (frame == NULL) {
+			printk(KERN_WARNING "kmalloc failed\n");
+			return;
+		}
+
+		cpu = pcbit_readb(dev);
+		proc = pcbit_readb(dev);
+
+
+		if (cpu != 0x06 && cpu != 0x02) {
+			printk(KERN_DEBUG "pcbit: invalid cpu value\n");
+			kfree(frame);
+			pcbit_l2_error(dev);
+			return;
+		}
+		/*
+		 * we discard cpu & proc on receiving
+		 * but we read it to update the pointer
+		 */
+
+		frame->hdr_len = pcbit_readw(dev);
+		frame->dt_len = pcbit_readw(dev);
+
+		/*
+		 * 0 sized packet
+		 * I don't know if they are an error or not...
+		 * But they are very frequent
+		 * Not documented
+		 */
+
+		if (frame->hdr_len == 0) {
+			kfree(frame);
+#ifdef DEBUG
+			printk(KERN_DEBUG "0 sized frame\n");
+#endif
+			pcbit_firmware_bug(dev);
+			return;
+		}
+		/* sanity check the length values */
+		if (frame->hdr_len > 1024 || frame->dt_len > 2048) {
+#ifdef DEBUG
+			printk(KERN_DEBUG "length problem: ");
+			printk(KERN_DEBUG "TH=%04x TD=%04x\n",
+			       frame->hdr_len,
+			       frame->dt_len);
+#endif
+			pcbit_l2_error(dev);
+			kfree(frame);
+			return;
+		}
+		/* minimum frame read */
+
+		frame->skb = dev_alloc_skb(frame->hdr_len + frame->dt_len +
+					   ((frame->hdr_len + 15) & ~15));
+
+		if (!frame->skb) {
+			printk(KERN_DEBUG "pcbit_receive: out of memory\n");
+			kfree(frame);
+			return;
+		}
+		/* 16 byte alignment for IP */
+		if (frame->dt_len)
+			skb_reserve(frame->skb, (frame->hdr_len + 15) & ~15);
+
+	} else {
+		/* Type 1 */
+		type1 = 1;
+		tt &= 0x7fffU;
+
+		if (!(frame = dev->read_frame)) {
+			printk("Type 1 frame and no frame queued\n");
+			/* usually after an error: toss frame */
+			dev->readptr += tt;
+			if (dev->readptr > dev->sh_mem + BANK2 + BANKLEN)
+				dev->readptr -= BANKLEN;
+			return;
+
+		}
+	}
+
+	memcpy_frompcbit(dev, skb_put(frame->skb, tt), tt);
+
+	frame->copied += tt;
+	spin_lock_irqsave(&dev->lock, flags);
+	if (frame->copied == frame->hdr_len + frame->dt_len) {
+
+		if (type1) {
+			dev->read_frame = NULL;
+		}
+		if (dev->read_queue) {
+			struct frame_buf *ptr;
+			for (ptr = dev->read_queue; ptr->next; ptr = ptr->next);
+			ptr->next = frame;
+		} else
+			dev->read_queue = frame;
+
+	} else {
+		dev->read_frame = frame;
+	}
+	spin_unlock_irqrestore(&dev->lock, flags);
+}
+
+/*
+ *  The board sends 0 sized frames
+ *  They are TDATA_CONFs that get messed up somehow
+ *  gotta send a fake acknowledgment to the upper layer somehow
+ */
+
+static __inline__ void
+pcbit_fake_conf(struct pcbit_dev *dev, struct pcbit_chan *chan)
+{
+	isdn_ctrl ictl;
+
+	if (chan->queued) {
+		chan->queued--;
+
+		ictl.driver = dev->id;
+		ictl.command = ISDN_STAT_BSENT;
+		ictl.arg = chan->id;
+		dev->dev_if->statcallb(&ictl);
+	}
+}
+
+static void
+pcbit_firmware_bug(struct pcbit_dev *dev)
+{
+	struct pcbit_chan *chan;
+
+	chan = dev->b1;
+
+	if (chan->fsm_state == ST_ACTIVE) {
+		pcbit_fake_conf(dev, chan);
+	}
+	chan = dev->b2;
+
+	if (chan->fsm_state == ST_ACTIVE) {
+		pcbit_fake_conf(dev, chan);
+	}
+}
+
+irqreturn_t
+pcbit_irq_handler(int interrupt, void *devptr)
+{
+	struct pcbit_dev *dev;
+	u_char info,
+		ack_seq,
+		read_seq;
+
+	dev = (struct pcbit_dev *) devptr;
+
+	if (!dev) {
+		printk(KERN_WARNING "pcbit_irq_handler: wrong device\n");
+		return IRQ_NONE;
+	}
+	if (dev->interrupt) {
+		printk(KERN_DEBUG "pcbit: reentering interrupt hander\n");
+		return IRQ_HANDLED;
+	}
+	dev->interrupt = 1;
+
+	info = readb(dev->sh_mem + BANK3);
+
+	if (dev->l2_state == L2_STARTING || dev->l2_state == L2_ERROR) {
+		pcbit_l2_active_conf(dev, info);
+		dev->interrupt = 0;
+		return IRQ_HANDLED;
+	}
+	if (info & 0x40U) {     /* E bit set */
+#ifdef DEBUG
+		printk(KERN_DEBUG "pcbit_irq_handler: E bit on\n");
+#endif
+		pcbit_l2_error(dev);
+		dev->interrupt = 0;
+		return IRQ_HANDLED;
+	}
+	if (dev->l2_state != L2_RUNNING && dev->l2_state != L2_LOADING) {
+		dev->interrupt = 0;
+		return IRQ_HANDLED;
+	}
+	ack_seq = (info >> 3) & 0x07U;
+	read_seq = (info & 0x07U);
+
+	dev->interrupt = 0;
+
+	if (read_seq != dev->rcv_seq) {
+		while (read_seq != dev->rcv_seq) {
+			pcbit_receive(dev);
+			dev->rcv_seq = (dev->rcv_seq + 1) % 8;
+		}
+		pcbit_sched_delivery(dev);
+	}
+	if (ack_seq != dev->unack_seq) {
+		pcbit_recv_ack(dev, ack_seq);
+	}
+	info = dev->rcv_seq << 3;
+	info |= dev->send_seq;
+
+	writeb(info, dev->sh_mem + BANK4);
+	return IRQ_HANDLED;
+}
+
+
+static void
+pcbit_l2_active_conf(struct pcbit_dev *dev, u_char info)
+{
+	u_char state;
+
+	state = dev->l2_state;
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "layer2_active_confirm\n");
+#endif
+
+
+	if (info & 0x80U) {
+		dev->rcv_seq = info & 0x07U;
+		dev->l2_state = L2_RUNNING;
+	} else
+		dev->l2_state = L2_DOWN;
+
+	if (state == L2_STARTING)
+		wake_up_interruptible(&dev->set_running_wq);
+
+	if (state == L2_ERROR && dev->l2_state == L2_RUNNING) {
+		pcbit_transmit(dev);
+	}
+}
+
+static void
+pcbit_l2_err_recover(unsigned long data)
+{
+
+	struct pcbit_dev *dev;
+	struct frame_buf *frame;
+
+	dev = (struct pcbit_dev *) data;
+
+	del_timer(&dev->error_recover_timer);
+	if (dev->w_busy || dev->r_busy) {
+		init_timer(&dev->error_recover_timer);
+		dev->error_recover_timer.expires = jiffies + ERRTIME;
+		add_timer(&dev->error_recover_timer);
+		return;
+	}
+	dev->w_busy = dev->r_busy = 1;
+
+	if (dev->read_frame) {
+		kfree_skb(dev->read_frame->skb);
+		kfree(dev->read_frame);
+		dev->read_frame = NULL;
+	}
+	if (dev->write_queue) {
+		frame = dev->write_queue;
+#ifdef FREE_ON_ERROR
+		dev->write_queue = dev->write_queue->next;
+
+		if (frame->skb) {
+			dev_kfree_skb(frame->skb);
+		}
+		kfree(frame);
+#else
+		frame->copied = 0;
+#endif
+	}
+	dev->rcv_seq = dev->send_seq = dev->unack_seq = 0;
+	dev->free = 511;
+	dev->l2_state = L2_ERROR;
+
+	/* this is an hack... */
+	pcbit_firmware_bug(dev);
+
+	dev->writeptr = dev->sh_mem;
+	dev->readptr = dev->sh_mem + BANK2;
+
+	writeb((0x80U | ((dev->rcv_seq & 0x07) << 3) | (dev->send_seq & 0x07)),
+	       dev->sh_mem + BANK4);
+	dev->w_busy = dev->r_busy = 0;
+
+}
+
+static void
+pcbit_l2_error(struct pcbit_dev *dev)
+{
+	if (dev->l2_state == L2_RUNNING) {
+
+		printk(KERN_INFO "pcbit: layer 2 error\n");
+
+#ifdef DEBUG
+		log_state(dev);
+#endif
+
+		dev->l2_state = L2_DOWN;
+
+		init_timer(&dev->error_recover_timer);
+		dev->error_recover_timer.function = &pcbit_l2_err_recover;
+		dev->error_recover_timer.data = (ulong) dev;
+		dev->error_recover_timer.expires = jiffies + ERRTIME;
+		add_timer(&dev->error_recover_timer);
+	}
+}
+
+/*
+ * Description:
+ * if board acks frames
+ *   update dev->free
+ *   call pcbit_transmit to write possible queued frames
+ */
+
+static void
+pcbit_recv_ack(struct pcbit_dev *dev, unsigned char ack)
+{
+	int i,
+		count;
+	int unacked;
+
+	unacked = (dev->send_seq + (8 - dev->unack_seq)) & 0x07;
+
+	/* dev->unack_seq < ack <= dev->send_seq; */
+
+	if (unacked) {
+
+		if (dev->send_seq > dev->unack_seq) {
+			if (ack <= dev->unack_seq || ack > dev->send_seq) {
+				printk(KERN_DEBUG
+				       "layer 2 ack unacceptable - dev %d",
+				       dev->id);
+
+				pcbit_l2_error(dev);
+			} else if (ack > dev->send_seq && ack <= dev->unack_seq) {
+				printk(KERN_DEBUG
+				       "layer 2 ack unacceptable - dev %d",
+				       dev->id);
+				pcbit_l2_error(dev);
+			}
+		}
+		/* ack is acceptable */
+
+
+		i = dev->unack_seq;
+
+		do {
+			dev->unack_seq = i = (i + 1) % 8;
+			dev->free += dev->fsize[i];
+		} while (i != ack);
+
+		count = 0;
+		while (count < 7 && dev->write_queue) {
+			u8 lsend_seq = dev->send_seq;
+
+			pcbit_transmit(dev);
+
+			if (dev->send_seq == lsend_seq)
+				break;
+			count++;
+		}
+	} else
+		printk(KERN_DEBUG "recv_ack: unacked = 0\n");
+}
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.h b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.h
new file mode 100644
index 0000000..be1327b
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/layer2.h
@@ -0,0 +1,281 @@
+/*
+ * PCBIT-D low-layer interface definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+/*
+ * 19991203 - Fernando Carvalho - takion@superbofh.org
+ * Hacked to compile with egcs and run with current version of isdn modules
+ */
+
+#ifndef LAYER2_H
+#define LAYER2_H
+
+#include <linux/interrupt.h>
+
+#include <asm/byteorder.h>
+
+#define BANK1 0x0000U /* PC -> Board */
+#define BANK2 0x01ffU /* Board -> PC */
+#define BANK3 0x03feU /* Att Board */
+#define BANK4 0x03ffU /* Att PC */
+
+#define BANKLEN 0x01FFU
+
+#define LOAD_ZONE_START 0x03f8U
+#define LOAD_ZONE_END   0x03fdU
+
+#define LOAD_RETRY      18000000
+
+
+
+/* TAM - XX - C - S  - NUM */
+#define PREHDR_LEN 8
+/* TT  - M  - I - TH - TD  */
+#define FRAME_HDR_LEN  8
+
+#define MSG_CONN_REQ		0x08000100
+#define MSG_CONN_CONF		0x00000101
+#define MSG_CONN_IND		0x00000102
+#define MSG_CONN_RESP		0x08000103
+
+#define MSG_CONN_ACTV_REQ	0x08000300
+#define MSG_CONN_ACTV_CONF	0x00000301
+#define MSG_CONN_ACTV_IND	0x00000302
+#define MSG_CONN_ACTV_RESP	0x08000303
+
+#define MSG_DISC_REQ		0x08000400
+#define MSG_DISC_CONF		0x00000401
+#define MSG_DISC_IND		0x00000402
+#define MSG_DISC_RESP		0x08000403
+
+#define MSG_TDATA_REQ		0x0908E200
+#define MSG_TDATA_CONF		0x0000E201
+#define MSG_TDATA_IND		0x0000E202
+#define MSG_TDATA_RESP		0x0908E203
+
+#define MSG_SELP_REQ		0x09004000
+#define MSG_SELP_CONF		0x00004001
+
+#define MSG_ACT_TRANSP_REQ      0x0908E000
+#define MSG_ACT_TRANSP_CONF     0x0000E001
+
+#define MSG_STPROT_REQ		0x09004100
+#define MSG_STPROT_CONF		0x00004101
+
+#define MSG_PING188_REQ		0x09030500
+#define MSG_PING188_CONF        0x000005bc
+
+#define MSG_WATCH188	        0x09030400
+
+#define MSG_API_ON              0x08020102
+#define MSG_POOL_PCBIT          0x08020400
+#define MSG_POOL_PCBIT_CONF     0x00000401
+
+#define MSG_INFO_IND            0x00002602
+#define MSG_INFO_RESP           0x08002603
+
+#define MSG_DEBUG_188           0x0000ff00
+
+/*
+
+  long  4 3 2 1
+  Intel 1 2 3 4
+*/
+
+#ifdef __LITTLE_ENDIAN
+#define SET_MSG_SCMD(msg, ch)	(msg = (msg & 0xffffff00) | (((ch) & 0xff)))
+#define SET_MSG_CMD(msg, ch)	(msg = (msg & 0xffff00ff) | (((ch) & 0xff) << 8))
+#define SET_MSG_PROC(msg, ch)	(msg = (msg & 0xff00ffff) | (((ch) & 0xff) << 16))
+#define SET_MSG_CPU(msg, ch)	(msg = (msg & 0x00ffffff) | (((ch) & 0xff) << 24))
+
+#define GET_MSG_SCMD(msg)	((msg) & 0xFF)
+#define GET_MSG_CMD(msg)	((msg) >> 8 & 0xFF)
+#define GET_MSG_PROC(msg)	((msg) >> 16 & 0xFF)
+#define GET_MSG_CPU(msg)	((msg) >> 24)
+
+#else
+#error "Non-Intel CPU"
+#endif
+
+#define MAX_QUEUED 7
+
+#define SCHED_READ    0x01
+#define SCHED_WRITE   0x02
+
+#define SET_RUN_TIMEOUT 2 * HZ /* 2 seconds */
+
+struct frame_buf {
+	ulong msg;
+	unsigned int refnum;
+	unsigned int dt_len;
+	unsigned int hdr_len;
+	struct sk_buff *skb;
+	unsigned int copied;
+	struct frame_buf *next;
+};
+
+extern int pcbit_l2_write(struct pcbit_dev *dev, ulong msg, ushort refnum,
+			  struct sk_buff *skb, unsigned short hdr_len);
+
+extern irqreturn_t pcbit_irq_handler(int interrupt, void *);
+
+extern struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
+
+#ifdef DEBUG
+static __inline__ void log_state(struct pcbit_dev *dev) {
+	printk(KERN_DEBUG "writeptr = %ld\n",
+	       (ulong) (dev->writeptr - dev->sh_mem));
+	printk(KERN_DEBUG "readptr  = %ld\n",
+	       (ulong) (dev->readptr - (dev->sh_mem + BANK2)));
+	printk(KERN_DEBUG "{rcv_seq=%01x, send_seq=%01x, unack_seq=%01x}\n",
+	       dev->rcv_seq, dev->send_seq, dev->unack_seq);
+}
+#endif
+
+static __inline__ struct pcbit_dev *chan2dev(struct pcbit_chan *chan)
+{
+	struct pcbit_dev *dev;
+	int i;
+
+
+	for (i = 0; i < MAX_PCBIT_CARDS; i++)
+		if ((dev = dev_pcbit[i]))
+			if (dev->b1 == chan || dev->b2 == chan)
+				return dev;
+	return NULL;
+
+}
+
+static __inline__ struct pcbit_dev *finddev(int id)
+{
+	struct pcbit_dev *dev;
+	int i;
+
+	for (i = 0; i < MAX_PCBIT_CARDS; i++)
+		if ((dev = dev_pcbit[i]))
+			if (dev->id == id)
+				return dev;
+	return NULL;
+}
+
+
+/*
+ *  Support routines for reading and writing in the board
+ */
+
+static __inline__ void pcbit_writeb(struct pcbit_dev *dev, unsigned char dt)
+{
+	writeb(dt, dev->writeptr++);
+	if (dev->writeptr == dev->sh_mem + BANKLEN)
+		dev->writeptr = dev->sh_mem;
+}
+
+static __inline__ void pcbit_writew(struct pcbit_dev *dev, unsigned short dt)
+{
+	int dist;
+
+	dist = BANKLEN - (dev->writeptr - dev->sh_mem);
+	switch (dist) {
+	case 2:
+		writew(dt, dev->writeptr);
+		dev->writeptr = dev->sh_mem;
+		break;
+	case 1:
+		writeb((u_char) (dt & 0x00ffU), dev->writeptr);
+		dev->writeptr = dev->sh_mem;
+		writeb((u_char) (dt >> 8), dev->writeptr++);
+		break;
+	default:
+		writew(dt, dev->writeptr);
+		dev->writeptr += 2;
+		break;
+	};
+}
+
+static __inline__ void memcpy_topcbit(struct pcbit_dev *dev, u_char *data,
+				      int len)
+{
+	int diff;
+
+	diff = len - (BANKLEN - (dev->writeptr - dev->sh_mem));
+
+	if (diff > 0)
+	{
+		memcpy_toio(dev->writeptr, data, len - diff);
+		memcpy_toio(dev->sh_mem, data + (len - diff), diff);
+		dev->writeptr = dev->sh_mem + diff;
+	}
+	else
+	{
+		memcpy_toio(dev->writeptr, data, len);
+
+		dev->writeptr += len;
+		if (diff == 0)
+			dev->writeptr = dev->sh_mem;
+	}
+}
+
+static __inline__ unsigned char pcbit_readb(struct pcbit_dev *dev)
+{
+	unsigned char val;
+
+	val = readb(dev->readptr++);
+	if (dev->readptr == dev->sh_mem + BANK2 + BANKLEN)
+		dev->readptr = dev->sh_mem + BANK2;
+
+	return val;
+}
+
+static __inline__ unsigned short pcbit_readw(struct pcbit_dev *dev)
+{
+	int dist;
+	unsigned short val;
+
+	dist = BANKLEN - (dev->readptr - (dev->sh_mem + BANK2));
+	switch (dist) {
+	case 2:
+		val = readw(dev->readptr);
+		dev->readptr = dev->sh_mem + BANK2;
+		break;
+	case 1:
+		val = readb(dev->readptr);
+		dev->readptr = dev->sh_mem + BANK2;
+		val = (readb(dev->readptr++) << 8) | val;
+		break;
+	default:
+		val = readw(dev->readptr);
+		dev->readptr += 2;
+		break;
+	};
+	return val;
+}
+
+static __inline__ void memcpy_frompcbit(struct pcbit_dev *dev, u_char *data, int len)
+{
+	int diff;
+
+	diff = len - (BANKLEN - (dev->readptr - (dev->sh_mem + BANK2)));
+	if (diff > 0)
+	{
+		memcpy_fromio(data, dev->readptr, len - diff);
+		memcpy_fromio(data + (len - diff), dev->sh_mem + BANK2 , diff);
+		dev->readptr = dev->sh_mem + BANK2 + diff;
+	}
+	else
+	{
+		memcpy_fromio(data, dev->readptr, len);
+		dev->readptr += len;
+		if (diff == 0)
+			dev->readptr = dev->sh_mem + BANK2;
+	}
+}
+
+
+#endif
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/module.c b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/module.c
new file mode 100644
index 0000000..0a59bd0
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/module.c
@@ -0,0 +1,125 @@
+/*
+ * PCBIT-D module support
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+
+#include <linux/isdnif.h>
+#include "pcbit.h"
+
+MODULE_DESCRIPTION("ISDN4Linux: Driver for PCBIT-T card");
+MODULE_AUTHOR("Pedro Roque Marques");
+MODULE_LICENSE("GPL");
+
+static int mem[MAX_PCBIT_CARDS];
+static int irq[MAX_PCBIT_CARDS];
+
+module_param_array(mem, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+
+static int num_boards;
+struct pcbit_dev *dev_pcbit[MAX_PCBIT_CARDS];
+
+static int __init pcbit_init(void)
+{
+	int board;
+
+	num_boards = 0;
+
+	printk(KERN_NOTICE
+	       "PCBIT-D device driver v 0.5-fjpc0 19991204 - "
+	       "Copyright (C) 1996 Universidade de Lisboa\n");
+
+	if (mem[0] || irq[0])
+	{
+		for (board = 0; board < MAX_PCBIT_CARDS && mem[board] && irq[board]; board++)
+		{
+			if (!mem[board])
+				mem[board] = 0xD0000;
+			if (!irq[board])
+				irq[board] = 5;
+
+			if (pcbit_init_dev(board, mem[board], irq[board]) == 0)
+				num_boards++;
+
+			else
+			{
+				printk(KERN_WARNING
+				       "pcbit_init failed for dev %d",
+				       board + 1);
+				return -EIO;
+			}
+		}
+	}
+
+	/* Hardcoded default settings detection */
+
+	if (!num_boards)
+	{
+		printk(KERN_INFO
+		       "Trying to detect board using default settings\n");
+		if (pcbit_init_dev(0, 0xD0000, 5) == 0)
+			num_boards++;
+		else
+			return -EIO;
+	}
+	return 0;
+}
+
+static void __exit pcbit_exit(void)
+{
+#ifdef MODULE
+	int board;
+
+	for (board = 0; board < num_boards; board++)
+		pcbit_terminate(board);
+	printk(KERN_NOTICE
+	       "PCBIT-D module unloaded\n");
+#endif
+}
+
+#ifndef MODULE
+#define MAX_PARA	(MAX_PCBIT_CARDS * 2)
+static int __init pcbit_setup(char *line)
+{
+	int i, j, argc;
+	char *str;
+	int ints[MAX_PARA + 1];
+
+	str = get_options(line, MAX_PARA, ints);
+	argc = ints[0];
+	i = 0;
+	j = 1;
+
+	while (argc && (i < MAX_PCBIT_CARDS)) {
+
+		if (argc) {
+			mem[i]	= ints[j];
+			j++; argc--;
+		}
+
+		if (argc) {
+			irq[i]	= ints[j];
+			j++; argc--;
+		}
+
+		i++;
+	}
+	return (1);
+}
+__setup("pcbit=", pcbit_setup);
+#endif
+
+module_init(pcbit_init);
+module_exit(pcbit_exit);
diff --git a/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/pcbit.h b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/pcbit.h
new file mode 100644
index 0000000..0a5a994
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/isdn/pcbit/pcbit.h
@@ -0,0 +1,177 @@
+/*
+ * PCBIT-D device driver definitions
+ *
+ * Copyright (C) 1996 Universidade de Lisboa
+ *
+ * Written by Pedro Roque Marques (roque@di.fc.ul.pt)
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License, incorporated herein by reference.
+ */
+
+#ifndef PCBIT_H
+#define PCBIT_H
+
+#include <linux/workqueue.h>
+
+#define MAX_PCBIT_CARDS 4
+
+
+#define BLOCK_TIMER
+
+#ifdef __KERNEL__
+
+struct pcbit_chan {
+	unsigned short id;
+	unsigned short callref;                   /* Call Reference */
+	unsigned char  proto;                     /* layer2protocol  */
+	unsigned char  queued;                    /* unacked data messages */
+	unsigned char  layer2link;                /* used in TData */
+	unsigned char  snum;                      /* used in TData */
+	unsigned short s_refnum;
+	unsigned short r_refnum;
+	unsigned short fsm_state;
+	struct timer_list fsm_timer;
+#ifdef BLOCK_TIMER
+	struct timer_list block_timer;
+#endif
+};
+
+struct msn_entry {
+	char *msn;
+	struct msn_entry *next;
+};
+
+struct pcbit_dev {
+	/* board */
+
+	volatile unsigned char __iomem *sh_mem;		/* RDP address	*/
+	unsigned long ph_mem;
+	unsigned int irq;
+	unsigned int id;
+	unsigned int interrupt;			/* set during interrupt
+						   processing */
+	spinlock_t lock;
+	/* isdn4linux */
+
+	struct msn_entry *msn_list;		/* ISDN address list */
+
+	isdn_if *dev_if;
+
+	ushort ll_hdrlen;
+	ushort hl_hdrlen;
+
+	/* link layer */
+	unsigned char l2_state;
+
+	struct frame_buf *read_queue;
+	struct frame_buf *read_frame;
+	struct frame_buf *write_queue;
+
+	/* Protocol start */
+	wait_queue_head_t set_running_wq;
+	struct timer_list set_running_timer;
+
+	struct timer_list error_recover_timer;
+
+	struct work_struct qdelivery;
+
+	u_char w_busy;
+	u_char r_busy;
+
+	volatile unsigned char __iomem *readptr;
+	volatile unsigned char __iomem *writeptr;
+
+	ushort loadptr;
+
+	unsigned short fsize[8];		/* sent layer2 frames size */
+
+	unsigned char send_seq;
+	unsigned char rcv_seq;
+	unsigned char unack_seq;
+
+	unsigned short free;
+
+	/* channels */
+
+	struct pcbit_chan *b1;
+	struct pcbit_chan *b2;
+};
+
+#define STATS_TIMER (10 * HZ)
+#define ERRTIME     (HZ / 10)
+
+/* MRU */
+#define MAXBUFSIZE  1534
+#define MRU   MAXBUFSIZE
+
+#define STATBUF_LEN 2048
+/*
+ *
+ */
+
+#endif /* __KERNEL__ */
+
+/* isdn_ctrl only allows a long sized argument */
+
+struct pcbit_ioctl {
+	union {
+		struct byte_op {
+			ushort addr;
+			ushort value;
+		} rdp_byte;
+		unsigned long l2_status;
+	} info;
+};
+
+
+
+#define PCBIT_IOCTL_GETSTAT  0x01    /* layer2 status */
+#define PCBIT_IOCTL_LWMODE   0x02    /* linear write mode */
+#define PCBIT_IOCTL_STRLOAD  0x03    /* start load mode */
+#define PCBIT_IOCTL_ENDLOAD  0x04    /* end load mode */
+#define PCBIT_IOCTL_SETBYTE  0x05    /* set byte */
+#define PCBIT_IOCTL_GETBYTE  0x06    /* get byte */
+#define PCBIT_IOCTL_RUNNING  0x07    /* set protocol running */
+#define PCBIT_IOCTL_WATCH188 0x08    /* set watch 188 */
+#define PCBIT_IOCTL_PING188  0x09    /* ping 188 */
+#define PCBIT_IOCTL_FWMODE   0x0A    /* firmware write mode */
+#define PCBIT_IOCTL_STOP     0x0B    /* stop protocol */
+#define PCBIT_IOCTL_APION    0x0C    /* issue API_ON  */
+
+#ifndef __KERNEL__
+
+#define PCBIT_GETSTAT  (PCBIT_IOCTL_GETSTAT  + IIOCDRVCTL)
+#define PCBIT_LWMODE   (PCBIT_IOCTL_LWMODE   + IIOCDRVCTL)
+#define PCBIT_STRLOAD  (PCBIT_IOCTL_STRLOAD  + IIOCDRVCTL)
+#define PCBIT_ENDLOAD  (PCBIT_IOCTL_ENDLOAD  + IIOCDRVCTL)
+#define PCBIT_SETBYTE  (PCBIT_IOCTL_SETBYTE  + IIOCDRVCTL)
+#define PCBIT_GETBYTE  (PCBIT_IOCTL_GETBYTE  + IIOCDRVCTL)
+#define PCBIT_RUNNING  (PCBIT_IOCTL_RUNNING  + IIOCDRVCTL)
+#define PCBIT_WATCH188 (PCBIT_IOCTL_WATCH188 + IIOCDRVCTL)
+#define PCBIT_PING188  (PCBIT_IOCTL_PING188  + IIOCDRVCTL)
+#define PCBIT_FWMODE   (PCBIT_IOCTL_FWMODE   + IIOCDRVCTL)
+#define PCBIT_STOP     (PCBIT_IOCTL_STOP     + IIOCDRVCTL)
+#define PCBIT_APION    (PCBIT_IOCTL_APION    + IIOCDRVCTL)
+
+#define MAXSUPERLINE 3000
+
+#endif
+
+#define L2_DOWN     0
+#define L2_LOADING  1
+#define L2_LWMODE   2
+#define L2_FWMODE   3
+#define L2_STARTING 4
+#define L2_RUNNING  5
+#define L2_ERROR    6
+
+void pcbit_deliver(struct work_struct *work);
+int pcbit_init_dev(int board, int mem_base, int irq);
+void pcbit_terminate(int board);
+void pcbit_l3_receive(struct pcbit_dev *dev, ulong msg, struct sk_buff *skb,
+		      ushort hdr_len, ushort refnum);
+void pcbit_state_change(struct pcbit_dev *dev, struct pcbit_chan *chan,
+			unsigned short i, unsigned short ev, unsigned short f);
+
+#endif