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