st_core.c revision dbd3a8709560365ff9b1e5eca263f608877a8a89
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/* strings to be used for rfkill entries and by 4253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * ST Core to be used for sysfs debug entry 4353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 4453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#define PROTO_ENTRY(type, name) name 4553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyconst unsigned char *protocol_strngs[] = { 4653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy PROTO_ENTRY(ST_BT, "Bluetooth"), 4753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy PROTO_ENTRY(ST_FM, "FM"), 4853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy PROTO_ENTRY(ST_GPS, "GPS"), 4953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy}; 5053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* function pointer pointing to either, 5153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_kim_recv during registration to receive fw download responses 5253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_int_recv after registration to receive proto stack responses 5353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 5453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid (*st_recv) (void*, const unsigned char*, long); 5553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 5753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0 5853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* internal misc functions */ 5953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoybool is_protocol_list_empty(void) 6053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 6153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 62e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" %s ", __func__); 6353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy for (i = 0; i < ST_MAX; i++) { 6453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[i] != NULL) 6553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return ST_NOTEMPTY; 6653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* not empty */ 6753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 6853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* list empty */ 6953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return ST_EMPTY; 7053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 7153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 7236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 7353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from 7453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download) 7553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write) 7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This is the internal write function - a wrapper 7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to tty->ops->write 7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata, 8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, int count) 8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 8353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct tty_struct *tty; 8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 8553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("tty unavailable to perform write"); 86320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 8853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty = st_gdata->tty; 8953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 90e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, 91e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 9253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 9353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return tty->ops->write(tty, data, count); 9453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant 9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks 10053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 10153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_send_frame(enum proto_type protoid, struct st_data_s *st_gdata) 10253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 10353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s(prot:%d) ", __func__, protoid); 10453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 10553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely 10653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (st_gdata == NULL || st_gdata->rx_skb == NULL 10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->list[protoid] == NULL)) { 10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("protocol %d not registered, no data to send?", 10953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid); 11053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 11153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 11253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this cannot fail 11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * this shouldn't take long 11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - should be just skb_queue_tail for the 11653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stack driver 11753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (likely(st_gdata->list[protoid]->recv != NULL)) { 119bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy if (unlikely 120bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[protoid]->recv 121bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[protoid]->priv_data, st_gdata->rx_skb) 122320920cba355146258da7de80bed0069c1dff24aPavan Savoy != 0)) { 12353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto stack %d's ->recv failed", protoid); 12453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 12553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 12653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 12853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto stack %d's ->recv null", protoid); 12953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 13053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 13153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 13436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 13536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_reg_complete - 13653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks 13753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers 13853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err) 14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 14153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s ", __func__); 14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy for (i = 0; i < ST_MAX; i++) { 14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && 14553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i]->reg_complete_cb != NULL)) 146bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->list[i]->reg_complete_cb 147bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[i]->priv_data, err); 14853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 14953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 15053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 15153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata, 15253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int protoid, int len) 15353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 15453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy register int room = skb_tailroom(st_gdata->rx_skb); 15553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 156e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("len %d room %d", len, room); 15753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 15853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!len) { 15953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet has only packet header and 16053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * has zero length payload. So, ask ST CORE to 16153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * forward the packet to protocol driver (BT/FM/GPS) 16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 16353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_send_frame(protoid, st_gdata); 16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (len > room) { 16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet's payload length is larger. 16753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * We can't accommodate it in created skb. 16853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 16953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Data length is too large len %d room %d", len, 17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy room); 17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 17253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 17353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Packet header has non-zero payload length and 17453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * we have enough space in created skb. Lets read 17553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * payload data */ 17653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_BT_W4_DATA; 17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = len; 17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 18053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Change ST state to continue to process next 18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet */ 18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 18553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 18753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 18953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 19136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack 19236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * received 19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata, 19553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char cmd) 19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy register struct sk_buff *waiting_skb; 19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 19953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 20153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* de-Q from waitQ and Q in txQ now that the 20253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * chip is awake 20353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 20453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) 20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, waiting_skb); 20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* state forwarded to ST LL */ 20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, (unsigned long)cmd); 20953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up to send the recently copied skbs from waitQ */ 21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 21636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function. 21736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Decodes received RAW data and forwards to corresponding 21836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * client drivers (Bluetooth,FM,GPS..etc). 21936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * This can receive various types of packets, 22036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets 22136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * CH-8 packets from FM, CH-9 packets from GPS cores. 22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data, 22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, long count) 22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy register char *ptr; 22753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct hci_event_hdr *eh; 22853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct hci_acl_hdr *ah; 22953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct hci_sco_hdr *sh; 23053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct fm_event_hdr *fm; 23153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct gps_event_hdr *gps; 23253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy register int len = 0, type = 0, dlen = 0; 23353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy static enum proto_type protoid = ST_MAX; 23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = (struct st_data_s *)disc_data; 23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr = (char *)data; 23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* tty_receive sent null ? */ 23853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(ptr == NULL) || (st_gdata == NULL)) { 23953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" received null from TTY "); 24053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 24153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 24253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("count %ld rx_state %ld" 24453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "rx_count %ld", count, st_gdata->rx_state, 24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count); 24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Decode received bytes here */ 24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while (count) { 24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) { 25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = min_t(unsigned int, st_gdata->rx_count, count); 25153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); 25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count -= len; 25353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count -= len; 25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr += len; 25553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 25653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) 25753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check ST RX state machine , where are we? */ 26053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_gdata->rx_state) { 26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Waiting for complete packet ? */ 26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT_W4_DATA: 264e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Complete pkt received"); 26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Ask ST CORE to forward 26753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * the packet to protocol driver */ 26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_send_frame(protoid, st_gdata); 26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 27253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_MAX; /* is this required ? */ 27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Waiting for Bluetooth event header ? */ 27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT_W4_EVENT_HDR: 27753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy eh = (struct hci_event_hdr *)st_gdata->rx_skb-> 27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy data; 27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 280e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Event header: evt 0x%2.2x" 28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "plen %d", eh->evt, eh->plen); 28253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 28353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_check_data_len(st_gdata, protoid, eh->plen); 28453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 28553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 28653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Waiting for Bluetooth acl header ? */ 28753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT_W4_ACL_HDR: 28853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ah = (struct hci_acl_hdr *)st_gdata->rx_skb-> 28953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy data; 29053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy dlen = __le16_to_cpu(ah->dlen); 29153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 29253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("ACL header: dlen %d", dlen); 29353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 29453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_check_data_len(st_gdata, protoid, dlen); 29553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 29653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 29753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Waiting for Bluetooth sco header ? */ 29853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT_W4_SCO_HDR: 29953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy sh = (struct hci_sco_hdr *)st_gdata->rx_skb-> 30053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy data; 30153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 30253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("SCO header: dlen %d", sh->dlen); 30353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 30453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_check_data_len(st_gdata, protoid, sh->dlen); 30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_FM_W4_EVENT_HDR: 30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy fm = (struct fm_event_hdr *)st_gdata->rx_skb-> 30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy data; 30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("FM Header: "); 31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_check_data_len(st_gdata, ST_FM, fm->plen); 31153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO : Add GPS packet machine logic here */ 31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_GPS_W4_EVENT_HDR: 31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* [0x09 pkt hdr][R/W byte][2 byte len] */ 31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy gps = (struct gps_event_hdr *)st_gdata->rx_skb-> 31653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy data; 31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("GPS Header: "); 31853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_check_data_len(st_gdata, ST_GPS, gps->plen); 31953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 32053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } /* end of switch rx_state */ 32153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 32253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 32353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* end of if rx_count */ 32453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check first byte of packet and identify module 32553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * owner (BT/FM/GPS) */ 32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (*ptr) { 32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 32853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Bluetooth event packet? */ 32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_EVENT_PKT: 33053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("Event packet"); 33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_BT_W4_EVENT_HDR; 33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = HCI_EVENT_HDR_SIZE; 33353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy type = HCI_EVENT_PKT; 33453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_BT; 33553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Bluetooth acl packet? */ 33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_ACLDATA_PKT: 33953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("ACL packet"); 34053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_BT_W4_ACL_HDR; 34153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = HCI_ACL_HDR_SIZE; 34253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy type = HCI_ACLDATA_PKT; 34353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_BT; 34453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 34553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 34653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Bluetooth sco packet? */ 34753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_SCODATA_PKT: 34853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("SCO packet"); 34953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_BT_W4_SCO_HDR; 35053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = HCI_SCO_HDR_SIZE; 35153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy type = HCI_SCODATA_PKT; 35253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_BT; 35353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 35453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 35553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Channel 8(FM) packet? */ 35653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_FM_CH8_PKT: 35753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("FM CH8 packet"); 35853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy type = ST_FM_CH8_PKT; 35953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_FM_W4_EVENT_HDR; 36053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = FM_EVENT_HDR_SIZE; 36153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_FM; 36253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 36353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 36453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Channel 9(GPS) packet? */ 36553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case 0x9: /*ST_LL_GPS_CH9_PKT */ 36653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("GPS CH9 packet"); 36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy type = 0x9; /* ST_LL_GPS_CH9_PKT; */ 36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_GPS; 36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_GPS_W4_EVENT_HDR; 37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 3; /* GPS_EVENT_HDR_SIZE -1*/ 37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 37253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_IND: 37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_ACK: 37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_IND: 37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("PM packet"); 37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this takes appropriate action based on 37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * sleep state received -- 37853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 37953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, *ptr); 38053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 38153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 38253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 38353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_ACK: 38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("PM packet"); 38553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up ack received */ 38653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_wakeup_ack(st_gdata, *ptr); 38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Unknow packet? */ 39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Unknown packet type %2.2x", (__u8) *ptr); 39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 39453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy }; 39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 39853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 39953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 40053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (protoid) { 40153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT: 40253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Allocate new packet to hold received data */ 40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = 40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); 40553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata->rx_skb) { 40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Can't allocate mem for new packet"); 40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy bt_cb(st_gdata->rx_skb)->pkt_type = type; 41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_FM: /* for FM */ 41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = 41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC); 41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata->rx_skb) { 41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Can't allocate mem for new packet"); 41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 42253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* place holder 0x08 */ 42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_reserve(st_gdata->rx_skb, 1); 42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT; 42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_GPS: 42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* for GPS */ 42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = 42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC); 43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata->rx_skb) { 43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Can't allocate mem for new packet"); 43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 43653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* place holder 0x09 */ 43753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_reserve(st_gdata->rx_skb, 1); 43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb->cb[0] = 0x09; /*ST_GPS_CH9_PKT; */ 43953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_MAX: 44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 444e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 44836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 44936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function. 45036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the previous data set was not written 45136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * completely, return that skb which has the pending data. 45236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * In normal cases, return top of txq. 45353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) 45553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 45653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *returning_skb; 45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 458e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tx_skb != NULL) { 46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy returning_skb = st_gdata->tx_skb; 46153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return returning_skb; 46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return skb_dequeue(&st_gdata->txq); 46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 46736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 46836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function. 46936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Will either Q the skb to txq or the tx_waitq 47036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * depending on the ST LL state. 47136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the chip is asleep, then Q it onto waitq and 47236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * wakeup the chip. 47336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * txq and waitq needs protection since the other contexts 47436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * may be sending data, waking up chip. 47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 47653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) 47753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 480e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 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; 49136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy case ST_LL_AWAKE_TO_ASLEEP: 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 case ST_LL_ASLEEP: 49753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 49853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_wakeup(st_gdata); 49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 50636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 508e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 50953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 51053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 51153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 51253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function 51453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either 51553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished 51653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack) 51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 51853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data) 51953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 52053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *skb; 52153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags; /* for irq save flags */ 522e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 52353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for sending & set flag sending here */ 52453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { 52553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("ST already sending"); 52653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* keep sending */ 52753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_TX_WAKEUP, &st_data->tx_state); 52853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TX_WAKEUP will be checked in another 53053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * context 53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 53353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy do { /* come back if st_tx_wakeup is set */ 53453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* woke-up to write */ 53553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_WAKEUP, &st_data->tx_state); 53653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((skb = st_int_dequeue(st_data))) { 53753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int len; 53853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_data->lock, flags); 53953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable wake-up from TTY */ 54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); 54153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = st_int_write(st_data, skb->data, skb->len); 54253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_pull(skb, len); 54353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if skb->len = len as expected, skb->len=0 */ 54453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (skb->len) { 54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* would be the next skb to be sent */ 54653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_data->tx_skb = skb; 54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 54853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 54953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 55053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 55153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 55253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if wake-up is set in another context- restart sending */ 55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); 55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 55653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* clear flag sending */ 55753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_SENDING, &st_data->tx_state); 55853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 55953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 56053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 56153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM 56253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/ 563c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) 56453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 565c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoy seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 56636e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered, 56736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_BT] != NULL ? 'R' : 'U', 56836e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_FM] != NULL ? 'R' : 'U', 56936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->list[ST_GPS] != NULL ? 'R' : 'U'); 57053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 57153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 57253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 57353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 57453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers 57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed 57653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 57753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto) 57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 57953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 580320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 58153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 58253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 583dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 58453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s(%d) ", __func__, new_proto->type); 58553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL 58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || new_proto->reg_complete_cb == NULL) { 58753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); 588320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 58953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 59053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 59153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) { 59253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("protocol %d not supported", new_proto->type); 593320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 59453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 59553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[new_proto->type] != NULL) { 59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("protocol %d already registered", new_proto->type); 598320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 59953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 60053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* can be from process context only */ 60253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 60353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { 60553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->type); 60653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* fw download in progress */ 60753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); 60853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[new_proto->type] = new_proto; 61036e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 61253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 61353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_PENDING, &st_gdata->st_state); 61453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 615320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EINPROGRESS; 61653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (st_gdata->protos_registered == ST_EMPTY) { 61753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" protocol list empty :%d ", new_proto->type); 61853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 61953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_kim_recv; 62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* release lock previously held - re-locked below */ 62253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 62353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable the ST LL - to set default chip state */ 62553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_enable(st_gdata); 62653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this may take a while to complete 62753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since it involves BT fw download 62853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 62938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy err = st_kim_start(st_gdata->kim_data); 630320920cba355146258da7de80bed0069c1dff24aPavan Savoy if (err != 0) { 63153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 63253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 63353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 63453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" KIM failure complete callback "); 635320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, -1); 63653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 638320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 63953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 64053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 64153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* the protocol might require other gpios to be toggled 64253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 64353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); 64453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 64553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 64653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_int_recv; 64753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this is where all pending registration 64953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * are signalled to be complete by calling callback functions 65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 65153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 65253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 653e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" call reg complete callback "); 654320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, 0); 65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 65653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 65753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for already registered once more, 65953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since the above check is old 66053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[new_proto->type] != NULL) { 66253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto %d already registered ", 66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->type); 664320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 66853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[new_proto->type] = new_proto; 66936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 67253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 67453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if fw is already downloaded & new stack registers protocol */ 67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy else { 67653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (new_proto->type) { 67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_BT: 67853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* do nothing */ 67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 68053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_FM: 68153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_GPS: 68253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE); 68353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 68453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_MAX: 68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d protocol not supported", 68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->type); 6880b6e7220ed2be6e40bbda4eeb2b9c397008f2cefDan Carpenter spin_unlock_irqrestore(&st_gdata->lock, flags); 6890b6e7220ed2be6e40bbda4eeb2b9c397008f2cefDan Carpenter return -EPROTONOSUPPORT; 69053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[new_proto->type] = new_proto; 69236e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 69353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* lock already held before entering else */ 69653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 699e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s(%d) ", __func__, new_proto->type); 70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 70153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register); 70253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol - 70453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver 70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 70653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_unregister(enum proto_type type) 70753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 708320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 712e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: %d ", __func__, type); 71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 714dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (type < ST_BT || type >= ST_MAX) { 71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" protocol %d not supported", type); 717320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 71853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 71953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 72053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[type] == NULL) { 72353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" protocol %d not registered", type); 72453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 725320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 72653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->protos_registered--; 72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[type] = NULL; 73053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* kim ignores BT in the below function 73253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * and handles the rest, BT is toggled 73353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * only in kim_start and kim_stop 73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 73553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_kim_chip_toggle(type, KIM_GPIO_INACTIVE); 73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered == ST_EMPTY) && 73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" all protocols unregistered "); 74153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 74253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* stop traffic on tty */ 74353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tty) { 74453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(st_gdata->tty); 74553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy stop_tty(st_gdata->tty); 74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 74753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* all protocols now unregistered */ 74938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_stop(st_gdata->kim_data); 75053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* disable ST LL */ 75153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_disable(st_gdata); 75253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 75353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 75453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 75553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers 75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer 75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb) 76153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 76353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG 76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy enum proto_type protoid = ST_MAX; 76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long len; 76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 768dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(skb == NULL || st_gdata == NULL 77053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->tty == NULL)) { 77153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("data/tty unavailable to perform write"); 772320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 77353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 77453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef DEBUG /* open-up skb to read the 1st byte */ 77553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (skb->data[0]) { 77653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_COMMAND_PKT: 77753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_ACLDATA_PKT: 77853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case HCI_SCODATA_PKT: 77953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_BT; 78053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 78153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_FM_CH8_PKT: 78253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_FM; 78353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 78453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case 0x09: 78553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid = ST_GPS; 78653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 78753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 78853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(st_gdata->list[protoid] == NULL)) { 78953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" protocol %d not registered, and writing? ", 79053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy protoid); 791320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -1; 79253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 79353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 794e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%d to be written", skb->len); 79553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = skb->len; 79653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 79753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* st_ll to decide where to enqueue the skb */ 79853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_int_enqueue(st_gdata, skb); 79953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up */ 80053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 80153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* return number of bytes written */ 80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 80453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */ 80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister); 80853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer 81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 81353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty) 81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 815320920cba355146258da7de80bed0069c1dff24aPavan Savoy int err = 0; 81653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 81753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 81853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 819dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 82053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = tty; 82153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->disc_data = st_gdata; 82253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 82353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 82453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 82553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 82653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* mem already allocated 82753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->receive_room = 65536; 82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 83253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 83453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * installation of N_TI_WL ldisc is complete 83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 83638d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 837e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 83853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 84053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty) 84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 84353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = ST_MAX; 84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 84553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO: 85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if a protocol has been registered & line discipline 85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * un-installed for some reason - what should be done ? 85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy for (i = ST_BT; i < ST_MAX; i++) { 85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->list[i] != NULL) 85653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d not un-registered", i); 85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i] = NULL; 85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 859bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->protos_registered = 0; 86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 86153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 86253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 86353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * N_TI_WL ldisc is un-installed 86453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 86538d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 86653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = NULL; 86753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 86853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 86953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 87053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 87153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 87253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* empty out txq and tx_waitq */ 87353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 87453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 87553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* reset the TTY Rx states of ST */ 87653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 87753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 87853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 87953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 88053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 88153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 882e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: done ", __func__); 88353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 88453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 88553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data, 88653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy char *tty_flags, int count) 88753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 88853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 88953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 890e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, 891e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 89253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 89353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 89453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 89553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if fw download is in progress then route incoming data 89653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to KIM for validation 89753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 89853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv(tty->disc_data, data, count); 899e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 90053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 90153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 90253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer 90353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called 90453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 90553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty) 90653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 90753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 908e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 90953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 91053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 91153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 91253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* call our internal wakeup */ 91353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup((void *)st_gdata); 91453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 91553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 91653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty) 91753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 91853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 919e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 92053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 92153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 92253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 92353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 92453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->ops->flush_buffer(tty); 92553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 92653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 92753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 92853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 92953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data) 93053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 93153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 93253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 93353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy static struct tty_ldisc_ops *st_ldisc_ops; 93453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 93553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* populate and register to TTY line discipline */ 93653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops = kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL); 93753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_ldisc_ops) { 93853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("no mem to allocate"); 93953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return -ENOMEM; 94053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 94153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 94253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->magic = TTY_LDISC_MAGIC; 94353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->name = "n_st"; /*"n_hci"; */ 94453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->open = st_tty_open; 94553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->close = st_tty_close; 94653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->receive_buf = st_tty_receive; 94753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->write_wakeup = st_tty_wakeup; 94853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->flush_buffer = st_tty_flush_buffer; 94953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ldisc_ops->owner = THIS_MODULE; 95053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 95153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_register_ldisc(N_TI_WL, st_ldisc_ops); 95253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 95353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error registering %d line discipline %ld", 95453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy N_TI_WL, err); 95553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_ldisc_ops); 95653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 95753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 958e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("registered n_shared line discipline"); 95953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 96053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); 96153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata) { 96253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("memory allocation failed"); 96353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 96453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 96553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 96653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_ldisc_ops); 96753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = -ENOMEM; 96853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 96953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 97053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 97153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's 97253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will be pushed in this queue for actual transmission. 97353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 97453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->txq); 97553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->tx_waitq); 97653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 97753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Locking used in st_int_enqueue() to avoid multiple execution */ 97853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_init(&st_gdata->lock); 97953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 98053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* ldisc_ops ref to be only used in __exit of module */ 98153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->ldisc_ops = st_ldisc_ops; 98253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 98353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0 98453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_kim_init(); 98553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 98653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during kim initialization(%ld)", err); 98753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 98853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 98953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 99053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 99153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_ldisc_ops); 99253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return -1; 99353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 99453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 99553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 99653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_init(st_gdata); 99753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 99853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during st_ll initialization(%ld)", err); 99953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 100053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 100153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 100253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 100353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_ldisc_ops); 100453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return -1; 100553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 100653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *core_data = st_gdata; 100753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 100853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 100953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 101053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata) 101153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 101253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 101353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* internal module cleanup */ 101453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_deinit(st_gdata); 101553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 101653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST LL %ld", err); 101753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#if 0 101853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_kim_deinit(); 101953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 102053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST KIM %ld", err); 102153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 102253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata != NULL) { 102353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Free ST Tx Qs and skbs */ 102453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 102553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 102653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 102753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 102853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TTY ldisc cleanup */ 102953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 103053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 103153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 103253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata->ldisc_ops); 103353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* free the global data pointer */ 103453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 103553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 103653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 103753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 103853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 1039