aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/bluetooth/hci_core.h6
-rw-r--r--net/bluetooth/hci_conn.c8
-rw-r--r--net/bluetooth/hci_sysfs.c79
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
413int hci_register_sysfs(struct hci_dev *hdev); 417int hci_register_sysfs(struct hci_dev *hdev);
414void hci_unregister_sysfs(struct hci_dev *hdev); 418void hci_unregister_sysfs(struct hci_dev *hdev);
419void hci_conn_add_sysfs(struct hci_conn *conn);
420void 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
173static 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
179static 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) \
188struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)
189
190static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
191static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);
192
193static struct device_attribute *conn_attrs[] = {
194 &conn_attr_type,
195 &conn_attr_address,
196 NULL
197};
198
173struct class *bt_class = NULL; 199struct class *bt_class = NULL;
174EXPORT_SYMBOL_GPL(bt_class); 200EXPORT_SYMBOL_GPL(bt_class);
175 201
@@ -181,8 +207,57 @@ static struct platform_device *bt_platform;
181 207
182static void bt_release(struct device *dev) 208static 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
214static 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
225void 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
248static void del_conn(void *data)
249{
250 struct hci_conn *conn = data;
251 device_del(&conn->dev);
252}
253
254void 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
188int hci_register_sysfs(struct hci_dev *hdev) 263int hci_register_sysfs(struct hci_dev *hdev)