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/tty.h> 2653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 275c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy#include <linux/seq_file.h> 285c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy#include <linux/skbuff.h> 295c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy 30e5558679bbb80788dc8c4c30484ac0a68e971ca5Pavan Savoy#include <linux/ti_wilink_st.h> 3153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 3227712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoyextern void st_kim_recv(void *, const unsigned char *, long); 3327712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoyvoid st_int_recv(void *, const unsigned char *, long); 3453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* function pointer pointing to either, 3553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_kim_recv during registration to receive fw download responses 3653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * st_int_recv after registration to receive proto stack responses 3753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 3827712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoystatic void (*st_recv) (void *, const unsigned char *, long); 3953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 4053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoystatic void add_channel_to_table(struct st_data_s *st_gdata, 425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *new_proto) 4353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 445c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: id %d\n", __func__, new_proto->chnl_id); 455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* list now has the channel id as index itself */ 465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[new_proto->chnl_id] = new_proto; 47764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[new_proto->chnl_id] = true; 485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy} 495c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy 505c88b02196a99332dacf305c8757674dd7a303ffPavan Savoystatic void remove_channel_from_table(struct st_data_s *st_gdata, 515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto) 525c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy{ 535c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: id %d\n", __func__, proto->chnl_id); 54764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy/* st_gdata->list[proto->chnl_id] = NULL; */ 55764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[proto->chnl_id] = false; 5653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 5736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 58ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy/* 59ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * called from KIM during firmware download. 60ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * 61ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * This is a wrapper function to tty->ops->write_room. 62ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * It returns number of free space available in 63ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy * uart tx buffer. 64ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy */ 65ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoyint st_get_uart_wr_room(struct st_data_s *st_gdata) 66ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy{ 67ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy struct tty_struct *tty; 68ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 69ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy pr_err("tty unavailable to perform write"); 70ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy return -1; 71ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy } 72ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy tty = st_gdata->tty; 73ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy return tty->ops->write_room(tty); 74ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy} 75ef04d121f030329aae0c2d3ec22beea0c5cbcfd3Pavan Savoy 7653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* can be called in from 7753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- KIM (during fw download) 7853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * -- ST Core (during st_write) 7953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * 8053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * This is the internal write function - a wrapper 8153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to tty->ops->write 8253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 8353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_int_write(struct st_data_s *st_gdata, 8453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, int count) 8553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 8653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct tty_struct *tty; 8753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) { 8853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("tty unavailable to perform write"); 89704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 9053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 9153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty = st_gdata->tty; 9253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 93e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, "<out<", DUMP_PREFIX_NONE, 94e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 9553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 9653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return tty->ops->write(tty, data, count); 9753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 9853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 9953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 10053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 10153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * push the skb received to relevant 10253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stacks 10353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 10427712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoystatic void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) 10553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 1066710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug(" %s(prot:%d) ", __func__, chnl_id); 10753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 10853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely 10953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (st_gdata == NULL || st_gdata->rx_skb == NULL 110764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy || st_gdata->is_registered[chnl_id] == false)) { 1115c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not registered, no data to send?", 1125c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy chnl_id); 11353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 11453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 11553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 11653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this cannot fail 11753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * this shouldn't take long 11853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - should be just skb_queue_tail for the 11953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * protocol stack driver 12053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1215c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (likely(st_gdata->list[chnl_id]->recv != NULL)) { 122bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy if (unlikely 1235c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->recv 1245c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy (st_gdata->list[chnl_id]->priv_data, st_gdata->rx_skb) 125320920cba355146258da7de80bed0069c1dff24aPavan Savoy != 0)) { 1265c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv failed", chnl_id); 12753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 12853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 12953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 13053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 1315c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" proto stack %d's ->recv null", chnl_id); 13253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 13353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 13453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 13553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 13653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 13736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 13836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_reg_complete - 13953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to call registration complete callbacks 14053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * of all protocol stack drivers 141bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy * This function is being called with spin lock held, protocol drivers are 142bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy * only expected to complete their waits and do nothing more than that. 14353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 14427712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoystatic void st_reg_complete(struct st_data_s *st_gdata, char err) 14553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 14653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char i = 0; 14753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info(" %s ", __func__); 1485c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = 0; i < ST_MAX_CHANNELS; i++) { 149764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (likely(st_gdata != NULL && 150764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] == true && 151764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->list[i]->reg_complete_cb != NULL)) { 152bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->list[i]->reg_complete_cb 153bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy (st_gdata->list[i]->priv_data, err); 154704426649dd4324b34cefea322f4333e5280f852Pavan Savoy pr_info("protocol %d's cb sent %d\n", i, err); 155704426649dd4324b34cefea322f4333e5280f852Pavan Savoy if (err) { /* cleanup registered protocol */ 156764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[i] = false; 157e4ebe5fe2d507a4c228bf90dea7dd4de57cbce92Lee Jones if (st_gdata->protos_registered) 158e4ebe5fe2d507a4c228bf90dea7dd4de57cbce92Lee Jones st_gdata->protos_registered--; 159704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 160704426649dd4324b34cefea322f4333e5280f852Pavan Savoy } 16153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 16253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 16353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 16453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline int st_check_data_len(struct st_data_s *st_gdata, 1655c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char chnl_id, int len) 16653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 16773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy int room = skb_tailroom(st_gdata->rx_skb); 16853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 169e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("len %d room %d", len, room); 17053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!len) { 17253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet has only packet header and 17353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * has zero length payload. So, ask ST CORE to 17453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * forward the packet to protocol driver (BT/FM/GPS) 17553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 1765c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(chnl_id, st_gdata); 17753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 17853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (len > room) { 17953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Received packet's payload length is larger. 18053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * We can't accommodate it in created skb. 18153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 18253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("Data length is too large len %d room %d", len, 18353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy room); 18453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 18553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else { 18653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Packet header has non-zero payload length and 18753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * we have enough space in created skb. Lets read 18853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * payload data */ 1895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_DATA; 19053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = len; 19153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 19253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 19353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 19453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Change ST state to continue to process next 19553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * packet */ 19653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 19753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 19853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 1995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = 0; 20053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 20253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 20353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 20436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 20536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_wakeup_ack - internal function for action when wake-up ack 20636b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * received 20753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 20853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic inline void st_wakeup_ack(struct st_data_s *st_gdata, 20953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned char cmd) 21053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 21173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy struct sk_buff *waiting_skb; 21253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 21353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 21453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 21553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* de-Q from waitQ and Q in txQ now that the 21653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * chip is awake 21753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 21853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq))) 21953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, waiting_skb); 22053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* state forwarded to ST LL */ 22253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, (unsigned long)cmd); 22353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 22453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up to send the recently copied skbs from waitQ */ 22653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 22753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 22853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 22936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 23036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_recv - ST's internal receive function. 23136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Decodes received RAW data and forwards to corresponding 23236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * client drivers (Bluetooth,FM,GPS..etc). 23336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * This can receive various types of packets, 23436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * HCI-Events, ACL, SCO, 4 types of HCI-LL PM packets 23536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * CH-8 packets from FM, CH-9 packets from GPS cores. 23653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 23753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_int_recv(void *disc_data, 23853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy const unsigned char *data, long count) 23953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 24073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy char *ptr; 2415c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy struct st_proto_s *proto; 2425c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned short payload_len = 0; 24325c22d5bead5b0211f3ecc84fd6152dfdf95c75dchanning int len = 0; 24425c22d5bead5b0211f3ecc84fd6152dfdf95c75dchanning unsigned char type = 0; 2455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char *plen; 24653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = (struct st_data_s *)disc_data; 2476d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy unsigned long flags; 24853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 24953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr = (char *)data; 25053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* tty_receive sent null ? */ 25153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(ptr == NULL) || (st_gdata == NULL)) { 25253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" received null from TTY "); 25353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 25453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 25553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2566710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("count %ld rx_state %ld" 25753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "rx_count %ld", count, st_gdata->rx_state, 25853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count); 25953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 2606d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 26153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Decode received bytes here */ 26253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while (count) { 26353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) { 26453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = min_t(unsigned int, st_gdata->rx_count, count); 26553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy memcpy(skb_put(st_gdata->rx_skb, len), ptr, len); 26653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count -= len; 26753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count -= len; 26853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr += len; 26953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->rx_count) 27153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 27253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 27353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check ST RX state machine , where are we? */ 27453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_gdata->rx_state) { 2755c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* Waiting for complete packet ? */ 2765c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_DATA: 277e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("Complete pkt received"); 27853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Ask ST CORE to forward 27953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * the packet to protocol driver */ 2805c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_send_frame(st_gdata->rx_chnl, st_gdata); 28153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 28253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 28353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 28453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 2855c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* parse the header to know details */ 2865c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy case ST_W4_HEADER: 2875c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto = st_gdata->list[st_gdata->rx_chnl]; 2885c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy plen = 2895c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy &st_gdata->rx_skb->data 2905c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy [proto->offset_len_in_hdr]; 2916710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("plen pointing to %x\n", *plen); 2925c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (proto->len_size == 1)/* 1 byte len field */ 2935c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = *(unsigned char *)plen; 2945c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else if (proto->len_size == 2) 2955c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len = 2965c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __le16_to_cpu(*(unsigned short *)plen); 2975c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy else 2985c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info("%s: invalid length " 2995c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy "for id %d\n", 3005c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy __func__, proto->chnl_id); 3015c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_check_data_len(st_gdata, proto->chnl_id, 3025c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy payload_len); 3036710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("off %d, pay len %d\n", 3045c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy proto->offset_len_in_hdr, payload_len); 30553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 30653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } /* end of switch rx_state */ 30753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 30853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 30953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* end of if rx_count */ 31053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Check first byte of packet and identify module 31153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * owner (BT/FM/GPS) */ 31253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (*ptr) { 31353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_IND: 31453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_SLEEP_ACK: 31553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_IND: 3166710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 31753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this takes appropriate action based on 31853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * sleep state received -- 31953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 32053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_sleep_state(st_gdata, *ptr); 3216d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy /* if WAKEUP_IND collides copy from waitq to txq 3226d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy * and assume chip awake 3236d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy */ 3246d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 3256d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy if (st_ll_getstate(st_gdata) == ST_LL_AWAKE) 3266d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy st_wakeup_ack(st_gdata, LL_WAKE_UP_ACK); 3276d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3286d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 32953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 33053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 33153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 33253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case LL_WAKE_UP_ACK: 3336710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("PM packet"); 3346d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 3356d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 33653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up ack received */ 33753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_wakeup_ack(st_gdata, *ptr); 3386d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 3396d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy 34053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 34153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 34253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy continue; 34353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Unknow packet? */ 34453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 3455c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy type = *ptr; 34678bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi if (st_gdata->list[type] == NULL) { 34778bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi pr_err("chip/interface misbehavior dropping" 34878bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi " frame starting with 0x%02x", type); 34978bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi goto done; 35078bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi 35178bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagi } 3525c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb = alloc_skb( 3535c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->max_frame_size, 3545c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy GFP_ATOMIC); 3555353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox if (st_gdata->rx_skb == NULL) { 3565353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox pr_err("out of memory: dropping\n"); 3575353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox goto done; 3585353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox } 3595353cf089bb32b69a7515be909c14bf05fe2e81eAlan Cox 3605c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy skb_reserve(st_gdata->rx_skb, 3615c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->list[type]->reserve); 3625c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* next 2 required for BT only */ 3635c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[0] = type; /*pkt_type*/ 3645c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_skb->cb[1] = 0; /*incoming*/ 3655c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_chnl = *ptr; 3665c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_state = ST_W4_HEADER; 3675c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy st_gdata->rx_count = st_gdata->list[type]->hdr_len; 3686710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("rx_count %ld\n", st_gdata->rx_count); 36953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy }; 37053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy ptr++; 37153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy count--; 37253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 37378bb9697e2c4b62c426f1a2571c293a2e4463adfVijay Badawadagidone: 3746d71ba2105a1d8c1712cdfcf46fc6040e4707cb9Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 375e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 37653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 37753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 37853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 37936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 38036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_dequeue - internal de-Q function. 38136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the previous data set was not written 38236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * completely, return that skb which has the pending data. 38336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * In normal cases, return top of txq. 38453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 38527712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoystatic struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) 38653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 38753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *returning_skb; 38853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 389e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 39053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tx_skb != NULL) { 39153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy returning_skb = st_gdata->tx_skb; 39253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 39353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return returning_skb; 39453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 39553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return skb_dequeue(&st_gdata->txq); 39653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 39753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 39836b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy/** 39936b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * st_int_enqueue - internal Q-ing function. 40036b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * Will either Q the skb to txq or the tx_waitq 40136b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * depending on the ST LL state. 40236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * If the chip is asleep, then Q it onto waitq and 40336b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * wakeup the chip. 40436b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * txq and waitq needs protection since the other contexts 40536b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy * may be sending data, waking up chip. 40653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 40727712b3928bec9b1a889d7f60d718a35ca6c23b3Pavan Savoystatic void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) 40853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 40953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 41053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 411e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 41253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 41353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 41453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy switch (st_ll_getstate(st_gdata)) { 41553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_AWAKE: 4166710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST LL is AWAKE, sending normally"); 41753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->txq, skb); 41853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 41953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP_TO_AWAKE: 42053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 42153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42236b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy case ST_LL_AWAKE_TO_ASLEEP: 42353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 42453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 42553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 42653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 42753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy case ST_LL_ASLEEP: 42853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_tail(&st_gdata->tx_waitq, skb); 42953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_wakeup(st_gdata); 43053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 43153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy default: 43253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("ST LL is illegal state(%ld)," 43353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy "purging received skb.", st_ll_getstate(st_gdata)); 43453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 43553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 43653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 43736b5aee46b5e4788758409829926c631de0a64a3Pavan Savoy 43853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 439e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 44053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 44153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 44253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 44353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 44453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * internal wakeup function 44553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called from either 44653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - TTY layer when write's finished 44753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * - st_write (in context of the protocol stack) 44853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 44953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_tx_wakeup(struct st_data_s *st_data) 45053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 45153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct sk_buff *skb; 45253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags; /* for irq save flags */ 453e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s", __func__); 45453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for sending & set flag sending here */ 45553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) { 4566710fcff66ef0330cdc458557271ee86026745d0Pavan Savoy pr_debug("ST already sending"); 45753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* keep sending */ 45853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_TX_WAKEUP, &st_data->tx_state); 45953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 46053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TX_WAKEUP will be checked in another 46153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * context 46253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 46353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 46453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy do { /* come back if st_tx_wakeup is set */ 46553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* woke-up to write */ 46653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_WAKEUP, &st_data->tx_state); 46753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy while ((skb = st_int_dequeue(st_data))) { 46853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy int len; 46953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_data->lock, flags); 47053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* enable wake-up from TTY */ 47153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags); 47253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = st_int_write(st_data, skb->data, skb->len); 47353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_pull(skb, len); 47453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if skb->len = len as expected, skb->len=0 */ 47553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (skb->len) { 47653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* would be the next skb to be sent */ 47753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_data->tx_skb = skb; 47853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 47953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy break; 48053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 48153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(skb); 48253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_data->lock, flags); 48353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 48453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if wake-up is set in another context- restart sending */ 48553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } while (test_bit(ST_TX_WAKEUP, &st_data->tx_state)); 48653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 48753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* clear flag sending */ 48853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_TX_SENDING, &st_data->tx_state); 48953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 49053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 49153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 49253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* functions called from ST KIM 49353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy*/ 494c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoyvoid kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) 49553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 496c1afac1502c4e519e6a1df08a5d9a2391d00388bPavan Savoy seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 49736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered, 498764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x04] == true ? 'R' : 'U', 499764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x08] == true ? 'R' : 'U', 500764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy st_gdata->is_registered[0x09] == true ? 'R' : 'U'); 50153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 50253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 50353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 50453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 50553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from protocol stack drivers 50653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be EXPORT-ed 50753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 50853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_register(struct st_proto_s *new_proto) 50953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 51053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 511320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 51253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 51353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 514dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 51553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL 51653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || new_proto->reg_complete_cb == NULL) { 51753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); 518704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 51953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 52053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5215c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy if (new_proto->chnl_id >= ST_MAX_CHANNELS) { 5225c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d not supported", new_proto->chnl_id); 523320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 52453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 52553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 526764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 5275c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err("chnl_id %d already registered", new_proto->chnl_id); 528320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 52953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 53053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* can be from process context only */ 53253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 53353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 53453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) { 5355c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" ST_REG_IN_PROGRESS:%d ", new_proto->chnl_id); 53653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* fw download in progress */ 53753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5385c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 53936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 54053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 54153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 54253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_PENDING, &st_gdata->st_state); 54353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 544320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EINPROGRESS; 54553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } else if (st_gdata->protos_registered == ST_EMPTY) { 5465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" chnl_id list empty :%d ", new_proto->chnl_id); 54753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 54853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_kim_recv; 54953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 550bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy /* enable the ST LL - to set default chip state */ 551bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy st_ll_enable(st_gdata); 552bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy 55353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* release lock previously held - re-locked below */ 55453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 55553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 55653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this may take a while to complete 55753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since it involves BT fw download 55853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 55938d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy err = st_kim_start(st_gdata->kim_data); 560320920cba355146258da7de80bed0069c1dff24aPavan Savoy if (err != 0) { 56153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 56253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 56353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 56453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" KIM failure complete callback "); 5653a2d3d213d7c9bb427cc5bdb0de34fe18a22363eOleksandr Kozaruk spin_lock_irqsave(&st_gdata->lock, flags); 566704426649dd4324b34cefea322f4333e5280f852Pavan Savoy st_reg_complete(st_gdata, err); 5673a2d3d213d7c9bb427cc5bdb0de34fe18a22363eOleksandr Kozaruk spin_unlock_irqrestore(&st_gdata->lock, flags); 568bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 56953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 570704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 57153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 57253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 573bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 574bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy 57553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); 57653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv = st_int_recv; 57753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 57853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* this is where all pending registration 57953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * are signalled to be complete by calling callback functions 58053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 58153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered != ST_EMPTY) && 58253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 583e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug(" call reg complete callback "); 584320920cba355146258da7de80bed0069c1dff24aPavan Savoy st_reg_complete(st_gdata, 0); 58553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 58653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(ST_REG_PENDING, &st_gdata->st_state); 58753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 58853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* check for already registered once more, 58953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * since the above check is old 59053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 591764b0c4b3256ad4431cb52eaf99c0abe6df0a085Pavan Savoy if (st_gdata->is_registered[new_proto->chnl_id] == true) { 59253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err(" proto %d already registered ", 5935c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy new_proto->chnl_id); 594bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 595320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EALREADY; 59653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 59753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 5985c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 59936e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 60053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 60153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 60253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 60353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 60453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* if fw is already downloaded & new stack registers protocol */ 60553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy else { 6065c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy add_channel_to_table(st_gdata, new_proto); 60736e574fed5578aeee0ce4c7359bc17cc0b8e0b57Naveen Jain st_gdata->protos_registered++; 60853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy new_proto->write = st_write; 60953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 61053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* lock already held before entering else */ 61153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 61253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 61353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 6145c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("done %s(%d) ", __func__, new_proto->chnl_id); 61553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 61653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_register); 61753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 61853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* to unregister a protocol - 61953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to be called from protocol stack driver 62053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 6215c88b02196a99332dacf305c8757674dd7a303ffPavan Savoylong st_unregister(struct st_proto_s *proto) 62253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 623320920cba355146258da7de80bed0069c1dff24aPavan Savoy long err = 0; 62453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 62553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 62653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6275c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_debug("%s: %d ", __func__, proto->chnl_id); 62853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 629dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 6307316a9f2a94c14e66e9421a777dffc509a2fe0e3Steven Rostedt if (!st_gdata || proto->chnl_id >= ST_MAX_CHANNELS) { 6315c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not supported", proto->chnl_id); 632320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 63353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 63453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 63553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 63653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 637bfb88d6c91a2cf507ff7763ebec94d72b4c98b07Pavan Savoy if (st_gdata->is_registered[proto->chnl_id] == false) { 6385c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_err(" chnl_id %d not registered", proto->chnl_id); 63953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 640320920cba355146258da7de80bed0069c1dff24aPavan Savoy return -EPROTONOSUPPORT; 64153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 64253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 643e4ebe5fe2d507a4c228bf90dea7dd4de57cbce92Lee Jones if (st_gdata->protos_registered) 644e4ebe5fe2d507a4c228bf90dea7dd4de57cbce92Lee Jones st_gdata->protos_registered--; 645e4ebe5fe2d507a4c228bf90dea7dd4de57cbce92Lee Jones 6465c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy remove_channel_from_table(st_gdata, proto); 64753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 64853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 64953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if ((st_gdata->protos_registered == ST_EMPTY) && 65053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { 6515c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy pr_info(" all chnl_ids unregistered "); 65253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 65353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* stop traffic on tty */ 65453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata->tty) { 65553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(st_gdata->tty); 65653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy stop_tty(st_gdata->tty); 65753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 65853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 6595c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy /* all chnl_ids now unregistered */ 66038d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_stop(st_gdata->kim_data); 66153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* disable ST LL */ 66253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_ll_disable(st_gdata); 66353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 66453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 66553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 66653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 66753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 66853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * called in protocol stack drivers 66953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * via the write function pointer 67053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 67153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoylong st_write(struct sk_buff *skb) 67253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 67353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 67453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long len; 67553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 676dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 67753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (unlikely(skb == NULL || st_gdata == NULL 67853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy || st_gdata->tty == NULL)) { 67953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("data/tty unavailable to perform write"); 680704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return -EINVAL; 68153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 682c1605f2e3312ca149caf32129e0b25b1e7296f36Pavan Savoy 683e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%d to be written", skb->len); 68453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy len = skb->len; 68553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 68653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* st_ll to decide where to enqueue the skb */ 68753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_int_enqueue(st_gdata, skb); 68853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* wake up */ 68953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup(st_gdata); 69053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* return number of bytes written */ 69253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return len; 69353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 69453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* for protocols making use of shared transport */ 69653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan SavoyEXPORT_SYMBOL_GPL(st_unregister); 69753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 69853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 69953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* 70053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * functions called from TTY layer 70153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 70253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic int st_tty_open(struct tty_struct *tty) 70353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 704320920cba355146258da7de80bed0069c1dff24aPavan Savoy int err = 0; 70553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 70653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 70753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 708dbd3a8709560365ff9b1e5eca263f608877a8a89Pavan Savoy st_kim_ref(&st_gdata, 0); 70953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = tty; 71053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->disc_data = st_gdata; 71153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 71353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 71453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 71553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* mem already allocated 71653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 71753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty->receive_room = 65536; 71853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 71953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 72053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 72153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 72253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 72353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * installation of N_TI_WL ldisc is complete 72453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 72538d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 726e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 72753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 72853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 72953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_close(struct tty_struct *tty) 73153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 7325c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy unsigned char i = ST_MAX_CHANNELS; 73353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy unsigned long flags = 0; 73453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 73553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_info("%s ", __func__); 73753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 73853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TODO: 73953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if a protocol has been registered & line discipline 74053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * un-installed for some reason - what should be done ? 74153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 74253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 7435c88b02196a99332dacf305c8757674dd7a303ffPavan Savoy for (i = ST_BT; i < ST_MAX_CHANNELS; i++) { 7445926cef26c72cd121266b000b8975e6373cbf2b3Pavan Savoy if (st_gdata->is_registered[i] == true) 74553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("%d not un-registered", i); 74653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->list[i] = NULL; 747651d62a8b0378b911f083a1712d9d228894f46d8Pavan Savoy st_gdata->is_registered[i] = false; 74853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 749bb8f3c061f2e7282730059ae524ff19d47d70b17Pavan Savoy st_gdata->protos_registered = 0; 75053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 75153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 75253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * signal to UIM via KIM that - 75353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * N_TI_WL ldisc is un-installed 75453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 75538d9df499dd3125465cf5aed3d3d6d5c26f0645dPavan Savoy st_kim_complete(st_gdata->kim_data); 75653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tty = NULL; 75753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Flush any pending characters in the driver and discipline. */ 75853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_ldisc_flush(tty); 75953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy tty_driver_flush_buffer(tty); 76053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 76153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_irqsave(&st_gdata->lock, flags); 76253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* empty out txq and tx_waitq */ 76353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 76453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 76553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* reset the TTY Rx states of ST */ 76653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_count = 0; 76753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_state = ST_W4_PACKET_TYPE; 76853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 76953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->rx_skb = NULL; 77053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_unlock_irqrestore(&st_gdata->lock, flags); 77153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 772e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s: done ", __func__); 77353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 77453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 77555db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvaldsstatic void st_tty_receive(struct tty_struct *tty, const unsigned char *data, 77655db4c64eddf37e31279ec15fe90314713bc9cfaLinus Torvalds char *tty_flags, int count) 77753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 77853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#ifdef VERBOSE 779e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE, 780e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy 16, 1, data, count, 0); 78153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy#endif 78253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 78353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* 78453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * if fw download is in progress then route incoming data 78553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * to KIM for validation 78653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 78753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_recv(tty->disc_data, data, count); 788e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("done %s", __func__); 78953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 79053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 79153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/* wake-up function called in from the TTY layer 79253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * inside the internal wakeup function will be called 79353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 79453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_wakeup(struct tty_struct *tty) 79553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 79653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 797e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 79853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* don't do an wakeup for now */ 79953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); 80053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* call our internal wakeup */ 80253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_tx_wakeup((void *)st_gdata); 80353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 80453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 80553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoystatic void st_tty_flush_buffer(struct tty_struct *tty) 80653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 80753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata = tty->disc_data; 808e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("%s ", __func__); 80953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 81153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata->tx_skb = NULL; 81253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81394459a975b7d4d70c20df1a32d63825469b8d4ccPeter Hurley tty_driver_flush_buffer(tty); 81453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return; 81553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 81653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 81773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoystatic struct tty_ldisc_ops st_ldisc_ops = { 81873f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .magic = TTY_LDISC_MAGIC, 81973f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .name = "n_st", 82073f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .open = st_tty_open, 82173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .close = st_tty_close, 82273f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .receive_buf = st_tty_receive, 82373f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .write_wakeup = st_tty_wakeup, 82473f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .flush_buffer = st_tty_flush_buffer, 82573f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy .owner = THIS_MODULE 82673f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy}; 82773f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 82853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy/********************************************************************/ 82953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyint st_core_init(struct st_data_s **core_data) 83053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 83153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy struct st_data_s *st_gdata; 83253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 83353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 83473f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy err = tty_register_ldisc(N_TI_WL, &st_ldisc_ops); 83553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 83653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error registering %d line discipline %ld", 83753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy N_TI_WL, err); 83853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 83953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 840e6d9e64e36fbeddc7d5b640379bd13930075129bPavan Savoy pr_debug("registered n_shared line discipline"); 84153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 84253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL); 84353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (!st_gdata) { 84453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("memory allocation failed"); 84553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 84653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 84753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 84853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = -ENOMEM; 84953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return err; 85053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 85153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 85253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's 85353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy * will be pushed in this queue for actual transmission. 85453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy */ 85553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->txq); 85653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_head_init(&st_gdata->tx_waitq); 85753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 85853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Locking used in st_int_enqueue() to avoid multiple execution */ 85953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy spin_lock_init(&st_gdata->lock); 86053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 86153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_init(st_gdata); 86253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) { 86353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during st_ll initialization(%ld)", err); 86453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 86553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 86653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 86753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc"); 868704426649dd4324b34cefea322f4333e5280f852Pavan Savoy return err; 86953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 87053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy *core_data = st_gdata; 87153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy return 0; 87253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 87353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 87453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoyvoid st_core_exit(struct st_data_s *st_gdata) 87553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy{ 87653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy long err; 87753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* internal module cleanup */ 87853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = st_ll_deinit(st_gdata); 87953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 88053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("error during deinit of ST LL %ld", err); 88173f12e8d3d94828b9efe2b8b8a34b4ad6d14ee47Pavan Savoy 88253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (st_gdata != NULL) { 88353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* Free ST Tx Qs and skbs */ 88453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->txq); 88553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy skb_queue_purge(&st_gdata->tx_waitq); 88653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->rx_skb); 88753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree_skb(st_gdata->tx_skb); 88853618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* TTY ldisc cleanup */ 88953618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy err = tty_unregister_ldisc(N_TI_WL); 89053618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy if (err) 89153618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy pr_err("unable to un-register ldisc %ld", err); 89253618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy /* free the global data pointer */ 89353618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy kfree(st_gdata); 89453618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy } 89553618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy} 89653618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 89753618cc1e51e1f406a467eca9d1dd2675f3ad88ePavan Savoy 898