Bluetooth: Add timer for automatically disabling the service cache
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / include / net / bluetooth / hci_core.h
index 5b924423cf205ad9e927c7de4045e86160f1a082..105eaa251034c263423e385a312ab2a5deaf34d3 100644 (file)
@@ -32,6 +32,9 @@
 #define HCI_PROTO_L2CAP        0
 #define HCI_PROTO_SCO  1
 
+/* HCI priority */
+#define HCI_PRIO_MAX   7
+
 /* HCI Core structures */
 struct inquiry_data {
        bdaddr_t        bdaddr;
@@ -58,7 +61,6 @@ struct inquiry_cache {
 
 struct hci_conn_hash {
        struct list_head list;
-       spinlock_t       lock;
        unsigned int     acl_num;
        unsigned int     sco_num;
        unsigned int     le_num;
@@ -115,7 +117,7 @@ struct adv_entry {
 #define NUM_REASSEMBLY 4
 struct hci_dev {
        struct list_head list;
-       spinlock_t      lock;
+       struct mutex    lock;
        atomic_t        refcnt;
 
        char            name[8];
@@ -150,6 +152,19 @@ struct hci_dev {
        __u16           sniff_min_interval;
        __u16           sniff_max_interval;
 
+       __u8            amp_status;
+       __u32           amp_total_bw;
+       __u32           amp_max_bw;
+       __u32           amp_min_latency;
+       __u32           amp_max_pdu;
+       __u8            amp_type;
+       __u16           amp_pal_cap;
+       __u16           amp_assoc_size;
+       __u32           amp_max_flush_to;
+       __u32           amp_be_flush_to;
+
+       __u8            flow_ctl_mode;
+
        unsigned int    auto_accept_delay;
 
        unsigned long   quirks;
@@ -173,13 +188,18 @@ struct hci_dev {
        struct workqueue_struct *workqueue;
 
        struct work_struct      power_on;
-       struct work_struct      power_off;
-       struct timer_list       off_timer;
+       struct delayed_work     power_off;
+
+       __u16                   discov_timeout;
+       struct delayed_work     discov_off;
+
+       struct delayed_work     service_cache;
 
        struct timer_list       cmd_timer;
-       struct tasklet_struct   cmd_task;
-       struct tasklet_struct   rx_task;
-       struct tasklet_struct   tx_task;
+
+       struct work_struct      rx_work;
+       struct work_struct      cmd_work;
+       struct work_struct      tx_work;
 
        struct sk_buff_head     rx_q;
        struct sk_buff_head     raw_q;
@@ -195,6 +215,8 @@ struct hci_dev {
 
        __u16                   init_last_cmd;
 
+       struct list_head        mgmt_pending;
+
        struct inquiry_cache    inq_cache;
        struct hci_conn_hash    conn_hash;
        struct list_head        blacklist;
@@ -206,7 +228,7 @@ struct hci_dev {
        struct list_head        remote_oob_data;
 
        struct list_head        adv_entries;
-       struct timer_list       adv_timer;
+       struct delayed_work     adv_work;
 
        struct hci_dev_stats    stat;
 
@@ -226,6 +248,8 @@ struct hci_dev {
 
        struct module           *owner;
 
+       unsigned long           dev_flags;
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
@@ -273,14 +297,12 @@ struct hci_conn {
        unsigned int    sent;
 
        struct sk_buff_head data_q;
+       struct list_head chan_list;
 
-       struct timer_list disc_timer;
+       struct delayed_work disc_work;
        struct timer_list idle_timer;
        struct timer_list auto_accept_timer;
 
-       struct work_struct work_add;
-       struct work_struct work_del;
-
        struct device   dev;
        atomic_t        devref;
 
@@ -295,6 +317,14 @@ struct hci_conn {
        void (*disconn_cfm_cb)  (struct hci_conn *conn, u8 reason);
 };
 
+struct hci_chan {
+       struct list_head list;
+
+       struct hci_conn *conn;
+       struct sk_buff_head data_q;
+       unsigned int    sent;
+};
+
 extern struct hci_proto *hci_proto[];
 extern struct list_head hci_dev_list;
 extern struct list_head hci_cb_list;
@@ -353,15 +383,15 @@ static inline void hci_conn_hash_init(struct hci_dev *hdev)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
        INIT_LIST_HEAD(&h->list);
-       spin_lock_init(&h->lock);
        h->acl_num = 0;
        h->sco_num = 0;
+       h->le_num = 0;
 }
 
 static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       list_add(&c->list, &h->list);
+       list_add_rcu(&c->list, &h->list);
        switch (c->type) {
        case ACL_LINK:
                h->acl_num++;
@@ -379,7 +409,10 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
 static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       list_del(&c->list);
+
+       list_del_rcu(&c->list);
+       synchronize_rcu();
+
        switch (c->type) {
        case ACL_LINK:
                h->acl_num--;
@@ -414,14 +447,18 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
                                                                __u16 handle)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
        struct hci_conn  *c;
 
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
-               if (c->handle == handle)
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(c, &h->list, list) {
+               if (c->handle == handle) {
+                       rcu_read_unlock();
                        return c;
+               }
        }
+       rcu_read_unlock();
+
        return NULL;
 }
 
@@ -429,14 +466,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
                                                        __u8 type, bdaddr_t *ba)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
        struct hci_conn  *c;
 
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
-               if (c->type == type && !bacmp(&c->dst, ba))
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(c, &h->list, list) {
+               if (c->type == type && !bacmp(&c->dst, ba)) {
+                       rcu_read_unlock();
                        return c;
+               }
        }
+
+       rcu_read_unlock();
+
        return NULL;
 }
 
@@ -444,14 +486,19 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
                                                        __u8 type, __u16 state)
 {
        struct hci_conn_hash *h = &hdev->conn_hash;
-       struct list_head *p;
        struct hci_conn  *c;
 
-       list_for_each(p, &h->list) {
-               c = list_entry(p, struct hci_conn, list);
-               if (c->type == type && c->state == state)
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(c, &h->list, list) {
+               if (c->type == type && c->state == state) {
+                       rcu_read_unlock();
                        return c;
+               }
        }
+
+       rcu_read_unlock();
+
        return NULL;
 }
 
@@ -466,6 +513,10 @@ int hci_conn_del(struct hci_conn *conn);
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
+struct hci_chan *hci_chan_create(struct hci_conn *conn);
+int hci_chan_del(struct hci_chan *chan);
+void hci_chan_list_flush(struct hci_conn *conn);
+
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                                                __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
@@ -475,7 +526,6 @@ int hci_conn_change_link_key(struct hci_conn *conn);
 int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
 
 void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
-void hci_conn_enter_sniff_mode(struct hci_conn *conn);
 
 void hci_conn_hold_device(struct hci_conn *conn);
 void hci_conn_put_device(struct hci_conn *conn);
@@ -483,7 +533,7 @@ void hci_conn_put_device(struct hci_conn *conn);
 static inline void hci_conn_hold(struct hci_conn *conn)
 {
        atomic_inc(&conn->refcnt);
-       del_timer(&conn->disc_timer);
+       cancel_delayed_work_sync(&conn->disc_work);
 }
 
 static inline void hci_conn_put(struct hci_conn *conn)
@@ -502,7 +552,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
                } else {
                        timeo = msecs_to_jiffies(10);
                }
-               mod_timer(&conn->disc_timer, jiffies + timeo);
+               cancel_delayed_work_sync(&conn->disc_work);
+               queue_delayed_work(conn->hdev->workqueue,
+                                       &conn->disc_work, jiffies + timeo);
        }
 }
 
@@ -532,10 +584,8 @@ static inline struct hci_dev *hci_dev_hold(struct hci_dev *d)
        return NULL;
 }
 
-#define hci_dev_lock(d)                spin_lock(&d->lock)
-#define hci_dev_unlock(d)      spin_unlock(&d->lock)
-#define hci_dev_lock_bh(d)     spin_lock_bh(&d->lock)
-#define hci_dev_unlock_bh(d)   spin_unlock_bh(&d->lock)
+#define hci_dev_lock(d)                mutex_lock(&d->lock)
+#define hci_dev_unlock(d)      mutex_unlock(&d->lock)
 
 struct hci_dev *hci_dev_get(int index);
 struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
@@ -543,7 +593,7 @@ struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
 int hci_register_dev(struct hci_dev *hdev);
-int hci_unregister_dev(struct hci_dev *hdev);
+void hci_unregister_dev(struct hci_dev *hdev);
 int hci_suspend_dev(struct hci_dev *hdev);
 int hci_resume_dev(struct hci_dev *hdev);
 int hci_dev_open(__u16 dev);
@@ -597,8 +647,9 @@ int hci_recv_frame(struct sk_buff *skb);
 int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
 int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
 
-int hci_register_sysfs(struct hci_dev *hdev);
-void hci_unregister_sysfs(struct hci_dev *hdev);
+void hci_init_sysfs(struct hci_dev *hdev);
+int hci_add_sysfs(struct hci_dev *hdev);
+void hci_del_sysfs(struct hci_dev *hdev);
 void hci_conn_init_sysfs(struct hci_conn *conn);
 void hci_conn_add_sysfs(struct hci_conn *conn);
 void hci_conn_del_sysfs(struct hci_conn *conn);
@@ -674,7 +725,7 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
 static inline int hci_proto_disconn_ind(struct hci_conn *conn)
 {
        register struct hci_proto *hp;
-       int reason = 0x13;
+       int reason = HCI_ERROR_REMOTE_USER_TERM;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->disconn_ind)
@@ -834,7 +885,7 @@ int hci_register_notifier(struct notifier_block *nb);
 int hci_unregister_notifier(struct notifier_block *nb);
 
 int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
-void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
+void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
 void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
 
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
@@ -847,44 +898,63 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
 
 /* Management interface */
 int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
-int mgmt_index_added(u16 index);
-int mgmt_index_removed(u16 index);
-int mgmt_powered(u16 index, u8 powered);
-int mgmt_discoverable(u16 index, u8 discoverable);
-int mgmt_connectable(u16 index, u8 connectable);
-int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
-int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
-int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
-int mgmt_disconnect_failed(u16 index);
-int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
-int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
-                                                       u8 confirm_hint);
-int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
+int mgmt_index_added(struct hci_dev *hdev);
+int mgmt_index_removed(struct hci_dev *hdev);
+int mgmt_powered(struct hci_dev *hdev, u8 powered);
+int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
+int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
+int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
+int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
+                                                               u8 persistent);
+int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                                                               u8 addr_type);
+int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                                                               u8 addr_type);
+int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                                               u8 addr_type, u8 status);
+int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
+int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                                                u8 status);
-int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
-int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
-int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
+int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                                                u8 status);
-int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
-                                                               u8 *eir);
-int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
-int mgmt_discovering(u16 index, u8 discovering);
-int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
-int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
+int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                               __le32 value, u8 confirm_hint);
+int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status);
+int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                                                               u8 status);
+int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
+                                               bdaddr_t *bdaddr, u8 status);
+int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
+int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
+int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
+                                               u8 *randomizer, u8 status);
+int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
+                               u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir);
+int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
+int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status);
+int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status);
+int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
+int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
+int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
 /* HCI info for socket */
 #define hci_pi(sk) ((struct hci_pinfo *) sk)
 
+/* HCI socket flags */
+#define HCI_PI_MGMT_INIT       0
+
 struct hci_pinfo {
        struct bt_sock    bt;
        struct hci_dev    *hdev;
        struct hci_filter filter;
        __u32             cmsg_mask;
        unsigned short   channel;
+       unsigned long     flags;
 };
 
 /* HCI security filter */
@@ -913,4 +983,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
 void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
 void hci_le_ltk_neg_reply(struct hci_conn *conn);
 
+int hci_do_inquiry(struct hci_dev *hdev, u8 length);
+int hci_cancel_inquiry(struct hci_dev *hdev);
+
 #endif /* __HCI_CORE_H */