diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2006-07-03 04:02:33 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-07-03 22:53:58 -0400 |
commit | 04837f6447c7f3ef114cda1ad761822dedbff8cf (patch) | |
tree | 66dbb53e82550723191ffe54f0457eafc3a92d32 /net/bluetooth | |
parent | da1f519851d1c66331363253f364bdb5d924ea96 (diff) |
[Bluetooth] Add automatic sniff mode support
This patch introduces the automatic sniff mode feature. This allows
the host to switch idle connections into sniff mode to safe power.
Signed-off-by: Ulisses Furquim <ulissesf@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/af_bluetooth.c | 2 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 100 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 34 | ||||
-rw-r--r-- | net/bluetooth/hci_event.c | 192 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 88 |
5 files changed, 368 insertions, 48 deletions
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 51f867062e1d..729461fcfe99 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c | |||
@@ -48,7 +48,7 @@ | |||
48 | #define BT_DBG(D...) | 48 | #define BT_DBG(D...) |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | #define VERSION "2.8" | 51 | #define VERSION "2.9" |
52 | 52 | ||
53 | /* Bluetooth sockets */ | 53 | /* Bluetooth sockets */ |
54 | #define BT_MAX_PROTO 8 | 54 | #define BT_MAX_PROTO 8 |
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 5c0c2b1ef34a..420ed4d7e57e 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -115,8 +115,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) | |||
115 | 115 | ||
116 | static void hci_conn_timeout(unsigned long arg) | 116 | static void hci_conn_timeout(unsigned long arg) |
117 | { | 117 | { |
118 | struct hci_conn *conn = (void *)arg; | 118 | struct hci_conn *conn = (void *) arg; |
119 | struct hci_dev *hdev = conn->hdev; | 119 | struct hci_dev *hdev = conn->hdev; |
120 | 120 | ||
121 | BT_DBG("conn %p state %d", conn, conn->state); | 121 | BT_DBG("conn %p state %d", conn, conn->state); |
122 | 122 | ||
@@ -132,11 +132,13 @@ static void hci_conn_timeout(unsigned long arg) | |||
132 | return; | 132 | return; |
133 | } | 133 | } |
134 | 134 | ||
135 | static void hci_conn_init_timer(struct hci_conn *conn) | 135 | static void hci_conn_idle(unsigned long arg) |
136 | { | 136 | { |
137 | init_timer(&conn->timer); | 137 | struct hci_conn *conn = (void *) arg; |
138 | conn->timer.function = hci_conn_timeout; | 138 | |
139 | conn->timer.data = (unsigned long)conn; | 139 | BT_DBG("conn %p mode %d", conn, conn->mode); |
140 | |||
141 | hci_conn_enter_sniff_mode(conn); | ||
140 | } | 142 | } |
141 | 143 | ||
142 | struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | 144 | struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) |
@@ -145,17 +147,27 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
145 | 147 | ||
146 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); | 148 | BT_DBG("%s dst %s", hdev->name, batostr(dst)); |
147 | 149 | ||
148 | if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) | 150 | conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); |
151 | if (!conn) | ||
149 | return NULL; | 152 | return NULL; |
150 | memset(conn, 0, sizeof(struct hci_conn)); | ||
151 | 153 | ||
152 | bacpy(&conn->dst, dst); | 154 | bacpy(&conn->dst, dst); |
153 | conn->type = type; | ||
154 | conn->hdev = hdev; | 155 | conn->hdev = hdev; |
156 | conn->type = type; | ||
157 | conn->mode = HCI_CM_ACTIVE; | ||
155 | conn->state = BT_OPEN; | 158 | conn->state = BT_OPEN; |
156 | 159 | ||
160 | conn->power_save = 1; | ||
161 | |||
157 | skb_queue_head_init(&conn->data_q); | 162 | skb_queue_head_init(&conn->data_q); |
158 | hci_conn_init_timer(conn); | 163 | |
164 | init_timer(&conn->disc_timer); | ||
165 | conn->disc_timer.function = hci_conn_timeout; | ||
166 | conn->disc_timer.data = (unsigned long) conn; | ||
167 | |||
168 | init_timer(&conn->idle_timer); | ||
169 | conn->idle_timer.function = hci_conn_idle; | ||
170 | conn->idle_timer.data = (unsigned long) conn; | ||
159 | 171 | ||
160 | atomic_set(&conn->refcnt, 0); | 172 | atomic_set(&conn->refcnt, 0); |
161 | 173 | ||
@@ -178,7 +190,9 @@ int hci_conn_del(struct hci_conn *conn) | |||
178 | 190 | ||
179 | BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); | 191 | BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); |
180 | 192 | ||
181 | hci_conn_del_timer(conn); | 193 | del_timer(&conn->idle_timer); |
194 | |||
195 | del_timer(&conn->disc_timer); | ||
182 | 196 | ||
183 | if (conn->type == SCO_LINK) { | 197 | if (conn->type == SCO_LINK) { |
184 | struct hci_conn *acl = conn->link; | 198 | struct hci_conn *acl = conn->link; |
@@ -364,6 +378,70 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role) | |||
364 | } | 378 | } |
365 | EXPORT_SYMBOL(hci_conn_switch_role); | 379 | EXPORT_SYMBOL(hci_conn_switch_role); |
366 | 380 | ||
381 | /* Enter active mode */ | ||
382 | void hci_conn_enter_active_mode(struct hci_conn *conn) | ||
383 | { | ||
384 | struct hci_dev *hdev = conn->hdev; | ||
385 | |||
386 | BT_DBG("conn %p mode %d", conn, conn->mode); | ||
387 | |||
388 | if (test_bit(HCI_RAW, &hdev->flags)) | ||
389 | return; | ||
390 | |||
391 | if (conn->mode != HCI_CM_SNIFF || !conn->power_save) | ||
392 | goto timer; | ||
393 | |||
394 | if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { | ||
395 | struct hci_cp_exit_sniff_mode cp; | ||
396 | cp.handle = __cpu_to_le16(conn->handle); | ||
397 | hci_send_cmd(hdev, OGF_LINK_POLICY, | ||
398 | OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp); | ||
399 | } | ||
400 | |||
401 | timer: | ||
402 | if (hdev->idle_timeout > 0) | ||
403 | mod_timer(&conn->idle_timer, | ||
404 | jiffies + msecs_to_jiffies(hdev->idle_timeout)); | ||
405 | } | ||
406 | |||
407 | /* Enter sniff mode */ | ||
408 | void hci_conn_enter_sniff_mode(struct hci_conn *conn) | ||
409 | { | ||
410 | struct hci_dev *hdev = conn->hdev; | ||
411 | |||
412 | BT_DBG("conn %p mode %d", conn, conn->mode); | ||
413 | |||
414 | if (test_bit(HCI_RAW, &hdev->flags)) | ||
415 | return; | ||
416 | |||
417 | if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) | ||
418 | return; | ||
419 | |||
420 | if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) | ||
421 | return; | ||
422 | |||
423 | if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { | ||
424 | struct hci_cp_sniff_subrate cp; | ||
425 | cp.handle = __cpu_to_le16(conn->handle); | ||
426 | cp.max_latency = __constant_cpu_to_le16(0); | ||
427 | cp.min_remote_timeout = __constant_cpu_to_le16(0); | ||
428 | cp.min_local_timeout = __constant_cpu_to_le16(0); | ||
429 | hci_send_cmd(hdev, OGF_LINK_POLICY, | ||
430 | OCF_SNIFF_SUBRATE, sizeof(cp), &cp); | ||
431 | } | ||
432 | |||
433 | if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { | ||
434 | struct hci_cp_sniff_mode cp; | ||
435 | cp.handle = __cpu_to_le16(conn->handle); | ||
436 | cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval); | ||
437 | cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval); | ||
438 | cp.attempt = __constant_cpu_to_le16(4); | ||
439 | cp.timeout = __constant_cpu_to_le16(1); | ||
440 | hci_send_cmd(hdev, OGF_LINK_POLICY, | ||
441 | OCF_SNIFF_MODE, sizeof(cp), &cp); | ||
442 | } | ||
443 | } | ||
444 | |||
367 | /* Drop all connection on the device */ | 445 | /* Drop all connection on the device */ |
368 | void hci_conn_hash_flush(struct hci_dev *hdev) | 446 | void hci_conn_hash_flush(struct hci_dev *hdev) |
369 | { | 447 | { |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index f67240beb0dd..3f9f1565bf06 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -411,7 +411,7 @@ int hci_inquiry(void __user *arg) | |||
411 | } | 411 | } |
412 | hci_dev_unlock_bh(hdev); | 412 | hci_dev_unlock_bh(hdev); |
413 | 413 | ||
414 | timeo = ir.length * 2 * HZ; | 414 | timeo = ir.length * msecs_to_jiffies(2000); |
415 | if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) | 415 | if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0) |
416 | goto done; | 416 | goto done; |
417 | 417 | ||
@@ -479,7 +479,8 @@ int hci_dev_open(__u16 dev) | |||
479 | set_bit(HCI_INIT, &hdev->flags); | 479 | set_bit(HCI_INIT, &hdev->flags); |
480 | 480 | ||
481 | //__hci_request(hdev, hci_reset_req, 0, HZ); | 481 | //__hci_request(hdev, hci_reset_req, 0, HZ); |
482 | ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT); | 482 | ret = __hci_request(hdev, hci_init_req, 0, |
483 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | ||
483 | 484 | ||
484 | clear_bit(HCI_INIT, &hdev->flags); | 485 | clear_bit(HCI_INIT, &hdev->flags); |
485 | } | 486 | } |
@@ -546,7 +547,8 @@ static int hci_dev_do_close(struct hci_dev *hdev) | |||
546 | atomic_set(&hdev->cmd_cnt, 1); | 547 | atomic_set(&hdev->cmd_cnt, 1); |
547 | if (!test_bit(HCI_RAW, &hdev->flags)) { | 548 | if (!test_bit(HCI_RAW, &hdev->flags)) { |
548 | set_bit(HCI_INIT, &hdev->flags); | 549 | set_bit(HCI_INIT, &hdev->flags); |
549 | __hci_request(hdev, hci_reset_req, 0, HZ/4); | 550 | __hci_request(hdev, hci_reset_req, 0, |
551 | msecs_to_jiffies(250)); | ||
550 | clear_bit(HCI_INIT, &hdev->flags); | 552 | clear_bit(HCI_INIT, &hdev->flags); |
551 | } | 553 | } |
552 | 554 | ||
@@ -619,7 +621,8 @@ int hci_dev_reset(__u16 dev) | |||
619 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; | 621 | hdev->acl_cnt = 0; hdev->sco_cnt = 0; |
620 | 622 | ||
621 | if (!test_bit(HCI_RAW, &hdev->flags)) | 623 | if (!test_bit(HCI_RAW, &hdev->flags)) |
622 | ret = __hci_request(hdev, hci_reset_req, 0, HCI_INIT_TIMEOUT); | 624 | ret = __hci_request(hdev, hci_reset_req, 0, |
625 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | ||
623 | 626 | ||
624 | done: | 627 | done: |
625 | tasklet_enable(&hdev->tx_task); | 628 | tasklet_enable(&hdev->tx_task); |
@@ -657,7 +660,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) | |||
657 | 660 | ||
658 | switch (cmd) { | 661 | switch (cmd) { |
659 | case HCISETAUTH: | 662 | case HCISETAUTH: |
660 | err = hci_request(hdev, hci_auth_req, dr.dev_opt, HCI_INIT_TIMEOUT); | 663 | err = hci_request(hdev, hci_auth_req, dr.dev_opt, |
664 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | ||
661 | break; | 665 | break; |
662 | 666 | ||
663 | case HCISETENCRYPT: | 667 | case HCISETENCRYPT: |
@@ -668,18 +672,19 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg) | |||
668 | 672 | ||
669 | if (!test_bit(HCI_AUTH, &hdev->flags)) { | 673 | if (!test_bit(HCI_AUTH, &hdev->flags)) { |
670 | /* Auth must be enabled first */ | 674 | /* Auth must be enabled first */ |
671 | err = hci_request(hdev, hci_auth_req, | 675 | err = hci_request(hdev, hci_auth_req, dr.dev_opt, |
672 | dr.dev_opt, HCI_INIT_TIMEOUT); | 676 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); |
673 | if (err) | 677 | if (err) |
674 | break; | 678 | break; |
675 | } | 679 | } |
676 | 680 | ||
677 | err = hci_request(hdev, hci_encrypt_req, | 681 | err = hci_request(hdev, hci_encrypt_req, dr.dev_opt, |
678 | dr.dev_opt, HCI_INIT_TIMEOUT); | 682 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); |
679 | break; | 683 | break; |
680 | 684 | ||
681 | case HCISETSCAN: | 685 | case HCISETSCAN: |
682 | err = hci_request(hdev, hci_scan_req, dr.dev_opt, HCI_INIT_TIMEOUT); | 686 | err = hci_request(hdev, hci_scan_req, dr.dev_opt, |
687 | msecs_to_jiffies(HCI_INIT_TIMEOUT)); | ||
683 | break; | 688 | break; |
684 | 689 | ||
685 | case HCISETPTYPE: | 690 | case HCISETPTYPE: |
@@ -848,6 +853,10 @@ int hci_register_dev(struct hci_dev *hdev) | |||
848 | hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); | 853 | hdev->pkt_type = (HCI_DM1 | HCI_DH1 | HCI_HV1); |
849 | hdev->link_mode = (HCI_LM_ACCEPT); | 854 | hdev->link_mode = (HCI_LM_ACCEPT); |
850 | 855 | ||
856 | hdev->idle_timeout = 0; | ||
857 | hdev->sniff_max_interval = 800; | ||
858 | hdev->sniff_min_interval = 80; | ||
859 | |||
851 | tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); | 860 | tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev); |
852 | tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); | 861 | tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev); |
853 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); | 862 | tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev); |
@@ -1220,6 +1229,9 @@ static inline void hci_sched_acl(struct hci_dev *hdev) | |||
1220 | while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { | 1229 | while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, "e))) { |
1221 | while (quote-- && (skb = skb_dequeue(&conn->data_q))) { | 1230 | while (quote-- && (skb = skb_dequeue(&conn->data_q))) { |
1222 | BT_DBG("skb %p len %d", skb, skb->len); | 1231 | BT_DBG("skb %p len %d", skb, skb->len); |
1232 | |||
1233 | hci_conn_enter_active_mode(conn); | ||
1234 | |||
1223 | hci_send_frame(skb); | 1235 | hci_send_frame(skb); |
1224 | hdev->acl_last_tx = jiffies; | 1236 | hdev->acl_last_tx = jiffies; |
1225 | 1237 | ||
@@ -1298,6 +1310,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
1298 | if (conn) { | 1310 | if (conn) { |
1299 | register struct hci_proto *hp; | 1311 | register struct hci_proto *hp; |
1300 | 1312 | ||
1313 | hci_conn_enter_active_mode(conn); | ||
1314 | |||
1301 | /* Send to upper protocol */ | 1315 | /* Send to upper protocol */ |
1302 | if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { | 1316 | if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) { |
1303 | hp->recv_acldata(conn, skb, flags); | 1317 | hp->recv_acldata(conn, skb, flags); |
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index f41cf1a6c11a..3896dabab11d 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c | |||
@@ -83,6 +83,8 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * | |||
83 | { | 83 | { |
84 | struct hci_conn *conn; | 84 | struct hci_conn *conn; |
85 | struct hci_rp_role_discovery *rd; | 85 | struct hci_rp_role_discovery *rd; |
86 | struct hci_rp_write_link_policy *lp; | ||
87 | void *sent; | ||
86 | 88 | ||
87 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | 89 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); |
88 | 90 | ||
@@ -106,6 +108,27 @@ static void hci_cc_link_policy(struct hci_dev *hdev, __u16 ocf, struct sk_buff * | |||
106 | hci_dev_unlock(hdev); | 108 | hci_dev_unlock(hdev); |
107 | break; | 109 | break; |
108 | 110 | ||
111 | case OCF_WRITE_LINK_POLICY: | ||
112 | sent = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY); | ||
113 | if (!sent) | ||
114 | break; | ||
115 | |||
116 | lp = (struct hci_rp_write_link_policy *) skb->data; | ||
117 | |||
118 | if (lp->status) | ||
119 | break; | ||
120 | |||
121 | hci_dev_lock(hdev); | ||
122 | |||
123 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(lp->handle)); | ||
124 | if (conn) { | ||
125 | __le16 policy = get_unaligned((__le16 *) (sent + 2)); | ||
126 | conn->link_policy = __le16_to_cpu(policy); | ||
127 | } | ||
128 | |||
129 | hci_dev_unlock(hdev); | ||
130 | break; | ||
131 | |||
109 | default: | 132 | default: |
110 | BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", | 133 | BT_DBG("%s: Command complete: ogf LINK_POLICY ocf %x", |
111 | hdev->name, ocf); | 134 | hdev->name, ocf); |
@@ -274,7 +297,7 @@ static void hci_cc_host_ctl(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb | |||
274 | /* Command Complete OGF INFO_PARAM */ | 297 | /* Command Complete OGF INFO_PARAM */ |
275 | static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) | 298 | static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *skb) |
276 | { | 299 | { |
277 | struct hci_rp_read_loc_features *lf; | 300 | struct hci_rp_read_local_features *lf; |
278 | struct hci_rp_read_buffer_size *bs; | 301 | struct hci_rp_read_buffer_size *bs; |
279 | struct hci_rp_read_bd_addr *ba; | 302 | struct hci_rp_read_bd_addr *ba; |
280 | 303 | ||
@@ -282,7 +305,7 @@ static void hci_cc_info_param(struct hci_dev *hdev, __u16 ocf, struct sk_buff *s | |||
282 | 305 | ||
283 | switch (ocf) { | 306 | switch (ocf) { |
284 | case OCF_READ_LOCAL_FEATURES: | 307 | case OCF_READ_LOCAL_FEATURES: |
285 | lf = (struct hci_rp_read_loc_features *) skb->data; | 308 | lf = (struct hci_rp_read_local_features *) skb->data; |
286 | 309 | ||
287 | if (lf->status) { | 310 | if (lf->status) { |
288 | BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); | 311 | BT_DBG("%s READ_LOCAL_FEATURES failed %d", hdev->name, lf->status); |
@@ -447,8 +470,46 @@ static void hci_cs_link_policy(struct hci_dev *hdev, __u16 ocf, __u8 status) | |||
447 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); | 470 | BT_DBG("%s ocf 0x%x", hdev->name, ocf); |
448 | 471 | ||
449 | switch (ocf) { | 472 | switch (ocf) { |
473 | case OCF_SNIFF_MODE: | ||
474 | if (status) { | ||
475 | struct hci_conn *conn; | ||
476 | struct hci_cp_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_SNIFF_MODE); | ||
477 | |||
478 | if (!cp) | ||
479 | break; | ||
480 | |||
481 | hci_dev_lock(hdev); | ||
482 | |||
483 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); | ||
484 | if (conn) { | ||
485 | clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); | ||
486 | } | ||
487 | |||
488 | hci_dev_unlock(hdev); | ||
489 | } | ||
490 | break; | ||
491 | |||
492 | case OCF_EXIT_SNIFF_MODE: | ||
493 | if (status) { | ||
494 | struct hci_conn *conn; | ||
495 | struct hci_cp_exit_sniff_mode *cp = hci_sent_cmd_data(hdev, OGF_LINK_POLICY, OCF_EXIT_SNIFF_MODE); | ||
496 | |||
497 | if (!cp) | ||
498 | break; | ||
499 | |||
500 | hci_dev_lock(hdev); | ||
501 | |||
502 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); | ||
503 | if (conn) { | ||
504 | clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend); | ||
505 | } | ||
506 | |||
507 | hci_dev_unlock(hdev); | ||
508 | } | ||
509 | break; | ||
510 | |||
450 | default: | 511 | default: |
451 | BT_DBG("%s Command status: ogf HOST_POLICY ocf %x", hdev->name, ocf); | 512 | BT_DBG("%s Command status: ogf LINK_POLICY ocf %x", hdev->name, ocf); |
452 | break; | 513 | break; |
453 | } | 514 | } |
454 | } | 515 | } |
@@ -630,14 +691,16 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
630 | else | 691 | else |
631 | cp.role = 0x01; /* Remain slave */ | 692 | cp.role = 0x01; /* Remain slave */ |
632 | 693 | ||
633 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); | 694 | hci_send_cmd(hdev, OGF_LINK_CTL, |
695 | OCF_ACCEPT_CONN_REQ, sizeof(cp), &cp); | ||
634 | } else { | 696 | } else { |
635 | /* Connection rejected */ | 697 | /* Connection rejected */ |
636 | struct hci_cp_reject_conn_req cp; | 698 | struct hci_cp_reject_conn_req cp; |
637 | 699 | ||
638 | bacpy(&cp.bdaddr, &ev->bdaddr); | 700 | bacpy(&cp.bdaddr, &ev->bdaddr); |
639 | cp.reason = 0x0f; | 701 | cp.reason = 0x0f; |
640 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_REJECT_CONN_REQ, sizeof(cp), &cp); | 702 | hci_send_cmd(hdev, OGF_LINK_CTL, |
703 | OCF_REJECT_CONN_REQ, sizeof(cp), &cp); | ||
641 | } | 704 | } |
642 | } | 705 | } |
643 | 706 | ||
@@ -645,7 +708,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk | |||
645 | static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 708 | static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
646 | { | 709 | { |
647 | struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; | 710 | struct hci_ev_conn_complete *ev = (struct hci_ev_conn_complete *) skb->data; |
648 | struct hci_conn *conn = NULL; | 711 | struct hci_conn *conn; |
649 | 712 | ||
650 | BT_DBG("%s", hdev->name); | 713 | BT_DBG("%s", hdev->name); |
651 | 714 | ||
@@ -667,12 +730,21 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
667 | if (test_bit(HCI_ENCRYPT, &hdev->flags)) | 730 | if (test_bit(HCI_ENCRYPT, &hdev->flags)) |
668 | conn->link_mode |= HCI_LM_ENCRYPT; | 731 | conn->link_mode |= HCI_LM_ENCRYPT; |
669 | 732 | ||
733 | /* Get remote features */ | ||
734 | if (conn->type == ACL_LINK) { | ||
735 | struct hci_cp_read_remote_features cp; | ||
736 | cp.handle = ev->handle; | ||
737 | hci_send_cmd(hdev, OGF_LINK_CTL, | ||
738 | OCF_READ_REMOTE_FEATURES, sizeof(cp), &cp); | ||
739 | } | ||
740 | |||
670 | /* Set link policy */ | 741 | /* Set link policy */ |
671 | if (conn->type == ACL_LINK && hdev->link_policy) { | 742 | if (conn->type == ACL_LINK && hdev->link_policy) { |
672 | struct hci_cp_write_link_policy cp; | 743 | struct hci_cp_write_link_policy cp; |
673 | cp.handle = ev->handle; | 744 | cp.handle = ev->handle; |
674 | cp.policy = __cpu_to_le16(hdev->link_policy); | 745 | cp.policy = __cpu_to_le16(hdev->link_policy); |
675 | hci_send_cmd(hdev, OGF_LINK_POLICY, OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); | 746 | hci_send_cmd(hdev, OGF_LINK_POLICY, |
747 | OCF_WRITE_LINK_POLICY, sizeof(cp), &cp); | ||
676 | } | 748 | } |
677 | 749 | ||
678 | /* Set packet type for incoming connection */ | 750 | /* Set packet type for incoming connection */ |
@@ -683,7 +755,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
683 | __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): | 755 | __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK): |
684 | __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); | 756 | __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK); |
685 | 757 | ||
686 | hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); | 758 | hci_send_cmd(hdev, OGF_LINK_CTL, |
759 | OCF_CHANGE_CONN_PTYPE, sizeof(cp), &cp); | ||
687 | } | 760 | } |
688 | } else | 761 | } else |
689 | conn->state = BT_CLOSED; | 762 | conn->state = BT_CLOSED; |
@@ -711,8 +784,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
711 | static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 784 | static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
712 | { | 785 | { |
713 | struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; | 786 | struct hci_ev_disconn_complete *ev = (struct hci_ev_disconn_complete *) skb->data; |
714 | struct hci_conn *conn = NULL; | 787 | struct hci_conn *conn; |
715 | __u16 handle = __le16_to_cpu(ev->handle); | ||
716 | 788 | ||
717 | BT_DBG("%s status %d", hdev->name, ev->status); | 789 | BT_DBG("%s status %d", hdev->name, ev->status); |
718 | 790 | ||
@@ -721,7 +793,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff | |||
721 | 793 | ||
722 | hci_dev_lock(hdev); | 794 | hci_dev_lock(hdev); |
723 | 795 | ||
724 | conn = hci_conn_hash_lookup_handle(hdev, handle); | 796 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
725 | if (conn) { | 797 | if (conn) { |
726 | conn->state = BT_CLOSED; | 798 | conn->state = BT_CLOSED; |
727 | hci_proto_disconn_ind(conn, ev->reason); | 799 | hci_proto_disconn_ind(conn, ev->reason); |
@@ -778,7 +850,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s | |||
778 | static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | 850 | static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb) |
779 | { | 851 | { |
780 | struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; | 852 | struct hci_ev_role_change *ev = (struct hci_ev_role_change *) skb->data; |
781 | struct hci_conn *conn = NULL; | 853 | struct hci_conn *conn; |
782 | 854 | ||
783 | BT_DBG("%s status %d", hdev->name, ev->status); | 855 | BT_DBG("%s status %d", hdev->name, ev->status); |
784 | 856 | ||
@@ -801,18 +873,43 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb | |||
801 | hci_dev_unlock(hdev); | 873 | hci_dev_unlock(hdev); |
802 | } | 874 | } |
803 | 875 | ||
876 | /* Mode Change */ | ||
877 | static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
878 | { | ||
879 | struct hci_ev_mode_change *ev = (struct hci_ev_mode_change *) skb->data; | ||
880 | struct hci_conn *conn; | ||
881 | |||
882 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
883 | |||
884 | hci_dev_lock(hdev); | ||
885 | |||
886 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | ||
887 | if (conn) { | ||
888 | conn->mode = ev->mode; | ||
889 | conn->interval = __le16_to_cpu(ev->interval); | ||
890 | |||
891 | if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { | ||
892 | if (conn->mode == HCI_CM_ACTIVE) | ||
893 | conn->power_save = 1; | ||
894 | else | ||
895 | conn->power_save = 0; | ||
896 | } | ||
897 | } | ||
898 | |||
899 | hci_dev_unlock(hdev); | ||
900 | } | ||
901 | |||
804 | /* Authentication Complete */ | 902 | /* Authentication Complete */ |
805 | static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 903 | static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
806 | { | 904 | { |
807 | struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; | 905 | struct hci_ev_auth_complete *ev = (struct hci_ev_auth_complete *) skb->data; |
808 | struct hci_conn *conn = NULL; | 906 | struct hci_conn *conn; |
809 | __u16 handle = __le16_to_cpu(ev->handle); | ||
810 | 907 | ||
811 | BT_DBG("%s status %d", hdev->name, ev->status); | 908 | BT_DBG("%s status %d", hdev->name, ev->status); |
812 | 909 | ||
813 | hci_dev_lock(hdev); | 910 | hci_dev_lock(hdev); |
814 | 911 | ||
815 | conn = hci_conn_hash_lookup_handle(hdev, handle); | 912 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
816 | if (conn) { | 913 | if (conn) { |
817 | if (!ev->status) | 914 | if (!ev->status) |
818 | conn->link_mode |= HCI_LM_AUTH; | 915 | conn->link_mode |= HCI_LM_AUTH; |
@@ -827,8 +924,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
827 | cp.handle = __cpu_to_le16(conn->handle); | 924 | cp.handle = __cpu_to_le16(conn->handle); |
828 | cp.encrypt = 1; | 925 | cp.encrypt = 1; |
829 | hci_send_cmd(conn->hdev, OGF_LINK_CTL, | 926 | hci_send_cmd(conn->hdev, OGF_LINK_CTL, |
830 | OCF_SET_CONN_ENCRYPT, | 927 | OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp); |
831 | sizeof(cp), &cp); | ||
832 | } else { | 928 | } else { |
833 | clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); | 929 | clear_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend); |
834 | hci_encrypt_cfm(conn, ev->status, 0x00); | 930 | hci_encrypt_cfm(conn, ev->status, 0x00); |
@@ -843,14 +939,13 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s | |||
843 | static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) | 939 | static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb) |
844 | { | 940 | { |
845 | struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; | 941 | struct hci_ev_encrypt_change *ev = (struct hci_ev_encrypt_change *) skb->data; |
846 | struct hci_conn *conn = NULL; | 942 | struct hci_conn *conn; |
847 | __u16 handle = __le16_to_cpu(ev->handle); | ||
848 | 943 | ||
849 | BT_DBG("%s status %d", hdev->name, ev->status); | 944 | BT_DBG("%s status %d", hdev->name, ev->status); |
850 | 945 | ||
851 | hci_dev_lock(hdev); | 946 | hci_dev_lock(hdev); |
852 | 947 | ||
853 | conn = hci_conn_hash_lookup_handle(hdev, handle); | 948 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
854 | if (conn) { | 949 | if (conn) { |
855 | if (!ev->status) { | 950 | if (!ev->status) { |
856 | if (ev->encrypt) | 951 | if (ev->encrypt) |
@@ -871,14 +966,13 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff * | |||
871 | static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) | 966 | static inline void hci_change_conn_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) |
872 | { | 967 | { |
873 | struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; | 968 | struct hci_ev_change_conn_link_key_complete *ev = (struct hci_ev_change_conn_link_key_complete *) skb->data; |
874 | struct hci_conn *conn = NULL; | 969 | struct hci_conn *conn; |
875 | __u16 handle = __le16_to_cpu(ev->handle); | ||
876 | 970 | ||
877 | BT_DBG("%s status %d", hdev->name, ev->status); | 971 | BT_DBG("%s status %d", hdev->name, ev->status); |
878 | 972 | ||
879 | hci_dev_lock(hdev); | 973 | hci_dev_lock(hdev); |
880 | 974 | ||
881 | conn = hci_conn_hash_lookup_handle(hdev, handle); | 975 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
882 | if (conn) { | 976 | if (conn) { |
883 | if (!ev->status) | 977 | if (!ev->status) |
884 | conn->link_mode |= HCI_LM_SECURE; | 978 | conn->link_mode |= HCI_LM_SECURE; |
@@ -906,18 +1000,35 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff | |||
906 | { | 1000 | { |
907 | } | 1001 | } |
908 | 1002 | ||
1003 | /* Remote Features */ | ||
1004 | static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
1005 | { | ||
1006 | struct hci_ev_remote_features *ev = (struct hci_ev_remote_features *) skb->data; | ||
1007 | struct hci_conn *conn; | ||
1008 | |||
1009 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
1010 | |||
1011 | hci_dev_lock(hdev); | ||
1012 | |||
1013 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | ||
1014 | if (conn && !ev->status) { | ||
1015 | memcpy(conn->features, ev->features, sizeof(conn->features)); | ||
1016 | } | ||
1017 | |||
1018 | hci_dev_unlock(hdev); | ||
1019 | } | ||
1020 | |||
909 | /* Clock Offset */ | 1021 | /* Clock Offset */ |
910 | static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) | 1022 | static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb) |
911 | { | 1023 | { |
912 | struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; | 1024 | struct hci_ev_clock_offset *ev = (struct hci_ev_clock_offset *) skb->data; |
913 | struct hci_conn *conn = NULL; | 1025 | struct hci_conn *conn; |
914 | __u16 handle = __le16_to_cpu(ev->handle); | ||
915 | 1026 | ||
916 | BT_DBG("%s status %d", hdev->name, ev->status); | 1027 | BT_DBG("%s status %d", hdev->name, ev->status); |
917 | 1028 | ||
918 | hci_dev_lock(hdev); | 1029 | hci_dev_lock(hdev); |
919 | 1030 | ||
920 | conn = hci_conn_hash_lookup_handle(hdev, handle); | 1031 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); |
921 | if (conn && !ev->status) { | 1032 | if (conn && !ev->status) { |
922 | struct inquiry_entry *ie; | 1033 | struct inquiry_entry *ie; |
923 | 1034 | ||
@@ -948,6 +1059,23 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff * | |||
948 | hci_dev_unlock(hdev); | 1059 | hci_dev_unlock(hdev); |
949 | } | 1060 | } |
950 | 1061 | ||
1062 | /* Sniff Subrate */ | ||
1063 | static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb) | ||
1064 | { | ||
1065 | struct hci_ev_sniff_subrate *ev = (struct hci_ev_sniff_subrate *) skb->data; | ||
1066 | struct hci_conn *conn; | ||
1067 | |||
1068 | BT_DBG("%s status %d", hdev->name, ev->status); | ||
1069 | |||
1070 | hci_dev_lock(hdev); | ||
1071 | |||
1072 | conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); | ||
1073 | if (conn) { | ||
1074 | } | ||
1075 | |||
1076 | hci_dev_unlock(hdev); | ||
1077 | } | ||
1078 | |||
951 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | 1079 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) |
952 | { | 1080 | { |
953 | struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; | 1081 | struct hci_event_hdr *hdr = (struct hci_event_hdr *) skb->data; |
@@ -996,6 +1124,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
996 | hci_role_change_evt(hdev, skb); | 1124 | hci_role_change_evt(hdev, skb); |
997 | break; | 1125 | break; |
998 | 1126 | ||
1127 | case HCI_EV_MODE_CHANGE: | ||
1128 | hci_mode_change_evt(hdev, skb); | ||
1129 | break; | ||
1130 | |||
999 | case HCI_EV_AUTH_COMPLETE: | 1131 | case HCI_EV_AUTH_COMPLETE: |
1000 | hci_auth_complete_evt(hdev, skb); | 1132 | hci_auth_complete_evt(hdev, skb); |
1001 | break; | 1133 | break; |
@@ -1020,6 +1152,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
1020 | hci_link_key_notify_evt(hdev, skb); | 1152 | hci_link_key_notify_evt(hdev, skb); |
1021 | break; | 1153 | break; |
1022 | 1154 | ||
1155 | case HCI_EV_REMOTE_FEATURES: | ||
1156 | hci_remote_features_evt(hdev, skb); | ||
1157 | break; | ||
1158 | |||
1023 | case HCI_EV_CLOCK_OFFSET: | 1159 | case HCI_EV_CLOCK_OFFSET: |
1024 | hci_clock_offset_evt(hdev, skb); | 1160 | hci_clock_offset_evt(hdev, skb); |
1025 | break; | 1161 | break; |
@@ -1028,6 +1164,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) | |||
1028 | hci_pscan_rep_mode_evt(hdev, skb); | 1164 | hci_pscan_rep_mode_evt(hdev, skb); |
1029 | break; | 1165 | break; |
1030 | 1166 | ||
1167 | case HCI_EV_SNIFF_SUBRATE: | ||
1168 | hci_sniff_subrate_evt(hdev, skb); | ||
1169 | break; | ||
1170 | |||
1031 | case HCI_EV_CMD_STATUS: | 1171 | case HCI_EV_CMD_STATUS: |
1032 | cs = (struct hci_ev_cmd_status *) skb->data; | 1172 | cs = (struct hci_ev_cmd_status *) skb->data; |
1033 | skb_pull(skb, sizeof(cs)); | 1173 | skb_pull(skb, sizeof(cs)); |
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 19b234c86f33..89918d2f1fdc 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c | |||
@@ -61,18 +61,106 @@ static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf) | |||
61 | return n; | 61 | return n; |
62 | } | 62 | } |
63 | 63 | ||
64 | static ssize_t show_idle_timeout(struct class_device *cdev, char *buf) | ||
65 | { | ||
66 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
67 | return sprintf(buf, "%d\n", hdev->idle_timeout); | ||
68 | } | ||
69 | |||
70 | static ssize_t store_idle_timeout(struct class_device *cdev, const char *buf, size_t count) | ||
71 | { | ||
72 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
73 | char *ptr; | ||
74 | __u32 val; | ||
75 | |||
76 | val = simple_strtoul(buf, &ptr, 10); | ||
77 | if (ptr == buf) | ||
78 | return -EINVAL; | ||
79 | |||
80 | if (val != 0 && (val < 500 || val > 3600000)) | ||
81 | return -EINVAL; | ||
82 | |||
83 | hdev->idle_timeout = val; | ||
84 | |||
85 | return count; | ||
86 | } | ||
87 | |||
88 | static ssize_t show_sniff_max_interval(struct class_device *cdev, char *buf) | ||
89 | { | ||
90 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
91 | return sprintf(buf, "%d\n", hdev->sniff_max_interval); | ||
92 | } | ||
93 | |||
94 | static ssize_t store_sniff_max_interval(struct class_device *cdev, const char *buf, size_t count) | ||
95 | { | ||
96 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
97 | char *ptr; | ||
98 | __u16 val; | ||
99 | |||
100 | val = simple_strtoul(buf, &ptr, 10); | ||
101 | if (ptr == buf) | ||
102 | return -EINVAL; | ||
103 | |||
104 | if (val < 0x0002 || val > 0xFFFE || val % 2) | ||
105 | return -EINVAL; | ||
106 | |||
107 | if (val < hdev->sniff_min_interval) | ||
108 | return -EINVAL; | ||
109 | |||
110 | hdev->sniff_max_interval = val; | ||
111 | |||
112 | return count; | ||
113 | } | ||
114 | |||
115 | static ssize_t show_sniff_min_interval(struct class_device *cdev, char *buf) | ||
116 | { | ||
117 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
118 | return sprintf(buf, "%d\n", hdev->sniff_min_interval); | ||
119 | } | ||
120 | |||
121 | static ssize_t store_sniff_min_interval(struct class_device *cdev, const char *buf, size_t count) | ||
122 | { | ||
123 | struct hci_dev *hdev = class_get_devdata(cdev); | ||
124 | char *ptr; | ||
125 | __u16 val; | ||
126 | |||
127 | val = simple_strtoul(buf, &ptr, 10); | ||
128 | if (ptr == buf) | ||
129 | return -EINVAL; | ||
130 | |||
131 | if (val < 0x0002 || val > 0xFFFE || val % 2) | ||
132 | return -EINVAL; | ||
133 | |||
134 | if (val > hdev->sniff_max_interval) | ||
135 | return -EINVAL; | ||
136 | |||
137 | hdev->sniff_min_interval = val; | ||
138 | |||
139 | return count; | ||
140 | } | ||
141 | |||
64 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | 142 | static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
65 | static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); | 143 | static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL); |
66 | static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); | 144 | static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL); |
67 | static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); | 145 | static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL); |
68 | static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); | 146 | static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL); |
69 | 147 | ||
148 | static CLASS_DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR, | ||
149 | show_idle_timeout, store_idle_timeout); | ||
150 | static CLASS_DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR, | ||
151 | show_sniff_max_interval, store_sniff_max_interval); | ||
152 | static CLASS_DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR, | ||
153 | show_sniff_min_interval, store_sniff_min_interval); | ||
154 | |||
70 | static struct class_device_attribute *bt_attrs[] = { | 155 | static struct class_device_attribute *bt_attrs[] = { |
71 | &class_device_attr_name, | 156 | &class_device_attr_name, |
72 | &class_device_attr_type, | 157 | &class_device_attr_type, |
73 | &class_device_attr_address, | 158 | &class_device_attr_address, |
74 | &class_device_attr_flags, | 159 | &class_device_attr_flags, |
75 | &class_device_attr_inquiry_cache, | 160 | &class_device_attr_inquiry_cache, |
161 | &class_device_attr_idle_timeout, | ||
162 | &class_device_attr_sniff_max_interval, | ||
163 | &class_device_attr_sniff_min_interval, | ||
76 | NULL | 164 | NULL |
77 | }; | 165 | }; |
78 | 166 | ||