st_core.c revision bb8f3c061f2e7282730059ae524ff19d47d70b17
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
41e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy#define VERBOSE
4253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG
4353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* strings to be used for rfkill entries and by
4453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * ST Core to be used for sysfs debug entry
4553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
4653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#define PROTO_ENTRY(type, name)	name
4753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyconst unsigned char *protocol_strngs[] = {
4853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_BT, "Bluetooth"),
4953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_FM, "FM"),
5053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	PROTO_ENTRY(ST_GPS, "GPS"),
5153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy};
5253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
5353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* function pointer pointing to either,
5453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_kim_recv during registration to receive fw download responses
5553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_int_recv after registration to receive proto stack responses
5653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
5753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid (*st_recv) (void*, const unsigned char*, long);
5853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
5953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
6053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
6153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal misc functions */
6253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoybool is_protocol_list_empty(void)
6353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
6453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = 0;
65e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug(" %s ", __func__);
6653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < ST_MAX; i++) {
6753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->list[i] != NULL)
6853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			return ST_NOTEMPTY;
6953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* not empty */
7053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
7153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* list empty */
7253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return ST_EMPTY;
7353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
7453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
7536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy
7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from
7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download)
7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write)
7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *
8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  This is the internal write function - a wrapper
8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *  to tty->ops->write
8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
8353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata,
8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	const unsigned char *data, int count)
8553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
8653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct tty_struct *tty;
8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
8853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("tty unavailable to perform write");
89320920cba355146258da7de80bed0069c1dff24aPavan Savoy		return -1;
9053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
9153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty = st_gdata->tty;
9253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE
93e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE,
94e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy		16, 1, data, count, 0);
9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return tty->ops->write(tty, data, count);
9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
10053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/*
10153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant
10253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks
10353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
10453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata)
10553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
10653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" %s(prot:%d) ", __func__, protoid);
10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely
10953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	    (st_gdata == NULL || st_gdata->rx_skb == NULL
11053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	     || st_gdata->list[protoid] == NULL)) {
11153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("protocol %d not registered, no data to send?",
11253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   protoid);
11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return;
11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
11653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* this cannot fail
11753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * this shouldn't take long
11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * - should be just skb_queue_tail for the
11953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 *   protocol stack driver
12053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
12153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (likely(st_gdata->list[protoid]->recv != NULL)) {
122bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy		if (unlikely
123bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy			(st_gdata->list[protoid]->recv
124bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy			(st_gdata->list[protoid]->priv_data, st_gdata->rx_skb)
125320920cba355146258da7de80bed0069c1dff24aPavan Savoy			     != 0)) {
12653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err(" proto stack %d's ->recv failed", protoid);
12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			kfree_skb(st_gdata->rx_skb);
12853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			return;
12953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
13053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	} else {
13153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" proto stack %d's ->recv null", protoid);
13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
13453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
13553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
13653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
13736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/**
13836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_reg_complete -
13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks
14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers
14153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err)
14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char i = 0;
14553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info(" %s ", __func__);
14653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	for (i = 0; i < ST_MAX; i++) {
14753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
14853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   st_gdata->list[i]->reg_complete_cb != NULL))
149bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy			st_gdata->list[i]->reg_complete_cb
150bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy				(st_gdata->list[i]->priv_data, 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
159e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("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
19336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/**
19436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack
19536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	received
19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata,
19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned char cmd)
19953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
20053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register struct sk_buff *waiting_skb;
20153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
20253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
20353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
20453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* de-Q from waitQ and Q in txQ now that the
20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * chip is awake
20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq)))
20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->txq, waiting_skb);
20953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* state forwarded to ST LL */
21153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ll_sleep_state(st_gdata, (unsigned long)cmd);
21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* wake up to send the recently copied skbs from waitQ */
21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_tx_wakeup(st_gdata);
21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
21836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/**
21936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function.
22036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	Decodes received RAW data and forwards to corresponding
22136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	client drivers (Bluetooth,FM,GPS..etc).
22236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	This can receive various types of packets,
22336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets
22436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	CH-8 packets from FM, CH-9 packets from GPS cores.
22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data,
22753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	const unsigned char *data, long count)
22853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
22953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register char *ptr;
23053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_event_hdr *eh;
23153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_acl_hdr *ah;
23253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct hci_sco_hdr *sh;
23353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct fm_event_hdr *fm;
23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct gps_event_hdr *gps;
23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	register int len = 0, type = 0, dlen = 0;
23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	static enum proto_type protoid = ST_MAX;
23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata = (struct st_data_s *)disc_data;
23853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
23953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	ptr = (char *)data;
24053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* tty_receive sent null ? */
24153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (unlikely(ptr == NULL) || (st_gdata == NULL)) {
24253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err(" received null from TTY ");
24353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return;
24453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	pr_info("count %ld rx_state %ld"
24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		   "rx_count %ld", count, st_gdata->rx_state,
24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		   st_gdata->rx_count);
24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Decode received bytes here */
25153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	while (count) {
25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (st_gdata->rx_count) {
25353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			len = min_t(unsigned int, st_gdata->rx_count, count);
25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
25553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count -= len;
25653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count -= len;
25753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr += len;
25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (st_gdata->rx_count)
26053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Check ST RX state machine , where are we? */
26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			switch (st_gdata->rx_state) {
26453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for complete packet ? */
26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_DATA:
267e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy				pr_debug("Complete pkt received");
26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Ask ST CORE to forward
27053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				 * the packet to protocol driver */
27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_send_frame(protoid, st_gdata);
27253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_skb = NULL;
27553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				protoid = ST_MAX;	/* is this required ? */
27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
27753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth event header ? */
27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_EVENT_HDR:
28053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				eh = (struct hci_event_hdr *)st_gdata->rx_skb->
28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
28253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
283e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy				pr_debug("Event header: evt 0x%2.2x"
28453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy					   "plen %d", eh->evt, eh->plen);
28553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
28653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, eh->plen);
28753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
28853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
28953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth acl header ? */
29053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_ACL_HDR:
29153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
29253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
29353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				dlen = __le16_to_cpu(ah->dlen);
29453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
29553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("ACL header: dlen %d", dlen);
29653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
29753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, dlen);
29853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
29953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
30053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* Waiting for Bluetooth sco header ? */
30153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_BT_W4_SCO_HDR:
30253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
30353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
30453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("SCO header: dlen %d", sh->dlen);
30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, protoid, sh->dlen);
30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_FM_W4_EVENT_HDR:
31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				fm = (struct fm_event_hdr *)st_gdata->rx_skb->
31153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				    data;
31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("FM Header: ");
31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, ST_FM, fm->plen);
31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* TODO : Add GPS packet machine logic here */
31653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			case ST_GPS_W4_EVENT_HDR:
31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				/* [0x09 pkt hdr][R/W byte][2 byte len] */
31853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				gps = (struct gps_event_hdr *)st_gdata->rx_skb->
31953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				     data;
32053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_info("GPS Header: ");
32153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_check_data_len(st_gdata, ST_GPS, gps->plen);
32253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				continue;
32353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}	/* end of switch rx_state */
32453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
32553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* end of if rx_count */
32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Check first byte of packet and identify module
32853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		 * owner (BT/FM/GPS) */
32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		switch (*ptr) {
33053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth event packet? */
33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_EVENT_PKT:
33353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("Event packet");
33453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
33553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_EVENT_PKT;
33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
33953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
34053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth acl packet? */
34153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_ACLDATA_PKT:
34253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("ACL packet");
34353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_ACL_HDR;
34453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_ACL_HDR_SIZE;
34553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_ACLDATA_PKT;
34653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
34753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
34853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
34953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Bluetooth sco packet? */
35053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case HCI_SCODATA_PKT:
35153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("SCO packet");
35253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_BT_W4_SCO_HDR;
35353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = HCI_SCO_HDR_SIZE;
35453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = HCI_SCODATA_PKT;
35553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_BT;
35653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
35753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
35853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Channel 8(FM) packet? */
35953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_FM_CH8_PKT:
36053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("FM CH8 packet");
36153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = ST_FM_CH8_PKT;
36253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
36353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = FM_EVENT_HDR_SIZE;
36453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_FM;
36553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
36653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Channel 9(GPS) packet? */
36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case 0x9:	/*ST_LL_GPS_CH9_PKT */
36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("GPS CH9 packet");
37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			type = 0x9;	/* ST_LL_GPS_CH9_PKT; */
37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			protoid = ST_GPS;
37253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_count = 3;	/* GPS_EVENT_HDR_SIZE -1*/
37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_SLEEP_IND:
37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_SLEEP_ACK:
37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_WAKE_UP_IND:
37853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("PM packet");
37953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* this takes appropriate action based on
38053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			 * sleep state received --
38153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			 */
38253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_ll_sleep_state(st_gdata, *ptr);
38353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
38553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
38653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case LL_WAKE_UP_ACK:
38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_info("PM packet");
38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* wake up ack received */
38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_wakeup_ack(st_gdata, *ptr);
39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Unknow packet? */
39453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		default:
39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("Unknown packet type %2.2x", (__u8) *ptr);
39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			ptr++;
39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			count--;
39853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			continue;
39953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		};
40053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		ptr++;
40153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		count--;
40253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		switch (protoid) {
40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_BT:
40553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* Allocate new packet to hold received data */
40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			bt_cb(st_gdata->rx_skb)->pkt_type = type;
41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_FM:	/* for FM */
41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
42253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* place holder 0x08 */
42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			skb_reserve(st_gdata->rx_skb, 1);
42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_GPS:
43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* for GPS */
43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb =
43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			    alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			if (!st_gdata->rx_skb) {
43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				pr_err("Can't allocate mem for new packet");
43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_state = ST_W4_PACKET_TYPE;
43653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				st_gdata->rx_count = 0;
43753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy				return;
43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			}
43953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			/* place holder 0x09 */
44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			skb_reserve(st_gdata->rx_skb, 1);
44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			st_gdata->rx_skb->cb[0] = 0x09;	/*ST_GPS_CH9_PKT; */
44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		case ST_MAX:
44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			break;
44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		}
44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
447e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("done %s", __func__);
44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
45053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
45136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/**
45236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function.
45336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	If the previous data set was not written
45436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	completely, return that skb which has the pending data.
45536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	In normal cases, return top of txq.
45653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata)
45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct sk_buff *returning_skb;
46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
461e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%s", __func__);
46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata->tx_skb != NULL) {
46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		returning_skb = st_gdata->tx_skb;
46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_gdata->tx_skb = NULL;
46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return returning_skb;
46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
46753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return skb_dequeue(&st_gdata->txq);
46853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
47036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/**
47136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function.
47236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	Will either Q the skb to txq or the tx_waitq
47336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	depending on the ST LL state.
47436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	If the chip is asleep, then Q it onto waitq and
47536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	wakeup the chip.
47636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	txq and waitq needs protection since the other contexts
47736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy *	may be sending data, waking up chip.
47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb)
48053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
48153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	unsigned long flags = 0;
48253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
483e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%s", __func__);
48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
48553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	switch (st_ll_getstate(st_gdata)) {
48753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_AWAKE:
48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_info("ST LL is AWAKE, sending normally");
48953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->txq, skb);
49053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
49153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_ASLEEP_TO_AWAKE:
49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->tx_waitq, skb);
49353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
49436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy	case ST_LL_AWAKE_TO_ASLEEP:
49553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("ST LL is illegal state(%ld),"
49653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   "purging received skb.", st_ll_getstate(st_gdata));
49753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(skb);
49853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	case ST_LL_ASLEEP:
50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_tail(&st_gdata->tx_waitq, skb);
50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		st_ll_wakeup(st_gdata);
50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	default:
50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("ST LL is illegal state(%ld),"
50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   "purging received skb.", st_ll_getstate(st_gdata));
50653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(skb);
50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		break;
50853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
50936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy
51053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
511e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("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 */
525e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%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))) {
677e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy			pr_debug(" 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	}
724e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("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
737e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%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
819e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%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);
862e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("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	}
884bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy	st_gdata->protos_registered = 0;
88553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
88653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/*
88753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * signal to UIM via KIM that -
88853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * N_TI_WL ldisc is un-installed
88953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
89038d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy	st_kim_complete(st_gdata->kim_data);
89153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->tty = NULL;
89253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Flush any pending characters in the driver and discipline. */
89353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_ldisc_flush(tty);
89453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty_driver_flush_buffer(tty);
89553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
89653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_irqsave(&st_gdata->lock, flags);
89753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* empty out txq and tx_waitq */
89853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_purge(&st_gdata->txq);
89953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_purge(&st_gdata->tx_waitq);
90053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* reset the TTY Rx states of ST */
90153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_count = 0;
90253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_state = ST_W4_PACKET_TYPE;
90353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	kfree_skb(st_gdata->rx_skb);
90453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->rx_skb = NULL;
90553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_unlock_irqrestore(&st_gdata->lock, flags);
90653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
907e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%s: done ", __func__);
90853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
90953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
91053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
91153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   char *tty_flags, int count)
91253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
91353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
91453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE
915e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
916e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy		16, 1, data, count, 0);
91753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
91853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
91953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/*
92053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * if fw download is in progress then route incoming data
92153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * to KIM for validation
92253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
92353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_recv(tty->disc_data, data, count);
924e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("done %s", __func__);
92553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
92653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
92753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer
92853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called
92953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */
93053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty)
93153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
93253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct	st_data_s *st_gdata = tty->disc_data;
933e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%s ", __func__);
93453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* don't do an wakeup for now */
93553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
93653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
93753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* call our internal wakeup */
93853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_tx_wakeup((void *)st_gdata);
93953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
94053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
94153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty)
94253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
94353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct	st_data_s *st_gdata = tty->disc_data;
944e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("%s ", __func__);
94553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
94653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	kfree_skb(st_gdata->tx_skb);
94753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->tx_skb = NULL;
94853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
94953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	tty->ops->flush_buffer(tty);
95053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return;
95153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
95253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
95353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/
95453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data)
95553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
95653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	struct st_data_s *st_gdata;
95753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long err;
95853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	static struct tty_ldisc_ops *st_ldisc_ops;
95953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
96053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* populate and register to TTY line discipline */
96153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops = kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL);
96253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (!st_ldisc_ops) {
96353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("no mem to allocate");
96453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -ENOMEM;
96553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
96653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
96753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->magic = TTY_LDISC_MAGIC;
96853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->name = "n_st";	/*"n_hci"; */
96953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->open = st_tty_open;
97053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->close = st_tty_close;
97153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->receive_buf = st_tty_receive;
97253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->write_wakeup = st_tty_wakeup;
97353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->flush_buffer = st_tty_flush_buffer;
97453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_ldisc_ops->owner = THIS_MODULE;
97553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
97653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = tty_register_ldisc(N_TI_WL, st_ldisc_ops);
97753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
97853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error registering %d line discipline %ld",
97953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			   N_TI_WL, err);
98053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
98153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
98253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
983e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy	pr_debug("registered n_shared line discipline");
98453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
98553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
98653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (!st_gdata) {
98753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("memory allocation failed");
98853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
98953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
99053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc %ld", err);
99153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
99253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = -ENOMEM;
99353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return err;
99453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
99553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
99653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
99753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 * will be pushed in this queue for actual transmission.
99853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	 */
99953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_head_init(&st_gdata->txq);
100053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	skb_queue_head_init(&st_gdata->tx_waitq);
100153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
100253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* Locking used in st_int_enqueue() to avoid multiple execution */
100353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	spin_lock_init(&st_gdata->lock);
100453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
100553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* ldisc_ops ref to be only used in __exit of module */
100653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	st_gdata->ldisc_ops = st_ldisc_ops;
100753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
100853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
100953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_kim_init();
101053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
101153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during kim initialization(%ld)", err);
101253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
101353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
101453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
101553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc");
101653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
101753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -1;
101853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
101953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
102053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
102153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_ll_init(st_gdata);
102253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err) {
102353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during st_ll initialization(%ld)", err);
102453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
102553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
102653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
102753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc");
102853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_ldisc_ops);
102953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		return -1;
103053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
103153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	*core_data = st_gdata;
103253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	return 0;
103353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
103453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
103553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata)
103653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{
103753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	long err;
103853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	/* internal module cleanup */
103953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_ll_deinit(st_gdata);
104053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err)
104153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during deinit of ST LL %ld", err);
104253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0
104353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	err = st_kim_deinit();
104453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (err)
104553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		pr_err("error during deinit of ST KIM %ld", err);
104653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif
104753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	if (st_gdata != NULL) {
104853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* Free ST Tx Qs and skbs */
104953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_purge(&st_gdata->txq);
105053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		skb_queue_purge(&st_gdata->tx_waitq);
105153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->rx_skb);
105253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree_skb(st_gdata->tx_skb);
105353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* TTY ldisc cleanup */
105453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		err = tty_unregister_ldisc(N_TI_WL);
105553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		if (err)
105653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy			pr_err("unable to un-register ldisc %ld", err);
105753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata->ldisc_ops);
105853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		/* free the global data pointer */
105953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy		kfree(st_gdata);
106053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy	}
106153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}
106253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
106353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy
1064