diff options
Diffstat (limited to 'drivers/misc/ti-st/st_core.c')
| -rw-r--r-- | drivers/misc/ti-st/st_core.c | 44 |
1 files changed, 31 insertions, 13 deletions
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c index ba168a7d54d..1972d57aadb 100644 --- a/drivers/misc/ti-st/st_core.c +++ b/drivers/misc/ti-st/st_core.c @@ -22,7 +22,6 @@ #define pr_fmt(fmt) "(stc): " fmt #include <linux/module.h> #include <linux/kernel.h> -#include <linux/init.h> #include <linux/tty.h> #include <linux/seq_file.h> @@ -30,11 +29,13 @@ #include <linux/ti_wilink_st.h> +extern void st_kim_recv(void *, const unsigned char *, long); +void st_int_recv(void *, const unsigned char *, long); /* function pointer pointing to either, * st_kim_recv during registration to receive fw download responses * st_int_recv after registration to receive proto stack responses */ -void (*st_recv) (void*, const unsigned char*, long); +static void (*st_recv) (void *, const unsigned char *, long); /********************************************************************/ static void add_channel_to_table(struct st_data_s *st_gdata, @@ -100,7 +101,7 @@ int st_int_write(struct st_data_s *st_gdata, * push the skb received to relevant * protocol stacks */ -void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) +static void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) { pr_debug(" %s(prot:%d) ", __func__, chnl_id); @@ -137,8 +138,10 @@ void st_send_frame(unsigned char chnl_id, struct st_data_s *st_gdata) * st_reg_complete - * to call registration complete callbacks * of all protocol stack drivers + * This function is being called with spin lock held, protocol drivers are + * only expected to complete their waits and do nothing more than that. */ -void st_reg_complete(struct st_data_s *st_gdata, char err) +static void st_reg_complete(struct st_data_s *st_gdata, char err) { unsigned char i = 0; pr_info(" %s ", __func__); @@ -236,7 +239,8 @@ void st_int_recv(void *disc_data, char *ptr; struct st_proto_s *proto; unsigned short payload_len = 0; - int len = 0, type = 0; + int len = 0; + unsigned char type = 0; unsigned char *plen; struct st_data_s *st_gdata = (struct st_data_s *)disc_data; unsigned long flags; @@ -347,6 +351,11 @@ void st_int_recv(void *disc_data, st_gdata->rx_skb = alloc_skb( st_gdata->list[type]->max_frame_size, GFP_ATOMIC); + if (st_gdata->rx_skb == NULL) { + pr_err("out of memory: dropping\n"); + goto done; + } + skb_reserve(st_gdata->rx_skb, st_gdata->list[type]->reserve); /* next 2 required for BT only */ @@ -372,7 +381,7 @@ done: * completely, return that skb which has the pending data. * In normal cases, return top of txq. */ -struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) +static struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) { struct sk_buff *returning_skb; @@ -394,7 +403,7 @@ struct sk_buff *st_int_dequeue(struct st_data_s *st_gdata) * txq and waitq needs protection since the other contexts * may be sending data, waking up chip. */ -void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) +static void st_int_enqueue(struct st_data_s *st_gdata, struct sk_buff *skb) { unsigned long flags = 0; @@ -502,7 +511,6 @@ long st_register(struct st_proto_s *new_proto) unsigned long flags = 0; st_kim_ref(&st_gdata, 0); - pr_info("%s(%d) ", __func__, new_proto->chnl_id); if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL || new_proto->reg_complete_cb == NULL) { pr_err("gdata/new_proto/recv or reg_complete_cb not ready"); @@ -538,11 +546,12 @@ long st_register(struct st_proto_s *new_proto) set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); st_recv = st_kim_recv; + /* enable the ST LL - to set default chip state */ + st_ll_enable(st_gdata); + /* release lock previously held - re-locked below */ spin_unlock_irqrestore(&st_gdata->lock, flags); - /* enable the ST LL - to set default chip state */ - st_ll_enable(st_gdata); /* this may take a while to complete * since it involves BT fw download */ @@ -552,11 +561,16 @@ long st_register(struct st_proto_s *new_proto) if ((st_gdata->protos_registered != ST_EMPTY) && (test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_err(" KIM failure complete callback "); + spin_lock_irqsave(&st_gdata->lock, flags); st_reg_complete(st_gdata, err); + spin_unlock_irqrestore(&st_gdata->lock, flags); + clear_bit(ST_REG_PENDING, &st_gdata->st_state); } return -EINVAL; } + spin_lock_irqsave(&st_gdata->lock, flags); + clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state); st_recv = st_int_recv; @@ -576,10 +590,10 @@ long st_register(struct st_proto_s *new_proto) if (st_gdata->is_registered[new_proto->chnl_id] == true) { pr_err(" proto %d already registered ", new_proto->chnl_id); + spin_unlock_irqrestore(&st_gdata->lock, flags); return -EALREADY; } - spin_lock_irqsave(&st_gdata->lock, flags); add_channel_to_table(st_gdata, new_proto); st_gdata->protos_registered++; new_proto->write = st_write; @@ -619,7 +633,7 @@ long st_unregister(struct st_proto_s *proto) spin_lock_irqsave(&st_gdata->lock, flags); - if (st_gdata->list[proto->chnl_id] == NULL) { + if (st_gdata->is_registered[proto->chnl_id] == false) { pr_err(" chnl_id %d not registered", proto->chnl_id); spin_unlock_irqrestore(&st_gdata->lock, flags); return -EPROTONOSUPPORT; @@ -629,6 +643,10 @@ long st_unregister(struct st_proto_s *proto) remove_channel_from_table(st_gdata, proto); spin_unlock_irqrestore(&st_gdata->lock, flags); + /* paranoid check */ + if (st_gdata->protos_registered < ST_EMPTY) + st_gdata->protos_registered = ST_EMPTY; + if ((st_gdata->protos_registered == ST_EMPTY) && (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) { pr_info(" all chnl_ids unregistered "); @@ -793,7 +811,7 @@ static void st_tty_flush_buffer(struct tty_struct *tty) kfree_skb(st_gdata->tx_skb); st_gdata->tx_skb = NULL; - tty->ops->flush_buffer(tty); + tty_driver_flush_buffer(tty); return; } |
