diff options
-rw-r--r-- | include/net/bluetooth/hci_core.h | 6 | ||||
-rw-r--r-- | net/bluetooth/hci_conn.c | 8 | ||||
-rw-r--r-- | net/bluetooth/hci_sysfs.c | 79 |
3 files changed, 90 insertions, 3 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index d84855fe7336..263e42b68e8d 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -165,6 +165,10 @@ struct hci_conn { | |||
165 | struct timer_list disc_timer; | 165 | struct timer_list disc_timer; |
166 | struct timer_list idle_timer; | 166 | struct timer_list idle_timer; |
167 | 167 | ||
168 | struct work_struct work; | ||
169 | |||
170 | struct device dev; | ||
171 | |||
168 | struct hci_dev *hdev; | 172 | struct hci_dev *hdev; |
169 | void *l2cap_data; | 173 | void *l2cap_data; |
170 | void *sco_data; | 174 | void *sco_data; |
@@ -412,6 +416,8 @@ static inline int hci_recv_frame(struct sk_buff *skb) | |||
412 | 416 | ||
413 | int hci_register_sysfs(struct hci_dev *hdev); | 417 | int hci_register_sysfs(struct hci_dev *hdev); |
414 | void hci_unregister_sysfs(struct hci_dev *hdev); | 418 | void hci_unregister_sysfs(struct hci_dev *hdev); |
419 | void hci_conn_add_sysfs(struct hci_conn *conn); | ||
420 | void hci_conn_del_sysfs(struct hci_conn *conn); | ||
415 | 421 | ||
416 | #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) | 422 | #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev)) |
417 | 423 | ||
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 420ed4d7e57e..7e9515b41cc0 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c | |||
@@ -179,6 +179,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) | |||
179 | if (hdev->notify) | 179 | if (hdev->notify) |
180 | hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); | 180 | hdev->notify(hdev, HCI_NOTIFY_CONN_ADD); |
181 | 181 | ||
182 | hci_conn_add_sysfs(conn); | ||
183 | |||
182 | tasklet_enable(&hdev->tx_task); | 184 | tasklet_enable(&hdev->tx_task); |
183 | 185 | ||
184 | return conn; | 186 | return conn; |
@@ -211,6 +213,8 @@ int hci_conn_del(struct hci_conn *conn) | |||
211 | 213 | ||
212 | tasklet_disable(&hdev->tx_task); | 214 | tasklet_disable(&hdev->tx_task); |
213 | 215 | ||
216 | hci_conn_del_sysfs(conn); | ||
217 | |||
214 | hci_conn_hash_del(hdev, conn); | 218 | hci_conn_hash_del(hdev, conn); |
215 | if (hdev->notify) | 219 | if (hdev->notify) |
216 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); | 220 | hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); |
@@ -221,7 +225,9 @@ int hci_conn_del(struct hci_conn *conn) | |||
221 | 225 | ||
222 | hci_dev_put(hdev); | 226 | hci_dev_put(hdev); |
223 | 227 | ||
224 | kfree(conn); | 228 | /* will free via device release */ |
229 | put_device(&conn->dev); | ||
230 | |||
225 | return 0; | 231 | return 0; |
226 | } | 232 | } |
227 | 233 | ||
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3ccb4b0b8fc2..58df4360d242 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c | |||
@@ -170,6 +170,32 @@ static struct device_attribute *bt_attrs[] = { | |||
170 | NULL | 170 | NULL |
171 | }; | 171 | }; |
172 | 172 | ||
173 | static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf) | ||
174 | { | ||
175 | struct hci_conn *conn = dev_get_drvdata(dev); | ||
176 | return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO"); | ||
177 | } | ||
178 | |||
179 | static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf) | ||
180 | { | ||
181 | struct hci_conn *conn = dev_get_drvdata(dev); | ||
182 | bdaddr_t bdaddr; | ||
183 | baswap(&bdaddr, &conn->dst); | ||
184 | return sprintf(buf, "%s\n", batostr(&bdaddr)); | ||
185 | } | ||
186 | |||
187 | #define CONN_ATTR(_name,_mode,_show,_store) \ | ||
188 | struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store) | ||
189 | |||
190 | static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL); | ||
191 | static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL); | ||
192 | |||
193 | static struct device_attribute *conn_attrs[] = { | ||
194 | &conn_attr_type, | ||
195 | &conn_attr_address, | ||
196 | NULL | ||
197 | }; | ||
198 | |||
173 | struct class *bt_class = NULL; | 199 | struct class *bt_class = NULL; |
174 | EXPORT_SYMBOL_GPL(bt_class); | 200 | EXPORT_SYMBOL_GPL(bt_class); |
175 | 201 | ||
@@ -181,8 +207,57 @@ static struct platform_device *bt_platform; | |||
181 | 207 | ||
182 | static void bt_release(struct device *dev) | 208 | static void bt_release(struct device *dev) |
183 | { | 209 | { |
184 | struct hci_dev *hdev = dev_get_drvdata(dev); | 210 | void *data = dev_get_drvdata(dev); |
185 | kfree(hdev); | 211 | kfree(data); |
212 | } | ||
213 | |||
214 | static void add_conn(void *data) | ||
215 | { | ||
216 | struct hci_conn *conn = data; | ||
217 | int i; | ||
218 | |||
219 | device_register(&conn->dev); | ||
220 | |||
221 | for (i = 0; conn_attrs[i]; i++) | ||
222 | device_create_file(&conn->dev, conn_attrs[i]); | ||
223 | } | ||
224 | |||
225 | void hci_conn_add_sysfs(struct hci_conn *conn) | ||
226 | { | ||
227 | struct hci_dev *hdev = conn->hdev; | ||
228 | bdaddr_t *ba = &conn->dst; | ||
229 | |||
230 | BT_DBG("conn %p", conn); | ||
231 | |||
232 | conn->dev.parent = &hdev->dev; | ||
233 | conn->dev.release = bt_release; | ||
234 | |||
235 | snprintf(conn->dev.bus_id, BUS_ID_SIZE, | ||
236 | "%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X", | ||
237 | conn->type == ACL_LINK ? "acl" : "sco", | ||
238 | ba->b[5], ba->b[4], ba->b[3], | ||
239 | ba->b[2], ba->b[1], ba->b[0]); | ||
240 | |||
241 | dev_set_drvdata(&conn->dev, conn); | ||
242 | |||
243 | INIT_WORK(&conn->work, add_conn, (void *) conn); | ||
244 | |||
245 | schedule_work(&conn->work); | ||
246 | } | ||
247 | |||
248 | static void del_conn(void *data) | ||
249 | { | ||
250 | struct hci_conn *conn = data; | ||
251 | device_del(&conn->dev); | ||
252 | } | ||
253 | |||
254 | void hci_conn_del_sysfs(struct hci_conn *conn) | ||
255 | { | ||
256 | BT_DBG("conn %p", conn); | ||
257 | |||
258 | INIT_WORK(&conn->work, del_conn, (void *) conn); | ||
259 | |||
260 | schedule_work(&conn->work); | ||
186 | } | 261 | } |
187 | 262 | ||
188 | int hci_register_sysfs(struct hci_dev *hdev) | 263 | int hci_register_sysfs(struct hci_dev *hdev) |