st_core.c revision 5926cef26c72cd121266b000b8975e6373cbf2b3
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; 46764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[new_proto->chnl_id] = true; 475c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy} 485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy 495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoystatic void remove_channel_from_table(struct st_data_s *st_gdata, 505c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto) 515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy{ 525c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: id %d\n", __func__, proto->chnl_id); 53764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy/* st_gdata->list[proto->chnl_id] = NULL; */ 54764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[proto->chnl_id] = false; 5553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 5636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 57ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy/* 58ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * called from KIM during firmware download. 59ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * 60ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * This is a wrapper function to tty->ops->write_room. 61ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * It returns number of free space available in 62ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * uart tx buffer. 63ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy */ 64ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoyint st_get_uart_wr_room(struct st_data_s *st_gdata) 65ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy{ 66ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy struct tty_struct *tty; 67ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 68ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy pr_err("tty unavailable to perform write"); 69ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy return -1; 70ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy } 71ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy tty = st_gdata->tty; 72ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy return tty->ops->write_room(tty); 73ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy} 74ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy 7553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from 7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download) 7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write) 7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This is the internal write function - a wrapper 8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to tty->ops->write 8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata, 8353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, int count) 8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 8553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct tty_struct *tty; 8653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("tty unavailable to perform write"); 88704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 8953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 9053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty = st_gdata->tty; 9153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 92e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, 93e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 9453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return tty->ops->write(tty, data, count); 9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 10053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant 10153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks 10253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1035c88b02196a99332dacf305c8757674dd7a303ffPavan Savoyvoid st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) 10453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 1056710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug(" %s(prot:%d) ", __func__, chnl_id); 10653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely 10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (st_gdata == NULL || st_gdata->rx_skb == NULL 109764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy || st_gdata->is_registered[chnl_id] == false)) { 1105c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not registered, no data to send?", 1115c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy chnl_id); 11253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this cannot fail 11653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * this shouldn't take long 11753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - should be just skb_queue_tail for the 11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stack driver 11953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1205c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (likely(st_gdata->list[chnl_id]->recv != NULL)) { 121bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy if (unlikely 1225c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->recv 1235c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) 124320920cba355146258da7de80bed0069c1dff24aPavan Savoy != 0)) { 1255c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv failed", chnl_id); 12653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 12853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 12953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 1305c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv null", chnl_id); 13153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 13453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 13553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 13636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 13736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_reg_complete - 13853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks 13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers 14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 14153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err) 14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s ", __func__); 1455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = 0; i < ST_MAX_CHANNELS; i++) { 146764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (likely(st_gdata != NULL && 147764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] == true && 148764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->list[i]->reg_complete_cb != NULL)) { 149bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->list[i]->reg_complete_cb 150bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[i]->priv_data, err); 151704426649dd4324b34cefea322f4333e5280f852Pavan Savoy pr_info("protocol %d's cb sent %d\n", i, err); 152704426649dd4324b34cefea322f4333e5280f852Pavan Savoy if (err) { /* cleanup registered protocol */ 153704426649dd4324b34cefea322f4333e5280f852Pavan Savoy st_gdata->protos_registered--; 154764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] = false; 155704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 156704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 15753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 15853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 15953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata, 1615c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char chnl_id, int len) 16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 16373f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy int room = skb_tailroom(st_gdata->rx_skb); 16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 165e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("len %d room %d", len, room); 16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!len) { 16853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet has only packet header and 16953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * has zero length payload. So, ask ST CORE to 17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * forward the packet to protocol driver (BT/FM/GPS) 17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1725c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(chnl_id, st_gdata); 17353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (len > room) { 17553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet's payload length is larger. 17653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * We can't accommodate it in created skb. 17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Data length is too large len %d room %d", len, 17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy room); 18053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Packet header has non-zero payload length and 18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * we have enough space in created skb. Lets read 18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * payload data */ 1855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_DATA; 18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = len; 18753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 18953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Change ST state to continue to process next 19153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet */ 19253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 1955c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = 0; 19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 19953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 20136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack 20236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * received 20353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 20453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata, 20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char cmd) 20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 20773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy struct sk_buff *waiting_skb; 20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 20953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 21153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* de-Q from waitQ and Q in txQ now that the 21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * chip is awake 21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) 21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, waiting_skb); 21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* state forwarded to ST LL */ 21853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, (unsigned long)cmd); 21953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 22053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up to send the recently copied skbs from waitQ */ 22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 22636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function. 22736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Decodes received RAW data and forwards to corresponding 22836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * client drivers (Bluetooth,FM,GPS..etc). 22936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * This can receive various types of packets, 23036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets 23136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * CH-8 packets from FM, CH-9 packets from GPS cores. 23253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 23353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data, 23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, long count) 23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 23673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy char *ptr; 2375c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto; 2385c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned short payload_len = 0; 2395c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy int len = 0, type = 0; 2405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char *plen; 24153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = (struct st_data_s *)disc_data; 2426d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy unsigned long flags; 24353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr = (char *)data; 24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* tty_receive sent null ? */ 24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(ptr == NULL) || (st_gdata == NULL)) { 24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" received null from TTY "); 24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2516710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("count %ld rx_state %ld" 25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "rx_count %ld", count, st_gdata->rx_state, 25353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count); 25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2556d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 25653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Decode received bytes here */ 25753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while (count) { 25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) { 25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = min_t(unsigned int, st_gdata->rx_count, count); 26053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); 26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count -= len; 26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count -= len; 26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr += len; 26453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) 26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 26753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check ST RX state machine , where are we? */ 26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_gdata->rx_state) { 2705c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* Waiting for complete packet ? */ 2715c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_DATA: 272e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Complete pkt received"); 27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Ask ST CORE to forward 27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * the packet to protocol driver */ 2755c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(st_gdata->rx_chnl, st_gdata); 27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 2805c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* parse the header to know details */ 2815c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_HEADER: 2825c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto = st_gdata->list[st_gdata->rx_chnl]; 2835c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy plen = 2845c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy &st_gdata->rx_skb->data 2855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy [proto->offset_len_in_hdr]; 2866710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("plen pointing to %x\n", *plen); 2875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (proto->len_size == 1)/* 1 byte len field */ 2885c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = *(unsigned char *)plen; 2895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else if (proto->len_size == 2) 2905c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = 2915c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __le16_to_cpu(*(unsigned short *)plen); 2925c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else 2935c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: invalid length " 2945c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy "for id %d\n", 2955c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __func__, proto->chnl_id); 2965c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_check_data_len(st_gdata, proto->chnl_id, 2975c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len); 2986710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("off %d, pay len %d\n", 2995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto->offset_len_in_hdr, payload_len); 30053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 30153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } /* end of switch rx_state */ 30253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 30353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 30453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* end of if rx_count */ 30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check first byte of packet and identify module 30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * owner (BT/FM/GPS) */ 30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (*ptr) { 30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_IND: 30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_ACK: 31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_IND: 3116710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this takes appropriate action based on 31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * sleep state received -- 31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, *ptr); 3166d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy /* if WAKEUP_IND collides copy from waitq to txq 3176d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy * and assume chip awake 3186d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy */ 3196d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 3206d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) 3216d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); 3226d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3236d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 32453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 32553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_ACK: 3286710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 3296d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 3306d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up ack received */ 33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_wakeup_ack(st_gdata, *ptr); 3336d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3346d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 33553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Unknow packet? */ 33953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 3405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy type = *ptr; 3415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb = alloc_skb( 3425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->max_frame_size, 3435c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy GFP_ATOMIC); 3445c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy skb_reserve(st_gdata->rx_skb, 3455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->reserve); 3465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* next 2 required for BT only */ 3475c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ 3485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[1] = 0; /*incoming*/ 3495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = *ptr; 3505c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_HEADER; 3515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_count = st_gdata->list[type]->hdr_len; 3526710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("rx_count %ld\n", st_gdata->rx_count); 35353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy }; 35453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 35553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 35653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 3576d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 358e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 35953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 36053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 36153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 36236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 36336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function. 36436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the previous data set was not written 36536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * completely, return that skb which has the pending data. 36636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * In normal cases, return top of txq. 36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) 36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *returning_skb; 37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 372e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tx_skb != NULL) { 37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy returning_skb = st_gdata->tx_skb; 37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return returning_skb; 37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 37853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return skb_dequeue(&st_gdata->txq); 37953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 38053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 38136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 38236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function. 38336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Will either Q the skb to txq or the tx_waitq 38436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * depending on the ST LL state. 38536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the chip is asleep, then Q it onto waitq and 38636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * wakeup the chip. 38736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * txq and waitq needs protection since the other contexts 38836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * may be sending data, waking up chip. 38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) 39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 394e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_ll_getstate(st_gdata)) { 39853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_AWAKE: 3996710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST LL is AWAKE, sending normally"); 40053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, skb); 40153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 40253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP_TO_AWAKE: 40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 40536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy case ST_LL_AWAKE_TO_ASLEEP: 40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP: 41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_wakeup(st_gdata); 41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 42036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 422e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function 42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either 42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished 43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack) 43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data) 43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *skb; 43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags; /* for irq save flags */ 436e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 43753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for sending & set flag sending here */ 43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { 4396710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST already sending"); 44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* keep sending */ 44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_TX_WAKEUP, &st_data->tx_state); 44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TX_WAKEUP will be checked in another 44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * context 44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy do { /* come back if st_tx_wakeup is set */ 44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* woke-up to write */ 44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_WAKEUP, &st_data->tx_state); 45053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((skb = st_int_dequeue(st_data))) { 45153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int len; 45253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_data->lock, flags); 45353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable wake-up from TTY */ 45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); 45553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = st_int_write(st_data, skb->data, skb->len); 45653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_pull(skb, len); 45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if skb->len = len as expected, skb->len=0 */ 45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (skb->len) { 45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* would be the next skb to be sent */ 46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_data->tx_skb = skb; 46153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 46753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if wake-up is set in another context- restart sending */ 46853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); 46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 47053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* clear flag sending */ 47153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_SENDING, &st_data->tx_state); 47253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 47353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 47453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM 47653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/ 477c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) 47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 479c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoy seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 48036e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered, 481764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x04] == true ? 'R' : 'U', 482764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x08] == true ? 'R' : 'U', 483764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x09] == true ? 'R' : 'U'); 48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 48553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 48753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers 48953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed 49053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 49153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto) 49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 49353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 494320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 49553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 49653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 497dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 4985c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s(%d) ", __func__, new_proto->chnl_id); 49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL 50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || new_proto->reg_complete_cb == NULL) { 50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); 502704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5055c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->chnl_id >= ST_MAX_CHANNELS) { 5065c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not supported", new_proto->chnl_id); 507320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 50853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 50953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 510764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 5115c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d already registered", new_proto->chnl_id); 512320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 51453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 51553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* can be from process context only */ 51653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 51853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { 5195c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); 52053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* fw download in progress */ 52153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5225c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 52336e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 52453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 52553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 52653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_PENDING, &st_gdata->st_state); 52753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 528320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EINPROGRESS; 52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (st_gdata->protos_registered == ST_EMPTY) { 5305c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); 53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_kim_recv; 53353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* release lock previously held - re-locked below */ 53553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 53653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable the ST LL - to set default chip state */ 53853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_enable(st_gdata); 53953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this may take a while to complete 54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since it involves BT fw download 54153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 54238d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy err = st_kim_start(st_gdata->kim_data); 543320920cba355146258da7de80bed0069c1dff24aPavan Savoy if (err != 0) { 54453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 54653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" KIM failure complete callback "); 548704426649dd4324b34cefea322f4333e5280f852Pavan Savoy st_reg_complete(st_gdata, err); 54953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 550704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 55153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 55253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_int_recv; 55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 55653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this is where all pending registration 55753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * are signalled to be complete by calling callback functions 55853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 55953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 56053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 561e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" call reg complete callback "); 562320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, 0); 56353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 56453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 56553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 56653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for already registered once more, 56753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since the above check is old 56853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 569764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 57053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto %d already registered ", 5715c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy new_proto->chnl_id); 572320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 57353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 57453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 5765c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 57736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 57953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 58053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 58153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 58253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if fw is already downloaded & new stack registers protocol */ 58353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy else { 5845c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 58536e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 58753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 58853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* lock already held before entering else */ 58953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 59053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 59153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 5925c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); 59353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 59453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register); 59553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol - 59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver 59853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 5995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoylong st_unregister(struct st_proto_s *proto) 60053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 601320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 60253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 60353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 60453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6055c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("%s: %d ", __func__, proto->chnl_id); 60653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 607dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 6087316a9f2a94c14e66e9421a777dffc509a2fe0e3Steven Rostedt if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { 6095c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not supported", proto->chnl_id); 610320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 61253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 61353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 61453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6155c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (st_gdata->list[proto->chnl_id] == NULL) { 6165c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not registered", proto->chnl_id); 61753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 618320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 61953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->protos_registered--; 6225c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy remove_channel_from_table(st_gdata, proto); 62353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered == ST_EMPTY) && 62653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 6275c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" all chnl_ids unregistered "); 62853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 62953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* stop traffic on tty */ 63053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tty) { 63153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(st_gdata->tty); 63253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy stop_tty(st_gdata->tty); 63353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6355c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* all chnl_ids now unregistered */ 63638d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_stop(st_gdata->kim_data); 63753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* disable ST LL */ 63853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_disable(st_gdata); 63953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 64053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 64153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 64253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 64353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 64453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers 64553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer 64653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 64753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb) 64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 64953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long len; 65153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 652dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 65353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(skb == NULL || st_gdata == NULL 65453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->tty == NULL)) { 65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("data/tty unavailable to perform write"); 656704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 65753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 658c1605f2e3312ca149caf32129e0b25b1e7296f36Pavan Savoy 659e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%d to be written", skb->len); 66053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = skb->len; 66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* st_ll to decide where to enqueue the skb */ 66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_int_enqueue(st_gdata, skb); 66453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up */ 66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* return number of bytes written */ 66853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 66953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */ 67253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister); 67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 67453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 67653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer 67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 67853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty) 67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 680320920cba355146258da7de80bed0069c1dff24aPavan Savoy int err = 0; 68153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 68253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 68353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 684dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = tty; 68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->disc_data = st_gdata; 68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 68853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 68953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 69053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* mem already allocated 69253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 69353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->receive_room = 65536; 69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 69653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 69953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * installation of N_TI_WL ldisc is complete 70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 70138d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 702e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 70453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 70653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty) 70753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 7085c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char i = ST_MAX_CHANNELS; 70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO: 71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if a protocol has been registered & line discipline 71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * un-installed for some reason - what should be done ? 71753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 71853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 7195c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { 7205926cef26c72cd121266b000b8975e6373cbf2b3Pavan Savoy if (st_gdata->is_registered[i] == true) 72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d not un-registered", i); 72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i] = NULL; 72353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 724bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->protos_registered = 0; 72553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 72653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * N_TI_WL ldisc is un-installed 72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 73038d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = NULL; 73253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 73353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 73553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* empty out txq and tx_waitq */ 73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* reset the TTY Rx states of ST */ 74153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 74253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 74353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 74453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 74553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 747e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: done ", __func__); 74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 74953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 75055db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvaldsstatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data, 75155db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvalds char *tty_flags, int count) 75253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 75353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 754e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, 755e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if fw download is in progress then route incoming data 76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to KIM for validation 76153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv(tty->disc_data, data, count); 763e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer 76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called 76853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(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 /* don't do an wakeup for now */ 77453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 77553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 77653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* call our internal wakeup */ 77753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup((void *)st_gdata); 77853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 77953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty) 78153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 78253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 783e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 78453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 78653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 78753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->ops->flush_buffer(tty); 78953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 79053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 79153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 79273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoystatic struct tty_ldisc_ops st_ldisc_ops = { 79373f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .magic = TTY_LDISC_MAGIC, 79473f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .name = "n_st", 79573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .open = st_tty_open, 79673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .close = st_tty_close, 79773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .receive_buf = st_tty_receive, 79873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .write_wakeup = st_tty_wakeup, 79973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .flush_buffer = st_tty_flush_buffer, 80073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .owner = THIS_MODULE 80173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy}; 80273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 80453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data) 80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 80653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 80853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); 81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error registering %d line discipline %ld", 81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy N_TI_WL, err); 81353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 815e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("registered n_shared line discipline"); 81653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); 81853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata) { 81953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("memory allocation failed"); 82053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 82153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 82253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 82353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = -ENOMEM; 82453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 82553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 82653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 82753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's 82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will be pushed in this queue for actual transmission. 82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->txq); 83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->tx_waitq); 83253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Locking used in st_int_enqueue() to avoid multiple execution */ 83453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_init(&st_gdata->lock); 83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 83653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_init(st_gdata); 83753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 83853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during st_ll initialization(%ld)", err); 83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 84053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 843704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return err; 84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 84553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *core_data = st_gdata; 84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata) 85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* internal module cleanup */ 85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_deinit(st_gdata); 85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST LL %ld", err); 85673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata != NULL) { 85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Free ST Tx Qs and skbs */ 85953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 86153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 86253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 86353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TTY ldisc cleanup */ 86453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 86553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 86653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 86753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* free the global data pointer */ 86853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 86953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 87053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 87153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 87253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 873