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