Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
[firefly-linux-kernel-4.4.55.git] / drivers / misc / ti-st / st_core.c
index ba168a7d54d42318d7d192e4158b482844c85be4..2b62232c2c6a3476551f11f86253dcf545234d07 100644 (file)
@@ -137,6 +137,8 @@ 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)
 {
@@ -538,11 +540,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
                 */
@@ -553,10 +556,13 @@ long st_register(struct st_proto_s *new_proto)
                            (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
                                pr_err(" KIM failure complete callback ");
                                st_reg_complete(st_gdata, err);
+                               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 +582,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 +625,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 +635,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 ");