st_core.c revision 5c88b02196a99332dacf305c8757674dd7a303ff
153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * Shared Transport Line discipline driver Core 353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This hooks up ST KIM driver and ST LL driver 4a0cc2f3b51a8649da5262aba7501dc21738e1b8dPavan Savoy * Copyright (C) 2009-2010 Texas Instruments 5a0cc2f3b51a8649da5262aba7501dc21738e1b8dPavan Savoy * Author: Pavan Savoy <pavan_savoy@ti.com> 653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This program is free software; you can redistribute it and/or modify 853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * it under the terms of the GNU General Public License version 2 as 953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * published by the Free Software Foundation. 1053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 1153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This program is distributed in the hope that it will be useful, 1253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * but WITHOUT ANY WARRANTY; without even the implied warranty of 1353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * GNU General Public License for more details. 1553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 1653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * You should have received a copy of the GNU General Public License 1753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * along with this program; if not, write to the Free Software 1853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 2053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 2153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#define pr_fmt(fmt) "(stc): " fmt 2353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/module.h> 2453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/kernel.h> 2553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/init.h> 2653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#include <linux/tty.h> 2753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 285c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy#include <linux/seq_file.h> 295c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy#include <linux/skbuff.h> 305c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy 31e5558679bbb80788dc8c4c30484ac0a68e971ca5Pavan Savoy#include <linux/ti_wilink_st.h> 3253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 3353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* function pointer pointing to either, 3453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_kim_recv during registration to receive fw download responses 3553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_int_recv after registration to receive proto stack responses 3653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 3753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid (*st_recv) (void*, const unsigned char*, long); 3853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 3953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoystatic void add_channel_to_table(struct st_data_s *st_gdata, 415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *new_proto) 4253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 435c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: id %d\n", __func__, new_proto->chnl_id); 445c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* list now has the channel id as index itself */ 455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[new_proto->chnl_id] = new_proto; 465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy} 475c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy 485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoystatic void remove_channel_from_table(struct st_data_s *st_gdata, 495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto) 505c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy{ 515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: id %d\n", __func__, proto->chnl_id); 525c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[proto->chnl_id] = NULL; 5353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 5436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 5553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from 5653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download) 5753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write) 5853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 5953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This is the internal write function - a wrapper 6053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to tty->ops->write 6153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 6253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata, 6353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, int count) 6453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 6553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct tty_struct *tty; 6653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 6753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("tty unavailable to perform write"); 68320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 6953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 7053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty = st_gdata->tty; 7153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 72e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, 73e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 7453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 7553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return tty->ops->write(tty, data, count); 7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant 8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks 8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 835c88b02196a99332dacf305c8757674dd7a303ffPavan Savoyvoid st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) 8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" %s(prot:%d) ", __func__, chnl_id); 8653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely 8853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (st_gdata == NULL || st_gdata->rx_skb == NULL 895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy || st_gdata->list[chnl_id] == NULL)) { 905c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not registered, no data to send?", 915c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy chnl_id); 9253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 9353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 9453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this cannot fail 9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * this shouldn't take long 9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - should be just skb_queue_tail for the 9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stack driver 9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1005c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (likely(st_gdata->list[chnl_id]->recv != NULL)) { 101bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy if (unlikely 1025c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->recv 1035c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) 104320920cba355146258da7de80bed0069c1dff24aPavan Savoy != 0)) { 1055c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv failed", chnl_id); 10653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 10953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 1105c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv null", chnl_id); 11153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 11253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 11636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 11736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_reg_complete - 11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks 11953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers 12053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 12153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err) 12253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 12353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 12453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s ", __func__); 1255c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = 0; i < ST_MAX_CHANNELS; i++) { 12653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && 12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i]->reg_complete_cb != NULL)) 128bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->list[i]->reg_complete_cb 129bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[i]->priv_data, err); 13053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 13153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata, 1345c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char chnl_id, int len) 13553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 13673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy int room = skb_tailroom(st_gdata->rx_skb); 13753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 138e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("len %d room %d", len, room); 13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!len) { 14153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet has only packet header and 14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * has zero length payload. So, ask ST CORE to 14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * forward the packet to protocol driver (BT/FM/GPS) 14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(chnl_id, st_gdata); 14653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 14753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (len > room) { 14853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet's payload length is larger. 14953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * We can't accommodate it in created skb. 15053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 15153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Data length is too large len %d room %d", len, 15253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy room); 15353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 15453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 15553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Packet header has non-zero payload length and 15653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * we have enough space in created skb. Lets read 15753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * payload data */ 1585c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_DATA; 15953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = len; 16053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 16153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Change ST state to continue to process next 16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet */ 16553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 16753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 1685c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = 0; 16953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 17253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 17436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack 17536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * received 17653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata, 17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char cmd) 17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 18073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy struct sk_buff *waiting_skb; 18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* de-Q from waitQ and Q in txQ now that the 18553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * chip is awake 18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 18753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) 18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, waiting_skb); 18953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* state forwarded to ST LL */ 19153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, (unsigned long)cmd); 19253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up to send the recently copied skbs from waitQ */ 19553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 19936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function. 20036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Decodes received RAW data and forwards to corresponding 20136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * client drivers (Bluetooth,FM,GPS..etc). 20236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * This can receive various types of packets, 20336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets 20436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * CH-8 packets from FM, CH-9 packets from GPS cores. 20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data, 20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, long count) 20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 20973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy char *ptr; 2105c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto; 2115c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned short payload_len = 0; 2125c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy int len = 0, type = 0; 2135c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char *plen; 21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = (struct st_data_s *)disc_data; 21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr = (char *)data; 21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* tty_receive sent null ? */ 21853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(ptr == NULL) || (st_gdata == NULL)) { 21953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" received null from TTY "); 22053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 22153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("count %ld rx_state %ld" 22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "rx_count %ld", count, st_gdata->rx_state, 22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count); 22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Decode received bytes here */ 22853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while (count) { 22953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) { 23053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = min_t(unsigned int, st_gdata->rx_count, count); 23153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); 23253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count -= len; 23353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count -= len; 23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr += len; 23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) 23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 23853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 23953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check ST RX state machine , where are we? */ 24053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_gdata->rx_state) { 2415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* Waiting for complete packet ? */ 2425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_DATA: 243e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Complete pkt received"); 24453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Ask ST CORE to forward 24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * the packet to protocol driver */ 2465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(st_gdata->rx_chnl, st_gdata); 24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 2515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* parse the header to know details */ 2525c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_HEADER: 2535c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto = st_gdata->list[st_gdata->rx_chnl]; 2545c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy plen = 2555c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy &st_gdata->rx_skb->data 2565c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy [proto->offset_len_in_hdr]; 2575c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("plen pointing to %x\n", *plen); 2585c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (proto->len_size == 1)/* 1 byte len field */ 2595c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = *(unsigned char *)plen; 2605c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else if (proto->len_size == 2) 2615c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = 2625c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __le16_to_cpu(*(unsigned short *)plen); 2635c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else 2645c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: invalid length " 2655c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy "for id %d\n", 2665c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __func__, proto->chnl_id); 2675c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_check_data_len(st_gdata, proto->chnl_id, 2685c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len); 2695c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("off %d, pay len %d\n", 2705c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto->offset_len_in_hdr, payload_len); 27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 27253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } /* end of switch rx_state */ 27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* end of if rx_count */ 27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check first byte of packet and identify module 27753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * owner (BT/FM/GPS) */ 27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (*ptr) { 27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_IND: 28053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_ACK: 28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_IND: 28253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("PM packet"); 28353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this takes appropriate action based on 28453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * sleep state received -- 28553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 28653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, *ptr); 28753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 28853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 28953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 29053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_ACK: 29153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("PM packet"); 29253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up ack received */ 29353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_wakeup_ack(st_gdata, *ptr); 29453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 29553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 29653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 29753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Unknow packet? */ 29853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 2995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy type = *ptr; 3005c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb = alloc_skb( 3015c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->max_frame_size, 3025c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy GFP_ATOMIC); 3035c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy skb_reserve(st_gdata->rx_skb, 3045c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->reserve); 3055c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* next 2 required for BT only */ 3065c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ 3075c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[1] = 0; /*incoming*/ 3085c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = *ptr; 3095c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_HEADER; 3105c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_count = st_gdata->list[type]->hdr_len; 3115c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("rx_count %ld\n", st_gdata->rx_count); 31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy }; 31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 316e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 31853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 31953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 32036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 32136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function. 32236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the previous data set was not written 32336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * completely, return that skb which has the pending data. 32436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * In normal cases, return top of txq. 32553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) 32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 32853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *returning_skb; 32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 330e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tx_skb != NULL) { 33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy returning_skb = st_gdata->tx_skb; 33353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 33453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return returning_skb; 33553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return skb_dequeue(&st_gdata->txq); 33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 33936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 34036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function. 34136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Will either Q the skb to txq or the tx_waitq 34236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * depending on the ST LL state. 34336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the chip is asleep, then Q it onto waitq and 34436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * wakeup the chip. 34536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * txq and waitq needs protection since the other contexts 34636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * may be sending data, waking up chip. 34753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 34853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) 34953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 35053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 35153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 352e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 35353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 35453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 35553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_ll_getstate(st_gdata)) { 35653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_AWAKE: 35753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("ST LL is AWAKE, sending normally"); 35853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, skb); 35953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 36053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP_TO_AWAKE: 36153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 36253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 36336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy case ST_LL_AWAKE_TO_ASLEEP: 36453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 36553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 36653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP: 36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_wakeup(st_gdata); 37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 37253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 37836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 37953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 380e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 38153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 38253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 38353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 38553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function 38653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either 38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished 38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack) 38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data) 39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *skb; 39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags; /* for irq save flags */ 394e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for sending & set flag sending here */ 39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { 39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("ST already sending"); 39853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* keep sending */ 39953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_TX_WAKEUP, &st_data->tx_state); 40053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 40153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TX_WAKEUP will be checked in another 40253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * context 40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 40553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy do { /* come back if st_tx_wakeup is set */ 40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* woke-up to write */ 40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_WAKEUP, &st_data->tx_state); 40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((skb = st_int_dequeue(st_data))) { 40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int len; 41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_data->lock, flags); 41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable wake-up from TTY */ 41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); 41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = st_int_write(st_data, skb->data, skb->len); 41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_pull(skb, len); 41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if skb->len = len as expected, skb->len=0 */ 41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (skb->len) { 41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* would be the next skb to be sent */ 41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_data->tx_skb = skb; 41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 42253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if wake-up is set in another context- restart sending */ 42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); 42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* clear flag sending */ 42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_SENDING, &st_data->tx_state); 43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM 43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/ 435c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) 43653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 437c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoy seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 43836e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered, 43936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_BT] != NULL ? 'R' : 'U', 44036e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_FM] != NULL ? 'R' : 'U', 44136e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_GPS] != NULL ? 'R' : 'U'); 44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers 44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed 44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto) 45053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 45153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 452320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 45353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 455dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 4565c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s(%d) ", __func__, new_proto->chnl_id); 45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL 45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || new_proto->reg_complete_cb == NULL) { 45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); 4605c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (st_gdata == NULL) 4615c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("error 1\n"); 4625c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto == NULL) 4635c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("error 2\n"); 4645c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->recv == NULL) 4655c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("error 3\n"); 4665c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->reg_complete_cb == NULL) 4675c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("erro 4\n"); 468320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 47053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 4715c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->chnl_id >= ST_MAX_CHANNELS) { 4725c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not supported", new_proto->chnl_id); 473320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 47453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 4765c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (st_gdata->list[new_proto->chnl_id] != NULL) { 4775c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d already registered", new_proto->chnl_id); 478320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 48053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* can be from process context only */ 48253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 48353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { 4855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); 48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* fw download in progress */ 4875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE); 48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 4895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 49036e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 49153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 49353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_PENDING, &st_gdata->st_state); 49453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 495320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EINPROGRESS; 49653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (st_gdata->protos_registered == ST_EMPTY) { 4975c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); 49853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_kim_recv; 50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* release lock previously held - re-locked below */ 50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable the ST LL - to set default chip state */ 50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_enable(st_gdata); 50653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this may take a while to complete 50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since it involves BT fw download 50853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 50938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy err = st_kim_start(st_gdata->kim_data); 510320920cba355146258da7de80bed0069c1dff24aPavan Savoy if (err != 0) { 51153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 51253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 51453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" KIM failure complete callback "); 515320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, -1); 51653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 518320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 51953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 52053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5215c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* the chnl_id might require other gpios to be toggled 52253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 5235c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_kim_chip_toggle(new_proto->chnl_id, KIM_GPIO_ACTIVE); 52453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 52553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 52653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_int_recv; 52753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 52853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this is where all pending registration 52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * are signalled to be complete by calling callback functions 53053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 533e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" call reg complete callback "); 534320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, 0); 53553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 53653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 53753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for already registered once more, 53953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since the above check is old 54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 5415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (st_gdata->list[new_proto->chnl_id] != NULL) { 54253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto %d already registered ", 5435c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy new_proto->chnl_id); 544320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 54653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 5485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 54936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 55053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 55153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 55253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if fw is already downloaded & new stack registers protocol */ 55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy else { 5565c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 55736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 55853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 55953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 56053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* lock already held before entering else */ 56153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 56253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 56353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 5645c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); 56553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 56653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register); 56753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 56853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol - 56953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver 57053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 5715c88b02196a99332dacf305c8757674dd7a303ffPavan Savoylong st_unregister(struct st_proto_s *proto) 57253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 573320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 57453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 57653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5775c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("%s: %d ", __func__, proto->chnl_id); 57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 579dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 5805c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (proto->chnl_id >= ST_MAX_CHANNELS) { 5815c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not supported", proto->chnl_id); 582320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 58353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 58453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 58553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (st_gdata->list[proto->chnl_id] == NULL) { 5885c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not registered", proto->chnl_id); 58953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 590320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 59153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 59253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 59353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->protos_registered--; 5945c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy remove_channel_from_table(st_gdata, proto); 59553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* kim ignores BT in the below function 59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * and handles the rest, BT is toggled 59853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * only in kim_start and kim_stop 59953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 6005c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_kim_chip_toggle(proto->chnl_id, KIM_GPIO_INACTIVE); 60153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 60253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered == ST_EMPTY) && 60453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 6055c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" all chnl_ids unregistered "); 60653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* stop traffic on tty */ 60853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tty) { 60953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(st_gdata->tty); 61053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy stop_tty(st_gdata->tty); 61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 61253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6135c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* all chnl_ids now unregistered */ 61438d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_stop(st_gdata->kim_data); 61553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* disable ST LL */ 61653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_disable(st_gdata); 61753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 61853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 61953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 62253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers 62353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer 62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 62553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb) 62653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 62753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 62853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG 6295c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char chnl_id = ST_MAX_CHANNELS; 63053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 63153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long len; 63253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 633dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 63453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(skb == NULL || st_gdata == NULL 63553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->tty == NULL)) { 63653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("data/tty unavailable to perform write"); 637320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 63853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG /* open-up skb to read the 1st byte */ 6405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy chnl_id = skb->data[0]; 6415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (unlikely(st_gdata->list[chnl_id] == NULL)) { 6425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not registered, and writing? ", 6435c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy chnl_id); 644320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 64553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 64653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 647e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%d to be written", skb->len); 64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = skb->len; 64953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* st_ll to decide where to enqueue the skb */ 65153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_int_enqueue(st_gdata, skb); 65253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up */ 65353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 65453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* return number of bytes written */ 65653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 65753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 65853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */ 66053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister); 66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 66453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer 66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty) 66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 668320920cba355146258da7de80bed0069c1dff24aPavan Savoy int err = 0; 66953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 672dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = tty; 67453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->disc_data = st_gdata; 67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 67653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 67853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* mem already allocated 68053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 68153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->receive_room = 65536; 68253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 68353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 68453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * installation of N_TI_WL ldisc is complete 68853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 68938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 690e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 69253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 69353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty) 69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 6965c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char i = ST_MAX_CHANNELS; 69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 69953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 70153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 70253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO: 70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if a protocol has been registered & line discipline 70453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * un-installed for some reason - what should be done ? 70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 70653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 7075c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { 70853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[i] != NULL) 70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d not un-registered", i); 71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i] = NULL; 71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 712bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->protos_registered = 0; 71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 71453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * N_TI_WL ldisc is un-installed 71753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 71838d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 71953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = NULL; 72053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 72353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 72453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 72553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* empty out txq and tx_waitq */ 72653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* reset the TTY Rx states of ST */ 72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 73053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 73253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 73353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 735e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: done ", __func__); 73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data, 73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy char *tty_flags, int count) 74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 7415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy#define VERBOSE 74253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 743e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, 744e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 74553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 74753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if fw download is in progress then route incoming data 74953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to KIM for validation 75053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 75153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv(tty->disc_data, data, count); 752e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 75353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 75453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 75553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer 75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called 75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty) 75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 761e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 76353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* call our internal wakeup */ 76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup((void *)st_gdata); 76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 76853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty) 77053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 77153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 772e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 77353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 77453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 77553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 77653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 77753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->ops->flush_buffer(tty); 77853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 77953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 78053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoystatic struct tty_ldisc_ops st_ldisc_ops = { 78273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .magic = TTY_LDISC_MAGIC, 78373f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .name = "n_st", 78473f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .open = st_tty_open, 78573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .close = st_tty_close, 78673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .receive_buf = st_tty_receive, 78773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .write_wakeup = st_tty_wakeup, 78873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .flush_buffer = st_tty_flush_buffer, 78973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .owner = THIS_MODULE 79073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy}; 79173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 79253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 79353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data) 79453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 79553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 79653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 79753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 79873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); 79953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 80053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error registering %d line discipline %ld", 80153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy N_TI_WL, err); 80253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 804e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("registered n_shared line discipline"); 80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); 80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata) { 80853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("memory allocation failed"); 80953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = -ENOMEM; 81353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 81553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's 81753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will be pushed in this queue for actual transmission. 81853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 81953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->txq); 82053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->tx_waitq); 82153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 82253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Locking used in st_int_enqueue() to avoid multiple execution */ 82353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_init(&st_gdata->lock); 82453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 82553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_init(st_gdata); 82653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 82753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during st_ll initialization(%ld)", err); 82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 83253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return -1; 83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 83453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *core_data = st_gdata; 83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 83653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 83753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 83853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata) 83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 84053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* internal module cleanup */ 84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_deinit(st_gdata); 84353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST LL %ld", err); 84573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata != NULL) { 84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Free ST Tx Qs and skbs */ 84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TTY ldisc cleanup */ 85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 85653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* free the global data pointer */ 85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 85953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 86153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 862