fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / bluetooth / hci_core.c
index 69ab2e7..338ae97 100644 (file)
 
 /* Bluetooth HCI core. */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kmod.h>
 
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/major.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/poll.h>
@@ -59,34 +57,38 @@ static void hci_rx_task(unsigned long arg);
 static void hci_tx_task(unsigned long arg);
 static void hci_notify(struct hci_dev *hdev, int event);
 
-rwlock_t hci_task_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(hci_task_lock);
 
 /* HCI device list */
 LIST_HEAD(hci_dev_list);
-rwlock_t hci_dev_list_lock = RW_LOCK_UNLOCKED;
+DEFINE_RWLOCK(hci_dev_list_lock);
+
+/* HCI callback list */
+LIST_HEAD(hci_cb_list);
+DEFINE_RWLOCK(hci_cb_list_lock);
 
 /* HCI protocols */
 #define HCI_MAX_PROTO  2
 struct hci_proto *hci_proto[HCI_MAX_PROTO];
 
 /* HCI notifiers list */
-static struct notifier_block *hci_notifier;
+static ATOMIC_NOTIFIER_HEAD(hci_notifier);
 
 /* ---- HCI notifications ---- */
 
 int hci_register_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_register(&hci_notifier, nb);
+       return atomic_notifier_chain_register(&hci_notifier, nb);
 }
 
 int hci_unregister_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_unregister(&hci_notifier, nb);
+       return atomic_notifier_chain_unregister(&hci_notifier, nb);
 }
 
-void hci_notify(struct hci_dev *hdev, int event)
+static void hci_notify(struct hci_dev *hdev, int event)
 {
-       notifier_call_chain(&hci_notifier, event, hdev);
+       atomic_notifier_call_chain(&hci_notifier, event, hdev);
 }
 
 /* ---- HCI requests ---- */
@@ -102,7 +104,7 @@ void hci_req_complete(struct hci_dev *hdev, int result)
        }
 }
 
-void hci_req_cancel(struct hci_dev *hdev, int err)
+static void hci_req_cancel(struct hci_dev *hdev, int err)
 {
        BT_DBG("%s err 0x%2.2x", hdev->name, err);
 
@@ -179,10 +181,22 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 
 static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
 {
-       __u16 param;
+       struct sk_buff *skb;
+       __le16 param;
 
        BT_DBG("%s %ld", hdev->name, opt);
 
+       /* Driver initialization */
+
+       /* Special commands */
+       while ((skb = skb_dequeue(&hdev->driver_init))) {
+               bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
+               skb->dev = (void *) hdev;
+               skb_queue_tail(&hdev->cmd_q, skb);
+               hci_sched_cmd(hdev);
+       }
+       skb_queue_purge(&hdev->driver_init);
+
        /* Mandatory initialization */
 
        /* Reset */
@@ -192,6 +206,9 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
        /* Read Local Supported Features */
        hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES, 0, NULL);
 
+       /* Read Local Version */
+       hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION, 0, NULL);
+
        /* Read Buffer Size (ACL mtu, max pkt, etc.) */
        hci_send_cmd(hdev, OGF_INFO_PARAM, OCF_READ_BUFFER_SIZE, 0, NULL);
 
@@ -284,10 +301,9 @@ struct hci_dev *hci_dev_get(int index)
        read_unlock(&hci_dev_list_lock);
        return hdev;
 }
-EXPORT_SYMBOL(hci_dev_get);
 
 /* ---- Inquiry support ---- */
-void inquiry_cache_flush(struct hci_dev *hdev)
+static void inquiry_cache_flush(struct hci_dev *hdev)
 {
        struct inquiry_cache *cache = &hdev->inq_cache;
        struct inquiry_entry *next  = cache->list, *e;
@@ -301,7 +317,7 @@ void inquiry_cache_flush(struct hci_dev *hdev)
        }
 }
 
-struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
+struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct inquiry_cache *cache = &hdev->inq_cache;
        struct inquiry_entry *e;
@@ -309,41 +325,48 @@ struct inquiry_entry *inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdadd
        BT_DBG("cache %p, %s", cache, batostr(bdaddr));
 
        for (e = cache->list; e; e = e->next)
-               if (!bacmp(&e->info.bdaddr, bdaddr))
+               if (!bacmp(&e->data.bdaddr, bdaddr))
                        break;
        return e;
 }
 
-void inquiry_cache_update(struct hci_dev *hdev, struct inquiry_info *info)
+void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
 {
        struct inquiry_cache *cache = &hdev->inq_cache;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p, %s", cache, batostr(&info->bdaddr));
+       BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 
-       if (!(e = inquiry_cache_lookup(hdev, &info->bdaddr))) {
+       if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) {
                /* Entry not in the cache. Add new one. */
-               if (!(e = kmalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+               if (!(e = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
                        return;
-               memset(e, 0, sizeof(struct inquiry_entry));
                e->next     = cache->list;
                cache->list = e;
        }
 
-       memcpy(&e->info, info, sizeof(*info));
+       memcpy(&e->data, data, sizeof(*data));
        e->timestamp = jiffies;
        cache->timestamp = jiffies;
 }
 
-int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
+static int inquiry_cache_dump(struct hci_dev *hdev, int num, __u8 *buf)
 {
        struct inquiry_cache *cache = &hdev->inq_cache;
        struct inquiry_info *info = (struct inquiry_info *) buf;
        struct inquiry_entry *e;
        int copied = 0;
 
-       for (e = cache->list; e && copied < num; e = e->next, copied++)
-               memcpy(info++, &e->info, sizeof(*info));
+       for (e = cache->list; e && copied < num; e = e->next, copied++) {
+               struct inquiry_data *data = &e->data;
+               bacpy(&info->bdaddr, &data->bdaddr);
+               info->pscan_rep_mode    = data->pscan_rep_mode;
+               info->pscan_period_mode = data->pscan_period_mode;
+               info->pscan_mode        = data->pscan_mode;
+               memcpy(info->dev_class, data->dev_class, 3);
+               info->clock_offset      = data->clock_offset;
+               info++;
+       }
 
        BT_DBG("cache %p, copied %d", cache, copied);
        return copied;
@@ -390,7 +413,7 @@ int hci_inquiry(void __user *arg)
        }
        hci_dev_unlock_bh(hdev);
 
-       timeo = ir.length * 2 * HZ;
+       timeo = ir.length * msecs_to_jiffies(2000);
        if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
                goto done;
 
@@ -445,6 +468,9 @@ int hci_dev_open(__u16 dev)
                goto done;
        }
 
+       if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
+               set_bit(HCI_RAW, &hdev->flags);
+
        if (hdev->open(hdev)) {
                ret = -EIO;
                goto done;
@@ -455,7 +481,8 @@ int hci_dev_open(__u16 dev)
                set_bit(HCI_INIT, &hdev->flags);
 
                //__hci_request(hdev, hci_reset_req, 0, HZ);
-               ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
+               ret = __hci_request(hdev, hci_init_req, 0,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
                clear_bit(HCI_INIT, &hdev->flags);
        }
@@ -520,9 +547,12 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        /* Reset device */
        skb_queue_purge(&hdev->cmd_q);
        atomic_set(&hdev->cmd_cnt, 1);
-       set_bit(HCI_INIT, &hdev->flags);
-       __hci_request(hdev, hci_reset_req, 0, HZ/4);
-       clear_bit(HCI_INIT, &hdev->flags);
+       if (!test_bit(HCI_RAW, &hdev->flags)) {
+               set_bit(HCI_INIT, &hdev->flags);
+               __hci_request(hdev, hci_reset_req, 0,
+                                       msecs_to_jiffies(250));
+               clear_bit(HCI_INIT, &hdev->flags);
+       }
 
        /* Kill cmd task */
        tasklet_kill(&hdev->cmd_task);
@@ -592,7 +622,9 @@ int hci_dev_reset(__u16 dev)
        atomic_set(&hdev->cmd_cnt, 1); 
        hdev->acl_cnt = 0; hdev->sco_cnt = 0;
 
-       ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT);
+       if (!test_bit(HCI_RAW, &hdev->flags))
+               ret = __hci_request(hdev, hci_reset_req, 0,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
 
 done:
        tasklet_enable(&hdev->tx_task);
@@ -630,7 +662,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
        switch (cmd) {
        case HCISETAUTH:
-               err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+               err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETENCRYPT:
@@ -641,18 +674,19 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
 
                if (!test_bit(HCI_AUTH, &hdev->flags)) {
                        /* Auth must be enabled first */
-                       err = hci_request(hdev, hci_auth_req,
-                                       dr.dev_opt, HCI_INIT_TIMEOUT);
+                       err = hci_request(hdev, hci_auth_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                        if (err)
                                break;
                }
 
-               err = hci_request(hdev, hci_encrypt_req,
-                                       dr.dev_opt, HCI_INIT_TIMEOUT);
+               err = hci_request(hdev, hci_encrypt_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETSCAN:
-               err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT);
+               err = hci_request(hdev, hci_scan_req, dr.dev_opt,
+                                       msecs_to_jiffies(HCI_INIT_TIMEOUT));
                break;
 
        case HCISETPTYPE:
@@ -768,11 +802,11 @@ struct hci_dev *hci_alloc_dev(void)
 {
        struct hci_dev *hdev;
 
-       hdev = kmalloc(sizeof(struct hci_dev), GFP_KERNEL);
+       hdev = kzalloc(sizeof(struct hci_dev), GFP_KERNEL);
        if (!hdev)
                return NULL;
 
-       memset(hdev, 0, sizeof(struct hci_dev));
+       skb_queue_head_init(&hdev->driver_init);
 
        return hdev;
 }
@@ -781,8 +815,10 @@ EXPORT_SYMBOL(hci_alloc_dev);
 /* Free HCI device */
 void hci_free_dev(struct hci_dev *hdev)
 {
-       /* will free via class release */
-       class_device_put(&hdev->class_dev);
+       skb_queue_purge(&hdev->driver_init);
+
+       /* will free via device release */
+       put_device(&hdev->dev);
 }
 EXPORT_SYMBOL(hci_free_dev);
 
@@ -817,6 +853,10 @@ int hci_register_dev(struct hci_dev *hdev)
        hdev->pkt_type  = (HCI_DM1 | HCI_DH1 | HCI_HV1);
        hdev->link_mode = (HCI_LM_ACCEPT);
 
+       hdev->idle_timeout = 0;
+       hdev->sniff_max_interval = 800;
+       hdev->sniff_min_interval = 80;
+
        tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
        tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
        tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
@@ -930,6 +970,30 @@ int hci_unregister_proto(struct hci_proto *hp)
 }
 EXPORT_SYMBOL(hci_unregister_proto);
 
+int hci_register_cb(struct hci_cb *cb)
+{
+       BT_DBG("%p name %s", cb, cb->name);
+
+       write_lock_bh(&hci_cb_list_lock);
+       list_add(&cb->list, &hci_cb_list);
+       write_unlock_bh(&hci_cb_list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(hci_register_cb);
+
+int hci_unregister_cb(struct hci_cb *cb)
+{
+       BT_DBG("%p name %s", cb, cb->name);
+
+       write_lock_bh(&hci_cb_list_lock);
+       list_del(&cb->list);
+       write_unlock_bh(&hci_cb_list_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(hci_unregister_cb);
+
 static int hci_send_frame(struct sk_buff *skb)
 {
        struct hci_dev *hdev = (struct hci_dev *) skb->dev;
@@ -939,11 +1003,11 @@ static int hci_send_frame(struct sk_buff *skb)
                return -ENODEV;
        }
 
-       BT_DBG("%s type %d len %d", hdev->name, skb->pkt_type, skb->len);
+       BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len);
 
        if (atomic_read(&hdev->promisc)) {
                /* Time stamp */
-               do_gettimeofday(&skb->stamp);
+               __net_timestamp(skb);
 
                hci_send_to_sock(hdev, skb);
        }
@@ -978,14 +1042,13 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 ogf, __u16 ocf, __u32 plen, void *p
 
        BT_DBG("skb len %d", skb->len);
 
-       skb->pkt_type = HCI_COMMAND_PKT;
+       bt_cb(skb)->pkt_type = HCI_COMMAND_PKT;
        skb->dev = (void *) hdev;
        skb_queue_tail(&hdev->cmd_q, skb);
        hci_sched_cmd(hdev);
 
        return 0;
 }
-EXPORT_SYMBOL(hci_send_cmd);
 
 /* Get data from the previously sent command */
 void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 ogf, __u16 ocf)
@@ -1026,7 +1089,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
        BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
 
        skb->dev = (void *) hdev;
-       skb->pkt_type = HCI_ACLDATA_PKT;
+       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
        hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
 
        if (!(list = skb_shinfo(skb)->frag_list)) {
@@ -1048,7 +1111,7 @@ int hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
                        skb = list; list = list->next;
                        
                        skb->dev = (void *) hdev;
-                       skb->pkt_type = HCI_ACLDATA_PKT;
+                       bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
                        hci_add_acl_hdr(skb, conn->handle, flags | ACL_CONT);
 
                        BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
@@ -1084,7 +1147,7 @@ int hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
        memcpy(skb->h.raw, &hdr, HCI_SCO_HDR_SIZE);
 
        skb->dev = (void *) hdev;
-       skb->pkt_type = HCI_SCODATA_PKT;
+       bt_cb(skb)->pkt_type = HCI_SCODATA_PKT;
        skb_queue_tail(&conn->data_q, skb);
        hci_sched_tx(hdev);
        return 0;
@@ -1156,14 +1219,19 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
 
        BT_DBG("%s", hdev->name);
 
-       /* ACL tx timeout must be longer than maximum
-        * link supervision timeout (40.9 seconds) */
-       if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
-               hci_acl_tx_to(hdev);
+       if (!test_bit(HCI_RAW, &hdev->flags)) {
+               /* ACL tx timeout must be longer than maximum
+                * link supervision timeout (40.9 seconds) */
+               if (!hdev->acl_cnt && (jiffies - hdev->acl_last_tx) > (HZ * 45))
+                       hci_acl_tx_to(hdev);
+       }
 
        while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
                while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
                        BT_DBG("skb %p len %d", skb, skb->len);
+
+                       hci_conn_enter_active_mode(conn);
+
                        hci_send_frame(skb);
                        hdev->acl_last_tx = jiffies;
 
@@ -1242,6 +1310,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        if (conn) {
                register struct hci_proto *hp;
 
+               hci_conn_enter_active_mode(conn);
+
                /* Send to upper protocol */
                if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
                        hp->recv_acldata(conn, skb, flags);
@@ -1290,7 +1360,7 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
        kfree_skb(skb);
 }
 
-void hci_rx_task(unsigned long arg)
+static void hci_rx_task(unsigned long arg)
 {
        struct hci_dev *hdev = (struct hci_dev *) arg;
        struct sk_buff *skb;
@@ -1312,7 +1382,7 @@ void hci_rx_task(unsigned long arg)
 
                if (test_bit(HCI_INIT, &hdev->flags)) {
                        /* Don't process data packets in this states. */
-                       switch (skb->pkt_type) {
+                       switch (bt_cb(skb)->pkt_type) {
                        case HCI_ACLDATA_PKT:
                        case HCI_SCODATA_PKT:
                                kfree_skb(skb);
@@ -1321,7 +1391,7 @@ void hci_rx_task(unsigned long arg)
                }
 
                /* Process frame */
-               switch (skb->pkt_type) {
+               switch (bt_cb(skb)->pkt_type) {
                case HCI_EVENT_PKT:
                        hci_event_packet(hdev, skb);
                        break;