diff options
-rw-r--r-- | include/net/bluetooth/hci.h | 11 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 194 |
3 files changed, 206 insertions, 1 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 4e2f008d32e1..99ac3516fe9d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
@@ -189,19 +189,26 @@ enum { | |||
189 | #define LMP_PSCHEME 0x02 | 189 | #define LMP_PSCHEME 0x02 |
190 | #define LMP_PCONTROL 0x04 | 190 | #define LMP_PCONTROL 0x04 |
191 | 191 | ||
192 | #define LMP_RSSI_INQ 0x40 | ||
192 | #define LMP_ESCO 0x80 | 193 | #define LMP_ESCO 0x80 |
193 | 194 | ||
194 | #define LMP_EV4 0x01 | 195 | #define LMP_EV4 0x01 |
195 | #define LMP_EV5 0x02 | 196 | #define LMP_EV5 0x02 |
197 | #define LMP_LE 0x40 | ||
196 | 198 | ||
197 | #define LMP_SNIFF_SUBR 0x02 | 199 | #define LMP_SNIFF_SUBR 0x02 |
200 | #define LMP_PAUSE_ENC 0x04 | ||
198 | #define LMP_EDR_ESCO_2M 0x20 | 201 | #define LMP_EDR_ESCO_2M 0x20 |
199 | #define LMP_EDR_ESCO_3M 0x40 | 202 | #define LMP_EDR_ESCO_3M 0x40 |
200 | #define LMP_EDR_3S_ESCO 0x80 | 203 | #define LMP_EDR_3S_ESCO 0x80 |
201 | 204 | ||
205 | #define LMP_EXT_INQ 0x01 | ||
202 | #define LMP_SIMPLE_PAIR 0x08 | 206 | #define LMP_SIMPLE_PAIR 0x08 |
203 | #define LMP_NO_FLUSH 0x40 | 207 | #define LMP_NO_FLUSH 0x40 |
204 | 208 | ||
209 | #define LMP_LSTO 0x01 | ||
210 | #define LMP_INQ_TX_PWR 0x02 | ||
211 | |||
205 | /* Connection modes */ | 212 | /* Connection modes */ |
206 | #define HCI_CM_ACTIVE 0x0000 | 213 | #define HCI_CM_ACTIVE 0x0000 |
207 | #define HCI_CM_HOLD 0x0001 | 214 | #define HCI_CM_HOLD 0x0001 |
@@ -556,6 +563,8 @@ struct hci_cp_host_buffer_size { | |||
556 | __le16 sco_max_pkt; | 563 | __le16 sco_max_pkt; |
557 | } __packed; | 564 | } __packed; |
558 | 565 | ||
566 | #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 | ||
567 | |||
559 | #define HCI_OP_READ_SSP_MODE 0x0c55 | 568 | #define HCI_OP_READ_SSP_MODE 0x0c55 |
560 | struct hci_rp_read_ssp_mode { | 569 | struct hci_rp_read_ssp_mode { |
561 | __u8 status; | 570 | __u8 status; |
@@ -567,6 +576,8 @@ struct hci_cp_write_ssp_mode { | |||
567 | __u8 mode; | 576 | __u8 mode; |
568 | } __packed; | 577 | } __packed; |
569 | 578 | ||
579 | #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 | ||
580 | |||
570 | #define HCI_OP_READ_LOCAL_VERSION 0x1001 | 581 | #define HCI_OP_READ_LOCAL_VERSION 0x1001 |
571 | struct hci_rp_read_local_version { | 582 | struct hci_rp_read_local_version { |
572 | __u8 status; | 583 | __u8 status; |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 0dbdcc5f44e4..71a3fbf1e785 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -91,7 +91,9 @@ struct hci_dev { | |||
91 | __u8 ssp_mode; | 91 | __u8 ssp_mode; |
92 | __u8 hci_ver; | 92 | __u8 hci_ver; |
93 | __u16 hci_rev; | 93 | __u16 hci_rev; |
94 | __u8 lmp_ver; | ||
94 | __u16 manufacturer; | 95 | __u16 manufacturer; |
96 | __le16 lmp_subver; | ||
95 | __u16 voice_setting; | 97 | __u16 voice_setting; |
96 | 98 | ||
97 | __u16 pkt_type; | 99 | __u16 pkt_type; |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 49b387cdcc38..c69ee44d5bd7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -424,6 +424,115 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) | |||
424 | hdev->ssp_mode = *((__u8 *) sent); | 424 | hdev->ssp_mode = *((__u8 *) sent); |
425 | } | 425 | } |
426 | 426 | ||
427 | static u8 hci_get_inquiry_mode(struct hci_dev *hdev) | ||
428 | { | ||
429 | if (hdev->features[6] & LMP_EXT_INQ) | ||
430 | return 2; | ||
431 | |||
432 | if (hdev->features[3] & LMP_RSSI_INQ) | ||
433 | return 1; | ||
434 | |||
435 | if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 && | ||
436 | hdev->lmp_subver == 0x0757) | ||
437 | return 1; | ||
438 | |||
439 | if (hdev->manufacturer == 15) { | ||
440 | if (hdev->hci_rev == 0x03 && hdev->lmp_subver == 0x6963) | ||
441 | return 1; | ||
442 | if (hdev->hci_rev == 0x09 && hdev->lmp_subver == 0x6963) | ||
443 | return 1; | ||
444 | if (hdev->hci_rev == 0x00 && hdev->lmp_subver == 0x6965) | ||
445 | return 1; | ||
446 | } | ||
447 | |||
448 | if (hdev->manufacturer == 31 && hdev->hci_rev == 0x2005 && | ||
449 | hdev->lmp_subver == 0x1805) | ||
450 | return 1; | ||
451 | |||
452 | return 0; | ||
453 | } | ||
454 | |||
455 | static void hci_setup_inquiry_mode(struct hci_dev *hdev) | ||
456 | { | ||
457 | u8 mode; | ||
458 | |||
459 | mode = hci_get_inquiry_mode(hdev); | ||
460 | |||
461 | hci_send_cmd(hdev, HCI_OP_WRITE_INQUIRY_MODE, 1, &mode); | ||
462 | } | ||
463 | |||
464 | static void hci_setup_event_mask(struct hci_dev *hdev) | ||
465 | { | ||
466 | /* The second byte is 0xff instead of 0x9f (two reserved bits | ||
467 | * disabled) since a Broadcom 1.2 dongle doesn't respond to the | ||
468 | * command otherwise */ | ||
469 | u8 events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 }; | ||
470 | |||
471 | /* Events for 1.2 and newer controllers */ | ||
472 | if (hdev->lmp_ver > 1) { | ||
473 | events[4] |= 0x01; /* Flow Specification Complete */ | ||
474 | events[4] |= 0x02; /* Inquiry Result with RSSI */ | ||
475 | events[4] |= 0x04; /* Read Remote Extended Features Complete */ | ||
476 | events[5] |= 0x08; /* Synchronous Connection Complete */ | ||
477 | events[5] |= 0x10; /* Synchronous Connection Changed */ | ||
478 | } | ||
479 | |||
480 | if (hdev->features[3] & LMP_RSSI_INQ) | ||
481 | events[4] |= 0x04; /* Inquiry Result with RSSI */ | ||
482 | |||
483 | if (hdev->features[5] & LMP_SNIFF_SUBR) | ||
484 | events[5] |= 0x20; /* Sniff Subrating */ | ||
485 | |||
486 | if (hdev->features[5] & LMP_PAUSE_ENC) | ||
487 | events[5] |= 0x80; /* Encryption Key Refresh Complete */ | ||
488 | |||
489 | if (hdev->features[6] & LMP_EXT_INQ) | ||
490 | events[5] |= 0x40; /* Extended Inquiry Result */ | ||
491 | |||
492 | if (hdev->features[6] & LMP_NO_FLUSH) | ||
493 | events[7] |= 0x01; /* Enhanced Flush Complete */ | ||
494 | |||
495 | if (hdev->features[7] & LMP_LSTO) | ||
496 | events[6] |= 0x80; /* Link Supervision Timeout Changed */ | ||
497 | |||
498 | if (hdev->features[6] & LMP_SIMPLE_PAIR) { | ||
499 | events[6] |= 0x01; /* IO Capability Request */ | ||
500 | events[6] |= 0x02; /* IO Capability Response */ | ||
501 | events[6] |= 0x04; /* User Confirmation Request */ | ||
502 | events[6] |= 0x08; /* User Passkey Request */ | ||
503 | events[6] |= 0x10; /* Remote OOB Data Request */ | ||
504 | events[6] |= 0x20; /* Simple Pairing Complete */ | ||
505 | events[7] |= 0x04; /* User Passkey Notification */ | ||
506 | events[7] |= 0x08; /* Keypress Notification */ | ||
507 | events[7] |= 0x10; /* Remote Host Supported | ||
508 | * Features Notification */ | ||
509 | } | ||
510 | |||
511 | if (hdev->features[4] & LMP_LE) | ||
512 | events[7] |= 0x20; /* LE Meta-Event */ | ||
513 | |||
514 | hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events); | ||
515 | } | ||
516 | |||
517 | static void hci_setup(struct hci_dev *hdev) | ||
518 | { | ||
519 | hci_setup_event_mask(hdev); | ||
520 | |||
521 | if (hdev->lmp_ver > 1) | ||
522 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); | ||
523 | |||
524 | if (hdev->features[6] & LMP_SIMPLE_PAIR) { | ||
525 | u8 mode = 0x01; | ||
526 | hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); | ||
527 | } | ||
528 | |||
529 | if (hdev->features[3] & LMP_RSSI_INQ) | ||
530 | hci_setup_inquiry_mode(hdev); | ||
531 | |||
532 | if (hdev->features[7] & LMP_INQ_TX_PWR) | ||
533 | hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL); | ||
534 | } | ||
535 | |||
427 | static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) | 536 | static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) |
428 | { | 537 | { |
429 | struct hci_rp_read_local_version *rp = (void *) skb->data; | 538 | struct hci_rp_read_local_version *rp = (void *) skb->data; |
@@ -435,11 +544,34 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb) | |||
435 | 544 | ||
436 | hdev->hci_ver = rp->hci_ver; | 545 | hdev->hci_ver = rp->hci_ver; |
437 | hdev->hci_rev = __le16_to_cpu(rp->hci_rev); | 546 | hdev->hci_rev = __le16_to_cpu(rp->hci_rev); |
547 | hdev->lmp_ver = rp->lmp_ver; | ||
438 | hdev->manufacturer = __le16_to_cpu(rp->manufacturer); | 548 | hdev->manufacturer = __le16_to_cpu(rp->manufacturer); |
549 | hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver); | ||
439 | 550 | ||
440 | BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, | 551 | BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name, |
441 | hdev->manufacturer, | 552 | hdev->manufacturer, |
442 | hdev->hci_ver, hdev->hci_rev); | 553 | hdev->hci_ver, hdev->hci_rev); |
554 | |||
555 | if (test_bit(HCI_INIT, &hdev->flags)) | ||
556 | hci_setup(hdev); | ||
557 | } | ||
558 | |||
559 | static void hci_setup_link_policy(struct hci_dev *hdev) | ||
560 | { | ||
561 | u16 link_policy = 0; | ||
562 | |||
563 | if (hdev->features[0] & LMP_RSWITCH) | ||
564 | link_policy |= HCI_LP_RSWITCH; | ||
565 | if (hdev->features[0] & LMP_HOLD) | ||
566 | link_policy |= HCI_LP_HOLD; | ||
567 | if (hdev->features[0] & LMP_SNIFF) | ||
568 | link_policy |= HCI_LP_SNIFF; | ||
569 | if (hdev->features[1] & LMP_PARK) | ||
570 | link_policy |= HCI_LP_PARK; | ||
571 | |||
572 | link_policy = cpu_to_le16(link_policy); | ||
573 | hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, | ||
574 | sizeof(link_policy), &link_policy); | ||
443 | } | 575 | } |
444 | 576 | ||
445 | static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) | 577 | static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -449,9 +581,15 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb | |||
449 | BT_DBG("%s status 0x%x", hdev->name, rp->status); | 581 | BT_DBG("%s status 0x%x", hdev->name, rp->status); |
450 | 582 | ||
451 | if (rp->status) | 583 | if (rp->status) |
452 | return; | 584 | goto done; |
453 | 585 | ||
454 | memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); | 586 | memcpy(hdev->commands, rp->commands, sizeof(hdev->commands)); |
587 | |||
588 | if (test_bit(HCI_INIT, &hdev->flags) && (hdev->commands[5] & 0x10)) | ||
589 | hci_setup_link_policy(hdev); | ||
590 | |||
591 | done: | ||
592 | hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status); | ||
455 | } | 593 | } |
456 | 594 | ||
457 | static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb) | 595 | static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb) |
@@ -567,6 +705,44 @@ static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, | |||
567 | hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status); | 705 | hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status); |
568 | } | 706 | } |
569 | 707 | ||
708 | static void hci_cc_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb) | ||
709 | { | ||
710 | __u8 status = *((__u8 *) skb->data); | ||
711 | |||
712 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
713 | |||
714 | hci_req_complete(hdev, HCI_OP_SET_EVENT_MASK, status); | ||
715 | } | ||
716 | |||
717 | static void hci_cc_write_inquiry_mode(struct hci_dev *hdev, | ||
718 | struct sk_buff *skb) | ||
719 | { | ||
720 | __u8 status = *((__u8 *) skb->data); | ||
721 | |||
722 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
723 | |||
724 | hci_req_complete(hdev, HCI_OP_WRITE_INQUIRY_MODE, status); | ||
725 | } | ||
726 | |||
727 | static void hci_cc_read_inq_rsp_tx_power(struct hci_dev *hdev, | ||
728 | struct sk_buff *skb) | ||
729 | { | ||
730 | __u8 status = *((__u8 *) skb->data); | ||
731 | |||
732 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
733 | |||
734 | hci_req_complete(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, status); | ||
735 | } | ||
736 | |||
737 | static void hci_cc_set_event_flt(struct hci_dev *hdev, struct sk_buff *skb) | ||
738 | { | ||
739 | __u8 status = *((__u8 *) skb->data); | ||
740 | |||
741 | BT_DBG("%s status 0x%x", hdev->name, status); | ||
742 | |||
743 | hci_req_complete(hdev, HCI_OP_SET_EVENT_FLT, status); | ||
744 | } | ||
745 | |||
570 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) | 746 | static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) |
571 | { | 747 | { |
572 | BT_DBG("%s status 0x%x", hdev->name, status); | 748 | BT_DBG("%s status 0x%x", hdev->name, status); |
@@ -1416,6 +1592,22 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
1416 | hci_cc_delete_stored_link_key(hdev, skb); | 1592 | hci_cc_delete_stored_link_key(hdev, skb); |
1417 | break; | 1593 | break; |
1418 | 1594 | ||
1595 | case HCI_OP_SET_EVENT_MASK: | ||
1596 | hci_cc_set_event_mask(hdev, skb); | ||
1597 | break; | ||
1598 | |||
1599 | case HCI_OP_WRITE_INQUIRY_MODE: | ||
1600 | hci_cc_write_inquiry_mode(hdev, skb); | ||
1601 | break; | ||
1602 | |||
1603 | case HCI_OP_READ_INQ_RSP_TX_POWER: | ||
1604 | hci_cc_read_inq_rsp_tx_power(hdev, skb); | ||
1605 | break; | ||
1606 | |||
1607 | case HCI_OP_SET_EVENT_FLT: | ||
1608 | hci_cc_set_event_flt(hdev, skb); | ||
1609 | break; | ||
1610 | |||
1419 | default: | 1611 | default: |
1420 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); | 1612 | BT_DBG("%s opcode 0x%x", hdev->name, opcode); |
1421 | break; | 1613 | break; |