st_core.c revision 320920cba355146258da7de80bed0069c1dff24a
153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  Shared Transport Line discipline driver Core
353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *	This hooks up ST KIM driver and ST LL driver
453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  Copyright (C) 2009 Texas Instruments
553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  This program is free software; you can redistribute it and/or modify
753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  it under the terms of the GNU General Public License version 2 as
853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  published by the Free Software Foundation.
953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
1053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  This program is distributed in the hope that it will be useful,
1153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  GNU General Public License for more details.
1453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
1553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  You should have received a copy of the GNU General Public License
1653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  along with this program; if not, write to the Free Software
1753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
1853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
1953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
2053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
2153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#define pr_fmt(fmt)	"(stc): " fmt
2253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/module.h>
2353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/kernel.h>
2453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/init.h>
2553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/tty.h>
2653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
2753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* understand BT, FM and GPS for now */
2853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <net/bluetooth/bluetooth.h>
2953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <net/bluetooth/hci_core.h>
3053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <net/bluetooth/hci.h>
3153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include "fm.h"
3253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
3353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet formats for fm and gps
3453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * #include "gps.h"
3553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
3653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include "st_core.h"
3753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include "st_kim.h"
3853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include "st_ll.h"
3953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include "st.h"
4053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
4153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG
4253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* strings to be used for rfkill entries and by
4353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * ST Core to be used for sysfs debug entry
4453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
4553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#define PROTO_ENTRY(type, name)	name
4653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyconst unsigned char *protocol_strngs[] = {
4753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_BT, "Bluetooth"),
4853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_FM, "FM"),
4953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_GPS, "GPS"),
5053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy};
5153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
5253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* function pointer pointing to either,
5353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_kim_recv during registration to receive fw download responses
5453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_int_recv after registration to receive proto stack responses
5553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
5653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid (*st_recv) (void*, const unsigned char*, long);
5753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
5853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
5953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
6053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal misc functions */
6153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoybool is_protocol_list_empty(void)
6253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
6353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = 0;
6453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" %s ", __func__);
6553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < ST_MAX; i++) {
6653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->list[i] != NULL)
6753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			return ST_NOTEMPTY;
6853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* not empty */
6953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
7053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* list empty */
7153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return ST_EMPTY;
7253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
7353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
7453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from
7553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download)
7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write)
7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  This is the internal write function - a wrapper
7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  to tty->ops->write
8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata,
8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	const unsigned char *data, int count)
8353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE			/* for debug */
8553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	int i;
8653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct tty_struct *tty;
8853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
8953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("tty unavailable to perform write");
90320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -1;
9153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
9253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty = st_gdata->tty;
9353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE
9453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	printk(KERN_ERR "start data..\n");
9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < count; i++)	/* no newlines for each datum */
9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		printk(" %x", data[i]);
9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	printk(KERN_ERR "\n ..end data\n");
9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return tty->ops->write(tty, data, count);
10053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
10153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
10253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
10353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
10453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant
10553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks
10653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
10953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" %s(prot:%d) ", __func__, protoid);
11053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
11153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely
11253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	    (st_gdata == NULL || st_gdata->rx_skb == NULL
11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	     || st_gdata->list[protoid] == NULL)) {
11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("protocol %d not registered, no data to send?",
11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   protoid);
11653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
11753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return;
11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
11953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* this cannot fail
12053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * this shouldn't take long
12153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * - should be just skb_queue_tail for the
12253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 *   protocol stack driver
12353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
12453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (likely(st_gdata->list[protoid]->recv != NULL)) {
12553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (unlikely(st_gdata->list[protoid]->recv(st_gdata->rx_skb)
126320920cba355146258da7de80bed0069c1dff24aPavan Savoy			     != 0)) {
12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err(" proto stack %d's ->recv failed", protoid);
12853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			kfree_skb(st_gdata->rx_skb);
12953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			return;
13053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
13153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} else {
13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" proto stack %d's ->recv null", protoid);
13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
13453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
13553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" done %s", __func__);
13653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
13753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
13853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks
14153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers
14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err)
14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
14553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = 0;
14653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" %s ", __func__);
14753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < ST_MAX; i++) {
14853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
14953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   st_gdata->list[i]->reg_complete_cb != NULL))
15053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->list[i]->reg_complete_cb(err);
15153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
15253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
15353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
15453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata,
15553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	int protoid, int len)
15653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
15753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register int room = skb_tailroom(st_gdata->rx_skb);
15853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
15953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("len %d room %d", len, room);
16053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
16153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (!len) {
16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Received packet has only packet header and
16353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * has zero length payload. So, ask ST CORE to
16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * forward the packet to protocol driver (BT/FM/GPS)
16553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_send_frame(protoid, st_gdata);
16753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
16853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} else if (len > room) {
16953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Received packet's payload length is larger.
17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * We can't accommodate it in created skb.
17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
17253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("Data length is too large len %d room %d", len,
17353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   room);
17453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
17553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} else {
17653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Packet header has non-zero payload length and
17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * we have enough space in created skb. Lets read
17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * payload data */
17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->rx_state = ST_BT_W4_DATA;
18053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->rx_count = len;
18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return len;
18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Change ST state to continue to process next
18553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * packet */
18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_state = ST_W4_PACKET_TYPE;
18753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_skb = NULL;
18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_count = 0;
18953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
19053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return 0;
19153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
19253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal function for action when wake-up ack
19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * received
19553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata,
19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char cmd)
19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
19953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register struct sk_buff *waiting_skb;
20053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
20153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
20253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
20353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* de-Q from waitQ and Q in txQ now that the
20453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * chip is awake
20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq)))
20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->txq, waiting_skb);
20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
20953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* state forwarded to ST LL */
21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ll_sleep_state(st_gdata, (unsigned long)cmd);
21153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* wake up to send the recently copied skbs from waitQ */
21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_tx_wakeup(st_gdata);
21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* Decodes received RAW data and forwards to corresponding
21853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * client drivers (Bluetooth,FM,GPS..etc).
21953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
22053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
22153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data,
22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	const unsigned char *data, long count)
22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register char *ptr;
22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_event_hdr *eh;
22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_acl_hdr *ah;
22753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_sco_hdr *sh;
22853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct fm_event_hdr *fm;
22953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct gps_event_hdr *gps;
23053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register int len = 0, type = 0, dlen = 0;
23153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	static enum proto_type protoid = ST_MAX;
23253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
23353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	ptr = (char *)data;
23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* tty_receive sent null ? */
23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(ptr == NULL) || (st_gdata == NULL)) {
23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" received null from TTY ");
23853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return;
23953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
24053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
24153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("count %ld rx_state %ld"
24253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		   "rx_count %ld", count, st_gdata->rx_state,
24353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		   st_gdata->rx_count);
24453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Decode received bytes here */
24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	while (count) {
24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->rx_count) {
24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			len = min_t(unsigned int, st_gdata->rx_count, count);
24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count -= len;
25153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count -= len;
25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr += len;
25353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (st_gdata->rx_count)
25553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
25653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
25753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Check ST RX state machine , where are we? */
25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			switch (st_gdata->rx_state) {
25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for complete packet ? */
26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_DATA:
26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("Complete pkt received");
26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Ask ST CORE to forward
26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				 * the packet to protocol driver */
26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_send_frame(protoid, st_gdata);
26753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_skb = NULL;
27053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				protoid = ST_MAX;	/* is this required ? */
27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
27253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth event header ? */
27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_EVENT_HDR:
27553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				eh = (struct hci_event_hdr *)st_gdata->rx_skb->
27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
27753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("Event header: evt 0x%2.2x"
27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy					   "plen %d", eh->evt, eh->plen);
28053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, eh->plen);
28253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
28353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
28453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth acl header ? */
28553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_ACL_HDR:
28653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
28753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
28853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				dlen = __le16_to_cpu(ah->dlen);
28953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
29053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("ACL header: dlen %d", dlen);
29153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
29253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, dlen);
29353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
29453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
29553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth sco header ? */
29653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_SCO_HDR:
29753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
29853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
29953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
30053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("SCO header: dlen %d", sh->dlen);
30153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
30253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, sh->dlen);
30353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
30453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_FM_W4_EVENT_HDR:
30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				fm = (struct fm_event_hdr *)st_gdata->rx_skb->
30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("FM Header: ");
30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, ST_FM, fm->plen);
30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* TODO : Add GPS packet machine logic here */
31153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_GPS_W4_EVENT_HDR:
31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* [0x09 pkt hdr][R/W byte][2 byte len] */
31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				gps = (struct gps_event_hdr *)st_gdata->rx_skb->
31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				     data;
31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("GPS Header: ");
31653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, ST_GPS, gps->plen);
31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
31853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}	/* end of switch rx_state */
31953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
32053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
32153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* end of if rx_count */
32253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Check first byte of packet and identify module
32353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * owner (BT/FM/GPS) */
32453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		switch (*ptr) {
32553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth event packet? */
32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_EVENT_PKT:
32853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("Event packet");
32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
33053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_EVENT_PKT;
33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
33353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
33453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
33553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth acl packet? */
33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_ACLDATA_PKT:
33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("ACL packet");
33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_ACL_HDR;
33953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_ACL_HDR_SIZE;
34053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_ACLDATA_PKT;
34153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
34253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
34353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
34453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth sco packet? */
34553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_SCODATA_PKT:
34653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("SCO packet");
34753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_SCO_HDR;
34853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_SCO_HDR_SIZE;
34953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_SCODATA_PKT;
35053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
35153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
35253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
35353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Channel 8(FM) packet? */
35453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_FM_CH8_PKT:
35553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("FM CH8 packet");
35653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = ST_FM_CH8_PKT;
35753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
35853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = FM_EVENT_HDR_SIZE;
35953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_FM;
36053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
36153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
36253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Channel 9(GPS) packet? */
36353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case 0x9:	/*ST_LL_GPS_CH9_PKT */
36453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("GPS CH9 packet");
36553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = 0x9;	/* ST_LL_GPS_CH9_PKT; */
36653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_GPS;
36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = 3;	/* GPS_EVENT_HDR_SIZE -1*/
36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_SLEEP_IND:
37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_SLEEP_ACK:
37253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_WAKE_UP_IND:
37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("PM packet");
37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* this takes appropriate action based on
37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			 * sleep state received --
37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			 */
37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_ll_sleep_state(st_gdata, *ptr);
37853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
37953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
38053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
38153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_WAKE_UP_ACK:
38253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("PM packet");
38353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* wake up ack received */
38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_wakeup_ack(st_gdata, *ptr);
38553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
38653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Unknow packet? */
38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		default:
39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("Unknown packet type %2.2x", (__u8) *ptr);
39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
39453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		};
39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		ptr++;
39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		count--;
39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
39853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		switch (protoid) {
39953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_BT:
40053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Allocate new packet to hold received data */
40153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
40253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
40553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			bt_cb(st_gdata->rx_skb)->pkt_type = type;
41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_FM:	/* for FM */
41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* place holder 0x08 */
42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			skb_reserve(st_gdata->rx_skb, 1);
42253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_GPS:
42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* for GPS */
42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* place holder 0x09 */
43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			skb_reserve(st_gdata->rx_skb, 1);
43653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb->cb[0] = 0x09;	/*ST_GPS_CH9_PKT; */
43753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_MAX:
43953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("done %s", __func__);
44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal de-Q function
44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- return previous in-completely written skb
44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  or return the skb in the txQ
44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
45053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
45153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
45253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct sk_buff *returning_skb;
45353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s", __func__);
45553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* if the previous skb wasn't written completely
45653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata->tx_skb != NULL) {
45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		returning_skb = st_gdata->tx_skb;
45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->tx_skb = NULL;
46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return returning_skb;
46153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* de-Q from the txQ always if previous write is complete */
46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return skb_dequeue(&st_gdata->txq);
46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
46753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal Q-ing function
46853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will either Q the skb to txq or the tx_waitq
46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * depending on the ST LL state
47053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
47153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * lock the whole func - since ll_getstate and Q-ing should happen
47253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * in one-shot
47353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
47453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
47653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
47753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s", __func__);
47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* this function can be invoked in more then one context.
48053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * so have a lock */
48153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
48253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
48353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	switch (st_ll_getstate(st_gdata)) {
48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_AWAKE:
48553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info("ST LL is AWAKE, sending normally");
48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->txq, skb);
48753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_ASLEEP_TO_AWAKE:
48953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->tx_waitq, skb);
49053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
49153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_AWAKE_TO_ASLEEP:	/* host cannot be in this state */
49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("ST LL is illegal state(%ld),"
49353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   "purging received skb.", st_ll_getstate(st_gdata));
49453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(skb);
49553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
49653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
49753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_ASLEEP:
49853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* call a function of ST LL to put data
49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * in tx_waitQ and wake_ind in txQ
50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->tx_waitq, skb);
50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_ll_wakeup(st_gdata);
50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	default:
50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("ST LL is illegal state(%ld),"
50653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   "purging received skb.", st_ll_getstate(st_gdata));
50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(skb);
50853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
50953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
51053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
51153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("done %s", __func__);
51253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
51453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
51553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
51653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function
51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either
51853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished
51953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack)
52053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
52153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data)
52253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
52353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct sk_buff *skb;
52453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags;	/* for irq save flags */
52553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s", __func__);
52653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* check for sending & set flag sending here */
52753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
52853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info("ST already sending");
52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* keep sending */
53053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		set_bit(ST_TX_WAKEUP, &st_data->tx_state);
53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return;
53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* TX_WAKEUP will be checked in another
53353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * context
53453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
53553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
53653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	do {			/* come back if st_tx_wakeup is set */
53753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* woke-up to write */
53853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		clear_bit(ST_TX_WAKEUP, &st_data->tx_state);
53953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		while ((skb = st_int_dequeue(st_data))) {
54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			int len;
54153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			spin_lock_irqsave(&st_data->lock, flags);
54253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* enable wake-up from TTY */
54353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags);
54453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			len = st_int_write(st_data, skb->data, skb->len);
54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			skb_pull(skb, len);
54653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* if skb->len = len as expected, skb->len=0 */
54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (skb->len) {
54853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* would be the next skb to be sent */
54953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_data->tx_skb = skb;
55053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				spin_unlock_irqrestore(&st_data->lock, flags);
55153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				break;
55253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			kfree_skb(skb);
55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			spin_unlock_irqrestore(&st_data->lock, flags);
55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
55653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* if wake-up is set in another context- restart sending */
55753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} while (test_bit(ST_TX_WAKEUP, &st_data->tx_state));
55853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
55953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* clear flag sending */
56053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	clear_bit(ST_TX_SENDING, &st_data->tx_state);
56153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
56253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
56353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
56453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM
56553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/
56653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, char *buf)
56753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
56853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
56953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG
57053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = ST_MAX;
57153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
57253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
57353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG			/* more detailed log */
57453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < ST_MAX; i++) {
57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (i == 0) {
57653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			sprintf(buf, "%s is %s", protocol_strngs[i],
57753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->list[i] !=
57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				NULL ? "Registered" : "Unregistered");
57953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		} else {
58053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			sprintf(buf, "%s\n%s is %s", buf, protocol_strngs[i],
58153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->list[i] !=
58253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				NULL ? "Registered" : "Unregistered");
58353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
58453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
58553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	sprintf(buf, "%s\n", buf);
58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#else /* limited info */
58736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain	sprintf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
58836e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain			st_gdata->protos_registered,
58936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain			st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
59036e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain			st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
59136e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain			st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
59253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
59353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
59453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
59553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
59853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers
59953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed
60053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
60153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto)
60253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
60353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s	*st_gdata;
604320920cba355146258da7de80bed0069c1dff24aPavan Savoy	long err = 0;
60553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
60653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
60753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_kim_ref(&st_gdata);
60853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s(%d) ", __func__, new_proto->type);
60953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
61053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	    || new_proto->reg_complete_cb == NULL) {
61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("gdata/new_proto/recv or reg_complete_cb not ready");
612320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -1;
61353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
61453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
61553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
61653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("protocol %d not supported", new_proto->type);
617320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -EPROTONOSUPPORT;
61853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
61953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata->list[new_proto->type] != NULL) {
62153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("protocol %d already registered", new_proto->type);
622320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -EALREADY;
62353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
62553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* can be from process context only */
62653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
62753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
62853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
62953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
63053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* fw download in progress */
63153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
63253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
63353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->list[new_proto->type] = new_proto;
63436e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain		st_gdata->protos_registered++;
63553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		new_proto->write = st_write;
63653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
63753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		set_bit(ST_REG_PENDING, &st_gdata->st_state);
63853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_unlock_irqrestore(&st_gdata->lock, flags);
639320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -EINPROGRESS;
64053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} else if (st_gdata->protos_registered == ST_EMPTY) {
64153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info(" protocol list empty :%d ", new_proto->type);
64253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
64353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_recv = st_kim_recv;
64453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
64553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* release lock previously held - re-locked below */
64653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_unlock_irqrestore(&st_gdata->lock, flags);
64753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* enable the ST LL - to set default chip state */
64953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_ll_enable(st_gdata);
65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* this may take a while to complete
65153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * since it involves BT fw download
65253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
65338d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy		err = st_kim_start(st_gdata->kim_data);
654320920cba355146258da7de80bed0069c1dff24aPavan Savoy		if (err != 0) {
65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
65653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if ((st_gdata->protos_registered != ST_EMPTY) &&
65753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
65853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err(" KIM failure complete callback ");
659320920cba355146258da7de80bed0069c1dff24aPavan Savoy				st_reg_complete(st_gdata, -1);
66053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
662320920cba355146258da7de80bed0069c1dff24aPavan Savoy			return -1;
66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
66453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* the protocol might require other gpios to be toggled
66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
66853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
66953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_recv = st_int_recv;
67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
67253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* this is where all pending registration
67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * are signalled to be complete by calling callback functions
67453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if ((st_gdata->protos_registered != ST_EMPTY) &&
67653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		    (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info(" call reg complete callback ");
678320920cba355146258da7de80bed0069c1dff24aPavan Savoy			st_reg_complete(st_gdata, 0);
67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
68053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		clear_bit(ST_REG_PENDING, &st_gdata->st_state);
68153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
68253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* check for already registered once more,
68353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * since the above check is old
68453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 */
68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->list[new_proto->type] != NULL) {
68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err(" proto %d already registered ",
68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				   new_proto->type);
688320920cba355146258da7de80bed0069c1dff24aPavan Savoy			return -EALREADY;
68953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
69053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_lock_irqsave(&st_gdata->lock, flags);
69253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->list[new_proto->type] = new_proto;
69336e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain		st_gdata->protos_registered++;
69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		new_proto->write = st_write;
69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_unlock_irqrestore(&st_gdata->lock, flags);
69653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* if fw is already downloaded & new stack registers protocol */
69953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	else {
70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		switch (new_proto->type) {
70153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_BT:
70253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* do nothing */
70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
70453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_FM:
70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_GPS:
70653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
70753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
70853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_MAX:
70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		default:
71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("%d protocol not supported",
71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				   new_proto->type);
712320920cba355146258da7de80bed0069c1dff24aPavan Savoy			err = -EPROTONOSUPPORT;
71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* something wrong */
71453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->list[new_proto->type] = new_proto;
71736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain		st_gdata->protos_registered++;
71853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		new_proto->write = st_write;
71953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
72053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* lock already held before entering else */
72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_unlock_irqrestore(&st_gdata->lock, flags);
72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
72353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
72453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("done %s(%d) ", __func__, new_proto->type);
72553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
72653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register);
72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol -
72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver
73053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_unregister(enum proto_type type)
73253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
733320920cba355146258da7de80bed0069c1dff24aPavan Savoy	long err = 0;
73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
73553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s	*st_gdata;
73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s: %d ", __func__, type);
73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_kim_ref(&st_gdata);
74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (type < ST_BT || type >= ST_MAX) {
74153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" protocol %d not supported", type);
742320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -EPROTONOSUPPORT;
74353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
74453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
74553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
74753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata->list[type] == NULL) {
74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" protocol %d not registered", type);
74953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		spin_unlock_irqrestore(&st_gdata->lock, flags);
750320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -EPROTONOSUPPORT;
75153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
75253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
75353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->protos_registered--;
75453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->list[type] = NULL;
75553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* kim ignores BT in the below function
75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * and handles the rest, BT is toggled
75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * only in kim_start and kim_stop
75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
76153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
76353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if ((st_gdata->protos_registered == ST_EMPTY) &&
76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	    (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info(" all protocols unregistered ");
76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* stop traffic on tty */
76853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->tty) {
76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			tty_ldisc_flush(st_gdata->tty);
77053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			stop_tty(st_gdata->tty);
77153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
77253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
77353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* all protocols now unregistered */
77438d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy		st_kim_stop(st_gdata->kim_data);
77553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* disable ST LL */
77653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_ll_disable(st_gdata);
77753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
77853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return err;
77953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
78053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
78153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
78253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers
78353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer
78453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
78553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb)
78653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
78753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata;
78853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG
78953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	enum proto_type protoid = ST_MAX;
79053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
79153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long len;
79253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
79353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_kim_ref(&st_gdata);
79453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(skb == NULL || st_gdata == NULL
79553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		|| st_gdata->tty == NULL)) {
79653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("data/tty unavailable to perform write");
797320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -1;
79853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
79953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG			/* open-up skb to read the 1st byte */
80053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	switch (skb->data[0]) {
80153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case HCI_COMMAND_PKT:
80253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case HCI_ACLDATA_PKT:
80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case HCI_SCODATA_PKT:
80453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		protoid = ST_BT;
80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
80653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_FM_CH8_PKT:
80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		protoid = ST_FM;
80853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
80953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case 0x09:
81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		protoid = ST_GPS;
81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
81353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(st_gdata->list[protoid] == NULL)) {
81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" protocol %d not registered, and writing? ",
81553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   protoid);
816320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -1;
81753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
81853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
81953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%d to be written", skb->len);
82053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	len = skb->len;
82153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
82253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* st_ll to decide where to enqueue the skb */
82353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_int_enqueue(st_gdata, skb);
82453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* wake up */
82553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_tx_wakeup(st_gdata);
82653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
82753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* return number of bytes written */
82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return len;
82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */
83253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister);
83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
83453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
83653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer
83753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
83853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty)
83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
840320920cba355146258da7de80bed0069c1dff24aPavan Savoy	int err = 0;
84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata;
84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s ", __func__);
84353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_kim_ref(&st_gdata);
84553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->tty = tty;
84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty->disc_data = st_gdata;
84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* don't do an wakeup for now */
84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* mem already allocated
85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty->receive_room = 65536;
85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Flush any pending characters in the driver and discipline. */
85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_ldisc_flush(tty);
85653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_driver_flush_buffer(tty);
85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/*
85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * signal to UIM via KIM that -
85953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * installation of N_TI_WL ldisc is complete
86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
86138d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy	st_kim_complete(st_gdata->kim_data);
86253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("done %s", __func__);
86353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return err;
86453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
86553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
86653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty)
86753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
86853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = ST_MAX;
86953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
87053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct	st_data_s *st_gdata = tty->disc_data;
87153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
87253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s ", __func__);
87353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
87453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* TODO:
87553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * if a protocol has been registered & line discipline
87653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * un-installed for some reason - what should be done ?
87753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
87853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
87953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = ST_BT; i < ST_MAX; i++) {
88053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->list[i] != NULL)
88153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("%d not un-registered", i);
88253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->list[i] = NULL;
88353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
88453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
88553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/*
88653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * signal to UIM via KIM that -
88753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * N_TI_WL ldisc is un-installed
88853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
88938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy	st_kim_complete(st_gdata->kim_data);
89053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->tty = NULL;
89153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Flush any pending characters in the driver and discipline. */
89253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_ldisc_flush(tty);
89353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_driver_flush_buffer(tty);
89453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
89553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
89653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* empty out txq and tx_waitq */
89753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_purge(&st_gdata->txq);
89853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_purge(&st_gdata->tx_waitq);
89953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* reset the TTY Rx states of ST */
90053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_count = 0;
90153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_state = ST_W4_PACKET_TYPE;
90253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	kfree_skb(st_gdata->rx_skb);
90353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_skb = NULL;
90453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
90553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
90653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s: done ", __func__);
90753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
90853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
90953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
91053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   char *tty_flags, int count)
91153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
91253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
91353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE
91453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long i;
91553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	printk(KERN_ERR "incoming data...\n");
91653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < count; i++)
91753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		printk(" %x", data[i]);
91853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	printk(KERN_ERR "\n.. data end\n");
91953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
92053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
92153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/*
92253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * if fw download is in progress then route incoming data
92353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * to KIM for validation
92453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
92553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_recv(tty->disc_data, data, count);
92653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("done %s", __func__);
92753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
92853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
92953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer
93053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called
93153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
93253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty)
93353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
93453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct	st_data_s *st_gdata = tty->disc_data;
93553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s ", __func__);
93653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* don't do an wakeup for now */
93753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
93853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
93953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* call our internal wakeup */
94053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_tx_wakeup((void *)st_gdata);
94153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
94253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
94353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty)
94453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
94553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct	st_data_s *st_gdata = tty->disc_data;
94653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("%s ", __func__);
94753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
94853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	kfree_skb(st_gdata->tx_skb);
94953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->tx_skb = NULL;
95053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
95153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty->ops->flush_buffer(tty);
95253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
95353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
95453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
95553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
95653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data)
95753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
95853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata;
95953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long err;
96053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	static struct tty_ldisc_ops *st_ldisc_ops;
96153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
96253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* populate and register to TTY line discipline */
96353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops = kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL);
96453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (!st_ldisc_ops) {
96553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("no mem to allocate");
96653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -ENOMEM;
96753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
96853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
96953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->magic = TTY_LDISC_MAGIC;
97053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->name = "n_st";	/*"n_hci"; */
97153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->open = st_tty_open;
97253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->close = st_tty_close;
97353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->receive_buf = st_tty_receive;
97453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->write_wakeup = st_tty_wakeup;
97553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->flush_buffer = st_tty_flush_buffer;
97653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->owner = THIS_MODULE;
97753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
97853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = tty_register_ldisc(N_TI_WL, st_ldisc_ops);
97953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
98053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error registering %d line discipline %ld",
98153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   N_TI_WL, err);
98253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
98353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
98453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
98553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("registered n_shared line discipline");
98653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
98753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
98853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (!st_gdata) {
98953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("memory allocation failed");
99053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
99153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
99253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc %ld", err);
99353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
99453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = -ENOMEM;
99553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
99653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
99753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
99853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
99953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * will be pushed in this queue for actual transmission.
100053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
100153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_head_init(&st_gdata->txq);
100253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_head_init(&st_gdata->tx_waitq);
100353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
100453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Locking used in st_int_enqueue() to avoid multiple execution */
100553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_init(&st_gdata->lock);
100653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
100753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* ldisc_ops ref to be only used in __exit of module */
100853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->ldisc_ops = st_ldisc_ops;
100953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
101053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
101153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_kim_init();
101253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
101353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during kim initialization(%ld)", err);
101453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
101553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
101653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
101753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc");
101853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
101953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -1;
102053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
102153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
102253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
102353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_ll_init(st_gdata);
102453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
102553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during st_ll initialization(%ld)", err);
102653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
102753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
102853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
102953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc");
103053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
103153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -1;
103253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
103353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	*core_data = st_gdata;
103453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return 0;
103553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
103653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
103753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata)
103853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
103953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long err;
104053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* internal module cleanup */
104153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_ll_deinit(st_gdata);
104253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err)
104353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during deinit of ST LL %ld", err);
104453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
104553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_kim_deinit();
104653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err)
104753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during deinit of ST KIM %ld", err);
104853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
104953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata != NULL) {
105053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Free ST Tx Qs and skbs */
105153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_purge(&st_gdata->txq);
105253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_purge(&st_gdata->tx_waitq);
105353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
105453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->tx_skb);
105553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* TTY ldisc cleanup */
105653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
105753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
105853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc %ld", err);
105953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata->ldisc_ops);
106053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* free the global data pointer */
106153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
106253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
106353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
106453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
106553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
1066