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 /include/net | |
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 'include/net')
-rw-r--r-- | include/net/bluetooth/hci.h | 70 | ||||
-rw-r--r-- | include/net/bluetooth/hci_core.h | 54 |
2 files changed, 86 insertions, 38 deletions
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 99c53f6b8252..b2bdb1aa0429 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h | |||
@@ -101,9 +101,10 @@ enum { | |||
101 | #define HCIINQUIRY _IOR('H', 240, int) | 101 | #define HCIINQUIRY _IOR('H', 240, int) |
102 | 102 | ||
103 | /* HCI timeouts */ | 103 | /* HCI timeouts */ |
104 | #define HCI_CONN_TIMEOUT (HZ * 40) | 104 | #define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */ |
105 | #define HCI_DISCONN_TIMEOUT (HZ * 2) | 105 | #define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */ |
106 | #define HCI_CONN_IDLE_TIMEOUT (HZ * 60) | 106 | #define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */ |
107 | #define HCI_INIT_TIMEOUT (10000) /* 10 seconds */ | ||
107 | 108 | ||
108 | /* HCI Packet types */ | 109 | /* HCI Packet types */ |
109 | #define HCI_COMMAND_PKT 0x01 | 110 | #define HCI_COMMAND_PKT 0x01 |
@@ -145,7 +146,7 @@ enum { | |||
145 | #define LMP_TACCURACY 0x10 | 146 | #define LMP_TACCURACY 0x10 |
146 | #define LMP_RSWITCH 0x20 | 147 | #define LMP_RSWITCH 0x20 |
147 | #define LMP_HOLD 0x40 | 148 | #define LMP_HOLD 0x40 |
148 | #define LMP_SNIF 0x80 | 149 | #define LMP_SNIFF 0x80 |
149 | 150 | ||
150 | #define LMP_PARK 0x01 | 151 | #define LMP_PARK 0x01 |
151 | #define LMP_RSSI 0x02 | 152 | #define LMP_RSSI 0x02 |
@@ -160,13 +161,21 @@ enum { | |||
160 | #define LMP_PSCHEME 0x02 | 161 | #define LMP_PSCHEME 0x02 |
161 | #define LMP_PCONTROL 0x04 | 162 | #define LMP_PCONTROL 0x04 |
162 | 163 | ||
164 | #define LMP_SNIFF_SUBR 0x02 | ||
165 | |||
166 | /* Connection modes */ | ||
167 | #define HCI_CM_ACTIVE 0x0000 | ||
168 | #define HCI_CM_HOLD 0x0001 | ||
169 | #define HCI_CM_SNIFF 0x0002 | ||
170 | #define HCI_CM_PARK 0x0003 | ||
171 | |||
163 | /* Link policies */ | 172 | /* Link policies */ |
164 | #define HCI_LP_RSWITCH 0x0001 | 173 | #define HCI_LP_RSWITCH 0x0001 |
165 | #define HCI_LP_HOLD 0x0002 | 174 | #define HCI_LP_HOLD 0x0002 |
166 | #define HCI_LP_SNIFF 0x0004 | 175 | #define HCI_LP_SNIFF 0x0004 |
167 | #define HCI_LP_PARK 0x0008 | 176 | #define HCI_LP_PARK 0x0008 |
168 | 177 | ||
169 | /* Link mode */ | 178 | /* Link modes */ |
170 | #define HCI_LM_ACCEPT 0x8000 | 179 | #define HCI_LM_ACCEPT 0x8000 |
171 | #define HCI_LM_MASTER 0x0001 | 180 | #define HCI_LM_MASTER 0x0001 |
172 | #define HCI_LM_AUTH 0x0002 | 181 | #define HCI_LM_AUTH 0x0002 |
@@ -192,7 +201,7 @@ struct hci_rp_read_loc_version { | |||
192 | } __attribute__ ((packed)); | 201 | } __attribute__ ((packed)); |
193 | 202 | ||
194 | #define OCF_READ_LOCAL_FEATURES 0x0003 | 203 | #define OCF_READ_LOCAL_FEATURES 0x0003 |
195 | struct hci_rp_read_loc_features { | 204 | struct hci_rp_read_local_features { |
196 | __u8 status; | 205 | __u8 status; |
197 | __u8 features[8]; | 206 | __u8 features[8]; |
198 | } __attribute__ ((packed)); | 207 | } __attribute__ ((packed)); |
@@ -376,17 +385,32 @@ struct hci_cp_change_conn_link_key { | |||
376 | } __attribute__ ((packed)); | 385 | } __attribute__ ((packed)); |
377 | 386 | ||
378 | #define OCF_READ_REMOTE_FEATURES 0x001B | 387 | #define OCF_READ_REMOTE_FEATURES 0x001B |
379 | struct hci_cp_read_rmt_features { | 388 | struct hci_cp_read_remote_features { |
380 | __le16 handle; | 389 | __le16 handle; |
381 | } __attribute__ ((packed)); | 390 | } __attribute__ ((packed)); |
382 | 391 | ||
383 | #define OCF_READ_REMOTE_VERSION 0x001D | 392 | #define OCF_READ_REMOTE_VERSION 0x001D |
384 | struct hci_cp_read_rmt_version { | 393 | struct hci_cp_read_remote_version { |
385 | __le16 handle; | 394 | __le16 handle; |
386 | } __attribute__ ((packed)); | 395 | } __attribute__ ((packed)); |
387 | 396 | ||
388 | /* Link Policy */ | 397 | /* Link Policy */ |
389 | #define OGF_LINK_POLICY 0x02 | 398 | #define OGF_LINK_POLICY 0x02 |
399 | |||
400 | #define OCF_SNIFF_MODE 0x0003 | ||
401 | struct hci_cp_sniff_mode { | ||
402 | __le16 handle; | ||
403 | __le16 max_interval; | ||
404 | __le16 min_interval; | ||
405 | __le16 attempt; | ||
406 | __le16 timeout; | ||
407 | } __attribute__ ((packed)); | ||
408 | |||
409 | #define OCF_EXIT_SNIFF_MODE 0x0004 | ||
410 | struct hci_cp_exit_sniff_mode { | ||
411 | __le16 handle; | ||
412 | } __attribute__ ((packed)); | ||
413 | |||
390 | #define OCF_ROLE_DISCOVERY 0x0009 | 414 | #define OCF_ROLE_DISCOVERY 0x0009 |
391 | struct hci_cp_role_discovery { | 415 | struct hci_cp_role_discovery { |
392 | __le16 handle; | 416 | __le16 handle; |
@@ -407,7 +431,7 @@ struct hci_rp_read_link_policy { | |||
407 | __le16 policy; | 431 | __le16 policy; |
408 | } __attribute__ ((packed)); | 432 | } __attribute__ ((packed)); |
409 | 433 | ||
410 | #define OCF_SWITCH_ROLE 0x000B | 434 | #define OCF_SWITCH_ROLE 0x000B |
411 | struct hci_cp_switch_role { | 435 | struct hci_cp_switch_role { |
412 | bdaddr_t bdaddr; | 436 | bdaddr_t bdaddr; |
413 | __u8 role; | 437 | __u8 role; |
@@ -423,6 +447,14 @@ struct hci_rp_write_link_policy { | |||
423 | __le16 handle; | 447 | __le16 handle; |
424 | } __attribute__ ((packed)); | 448 | } __attribute__ ((packed)); |
425 | 449 | ||
450 | #define OCF_SNIFF_SUBRATE 0x0011 | ||
451 | struct hci_cp_sniff_subrate { | ||
452 | __le16 handle; | ||
453 | __le16 max_latency; | ||
454 | __le16 min_remote_timeout; | ||
455 | __le16 min_local_timeout; | ||
456 | } __attribute__ ((packed)); | ||
457 | |||
426 | /* Status params */ | 458 | /* Status params */ |
427 | #define OGF_STATUS_PARAM 0x05 | 459 | #define OGF_STATUS_PARAM 0x05 |
428 | 460 | ||
@@ -582,15 +614,15 @@ struct hci_ev_link_key_notify { | |||
582 | __u8 key_type; | 614 | __u8 key_type; |
583 | } __attribute__ ((packed)); | 615 | } __attribute__ ((packed)); |
584 | 616 | ||
585 | #define HCI_EV_RMT_FEATURES 0x0B | 617 | #define HCI_EV_REMOTE_FEATURES 0x0B |
586 | struct hci_ev_rmt_features { | 618 | struct hci_ev_remote_features { |
587 | __u8 status; | 619 | __u8 status; |
588 | __le16 handle; | 620 | __le16 handle; |
589 | __u8 features[8]; | 621 | __u8 features[8]; |
590 | } __attribute__ ((packed)); | 622 | } __attribute__ ((packed)); |
591 | 623 | ||
592 | #define HCI_EV_RMT_VERSION 0x0C | 624 | #define HCI_EV_REMOTE_VERSION 0x0C |
593 | struct hci_ev_rmt_version { | 625 | struct hci_ev_remote_version { |
594 | __u8 status; | 626 | __u8 status; |
595 | __le16 handle; | 627 | __le16 handle; |
596 | __u8 lmp_ver; | 628 | __u8 lmp_ver; |
@@ -611,6 +643,16 @@ struct hci_ev_pscan_rep_mode { | |||
611 | __u8 pscan_rep_mode; | 643 | __u8 pscan_rep_mode; |
612 | } __attribute__ ((packed)); | 644 | } __attribute__ ((packed)); |
613 | 645 | ||
646 | #define HCI_EV_SNIFF_SUBRATE 0x2E | ||
647 | struct hci_ev_sniff_subrate { | ||
648 | __u8 status; | ||
649 | __le16 handle; | ||
650 | __le16 max_tx_latency; | ||
651 | __le16 max_rx_latency; | ||
652 | __le16 max_remote_timeout; | ||
653 | __le16 max_local_timeout; | ||
654 | } __attribute__ ((packed)); | ||
655 | |||
614 | /* Internal events generated by Bluetooth stack */ | 656 | /* Internal events generated by Bluetooth stack */ |
615 | #define HCI_EV_STACK_INTERNAL 0xFD | 657 | #define HCI_EV_STACK_INTERNAL 0xFD |
616 | struct hci_ev_stack_internal { | 658 | struct hci_ev_stack_internal { |
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index bb9f81dc8723..f6852707bd64 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -31,10 +31,7 @@ | |||
31 | #define HCI_PROTO_L2CAP 0 | 31 | #define HCI_PROTO_L2CAP 0 |
32 | #define HCI_PROTO_SCO 1 | 32 | #define HCI_PROTO_SCO 1 |
33 | 33 | ||
34 | #define HCI_INIT_TIMEOUT (HZ * 10) | ||
35 | |||
36 | /* HCI Core structures */ | 34 | /* HCI Core structures */ |
37 | |||
38 | struct inquiry_data { | 35 | struct inquiry_data { |
39 | bdaddr_t bdaddr; | 36 | bdaddr_t bdaddr; |
40 | __u8 pscan_rep_mode; | 37 | __u8 pscan_rep_mode; |
@@ -81,6 +78,10 @@ struct hci_dev { | |||
81 | __u16 link_policy; | 78 | __u16 link_policy; |
82 | __u16 link_mode; | 79 | __u16 link_mode; |
83 | 80 | ||
81 | __u32 idle_timeout; | ||
82 | __u16 sniff_min_interval; | ||
83 | __u16 sniff_max_interval; | ||
84 | |||
84 | unsigned long quirks; | 85 | unsigned long quirks; |
85 | 86 | ||
86 | atomic_t cmd_cnt; | 87 | atomic_t cmd_cnt; |
@@ -145,18 +146,24 @@ struct hci_conn { | |||
145 | bdaddr_t dst; | 146 | bdaddr_t dst; |
146 | __u16 handle; | 147 | __u16 handle; |
147 | __u16 state; | 148 | __u16 state; |
149 | __u8 mode; | ||
148 | __u8 type; | 150 | __u8 type; |
149 | __u8 out; | 151 | __u8 out; |
150 | __u8 dev_class[3]; | 152 | __u8 dev_class[3]; |
153 | __u8 features[8]; | ||
154 | __u16 interval; | ||
155 | __u16 link_policy; | ||
151 | __u32 link_mode; | 156 | __u32 link_mode; |
157 | __u8 power_save; | ||
152 | unsigned long pend; | 158 | unsigned long pend; |
153 | 159 | ||
154 | unsigned int sent; | 160 | unsigned int sent; |
155 | 161 | ||
156 | struct sk_buff_head data_q; | 162 | struct sk_buff_head data_q; |
157 | 163 | ||
158 | struct timer_list timer; | 164 | struct timer_list disc_timer; |
159 | 165 | struct timer_list idle_timer; | |
166 | |||
160 | struct hci_dev *hdev; | 167 | struct hci_dev *hdev; |
161 | void *l2cap_data; | 168 | void *l2cap_data; |
162 | void *sco_data; | 169 | void *sco_data; |
@@ -211,7 +218,8 @@ void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data); | |||
211 | enum { | 218 | enum { |
212 | HCI_CONN_AUTH_PEND, | 219 | HCI_CONN_AUTH_PEND, |
213 | HCI_CONN_ENCRYPT_PEND, | 220 | HCI_CONN_ENCRYPT_PEND, |
214 | HCI_CONN_RSWITCH_PEND | 221 | HCI_CONN_RSWITCH_PEND, |
222 | HCI_CONN_MODE_CHANGE_PEND, | ||
215 | }; | 223 | }; |
216 | 224 | ||
217 | static inline void hci_conn_hash_init(struct hci_dev *hdev) | 225 | static inline void hci_conn_hash_init(struct hci_dev *hdev) |
@@ -286,31 +294,27 @@ int hci_conn_encrypt(struct hci_conn *conn); | |||
286 | int hci_conn_change_link_key(struct hci_conn *conn); | 294 | int hci_conn_change_link_key(struct hci_conn *conn); |
287 | int hci_conn_switch_role(struct hci_conn *conn, uint8_t role); | 295 | int hci_conn_switch_role(struct hci_conn *conn, uint8_t role); |
288 | 296 | ||
289 | static inline void hci_conn_set_timer(struct hci_conn *conn, unsigned long timeout) | 297 | void hci_conn_enter_active_mode(struct hci_conn *conn); |
290 | { | 298 | void hci_conn_enter_sniff_mode(struct hci_conn *conn); |
291 | mod_timer(&conn->timer, jiffies + timeout); | ||
292 | } | ||
293 | |||
294 | static inline void hci_conn_del_timer(struct hci_conn *conn) | ||
295 | { | ||
296 | del_timer(&conn->timer); | ||
297 | } | ||
298 | 299 | ||
299 | static inline void hci_conn_hold(struct hci_conn *conn) | 300 | static inline void hci_conn_hold(struct hci_conn *conn) |
300 | { | 301 | { |
301 | atomic_inc(&conn->refcnt); | 302 | atomic_inc(&conn->refcnt); |
302 | hci_conn_del_timer(conn); | 303 | del_timer(&conn->disc_timer); |
303 | } | 304 | } |
304 | 305 | ||
305 | static inline void hci_conn_put(struct hci_conn *conn) | 306 | static inline void hci_conn_put(struct hci_conn *conn) |
306 | { | 307 | { |
307 | if (atomic_dec_and_test(&conn->refcnt)) { | 308 | if (atomic_dec_and_test(&conn->refcnt)) { |
309 | unsigned long timeo; | ||
308 | if (conn->type == ACL_LINK) { | 310 | if (conn->type == ACL_LINK) { |
309 | unsigned long timeo = (conn->out) ? | 311 | timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT); |
310 | HCI_DISCONN_TIMEOUT : HCI_DISCONN_TIMEOUT * 2; | 312 | if (!conn->out) |
311 | hci_conn_set_timer(conn, timeo); | 313 | timeo *= 2; |
314 | del_timer(&conn->idle_timer); | ||
312 | } else | 315 | } else |
313 | hci_conn_set_timer(conn, HZ / 100); | 316 | timeo = msecs_to_jiffies(10); |
317 | mod_timer(&conn->disc_timer, jiffies + timeo); | ||
314 | } | 318 | } |
315 | } | 319 | } |
316 | 320 | ||
@@ -411,8 +415,10 @@ void hci_unregister_sysfs(struct hci_dev *hdev); | |||
411 | #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev)) | 415 | #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->class_dev.dev = (pdev)) |
412 | 416 | ||
413 | /* ----- LMP capabilities ----- */ | 417 | /* ----- LMP capabilities ----- */ |
414 | #define lmp_rswitch_capable(dev) (dev->features[0] & LMP_RSWITCH) | 418 | #define lmp_rswitch_capable(dev) ((dev)->features[0] & LMP_RSWITCH) |
415 | #define lmp_encrypt_capable(dev) (dev->features[0] & LMP_ENCRYPT) | 419 | #define lmp_encrypt_capable(dev) ((dev)->features[0] & LMP_ENCRYPT) |
420 | #define lmp_sniff_capable(dev) ((dev)->features[0] & LMP_SNIFF) | ||
421 | #define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR) | ||
416 | 422 | ||
417 | /* ----- HCI protocols ----- */ | 423 | /* ----- HCI protocols ----- */ |
418 | struct hci_proto { | 424 | struct hci_proto { |