Commit | Line | Data |
---|---|---|
903e4541 AE |
1 | /* |
2 | Copyright (c) 2011,2012 Intel Corp. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License version 2 and | |
6 | only version 2 as published by the Free Software Foundation. | |
7 | ||
8 | This program is distributed in the hope that it will be useful, | |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | GNU General Public License for more details. | |
12 | */ | |
13 | ||
14 | #include <net/bluetooth/bluetooth.h> | |
15 | #include <net/bluetooth/hci.h> | |
16 | #include <net/bluetooth/hci_core.h> | |
17 | #include <net/bluetooth/a2mp.h> | |
18 | #include <net/bluetooth/amp.h> | |
19 | ||
52c0d6e5 AE |
20 | /* Remote AMP Controllers interface */ |
21 | static void amp_ctrl_get(struct amp_ctrl *ctrl) | |
22 | { | |
23 | BT_DBG("ctrl %p orig refcnt %d", ctrl, | |
24 | atomic_read(&ctrl->kref.refcount)); | |
25 | ||
26 | kref_get(&ctrl->kref); | |
27 | } | |
28 | ||
29 | static void amp_ctrl_destroy(struct kref *kref) | |
30 | { | |
31 | struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref); | |
32 | ||
33 | BT_DBG("ctrl %p", ctrl); | |
34 | ||
35 | kfree(ctrl->assoc); | |
36 | kfree(ctrl); | |
37 | } | |
38 | ||
39 | int amp_ctrl_put(struct amp_ctrl *ctrl) | |
40 | { | |
41 | BT_DBG("ctrl %p orig refcnt %d", ctrl, | |
42 | atomic_read(&ctrl->kref.refcount)); | |
43 | ||
44 | return kref_put(&ctrl->kref, &_ctrl_destroy); | |
45 | } | |
46 | ||
47 | struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr) | |
48 | { | |
49 | struct amp_ctrl *ctrl; | |
50 | ||
51 | ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); | |
52 | if (!ctrl) | |
53 | return NULL; | |
54 | ||
55 | mutex_lock(&mgr->amp_ctrls_lock); | |
56 | list_add(&ctrl->list, &mgr->amp_ctrls); | |
57 | mutex_unlock(&mgr->amp_ctrls_lock); | |
58 | ||
59 | kref_init(&ctrl->kref); | |
60 | ||
61 | BT_DBG("mgr %p ctrl %p", mgr, ctrl); | |
62 | ||
63 | return ctrl; | |
64 | } | |
65 | ||
66 | void amp_ctrl_list_flush(struct amp_mgr *mgr) | |
67 | { | |
68 | struct amp_ctrl *ctrl, *n; | |
69 | ||
70 | BT_DBG("mgr %p", mgr); | |
71 | ||
72 | mutex_lock(&mgr->amp_ctrls_lock); | |
73 | list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) { | |
74 | list_del(&ctrl->list); | |
75 | amp_ctrl_put(ctrl); | |
76 | } | |
77 | mutex_unlock(&mgr->amp_ctrls_lock); | |
78 | } | |
79 | ||
80 | struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id) | |
81 | { | |
82 | struct amp_ctrl *ctrl; | |
83 | ||
84 | BT_DBG("mgr %p id %d", mgr, id); | |
85 | ||
86 | mutex_lock(&mgr->amp_ctrls_lock); | |
87 | list_for_each_entry(ctrl, &mgr->amp_ctrls, list) { | |
88 | if (ctrl->id == id) { | |
89 | amp_ctrl_get(ctrl); | |
90 | mutex_unlock(&mgr->amp_ctrls_lock); | |
91 | return ctrl; | |
92 | } | |
93 | } | |
94 | mutex_unlock(&mgr->amp_ctrls_lock); | |
95 | ||
96 | return NULL; | |
97 | } | |
98 | ||
3161ae1c AE |
99 | /* Physical Link interface */ |
100 | static u8 __next_handle(struct amp_mgr *mgr) | |
101 | { | |
102 | if (++mgr->handle == 0) | |
103 | mgr->handle = 1; | |
104 | ||
105 | return mgr->handle; | |
106 | } | |
107 | ||
108 | struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr, | |
109 | u8 remote_id) | |
110 | { | |
111 | bdaddr_t *dst = mgr->l2cap_conn->dst; | |
112 | struct hci_conn *hcon; | |
113 | ||
114 | hcon = hci_conn_add(hdev, AMP_LINK, dst); | |
115 | if (!hcon) | |
116 | return NULL; | |
117 | ||
118 | hcon->state = BT_CONNECT; | |
119 | hcon->out = true; | |
120 | hcon->attempt++; | |
121 | hcon->handle = __next_handle(mgr); | |
122 | hcon->remote_id = remote_id; | |
123 | hcon->amp_mgr = mgr; | |
124 | ||
125 | return hcon; | |
126 | } | |
127 | ||
903e4541 AE |
128 | void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle) |
129 | { | |
130 | struct hci_cp_read_local_amp_assoc cp; | |
131 | struct amp_assoc *loc_assoc = &hdev->loc_assoc; | |
132 | ||
133 | BT_DBG("%s handle %d", hdev->name, phy_handle); | |
134 | ||
135 | cp.phy_handle = phy_handle; | |
136 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); | |
137 | cp.len_so_far = cpu_to_le16(loc_assoc->offset); | |
138 | ||
139 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | |
140 | } | |
141 | ||
142 | void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) | |
143 | { | |
144 | struct hci_cp_read_local_amp_assoc cp; | |
145 | ||
146 | memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); | |
147 | memset(&cp, 0, sizeof(cp)); | |
148 | ||
149 | cp.max_len = cpu_to_le16(hdev->amp_assoc_size); | |
150 | ||
151 | mgr->state = READ_LOC_AMP_ASSOC; | |
152 | hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); | |
153 | } |