X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fbluetooth%2Fhci_core.c;h=338ae977a31b2209fb39e1a97d644db185d4597a;hb=refs%2Fheads%2Fvserver;hp=69ab2e7b9ea79074533893dfb0f17959272d8f74;hpb=9213980e6a70d8473e0ffd4b39ab5b6caaba9ff5;p=linux-2.6.git diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 69ab2e7b9..338ae977a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -24,14 +24,12 @@ /* Bluetooth HCI core. */ -#include #include #include #include #include #include -#include #include #include #include @@ -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, "e))) { 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;