Skip to content

Commit d5859e2

Browse files
Johan HedbergGustavo F. Padovan
authored andcommitted
Bluetooth: Implement a more complete adapter initialization sequence
Using the managment interface means that user space doesn't need to do any HCI command sending at all. This patch moves the remaining initialization commands from user space to the kernel side. The patch makes use of the new feature of __hci_request which allows the request to be dynamically modified while it is ongoing (something that is needed to react appropriately to the local features and the version of the adapter). Signed-off-by: Johan Hedberg <[email protected]> Signed-off-by: Gustavo F. Padovan <[email protected]>
1 parent d835060 commit d5859e2

File tree

3 files changed

+206
-1
lines changed

3 files changed

+206
-1
lines changed

include/net/bluetooth/hci.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,19 +189,26 @@ enum {
189189
#define LMP_PSCHEME 0x02
190190
#define LMP_PCONTROL 0x04
191191

192+
#define LMP_RSSI_INQ 0x40
192193
#define LMP_ESCO 0x80
193194

194195
#define LMP_EV4 0x01
195196
#define LMP_EV5 0x02
197+
#define LMP_LE 0x40
196198

197199
#define LMP_SNIFF_SUBR 0x02
200+
#define LMP_PAUSE_ENC 0x04
198201
#define LMP_EDR_ESCO_2M 0x20
199202
#define LMP_EDR_ESCO_3M 0x40
200203
#define LMP_EDR_3S_ESCO 0x80
201204

205+
#define LMP_EXT_INQ 0x01
202206
#define LMP_SIMPLE_PAIR 0x08
203207
#define LMP_NO_FLUSH 0x40
204208

209+
#define LMP_LSTO 0x01
210+
#define LMP_INQ_TX_PWR 0x02
211+
205212
/* Connection modes */
206213
#define HCI_CM_ACTIVE 0x0000
207214
#define HCI_CM_HOLD 0x0001
@@ -556,6 +563,8 @@ struct hci_cp_host_buffer_size {
556563
__le16 sco_max_pkt;
557564
} __packed;
558565

566+
#define HCI_OP_WRITE_INQUIRY_MODE 0x0c45
567+
559568
#define HCI_OP_READ_SSP_MODE 0x0c55
560569
struct hci_rp_read_ssp_mode {
561570
__u8 status;
@@ -567,6 +576,8 @@ struct hci_cp_write_ssp_mode {
567576
__u8 mode;
568577
} __packed;
569578

579+
#define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58
580+
570581
#define HCI_OP_READ_LOCAL_VERSION 0x1001
571582
struct hci_rp_read_local_version {
572583
__u8 status;

include/net/bluetooth/hci_core.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,9 @@ struct hci_dev {
9191
__u8 ssp_mode;
9292
__u8 hci_ver;
9393
__u16 hci_rev;
94+
__u8 lmp_ver;
9495
__u16 manufacturer;
96+
__le16 lmp_subver;
9597
__u16 voice_setting;
9698

9799
__u16 pkt_type;

net/bluetooth/hci_event.c

Lines changed: 193 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,115 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
424424
hdev->ssp_mode = *((__u8 *) sent);
425425
}
426426

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+
427536
static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
428537
{
429538
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)
435544

436545
hdev->hci_ver = rp->hci_ver;
437546
hdev->hci_rev = __le16_to_cpu(rp->hci_rev);
547+
hdev->lmp_ver = rp->lmp_ver;
438548
hdev->manufacturer = __le16_to_cpu(rp->manufacturer);
549+
hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
439550

440551
BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
441552
hdev->manufacturer,
442553
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);
443575
}
444576

445577
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
449581
BT_DBG("%s status 0x%x", hdev->name, rp->status);
450582

451583
if (rp->status)
452-
return;
584+
goto done;
453585

454586
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);
455593
}
456594

457595
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,
567705
hci_req_complete(hdev, HCI_OP_DELETE_STORED_LINK_KEY, status);
568706
}
569707

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+
570746
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
571747
{
572748
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
14161592
hci_cc_delete_stored_link_key(hdev, skb);
14171593
break;
14181594

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+
14191611
default:
14201612
BT_DBG("%s opcode 0x%x", hdev->name, opcode);
14211613
break;

0 commit comments

Comments
 (0)