st_core.c revision 5353cf089bb32b69a7515be909c14bf05fe2e81e
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 140bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy * This function is being called with spin lock held, protocol drivers are 141bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy * only expected to complete their waits and do nothing more than that. 14253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_reg_complete(struct st_data_s *st_gdata, char err) 14453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 14553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 14653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s ", __func__); 1475c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = 0; i < ST_MAX_CHANNELS; i++) { 148764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (likely(st_gdata != NULL && 149764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] == true && 150764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->list[i]->reg_complete_cb != NULL)) { 151bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->list[i]->reg_complete_cb 152bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[i]->priv_data, err); 153704426649dd4324b34cefea322f4333e5280f852Pavan Savoy pr_info("protocol %d's cb sent %d\n", i, err); 154704426649dd4324b34cefea322f4333e5280f852Pavan Savoy if (err) { /* cleanup registered protocol */ 155704426649dd4324b34cefea322f4333e5280f852Pavan Savoy st_gdata->protos_registered--; 156764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] = false; 157704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 158704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 15953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 16053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 16153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata, 1635c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char chnl_id, int len) 16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 16573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy int room = skb_tailroom(st_gdata->rx_skb); 16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 167e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("len %d room %d", len, room); 16853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!len) { 17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet has only packet header and 17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * has zero length payload. So, ask ST CORE to 17253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * forward the packet to protocol driver (BT/FM/GPS) 17353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1745c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(chnl_id, st_gdata); 17553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (len > room) { 17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet's payload length is larger. 17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * We can't accommodate it in created skb. 17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 18053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Data length is too large len %d room %d", len, 18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy room); 18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Packet header has non-zero payload length and 18553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * we have enough space in created skb. Lets read 18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * payload data */ 1875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_DATA; 18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = len; 18953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 19053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 19153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Change ST state to continue to process next 19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet */ 19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 19553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 1975c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = 0; 19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 20053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 20153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 20336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack 20436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * received 20553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 20653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata, 20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char cmd) 20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 20973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy struct sk_buff *waiting_skb; 21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 21153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* de-Q from waitQ and Q in txQ now that the 21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * chip is awake 21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) 21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, waiting_skb); 21853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* state forwarded to ST LL */ 22053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, (unsigned long)cmd); 22153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up to send the recently copied skbs from waitQ */ 22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 22836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function. 22936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Decodes received RAW data and forwards to corresponding 23036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * client drivers (Bluetooth,FM,GPS..etc). 23136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * This can receive various types of packets, 23236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets 23336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * CH-8 packets from FM, CH-9 packets from GPS cores. 23453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 23553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data, 23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, long count) 23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 23873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy char *ptr; 2395c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto; 2405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned short payload_len = 0; 2415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy int len = 0, type = 0; 2425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char *plen; 24353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = (struct st_data_s *)disc_data; 2446d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy unsigned long flags; 24553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr = (char *)data; 24753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* tty_receive sent null ? */ 24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(ptr == NULL) || (st_gdata == NULL)) { 24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" received null from TTY "); 25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 25153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2536710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("count %ld rx_state %ld" 25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "rx_count %ld", count, st_gdata->rx_state, 25553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count); 25653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2576d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Decode received bytes here */ 25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while (count) { 26053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) { 26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = min_t(unsigned int, st_gdata->rx_count, count); 26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); 26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count -= len; 26453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count -= len; 26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr += len; 26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 26753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) 26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check ST RX state machine , where are we? */ 27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_gdata->rx_state) { 2725c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* Waiting for complete packet ? */ 2735c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_DATA: 274e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Complete pkt received"); 27553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Ask ST CORE to forward 27653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * the packet to protocol driver */ 2775c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(st_gdata->rx_chnl, st_gdata); 27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 28053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 2825c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* parse the header to know details */ 2835c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_HEADER: 2845c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto = st_gdata->list[st_gdata->rx_chnl]; 2855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy plen = 2865c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy &st_gdata->rx_skb->data 2875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy [proto->offset_len_in_hdr]; 2886710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("plen pointing to %x\n", *plen); 2895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (proto->len_size == 1)/* 1 byte len field */ 2905c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = *(unsigned char *)plen; 2915c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else if (proto->len_size == 2) 2925c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = 2935c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __le16_to_cpu(*(unsigned short *)plen); 2945c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else 2955c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: invalid length " 2965c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy "for id %d\n", 2975c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __func__, proto->chnl_id); 2985c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_check_data_len(st_gdata, proto->chnl_id, 2995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len); 3006710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("off %d, pay len %d\n", 3015c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto->offset_len_in_hdr, payload_len); 30253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 30353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } /* end of switch rx_state */ 30453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* end of if rx_count */ 30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check first byte of packet and identify module 30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * owner (BT/FM/GPS) */ 30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (*ptr) { 31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_IND: 31153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_ACK: 31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_IND: 3136710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this takes appropriate action based on 31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * sleep state received -- 31653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, *ptr); 3186d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy /* if WAKEUP_IND collides copy from waitq to txq 3196d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy * and assume chip awake 3206d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy */ 3216d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 3226d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) 3236d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); 3246d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3256d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 32653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 32753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 32853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_ACK: 3306710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 3316d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 3326d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 33353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up ack received */ 33453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_wakeup_ack(st_gdata, *ptr); 3356d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3366d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 33853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 33953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 34053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Unknow packet? */ 34153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 3425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy type = *ptr; 34378bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi if (st_gdata->list[type] == NULL) { 34478bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi pr_err("chip/interface misbehavior dropping" 34578bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi " frame starting with 0x%02x", type); 34678bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi goto done; 34778bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi 34878bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi } 3495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb = alloc_skb( 3505c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->max_frame_size, 3515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy GFP_ATOMIC); 3525353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox if (st_gdata->rx_skb == NULL) { 3535353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox pr_err("out of memory: dropping\n"); 3545353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox goto done; 3555353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox } 3565353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox 3575c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy skb_reserve(st_gdata->rx_skb, 3585c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->reserve); 3595c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* next 2 required for BT only */ 3605c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ 3615c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[1] = 0; /*incoming*/ 3625c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = *ptr; 3635c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_HEADER; 3645c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_count = st_gdata->list[type]->hdr_len; 3656710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("rx_count %ld\n", st_gdata->rx_count); 36653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy }; 36753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 36853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 37078bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagidone: 3716d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 372e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 37353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 37453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 37553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 37636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 37736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function. 37836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the previous data set was not written 37936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * completely, return that skb which has the pending data. 38036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * In normal cases, return top of txq. 38153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 38253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystruct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) 38353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *returning_skb; 38553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 386e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tx_skb != NULL) { 38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy returning_skb = st_gdata->tx_skb; 38953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return returning_skb; 39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return skb_dequeue(&st_gdata->txq); 39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 39453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 39536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 39636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function. 39736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Will either Q the skb to txq or the tx_waitq 39836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * depending on the ST LL state. 39936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the chip is asleep, then Q it onto waitq and 40036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * wakeup the chip. 40136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * txq and waitq needs protection since the other contexts 40236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * may be sending data, waking up chip. 40353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 40453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) 40553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 40753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 408e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 41153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_ll_getstate(st_gdata)) { 41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_AWAKE: 4136710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST LL is AWAKE, sending normally"); 41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, skb); 41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP_TO_AWAKE: 41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy case ST_LL_AWAKE_TO_ASLEEP: 42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 42253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP: 42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_wakeup(st_gdata); 42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 43436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 436e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 43753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 43953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function 44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either 44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished 44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack) 44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data) 44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *skb; 44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags; /* for irq save flags */ 450e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 45153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for sending & set flag sending here */ 45253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { 4536710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST already sending"); 45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* keep sending */ 45553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_TX_WAKEUP, &st_data->tx_state); 45653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TX_WAKEUP will be checked in another 45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * context 45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 46153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy do { /* come back if st_tx_wakeup is set */ 46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* woke-up to write */ 46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_WAKEUP, &st_data->tx_state); 46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((skb = st_int_dequeue(st_data))) { 46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int len; 46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_data->lock, flags); 46753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable wake-up from TTY */ 46853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); 46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = st_int_write(st_data, skb->data, skb->len); 47053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_pull(skb, len); 47153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if skb->len = len as expected, skb->len=0 */ 47253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (skb->len) { 47353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* would be the next skb to be sent */ 47453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_data->tx_skb = skb; 47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 47653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 47753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 48053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 48153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if wake-up is set in another context- restart sending */ 48253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); 48353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* clear flag sending */ 48553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_SENDING, &st_data->tx_state); 48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 48753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 48953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM 49053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/ 491c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) 49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 493c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoy seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 49436e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered, 495764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x04] == true ? 'R' : 'U', 496764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x08] == true ? 'R' : 'U', 497764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x09] == true ? 'R' : 'U'); 49853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 49953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 50053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers 50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed 50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto) 50653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 508320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 50953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 51053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 511dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 5125c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s(%d) ", __func__, new_proto->chnl_id); 51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL 51453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || new_proto->reg_complete_cb == NULL) { 51553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); 516704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 51853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5195c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->chnl_id >= ST_MAX_CHANNELS) { 5205c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not supported", new_proto->chnl_id); 521320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 52253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 52353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 524764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 5255c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d already registered", new_proto->chnl_id); 526320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 52753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 52853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* can be from process context only */ 53053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { 5335c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); 53453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* fw download in progress */ 53553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5365c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 53736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 53853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 53953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_PENDING, &st_gdata->st_state); 54153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 542320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EINPROGRESS; 54353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (st_gdata->protos_registered == ST_EMPTY) { 5445c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); 54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 54653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_kim_recv; 54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 548bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy /* enable the ST LL - to set default chip state */ 549bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy st_ll_enable(st_gdata); 550bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy 55153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* release lock previously held - re-locked below */ 55253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this may take a while to complete 55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since it involves BT fw download 55653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 55738d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy err = st_kim_start(st_gdata->kim_data); 558320920cba355146258da7de80bed0069c1dff24aPavan Savoy if (err != 0) { 55953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 56053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 56153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 56253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" KIM failure complete callback "); 563704426649dd4324b34cefea322f4333e5280f852Pavan Savoy st_reg_complete(st_gdata, err); 564bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 56553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 566704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 56753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 56853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 569bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 570bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy 57153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 57253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_int_recv; 57353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 57453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this is where all pending registration 57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * are signalled to be complete by calling callback functions 57653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 57753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 579e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" call reg complete callback "); 580320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, 0); 58153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 58253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 58353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 58453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for already registered once more, 58553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since the above check is old 58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 587764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 58853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto %d already registered ", 5895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy new_proto->chnl_id); 590bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 591320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 59253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 59353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5945c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 59536e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 59853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 59953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 60053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if fw is already downloaded & new stack registers protocol */ 60153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy else { 6025c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 60336e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 60453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 60553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 60653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* lock already held before entering else */ 60753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 60853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 60953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 6105c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); 61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 61253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register); 61353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 61453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol - 61553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver 61653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 6175c88b02196a99332dacf305c8757674dd7a303ffPavan Savoylong st_unregister(struct st_proto_s *proto) 61853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 619320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 62153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 62253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6235c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("%s: %d ", __func__, proto->chnl_id); 62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 625dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 6267316a9f2a94c14e66e9421a777dffc509a2fe0e3Steven Rostedt if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { 6275c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not supported", proto->chnl_id); 628320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 62953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 63153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 63253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 633bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy if (st_gdata->is_registered[proto->chnl_id] == false) { 6345c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not registered", proto->chnl_id); 63553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 636320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 63753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 63953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->protos_registered--; 6405c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy remove_channel_from_table(st_gdata, proto); 64153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 64253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 643bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy /* paranoid check */ 644bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy if (st_gdata->protos_registered < ST_EMPTY) 645bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy st_gdata->protos_registered = ST_EMPTY; 646bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy 64753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered == ST_EMPTY) && 64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 6495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" all chnl_ids unregistered "); 65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* stop traffic on tty */ 65253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tty) { 65353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(st_gdata->tty); 65453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy stop_tty(st_gdata->tty); 65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 65653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6575c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* all chnl_ids now unregistered */ 65838d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_stop(st_gdata->kim_data); 65953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* disable ST LL */ 66053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_disable(st_gdata); 66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 66253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 66453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers 66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer 66853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 66953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb) 67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 67253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long len; 67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 674dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(skb == NULL || st_gdata == NULL 67653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->tty == NULL)) { 67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("data/tty unavailable to perform write"); 678704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 680c1605f2e3312ca149caf32129e0b25b1e7296f36Pavan Savoy 681e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%d to be written", skb->len); 68253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = skb->len; 68353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 68453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* st_ll to decide where to enqueue the skb */ 68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_int_enqueue(st_gdata, skb); 68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up */ 68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 68853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 68953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* return number of bytes written */ 69053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 69253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */ 69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister); 69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer 69953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty) 70153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 702320920cba355146258da7de80bed0069c1dff24aPavan Savoy int err = 0; 70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 70453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 706dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 70753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = tty; 70853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->disc_data = st_gdata; 70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 71253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* mem already allocated 71453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->receive_room = 65536; 71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 71753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 71853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 71953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 72053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * installation of N_TI_WL ldisc is complete 72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 72338d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 724e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 72553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 72653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty) 72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 7305c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char i = ST_MAX_CHANNELS; 73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 73253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 73353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 73553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO: 73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if a protocol has been registered & line discipline 73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * un-installed for some reason - what should be done ? 73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 7415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { 7425926cef26c72cd121266b000b8975e6373cbf2b3Pavan Savoy if (st_gdata->is_registered[i] == true) 74353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d not un-registered", i); 74453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i] = NULL; 745651d62a8b0378b911f083a1712d9d228894f46d8Pavan Savoy st_gdata->is_registered[i] = false; 74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 747bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->protos_registered = 0; 74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 74953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 75053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 75153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * N_TI_WL ldisc is un-installed 75253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 75338d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 75453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = NULL; 75553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* empty out txq and tx_waitq */ 76153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 76353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* reset the TTY Rx states of ST */ 76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 76853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 770e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: done ", __func__); 77153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 77253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 77355db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvaldsstatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data, 77455db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvalds char *tty_flags, int count) 77553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 77653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 777e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, 778e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 77953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 78053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 78253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if fw download is in progress then route incoming data 78353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to KIM for validation 78453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 78553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv(tty->disc_data, data, count); 786e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 78753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 78853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer 79053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called 79153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 79253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty) 79353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 79453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 795e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 79653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 79753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 79853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 79953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* call our internal wakeup */ 80053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup((void *)st_gdata); 80153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 80253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty) 80453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 806e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 80953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->ops->flush_buffer(tty); 81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 81353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoystatic struct tty_ldisc_ops st_ldisc_ops = { 81673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .magic = TTY_LDISC_MAGIC, 81773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .name = "n_st", 81873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .open = st_tty_open, 81973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .close = st_tty_close, 82073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .receive_buf = st_tty_receive, 82173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .write_wakeup = st_tty_wakeup, 82273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .flush_buffer = st_tty_flush_buffer, 82373f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .owner = THIS_MODULE 82473f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy}; 82573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 82653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 82753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data) 82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 83273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); 83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 83453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error registering %d line discipline %ld", 83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy N_TI_WL, err); 83653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 83753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 838e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("registered n_shared line discipline"); 83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); 84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata) { 84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("memory allocation failed"); 84353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 84553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = -ENOMEM; 84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's 85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will be pushed in this queue for actual transmission. 85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->txq); 85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->tx_waitq); 85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 85653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Locking used in st_int_enqueue() to avoid multiple execution */ 85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_init(&st_gdata->lock); 85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 85953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_init(st_gdata); 86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 86153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during st_ll initialization(%ld)", err); 86253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 86353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 86453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 86553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 866704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return err; 86753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 86853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *core_data = st_gdata; 86953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 87053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 87153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 87253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata) 87353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 87453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 87553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* internal module cleanup */ 87653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_deinit(st_gdata); 87753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 87853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST LL %ld", err); 87973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 88053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata != NULL) { 88153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Free ST Tx Qs and skbs */ 88253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 88353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 88453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 88553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 88653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TTY ldisc cleanup */ 88753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 88853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 88953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 89053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* free the global data pointer */ 89153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 89253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 89353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 89453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 89553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 896