aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/misc
diff options
context:
space:
mode:
authorPavan Savoy <pavan_savoy@ti.com>2011-04-08 05:57:42 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2011-04-22 20:01:09 -0400
commit764b0c4b3256ad4431cb52eaf99c0abe6df0a085 (patch)
treebf1aabc7468e61a4bfaaa4e178baf2ef31a2b57a /drivers/misc
parent70a5f52165bd04cf3b33f30d5d234be28dcf29d4 (diff)
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: Pavan Savoy <pavan_savoy@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/misc')
-rw-r--r--drivers/misc/ti-st/st_core.c23
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 486117f72c9f..f91f82eabda7 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -43,13 +43,15 @@ static void add_channel_to_table(struct st_data_s *st_gdata,
43 pr_info("%s: id %d\n", __func__, new_proto->chnl_id); 43 pr_info("%s: id %d\n", __func__, new_proto->chnl_id);
44 /* list now has the channel id as index itself */ 44 /* list now has the channel id as index itself */
45 st_gdata->list[new_proto->chnl_id] = new_proto; 45 st_gdata->list[new_proto->chnl_id] = new_proto;
46 st_gdata->is_registered[new_proto->chnl_id] = true;
46} 47}
47 48
48static void remove_channel_from_table(struct st_data_s *st_gdata, 49static void remove_channel_from_table(struct st_data_s *st_gdata,
49 struct st_proto_s *proto) 50 struct st_proto_s *proto)
50{ 51{
51 pr_info("%s: id %d\n", __func__, proto->chnl_id); 52 pr_info("%s: id %d\n", __func__, proto->chnl_id);
52 st_gdata->list[proto->chnl_id] = NULL; 53/* st_gdata->list[proto->chnl_id] = NULL; */
54 st_gdata->is_registered[proto->chnl_id] = false;
53} 55}
54 56
55/* 57/*
@@ -104,7 +106,7 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata)
104 106
105 if (unlikely 107 if (unlikely
106 (st_gdata == NULL || st_gdata->rx_skb == NULL 108 (st_gdata == NULL || st_gdata->rx_skb == NULL
107 || st_gdata->list[chnl_id] == NULL)) { 109 || st_gdata->is_registered[chnl_id] == false)) {
108 pr_err("chnl_id %d not registered, no data to send?", 110 pr_err("chnl_id %d not registered, no data to send?",
109 chnl_id); 111 chnl_id);
110 kfree_skb(st_gdata->rx_skb); 112 kfree_skb(st_gdata->rx_skb);
@@ -141,14 +143,15 @@ void st_reg_complete(struct st_data_s *st_gdata, char err)
141 unsigned char i = 0; 143 unsigned char i = 0;
142 pr_info(" %s ", __func__); 144 pr_info(" %s ", __func__);
143 for (i = 0; i < ST_MAX_CHANNELS; i++) { 145 for (i = 0; i < ST_MAX_CHANNELS; i++) {
144 if (likely(st_gdata != NULL && st_gdata->list[i] != NULL && 146 if (likely(st_gdata != NULL &&
145 st_gdata->list[i]->reg_complete_cb != NULL)) { 147 st_gdata->is_registered[i] == true &&
148 st_gdata->list[i]->reg_complete_cb != NULL)) {
146 st_gdata->list[i]->reg_complete_cb 149 st_gdata->list[i]->reg_complete_cb
147 (st_gdata->list[i]->priv_data, err); 150 (st_gdata->list[i]->priv_data, err);
148 pr_info("protocol %d's cb sent %d\n", i, err); 151 pr_info("protocol %d's cb sent %d\n", i, err);
149 if (err) { /* cleanup registered protocol */ 152 if (err) { /* cleanup registered protocol */
150 st_gdata->protos_registered--; 153 st_gdata->protos_registered--;
151 st_gdata->list[i] = NULL; 154 st_gdata->is_registered[i] = false;
152 } 155 }
153 } 156 }
154 } 157 }
@@ -475,9 +478,9 @@ void kim_st_list_protocols(struct st_data_s *st_gdata, void *buf)
475{ 478{
476 seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n", 479 seq_printf(buf, "[%d]\nBT=%c\nFM=%c\nGPS=%c\n",
477 st_gdata->protos_registered, 480 st_gdata->protos_registered,
478 st_gdata->list[0x04] != NULL ? 'R' : 'U', 481 st_gdata->is_registered[0x04] == true ? 'R' : 'U',
479 st_gdata->list[0x08] != NULL ? 'R' : 'U', 482 st_gdata->is_registered[0x08] == true ? 'R' : 'U',
480 st_gdata->list[0x09] != NULL ? 'R' : 'U'); 483 st_gdata->is_registered[0x09] == true ? 'R' : 'U');
481} 484}
482 485
483/********************************************************************/ 486/********************************************************************/
@@ -504,7 +507,7 @@ long st_register(struct st_proto_s *new_proto)
504 return -EPROTONOSUPPORT; 507 return -EPROTONOSUPPORT;
505 } 508 }
506 509
507 if (st_gdata->list[new_proto->chnl_id] != NULL) { 510 if (st_gdata->is_registered[new_proto->chnl_id] == true) {
508 pr_err("chnl_id %d already registered", new_proto->chnl_id); 511 pr_err("chnl_id %d already registered", new_proto->chnl_id);
509 return -EALREADY; 512 return -EALREADY;
510 } 513 }
@@ -563,7 +566,7 @@ long st_register(struct st_proto_s *new_proto)
563 /* check for already registered once more, 566 /* check for already registered once more,
564 * since the above check is old 567 * since the above check is old
565 */ 568 */
566 if (st_gdata->list[new_proto->chnl_id] != NULL) { 569 if (st_gdata->is_registered[new_proto->chnl_id] == true) {
567 pr_err(" proto %d already registered ", 570 pr_err(" proto %d already registered ",
568 new_proto->chnl_id); 571 new_proto->chnl_id);
569 return -EALREADY; 572 return -EALREADY;