Commit 764b0c4b authored by Pavan Savoy's avatar Pavan Savoy Committed by Greg Kroah-Hartman

drivers:misc:ti-st: handle delayed tty receive

When certain technologies shutdown their interface without waiting for
the acknowledgement from the chip. The receive_buf from the TTY would be
invoked a while after the relevant technology is unregistered.

This patch introduces a new flag "is_registered" which maintains the
state of protocols BT, FM or GPS and thereby removes the need to clear
the protocol data from ST when protocols gets unregistered.

This fixes corner cases when HCI RESET is sent down from bluetooth stack
and the receive_buf is called from tty after 250ms before which
bluetooth would have unregistered from the system.
OR - when FM application decides to close down the device without
sending a power-off FM command resulting in some RDS data or interrupt
data coming in after the driver is unregistered.
Signed-off-by: default avatarPavan Savoy <pavan_savoy@ti.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 70a5f521
...@@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata, ...@@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata,
pr_info("%s: id %d\n", __func__, new_proto->chnl_id); pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
/* list now has the channel id as index itself */ /* list now has the channel id as index itself */
st_gdata->list[new_proto->chnl_id] = new_proto; st_gdata->list[new_proto->chnl_id] = new_proto;
st_gdata->is_registered[new_proto->chnl_id] = true;
} }
static void remove_channel_from_table(struct st_data_s *st_gdata, static void remove_channel_from_table(struct st_data_s *st_gdata,
struct st_proto_s *proto) struct st_proto_s *proto)
{ {
pr_info("%s: id %d\n", __func__, proto->chnl_id); pr_info("%s: id %d\n", __func__, proto->chnl_id);
st_gdata->list[proto->chnl_id] = NULL; /* st_gdata->list[proto->chnl_id] = NULL; */
st_gdata->is_registered[proto->chnl_id] = false;
} }
/* /*
...@@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) ...@@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
if (unlikely if (unlikely
(st_gdata == NULL || st_gdata->rx_skb == NULL (st_gdata == NULL || st_gdata->rx_skb == NULL
|| st_gdata->list[chnl_id] == NULL)) { || st_gdata->is_registered[chnl_id] == false)) {
pr_err("chnl_id %d not registered, no data to send?", pr_err("chnl_id %d not registered, no data to send?",
chnl_id); chnl_id);
kfree_skb(st_gdata->rx_skb); kfree_skb(st_gdata->rx_skb);
...@@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err) ...@@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
unsigned char i = 0; unsigned char i = 0;
pr_info(" %s ", __func__); pr_info(" %s ", __func__);
for (i = 0; i < ST_MAX_CHANNELS; i++) { for (i = 0; i < ST_MAX_CHANNELS; i++) {
if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && if (likely(st_gdata != NULL &&
st_gdata->list[i]->reg_complete_cb != NULL)) { st_gdata->is_registered[i] == true &&
st_gdata->list[i]->reg_complete_cb != NULL)) {
st_gdata->list[i]->reg_complete_cb st_gdata->list[i]->reg_complete_cb
(st_gdata->list[i]->priv_data, err); (st_gdata->list[i]->priv_data, err);
pr_info("protocol %d's cb sent %d\n", i, err); pr_info("protocol %d's cb sent %d\n", i, err);
if (err) { /* cleanup registered protocol */ if (err) { /* cleanup registered protocol */
st_gdata->protos_registered--; st_gdata->protos_registered--;
st_gdata->list[i] = NULL; st_gdata->is_registered[i] = false;
} }
} }
} }
...@@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf) ...@@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
{ {
seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
st_gdata->protos_registered, st_gdata->protos_registered,
st_gdata->list[0x04] != NULL ? 'R' : 'U', st_gdata->is_registered[0x04] == true ? 'R' : 'U',
st_gdata->list[0x08] != NULL ? 'R' : 'U', st_gdata->is_registered[0x08] == true ? 'R' : 'U',
st_gdata->list[0x09] != NULL ? 'R' : 'U'); st_gdata->is_registered[0x09] == true ? 'R' : 'U');
} }
/********************************************************************/ /********************************************************************/
...@@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto) ...@@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto)
return -EPROTONOSUPPORT; return -EPROTONOSUPPORT;
} }
if (st_gdata->list[new_proto->chnl_id] != NULL) { if (st_gdata->is_registered[new_proto->chnl_id] == true) {
pr_err("chnl_id %d already registered", new_proto->chnl_id); pr_err("chnl_id %d already registered", new_proto->chnl_id);
return -EALREADY; return -EALREADY;
} }
...@@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto) ...@@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto)
/* check for already registered once more, /* check for already registered once more,
* since the above check is old * since the above check is old
*/ */
if (st_gdata->list[new_proto->chnl_id] != NULL) { if (st_gdata->is_registered[new_proto->chnl_id] == true) {
pr_err(" proto %d already registered ", pr_err(" proto %d already registered ",
new_proto->chnl_id); new_proto->chnl_id);
return -EALREADY; return -EALREADY;
......
...@@ -140,12 +140,12 @@ extern long st_unregister(struct st_proto_s *); ...@@ -140,12 +140,12 @@ extern long st_unregister(struct st_proto_s *);
*/ */
struct st_data_s { struct st_data_s {
unsigned long st_state; unsigned long st_state;
struct tty_struct *tty;
struct sk_buff *tx_skb; struct sk_buff *tx_skb;
#define ST_TX_SENDING 1 #define ST_TX_SENDING 1
#define ST_TX_WAKEUP 2 #define ST_TX_WAKEUP 2
unsigned long tx_state; unsigned long tx_state;
struct st_proto_s *list[ST_MAX_CHANNELS]; struct st_proto_s *list[ST_MAX_CHANNELS];
bool is_registered[ST_MAX_CHANNELS];
unsigned long rx_state; unsigned long rx_state;
unsigned long rx_count; unsigned long rx_count;
struct sk_buff *rx_skb; struct sk_buff *rx_skb;
...@@ -155,6 +155,7 @@ struct st_data_s { ...@@ -155,6 +155,7 @@ struct st_data_s {
unsigned char protos_registered; unsigned char protos_registered;
unsigned long ll_state; unsigned long ll_state;
void *kim_data; void *kim_data;
struct tty_struct *tty;
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment