diff options
| author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-05 13:13:03 -0400 | 
|---|---|---|
| committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2006-07-05 13:13:03 -0400 | 
| commit | 5e66dd6d66ffe758b39b6dcadf2330753ee1159b (patch) | |
| tree | a72cdcff4448e4af9425cc213ddf56ab23e697fe /net/bluetooth/hci_conn.c | |
| parent | 026477c1141b67e98e3bd8bdedb7d4b88a3ecd09 (diff) | |
| parent | ca78f6baca863afe2e6a244a0fe94b3a70211d46 (diff) | |
Merge branch 'master' of /home/trondmy/kernel/linux-2.6/
Diffstat (limited to 'net/bluetooth/hci_conn.c')
| -rw-r--r-- | net/bluetooth/hci_conn.c | 100 | 
1 files changed, 89 insertions, 11 deletions
| 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)  static void hci_conn_timeout(unsigned long arg)  { -	struct hci_conn *conn = (void *)arg; -	struct hci_dev  *hdev = conn->hdev; +	struct hci_conn *conn = (void *) arg; +	struct hci_dev *hdev = conn->hdev;  	BT_DBG("conn %p state %d", conn, conn->state); @@ -132,11 +132,13 @@ static void hci_conn_timeout(unsigned long arg)  	return;  } -static void hci_conn_init_timer(struct hci_conn *conn) +static void hci_conn_idle(unsigned long arg)  { -	init_timer(&conn->timer); -	conn->timer.function = hci_conn_timeout; -	conn->timer.data = (unsigned long)conn; +	struct hci_conn *conn = (void *) arg; + +	BT_DBG("conn %p mode %d", conn, conn->mode); + +	hci_conn_enter_sniff_mode(conn);  }  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)  	BT_DBG("%s dst %s", hdev->name, batostr(dst)); -	if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC))) +	conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); +	if (!conn)  		return NULL; -	memset(conn, 0, sizeof(struct hci_conn));  	bacpy(&conn->dst, dst); -	conn->type   = type;  	conn->hdev   = hdev; +	conn->type   = type; +	conn->mode   = HCI_CM_ACTIVE;  	conn->state  = BT_OPEN; +	conn->power_save = 1; +  	skb_queue_head_init(&conn->data_q); -	hci_conn_init_timer(conn); + +	init_timer(&conn->disc_timer); +	conn->disc_timer.function = hci_conn_timeout; +	conn->disc_timer.data = (unsigned long) conn; + +	init_timer(&conn->idle_timer); +	conn->idle_timer.function = hci_conn_idle; +	conn->idle_timer.data = (unsigned long) conn;  	atomic_set(&conn->refcnt, 0); @@ -178,7 +190,9 @@ int hci_conn_del(struct hci_conn *conn)  	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle); -	hci_conn_del_timer(conn); +	del_timer(&conn->idle_timer); + +	del_timer(&conn->disc_timer);  	if (conn->type == SCO_LINK) {  		struct hci_conn *acl = conn->link; @@ -364,6 +378,70 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)  }  EXPORT_SYMBOL(hci_conn_switch_role); +/* Enter active mode */ +void hci_conn_enter_active_mode(struct hci_conn *conn) +{ +	struct hci_dev *hdev = conn->hdev; + +	BT_DBG("conn %p mode %d", conn, conn->mode); + +	if (test_bit(HCI_RAW, &hdev->flags)) +		return; + +	if (conn->mode != HCI_CM_SNIFF || !conn->power_save) +		goto timer; + +	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { +		struct hci_cp_exit_sniff_mode cp; +		cp.handle = __cpu_to_le16(conn->handle); +		hci_send_cmd(hdev, OGF_LINK_POLICY, +				OCF_EXIT_SNIFF_MODE, sizeof(cp), &cp); +	} + +timer: +	if (hdev->idle_timeout > 0) +		mod_timer(&conn->idle_timer, +			jiffies + msecs_to_jiffies(hdev->idle_timeout)); +} + +/* Enter sniff mode */ +void hci_conn_enter_sniff_mode(struct hci_conn *conn) +{ +	struct hci_dev *hdev = conn->hdev; + +	BT_DBG("conn %p mode %d", conn, conn->mode); + +	if (test_bit(HCI_RAW, &hdev->flags)) +		return; + +	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn)) +		return; + +	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF)) +		return; + +	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) { +		struct hci_cp_sniff_subrate cp; +		cp.handle             = __cpu_to_le16(conn->handle); +		cp.max_latency        = __constant_cpu_to_le16(0); +		cp.min_remote_timeout = __constant_cpu_to_le16(0); +		cp.min_local_timeout  = __constant_cpu_to_le16(0); +		hci_send_cmd(hdev, OGF_LINK_POLICY, +				OCF_SNIFF_SUBRATE, sizeof(cp), &cp); +	} + +	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { +		struct hci_cp_sniff_mode cp; +		cp.handle       = __cpu_to_le16(conn->handle); +		cp.max_interval = __cpu_to_le16(hdev->sniff_max_interval); +		cp.min_interval = __cpu_to_le16(hdev->sniff_min_interval); +		cp.attempt      = __constant_cpu_to_le16(4); +		cp.timeout      = __constant_cpu_to_le16(1); +		hci_send_cmd(hdev, OGF_LINK_POLICY, +				OCF_SNIFF_MODE, sizeof(cp), &cp); +	} +} +  /* Drop all connection on the device */  void hci_conn_hash_flush(struct hci_dev *hdev)  { | 
