aboutsummaryrefslogtreecommitdiffstats
path: root/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch
diff options
context:
space:
mode:
Diffstat (limited to 'extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch')
-rw-r--r--extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch900
1 files changed, 900 insertions, 0 deletions
diff --git a/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch
new file mode 100644
index 00000000..c16dc453
--- /dev/null
+++ b/extras/recipes-kernel/linux/linux-omap/wl1271/0014-drivers-misc-ti-st-change-protocol-parse-logic.patch
@@ -0,0 +1,900 @@
+From 46b2c4077bedb96a38cdceff88f2c9b0a9923a8c Mon Sep 17 00:00:00 2001
+From: Pavan Savoy <pavan_savoy@ti.com>
+Date: Tue, 4 Jan 2011 10:59:47 +0000
+Subject: [PATCH 14/15] drivers:misc:ti-st: change protocol parse logic
+
+TI shared transport driver had to specifically know the
+protocol headers for each type of data it can receive to
+properly re-assemble data if its fragmented during UART
+transaction or fragment if the data is an assembly of
+
+different protocol data.
+
+Now the individual protocol drivers provide enough header
+information for shared transport driver to do this in a
+generic way applicable for all protocols.
+
+Signed-off-by: Pavan Savoy <pavan_savoy@ti.com>
+---
+ drivers/misc/ti-st/st_core.c | 355 +++++++++++++-----------------------------
+ drivers/misc/ti-st/st_kim.c | 56 ++++----
+ include/linux/ti_wilink_st.h | 40 ++++--
+ 3 files changed, 167 insertions(+), 284 deletions(-)
+
+diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
+index f9aad06..84d73c5 100644
+--- a/drivers/misc/ti-st/st_core.c
++++ b/drivers/misc/ti-st/st_core.c
+@@ -25,10 +25,9 @@
+ #include <linux/init.h>
+ #include <linux/tty.h>
+
+-/* understand BT, FM and GPS for now */
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci.h>
++#include <linux/seq_file.h>
++#include <linux/skbuff.h>
++
+ #include <linux/ti_wilink_st.h>
+
+ /* function pointer pointing to either,
+@@ -38,21 +37,20 @@
+ void (*st_recv) (void*, const unsigned char*, long);
+
+ /********************************************************************/
+-#if 0
+-/* internal misc functions */
+-bool is_protocol_list_empty(void)
++static void add_channel_to_table(struct st_data_s *st_gdata,
++ struct st_proto_s *new_proto)
+ {
+- unsigned char i = 0;
+- pr_debug(" %s ", __func__);
+- for (i = 0; i < ST_MAX; i++) {
+- if (st_gdata->list[i] != NULL)
+- return ST_NOTEMPTY;
+- /* not empty */
+- }
+- /* list empty */
+- return ST_EMPTY;
++ pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
++ /* list now has the channel id as index itself */
++ st_gdata->list[new_proto->chnl_id] = new_proto;
++}
++
++static void remove_channel_from_table(struct st_data_s *st_gdata,
++ struct st_proto_s *proto)
++{
++ pr_info("%s: id %d\n", __func__, proto->chnl_id);
++ st_gdata->list[proto->chnl_id] = NULL;
+ }
+-#endif
+
+ /* can be called in from
+ * -- KIM (during fw download)
+@@ -82,15 +80,15 @@ int st_int_write(struct st_data_s *st_gdata,
+ * push the skb received to relevant
+ * protocol stacks
+ */
+-void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
++void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
+ {
+- pr_info(" %s(prot:%d) ", __func__, protoid);
++ pr_info(" %s(prot:%d) ", __func__, chnl_id);
+
+ if (unlikely
+ (st_gdata == NULL || st_gdata->rx_skb == NULL
+- || st_gdata->list[protoid] == NULL)) {
+- pr_err("protocol %d not registered, no data to send?",
+- protoid);
++ || st_gdata->list[chnl_id] == NULL)) {
++ pr_err("chnl_id %d not registered, no data to send?",
++ chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ return;
+ }
+@@ -99,17 +97,17 @@ void st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
+ * - should be just skb_queue_tail for the
+ * protocol stack driver
+ */
+- if (likely(st_gdata->list[protoid]->recv != NULL)) {
++ if (likely(st_gdata->list[chnl_id]->recv != NULL)) {
+ if (unlikely
+- (st_gdata->list[protoid]->recv
+- (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
++ (st_gdata->list[chnl_id]->recv
++ (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb)
+ != 0)) {
+- pr_err(" proto stack %d's ->recv failed", protoid);
++ pr_err(" proto stack %d's ->recv failed", chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ return;
+ }
+ } else {
+- pr_err(" proto stack %d's ->recv null", protoid);
++ pr_err(" proto stack %d's ->recv null", chnl_id);
+ kfree_skb(st_gdata->rx_skb);
+ }
+ return;
+@@ -124,7 +122,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
+ {
+ unsigned char i = 0;
+ pr_info(" %s ", __func__);
+- for (i = 0; i < ST_MAX; i++) {
++ for (i = 0; i < ST_MAX_CHANNELS; i++) {
+ if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
+ st_gdata->list[i]->reg_complete_cb != NULL))
+ st_gdata->list[i]->reg_complete_cb
+@@ -133,7 +131,7 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
+ }
+
+ static inline int st_check_data_len(struct st_data_s *st_gdata,
+- int protoid, int len)
++ unsigned char chnl_id, int len)
+ {
+ int room = skb_tailroom(st_gdata->rx_skb);
+
+@@ -144,7 +142,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ * has zero length payload. So, ask ST CORE to
+ * forward the packet to protocol driver (BT/FM/GPS)
+ */
+- st_send_frame(protoid, st_gdata);
++ st_send_frame(chnl_id, st_gdata);
+
+ } else if (len > room) {
+ /* Received packet's payload length is larger.
+@@ -157,7 +155,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+- st_gdata->rx_state = ST_BT_W4_DATA;
++ st_gdata->rx_state = ST_W4_DATA;
+ st_gdata->rx_count = len;
+ return len;
+ }
+@@ -167,6 +165,7 @@ static inline int st_check_data_len(struct st_data_s *st_gdata,
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+ st_gdata->rx_count = 0;
++ st_gdata->rx_chnl = 0;
+
+ return 0;
+ }
+@@ -208,13 +207,10 @@ void st_int_recv(void *disc_data,
+ const unsigned char *data, long count)
+ {
+ char *ptr;
+- struct hci_event_hdr *eh;
+- struct hci_acl_hdr *ah;
+- struct hci_sco_hdr *sh;
+- struct fm_event_hdr *fm;
+- struct gps_event_hdr *gps;
+- int len = 0, type = 0, dlen = 0;
+- static enum proto_type protoid = ST_MAX;
++ struct st_proto_s *proto;
++ unsigned short payload_len = 0;
++ int len = 0, type = 0;
++ unsigned char *plen;
+ struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+
+ ptr = (char *)data;
+@@ -242,64 +238,36 @@ void st_int_recv(void *disc_data,
+
+ /* Check ST RX state machine , where are we? */
+ switch (st_gdata->rx_state) {
+-
+- /* Waiting for complete packet ? */
+- case ST_BT_W4_DATA:
++ /* Waiting for complete packet ? */
++ case ST_W4_DATA:
+ pr_debug("Complete pkt received");
+-
+ /* Ask ST CORE to forward
+ * the packet to protocol driver */
+- st_send_frame(protoid, st_gdata);
++ st_send_frame(st_gdata->rx_chnl, st_gdata);
+
+ st_gdata->rx_state = ST_W4_PACKET_TYPE;
+ st_gdata->rx_skb = NULL;
+- protoid = ST_MAX; /* is this required ? */
+- continue;
+-
+- /* Waiting for Bluetooth event header ? */
+- case ST_BT_W4_EVENT_HDR:
+- eh = (struct hci_event_hdr *)st_gdata->rx_skb->
+- data;
+-
+- pr_debug("Event header: evt 0x%2.2x"
+- "plen %d", eh->evt, eh->plen);
+-
+- st_check_data_len(st_gdata, protoid, eh->plen);
+- continue;
+-
+- /* Waiting for Bluetooth acl header ? */
+- case ST_BT_W4_ACL_HDR:
+- ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
+- data;
+- dlen = __le16_to_cpu(ah->dlen);
+-
+- pr_info("ACL header: dlen %d", dlen);
+-
+- st_check_data_len(st_gdata, protoid, dlen);
+- continue;
+-
+- /* Waiting for Bluetooth sco header ? */
+- case ST_BT_W4_SCO_HDR:
+- sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
+- data;
+-
+- pr_info("SCO header: dlen %d", sh->dlen);
+-
+- st_check_data_len(st_gdata, protoid, sh->dlen);
+- continue;
+- case ST_FM_W4_EVENT_HDR:
+- fm = (struct fm_event_hdr *)st_gdata->rx_skb->
+- data;
+- pr_info("FM Header: ");
+- st_check_data_len(st_gdata, ST_FM, fm->plen);
+ continue;
+- /* TODO : Add GPS packet machine logic here */
+- case ST_GPS_W4_EVENT_HDR:
+- /* [0x09 pkt hdr][R/W byte][2 byte len] */
+- gps = (struct gps_event_hdr *)st_gdata->rx_skb->
+- data;
+- pr_info("GPS Header: ");
+- st_check_data_len(st_gdata, ST_GPS, gps->plen);
++ /* parse the header to know details */
++ case ST_W4_HEADER:
++ proto = st_gdata->list[st_gdata->rx_chnl];
++ plen =
++ &st_gdata->rx_skb->data
++ [proto->offset_len_in_hdr];
++ pr_info("plen pointing to %x\n", *plen);
++ if (proto->len_size == 1)/* 1 byte len field */
++ payload_len = *(unsigned char *)plen;
++ else if (proto->len_size == 2)
++ payload_len =
++ __le16_to_cpu(*(unsigned short *)plen);
++ else
++ pr_info("%s: invalid length "
++ "for id %d\n",
++ __func__, proto->chnl_id);
++ st_check_data_len(st_gdata, proto->chnl_id,
++ payload_len);
++ pr_info("off %d, pay len %d\n",
++ proto->offset_len_in_hdr, payload_len);
+ continue;
+ } /* end of switch rx_state */
+ }
+@@ -308,51 +276,6 @@ void st_int_recv(void *disc_data,
+ /* Check first byte of packet and identify module
+ * owner (BT/FM/GPS) */
+ switch (*ptr) {
+-
+- /* Bluetooth event packet? */
+- case HCI_EVENT_PKT:
+- pr_info("Event packet");
+- st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+- st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+- type = HCI_EVENT_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Bluetooth acl packet? */
+- case HCI_ACLDATA_PKT:
+- pr_info("ACL packet");
+- st_gdata->rx_state = ST_BT_W4_ACL_HDR;
+- st_gdata->rx_count = HCI_ACL_HDR_SIZE;
+- type = HCI_ACLDATA_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Bluetooth sco packet? */
+- case HCI_SCODATA_PKT:
+- pr_info("SCO packet");
+- st_gdata->rx_state = ST_BT_W4_SCO_HDR;
+- st_gdata->rx_count = HCI_SCO_HDR_SIZE;
+- type = HCI_SCODATA_PKT;
+- protoid = ST_BT;
+- break;
+-
+- /* Channel 8(FM) packet? */
+- case ST_FM_CH8_PKT:
+- pr_info("FM CH8 packet");
+- type = ST_FM_CH8_PKT;
+- st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
+- st_gdata->rx_count = FM_EVENT_HDR_SIZE;
+- protoid = ST_FM;
+- break;
+-
+- /* Channel 9(GPS) packet? */
+- case 0x9: /*ST_LL_GPS_CH9_PKT */
+- pr_info("GPS CH9 packet");
+- type = 0x9; /* ST_LL_GPS_CH9_PKT; */
+- protoid = ST_GPS;
+- st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
+- st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/
+- break;
+ case LL_SLEEP_IND:
+ case LL_SLEEP_ACK:
+ case LL_WAKE_UP_IND:
+@@ -373,57 +296,22 @@ void st_int_recv(void *disc_data,
+ continue;
+ /* Unknow packet? */
+ default:
+- pr_err("Unknown packet type %2.2x", (__u8) *ptr);
+- ptr++;
+- count--;
+- continue;
++ type = *ptr;
++ st_gdata->rx_skb = alloc_skb(
++ st_gdata->list[type]->max_frame_size,
++ GFP_ATOMIC);
++ skb_reserve(st_gdata->rx_skb,
++ st_gdata->list[type]->reserve);
++ /* next 2 required for BT only */
++ st_gdata->rx_skb->cb[0] = type; /*pkt_type*/
++ st_gdata->rx_skb->cb[1] = 0; /*incoming*/
++ st_gdata->rx_chnl = *ptr;
++ st_gdata->rx_state = ST_W4_HEADER;
++ st_gdata->rx_count = st_gdata->list[type]->hdr_len;
++ pr_info("rx_count %ld\n", st_gdata->rx_count);
+ };
+ ptr++;
+ count--;
+-
+- switch (protoid) {
+- case ST_BT:
+- /* Allocate new packet to hold received data */
+- st_gdata->rx_skb =
+- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- bt_cb(st_gdata->rx_skb)->pkt_type = type;
+- break;
+- case ST_FM: /* for FM */
+- st_gdata->rx_skb =
+- alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- /* place holder 0x08 */
+- skb_reserve(st_gdata->rx_skb, 1);
+- st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
+- break;
+- case ST_GPS:
+- /* for GPS */
+- st_gdata->rx_skb =
+- alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
+- if (!st_gdata->rx_skb) {
+- pr_err("Can't allocate mem for new packet");
+- st_gdata->rx_state = ST_W4_PACKET_TYPE;
+- st_gdata->rx_count = 0;
+- return;
+- }
+- /* place holder 0x09 */
+- skb_reserve(st_gdata->rx_skb, 1);
+- st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */
+- break;
+- case ST_MAX:
+- break;
+- }
+ }
+ pr_debug("done %s", __func__);
+ return;
+@@ -565,20 +453,28 @@ long st_register(struct st_proto_s *new_proto)
+ unsigned long flags = 0;
+
+ st_kim_ref(&st_gdata, 0);
+- pr_info("%s(%d) ", __func__, new_proto->type);
++ pr_info("%s(%d) ", __func__, new_proto->chnl_id);
+ if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
+ || new_proto->reg_complete_cb == NULL) {
+ pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
++ if (st_gdata == NULL)
++ pr_err("error 1\n");
++ if (new_proto == NULL)
++ pr_err("error 2\n");
++ if (new_proto->recv == NULL)
++ pr_err("error 3\n");
++ if (new_proto->reg_complete_cb == NULL)
++ pr_err("erro 4\n");
+ return -1;
+ }
+
+- if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
+- pr_err("protocol %d not supported", new_proto->type);
++ if (new_proto->chnl_id >= ST_MAX_CHANNELS) {
++ pr_err("chnl_id %d not supported", new_proto->chnl_id);
+ return -EPROTONOSUPPORT;
+ }
+
+- if (st_gdata->list[new_proto->type] != NULL) {
+- pr_err("protocol %d already registered", new_proto->type);
++ if (st_gdata->list[new_proto->chnl_id] != NULL) {
++ pr_err("chnl_id %d already registered", new_proto->chnl_id);
+ return -EALREADY;
+ }
+
+@@ -586,11 +482,11 @@ long st_register(struct st_proto_s *new_proto)
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
+ if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
+- pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
++ pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id);
+ /* fw download in progress */
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
++ st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE);
+
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+
+@@ -598,7 +494,7 @@ long st_register(struct st_proto_s *new_proto)
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return -EINPROGRESS;
+ } else if (st_gdata->protos_registered == ST_EMPTY) {
+- pr_info(" protocol list empty :%d ", new_proto->type);
++ pr_info(" chnl_id list empty :%d ", new_proto->chnl_id);
+ set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_kim_recv;
+
+@@ -622,9 +518,9 @@ long st_register(struct st_proto_s *new_proto)
+ return -1;
+ }
+
+- /* the protocol might require other gpios to be toggled
++ /* the chnl_id might require other gpios to be toggled
+ */
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
++ st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE);
+
+ clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+ st_recv = st_int_recv;
+@@ -642,14 +538,14 @@ long st_register(struct st_proto_s *new_proto)
+ /* check for already registered once more,
+ * since the above check is old
+ */
+- if (st_gdata->list[new_proto->type] != NULL) {
++ if (st_gdata->list[new_proto->chnl_id] != NULL) {
+ pr_err(" proto %d already registered ",
+- new_proto->type);
++ new_proto->chnl_id);
+ return -EALREADY;
+ }
+
+ spin_lock_irqsave(&st_gdata->lock, flags);
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+@@ -657,22 +553,7 @@ long st_register(struct st_proto_s *new_proto)
+ }
+ /* if fw is already downloaded & new stack registers protocol */
+ else {
+- switch (new_proto->type) {
+- case ST_BT:
+- /* do nothing */
+- break;
+- case ST_FM:
+- case ST_GPS:
+- st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+- break;
+- case ST_MAX:
+- default:
+- pr_err("%d protocol not supported",
+- new_proto->type);
+- spin_unlock_irqrestore(&st_gdata->lock, flags);
+- return -EPROTONOSUPPORT;
+- }
+- st_gdata->list[new_proto->type] = new_proto;
++ add_channel_to_table(st_gdata, new_proto);
+ st_gdata->protos_registered++;
+ new_proto->write = st_write;
+
+@@ -680,48 +561,48 @@ long st_register(struct st_proto_s *new_proto)
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return err;
+ }
+- pr_debug("done %s(%d) ", __func__, new_proto->type);
++ pr_debug("done %s(%d) ", __func__, new_proto->chnl_id);
+ }
+ EXPORT_SYMBOL_GPL(st_register);
+
+ /* to unregister a protocol -
+ * to be called from protocol stack driver
+ */
+-long st_unregister(enum proto_type type)
++long st_unregister(struct st_proto_s *proto)
+ {
+ long err = 0;
+ unsigned long flags = 0;
+ struct st_data_s *st_gdata;
+
+- pr_debug("%s: %d ", __func__, type);
++ pr_debug("%s: %d ", __func__, proto->chnl_id);
+
+ st_kim_ref(&st_gdata, 0);
+- if (type < ST_BT || type >= ST_MAX) {
+- pr_err(" protocol %d not supported", type);
++ if (proto->chnl_id >= ST_MAX_CHANNELS) {
++ pr_err(" chnl_id %d not supported", proto->chnl_id);
+ return -EPROTONOSUPPORT;
+ }
+
+ spin_lock_irqsave(&st_gdata->lock, flags);
+
+- if (st_gdata->list[type] == NULL) {
+- pr_err(" protocol %d not registered", type);
++ if (st_gdata->list[proto->chnl_id] == NULL) {
++ pr_err(" chnl_id %d not registered", proto->chnl_id);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+ return -EPROTONOSUPPORT;
+ }
+
+ st_gdata->protos_registered--;
+- st_gdata->list[type] = NULL;
++ remove_channel_from_table(st_gdata, proto);
+
+ /* kim ignores BT in the below function
+ * and handles the rest, BT is toggled
+ * only in kim_start and kim_stop
+ */
+- st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
++ st_kim_chip_toggle(proto->chnl_id, KIM_GPIO_INACTIVE);
+ spin_unlock_irqrestore(&st_gdata->lock, flags);
+
+ if ((st_gdata->protos_registered == ST_EMPTY) &&
+ (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+- pr_info(" all protocols unregistered ");
++ pr_info(" all chnl_ids unregistered ");
+
+ /* stop traffic on tty */
+ if (st_gdata->tty) {
+@@ -729,7 +610,7 @@ long st_unregister(enum proto_type type)
+ stop_tty(st_gdata->tty);
+ }
+
+- /* all protocols now unregistered */
++ /* all chnl_ids now unregistered */
+ st_kim_stop(st_gdata->kim_data);
+ /* disable ST LL */
+ st_ll_disable(st_gdata);
+@@ -745,7 +626,7 @@ long st_write(struct sk_buff *skb)
+ {
+ struct st_data_s *st_gdata;
+ #ifdef DEBUG
+- enum proto_type protoid = ST_MAX;
++ unsigned char chnl_id = ST_MAX_CHANNELS;
+ #endif
+ long len;
+
+@@ -756,22 +637,10 @@ long st_write(struct sk_buff *skb)
+ return -1;
+ }
+ #ifdef DEBUG /* open-up skb to read the 1st byte */
+- switch (skb->data[0]) {
+- case HCI_COMMAND_PKT:
+- case HCI_ACLDATA_PKT:
+- case HCI_SCODATA_PKT:
+- protoid = ST_BT;
+- break;
+- case ST_FM_CH8_PKT:
+- protoid = ST_FM;
+- break;
+- case 0x09:
+- protoid = ST_GPS;
+- break;
+- }
+- if (unlikely(st_gdata->list[protoid] == NULL)) {
+- pr_err(" protocol %d not registered, and writing? ",
+- protoid);
++ chnl_id = skb->data[0];
++ if (unlikely(st_gdata->list[chnl_id] == NULL)) {
++ pr_err(" chnl_id %d not registered, and writing? ",
++ chnl_id);
+ return -1;
+ }
+ #endif
+@@ -824,7 +693,7 @@ static int st_tty_open(struct tty_struct *tty)
+
+ static void st_tty_close(struct tty_struct *tty)
+ {
+- unsigned char i = ST_MAX;
++ unsigned char i = ST_MAX_CHANNELS;
+ unsigned long flags = 0;
+ struct st_data_s *st_gdata = tty->disc_data;
+
+@@ -835,7 +704,7 @@ static void st_tty_close(struct tty_struct *tty)
+ * un-installed for some reason - what should be done ?
+ */
+ spin_lock_irqsave(&st_gdata->lock, flags);
+- for (i = ST_BT; i < ST_MAX; i++) {
++ for (i = ST_BT; i < ST_MAX_CHANNELS; i++) {
+ if (st_gdata->list[i] != NULL)
+ pr_err("%d not un-registered", i);
+ st_gdata->list[i] = NULL;
+@@ -869,7 +738,7 @@ static void st_tty_close(struct tty_struct *tty)
+ static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+ char *tty_flags, int count)
+ {
+-
++#define VERBOSE
+ #ifdef VERBOSE
+ print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
+ 16, 1, data, count, 0);
+diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
+index 73b6c8b..707c858 100644
+--- a/drivers/misc/ti-st/st_kim.c
++++ b/drivers/misc/ti-st/st_kim.c
+@@ -32,11 +32,7 @@
+ #include <linux/sched.h>
+ #include <linux/rfkill.h>
+
+-/* understand BT events for fw response */
+-#include <net/bluetooth/bluetooth.h>
+-#include <net/bluetooth/hci_core.h>
+-#include <net/bluetooth/hci.h>
+-
++#include <linux/skbuff.h>
+ #include <linux/ti_wilink_st.h>
+
+
+@@ -134,7 +130,7 @@ static inline int kim_check_data_len(struct kim_data_s *kim_gdata, int len)
+ /* Packet header has non-zero payload length and
+ * we have enough space in created skb. Lets read
+ * payload data */
+- kim_gdata->rx_state = ST_BT_W4_DATA;
++ kim_gdata->rx_state = ST_W4_DATA;
+ kim_gdata->rx_count = len;
+ return len;
+ }
+@@ -158,8 +154,8 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ const unsigned char *data, long count)
+ {
+ const unsigned char *ptr;
+- struct hci_event_hdr *eh;
+ int len = 0, type = 0;
++ unsigned char *plen;
+
+ pr_debug("%s", __func__);
+ /* Decode received bytes here */
+@@ -183,29 +179,27 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ /* Check ST RX state machine , where are we? */
+ switch (kim_gdata->rx_state) {
+ /* Waiting for complete packet ? */
+- case ST_BT_W4_DATA:
++ case ST_W4_DATA:
+ pr_debug("Complete pkt received");
+ validate_firmware_response(kim_gdata);
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_skb = NULL;
+ continue;
+ /* Waiting for Bluetooth event header ? */
+- case ST_BT_W4_EVENT_HDR:
+- eh = (struct hci_event_hdr *)kim_gdata->
+- rx_skb->data;
+- pr_debug("Event header: evt 0x%2.2x"
+- "plen %d", eh->evt, eh->plen);
+- kim_check_data_len(kim_gdata, eh->plen);
++ case ST_W4_HEADER:
++ plen =
++ (unsigned char *)&kim_gdata->rx_skb->data[1];
++ pr_debug("event hdr: plen 0x%02x\n", *plen);
++ kim_check_data_len(kim_gdata, *plen);
+ continue;
+ } /* end of switch */
+ } /* end of if rx_state */
+ switch (*ptr) {
+ /* Bluetooth event packet? */
+- case HCI_EVENT_PKT:
+- pr_info("Event packet");
+- kim_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+- kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+- type = HCI_EVENT_PKT;
++ case 0x04:
++ kim_gdata->rx_state = ST_W4_HEADER;
++ kim_gdata->rx_count = 2;
++ type = *ptr;
+ break;
+ default:
+ pr_info("unknown packet");
+@@ -216,16 +210,18 @@ void kim_int_recv(struct kim_data_s *kim_gdata,
+ ptr++;
+ count--;
+ kim_gdata->rx_skb =
+- bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
++ alloc_skb(1024+8, GFP_ATOMIC);
+ if (!kim_gdata->rx_skb) {
+ pr_err("can't allocate mem for new packet");
+ kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+ kim_gdata->rx_count = 0;
+ return;
+ }
+- bt_cb(kim_gdata->rx_skb)->pkt_type = type;
++ skb_reserve(kim_gdata->rx_skb, 8);
++ kim_gdata->rx_skb->cb[0] = 4;
++ kim_gdata->rx_skb->cb[1] = 0;
++
+ }
+- pr_info("done %s", __func__);
+ return;
+ }
+
+@@ -398,7 +394,7 @@ void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
+ gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW);
+ break;
+
+- case ST_MAX:
++ case ST_MAX_CHANNELS:
+ default:
+ break;
+ }
+@@ -416,7 +412,6 @@ void st_kim_recv(void *disc_data, const unsigned char *data, long count)
+ struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
+ struct kim_data_s *kim_gdata = st_gdata->kim_data;
+
+- pr_info(" %s ", __func__);
+ /* copy to local buffer */
+ if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
+ /* must be the read_ver_cmd */
+@@ -578,7 +573,7 @@ static int kim_toggle_radio(void *data, bool blocked)
+ else
+ st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
+ break;
+- case ST_MAX:
++ case ST_MAX_CHANNELS:
+ pr_err(" wrong proto type ");
+ break;
+ }
+@@ -664,12 +659,13 @@ static int kim_probe(struct platform_device *pdev)
+ /* refer to itself */
+ kim_gdata->core_data->kim_data = kim_gdata;
+
+- for (proto = 0; proto < ST_MAX; proto++) {
++ for (proto = 0; proto < ST_MAX_CHANNELS; proto++) {
+ kim_gdata->gpios[proto] = gpios[proto];
+ pr_info(" %ld gpio to be requested", gpios[proto]);
+ }
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+@@ -704,7 +700,8 @@ static int kim_probe(struct platform_device *pdev)
+ init_completion(&kim_gdata->kim_rcvd);
+ init_completion(&kim_gdata->ldisc_installed);
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* TODO: should all types be rfkill_type_bt ? */
+ kim_gdata->rf_protos[proto] = proto;
+ kim_gdata->rfkill[proto] = rfkill_alloc(protocol_names[proto],
+@@ -752,7 +749,8 @@ static int kim_remove(struct platform_device *pdev)
+
+ kim_gdata = dev_get_drvdata(&pdev->dev);
+
+- for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
++ for (proto = 0; (proto < ST_MAX_CHANNELS)
++ && (gpios[proto] != -1); proto++) {
+ /* Claim the Bluetooth/FM/GPIO
+ * nShutdown gpio from the system
+ */
+diff --git a/include/linux/ti_wilink_st.h b/include/linux/ti_wilink_st.h
+index 4c7be22..1674ca7 100644
+--- a/include/linux/ti_wilink_st.h
++++ b/include/linux/ti_wilink_st.h
+@@ -42,7 +42,7 @@ enum proto_type {
+ ST_BT,
+ ST_FM,
+ ST_GPS,
+- ST_MAX,
++ ST_MAX_CHANNELS = 16,
+ };
+
+ /**
+@@ -62,6 +62,17 @@ enum proto_type {
+ * @priv_data: privdate data holder for the protocol drivers, sent
+ * from the protocol drivers during registration, and sent back on
+ * reg_complete_cb and recv.
++ * @chnl_id: channel id the protocol driver is interested in, the channel
++ * id is nothing but the 1st byte of the packet in UART frame.
++ * @max_frame_size: size of the largest frame the protocol can receive.
++ * @hdr_len: length of the header structure of the protocol.
++ * @offset_len_in_hdr: this provides the offset of the length field in the
++ * header structure of the protocol header, to assist ST to know
++ * how much to receive, if the data is split across UART frames.
++ * @len_size: whether the length field inside the header is 2 bytes
++ * or 1 byte.
++ * @reserve: the number of bytes ST needs to reserve in the skb being
++ * prepared for the protocol driver.
+ */
+ struct st_proto_s {
+ enum proto_type type;
+@@ -70,10 +81,17 @@ struct st_proto_s {
+ void (*reg_complete_cb) (void *, char data);
+ long (*write) (struct sk_buff *skb);
+ void *priv_data;
++
++ unsigned char chnl_id;
++ unsigned short max_frame_size;
++ unsigned char hdr_len;
++ unsigned char offset_len_in_hdr;
++ unsigned char len_size;
++ unsigned char reserve;
+ };
+
+ extern long st_register(struct st_proto_s *);
+-extern long st_unregister(enum proto_type);
++extern long st_unregister(struct st_proto_s *);
+
+
+ /*
+@@ -114,6 +132,7 @@ extern long st_unregister(enum proto_type);
+ * @rx_skb: the skb where all data for a protocol gets accumulated,
+ * since tty might not call receive when a complete event packet
+ * is received, the states, count and the skb needs to be maintained.
++ * @rx_chnl: the channel ID for which the data is getting accumalated for.
+ * @txq: the list of skbs which needs to be sent onto the TTY.
+ * @tx_waitq: if the chip is not in AWAKE state, the skbs needs to be queued
+ * up in here, PM(WAKEUP_IND) data needs to be sent and then the skbs
+@@ -135,10 +154,11 @@ struct st_data_s {
+ #define ST_TX_SENDING 1
+ #define ST_TX_WAKEUP 2
+ unsigned long tx_state;
+- struct st_proto_s *list[ST_MAX];
++ struct st_proto_s *list[ST_MAX_CHANNELS];
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
++ unsigned char rx_chnl;
+ struct sk_buff_head txq, tx_waitq;
+ spinlock_t lock;
+ unsigned char protos_registered;
+@@ -243,12 +263,12 @@ struct kim_data_s {
+ struct completion kim_rcvd, ldisc_installed;
+ char resp_buffer[30];
+ const struct firmware *fw_entry;
+- long gpios[ST_MAX];
++ long gpios[ST_MAX_CHANNELS];
+ unsigned long rx_state;
+ unsigned long rx_count;
+ struct sk_buff *rx_skb;
+- struct rfkill *rfkill[ST_MAX];
+- enum proto_type rf_protos[ST_MAX];
++ struct rfkill *rfkill[ST_MAX_CHANNELS];
++ enum proto_type rf_protos[ST_MAX_CHANNELS];
+ struct st_data_s *core_data;
+ struct chip_version version;
+ };
+@@ -338,12 +358,8 @@ struct hci_command {
+
+ /* ST LL receiver states */
+ #define ST_W4_PACKET_TYPE 0
+-#define ST_BT_W4_EVENT_HDR 1
+-#define ST_BT_W4_ACL_HDR 2
+-#define ST_BT_W4_SCO_HDR 3
+-#define ST_BT_W4_DATA 4
+-#define ST_FM_W4_EVENT_HDR 5
+-#define ST_GPS_W4_EVENT_HDR 6
++#define ST_W4_HEADER 1
++#define ST_W4_DATA 2
+
+ /* ST LL state machines */
+ #define ST_LL_ASLEEP 0
+--
+1.6.6.1
+