blob: 4fac57c5ddb7a104cde63c9d0ca83d61d4151410 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* Bluetooth HCI driver model support. */
2
Paul Gortmaker3a9a2312011-05-27 09:12:25 -04003#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5#include <net/bluetooth/bluetooth.h>
6#include <net/bluetooth/hci_core.h>
7
Marcel Holtmannaef7d972010-03-21 05:27:45 +01008static struct class *bt_class;
Marcel Holtmann90855d72008-08-18 13:23:53 +02009
Marcel Holtmann90855d72008-08-18 13:23:53 +020010static inline char *link_typetostr(int type)
11{
12 switch (type) {
13 case ACL_LINK:
14 return "ACL";
15 case SCO_LINK:
16 return "SCO";
17 case ESCO_LINK:
18 return "eSCO";
Peter Hurley21061df2011-08-24 10:04:56 -040019 case LE_LINK:
20 return "LE";
Marcel Holtmann90855d72008-08-18 13:23:53 +020021 default:
22 return "UNKNOWN";
23 }
24}
25
Gustavo Padovanb80f0212012-05-17 00:36:23 -030026static ssize_t show_link_type(struct device *dev,
27 struct device_attribute *attr, char *buf)
Marcel Holtmann90855d72008-08-18 13:23:53 +020028{
David Herrmann3dc07322012-02-09 21:58:33 +010029 struct hci_conn *conn = to_hci_conn(dev);
Marcel Holtmann90855d72008-08-18 13:23:53 +020030 return sprintf(buf, "%s\n", link_typetostr(conn->type));
31}
32
Gustavo Padovanb80f0212012-05-17 00:36:23 -030033static ssize_t show_link_address(struct device *dev,
34 struct device_attribute *attr, char *buf)
Marcel Holtmann90855d72008-08-18 13:23:53 +020035{
David Herrmann3dc07322012-02-09 21:58:33 +010036 struct hci_conn *conn = to_hci_conn(dev);
Andrei Emeltchenkofcb73332012-09-25 12:49:44 +030037 return sprintf(buf, "%pMR\n", &conn->dst);
Marcel Holtmann90855d72008-08-18 13:23:53 +020038}
39
Gustavo Padovanb80f0212012-05-17 00:36:23 -030040static ssize_t show_link_features(struct device *dev,
41 struct device_attribute *attr, char *buf)
Marcel Holtmann90855d72008-08-18 13:23:53 +020042{
David Herrmann3dc07322012-02-09 21:58:33 +010043 struct hci_conn *conn = to_hci_conn(dev);
Marcel Holtmann90855d72008-08-18 13:23:53 +020044
45 return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
Johan Hedbergcad718e2013-04-17 15:00:51 +030046 conn->features[0][0], conn->features[0][1],
47 conn->features[0][2], conn->features[0][3],
48 conn->features[0][4], conn->features[0][5],
49 conn->features[0][6], conn->features[0][7]);
Marcel Holtmann90855d72008-08-18 13:23:53 +020050}
51
Gustavo F. Padovan602f9882011-02-17 19:22:19 -030052#define LINK_ATTR(_name, _mode, _show, _store) \
53struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store)
Marcel Holtmann90855d72008-08-18 13:23:53 +020054
55static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
56static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);
57static LINK_ATTR(features, S_IRUGO, show_link_features, NULL);
58
59static struct attribute *bt_link_attrs[] = {
60 &link_attr_type.attr,
61 &link_attr_address.attr,
62 &link_attr_features.attr,
63 NULL
64};
65
66static struct attribute_group bt_link_group = {
67 .attrs = bt_link_attrs,
68};
69
David Brownella4dbd672009-06-24 10:06:31 -070070static const struct attribute_group *bt_link_groups[] = {
Marcel Holtmann90855d72008-08-18 13:23:53 +020071 &bt_link_group,
72 NULL
73};
74
75static void bt_link_release(struct device *dev)
76{
David Herrmann2dd10682012-02-09 21:58:34 +010077 struct hci_conn *conn = to_hci_conn(dev);
78 kfree(conn);
Marcel Holtmann90855d72008-08-18 13:23:53 +020079}
80
81static struct device_type bt_link = {
82 .name = "link",
83 .groups = bt_link_groups,
84 .release = bt_link_release,
85};
86
Gustavo F. Padovan6d438e32011-12-17 18:53:02 -020087/*
88 * The rfcomm tty device will possibly retain even when conn
89 * is down, and sysfs doesn't support move zombie device,
90 * so we should move the device before conn device is destroyed.
91 */
92static int __match_tty(struct device *dev, void *data)
Marcel Holtmann90855d72008-08-18 13:23:53 +020093{
Gustavo F. Padovan6d438e32011-12-17 18:53:02 -020094 return !strncmp(dev_name(dev), "rfcomm", 6);
95}
96
97void hci_conn_init_sysfs(struct hci_conn *conn)
98{
Marcel Holtmann457ca7b2009-05-05 13:09:01 -070099 struct hci_dev *hdev = conn->hdev;
Marcel Holtmann90855d72008-08-18 13:23:53 +0200100
Gustavo F. Padovan6d438e32011-12-17 18:53:02 -0200101 BT_DBG("conn %p", conn);
102
103 conn->dev.type = &bt_link;
104 conn->dev.class = bt_class;
105 conn->dev.parent = &hdev->dev;
106
107 device_initialize(&conn->dev);
108}
109
110void hci_conn_add_sysfs(struct hci_conn *conn)
111{
112 struct hci_dev *hdev = conn->hdev;
113
114 BT_DBG("conn %p", conn);
115
Marcel Holtmann457ca7b2009-05-05 13:09:01 -0700116 dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
117
Marcel Holtmann90855d72008-08-18 13:23:53 +0200118 if (device_add(&conn->dev) < 0) {
119 BT_ERR("Failed to register connection device");
120 return;
121 }
Marcel Holtmann384943e2009-05-08 18:20:43 -0700122
123 hci_dev_hold(hdev);
Marcel Holtmann90855d72008-08-18 13:23:53 +0200124}
125
Gustavo F. Padovan6d438e32011-12-17 18:53:02 -0200126void hci_conn_del_sysfs(struct hci_conn *conn)
Marcel Holtmann90855d72008-08-18 13:23:53 +0200127{
Marcel Holtmann90855d72008-08-18 13:23:53 +0200128 struct hci_dev *hdev = conn->hdev;
129
Marcel Holtmanna67e8992009-05-02 18:24:06 -0700130 if (!device_is_registered(&conn->dev))
131 return;
Roger Quadrosf3784d82009-04-23 14:50:54 +0300132
Marcel Holtmann90855d72008-08-18 13:23:53 +0200133 while (1) {
134 struct device *dev;
135
136 dev = device_find_child(&conn->dev, NULL, __match_tty);
137 if (!dev)
138 break;
Cornelia Huckffa6a702009-03-04 12:44:00 +0100139 device_move(dev, NULL, DPM_ORDER_DEV_LAST);
Marcel Holtmann90855d72008-08-18 13:23:53 +0200140 put_device(dev);
141 }
142
143 device_del(&conn->dev);
Marcel Holtmann384943e2009-05-08 18:20:43 -0700144
Marcel Holtmann90855d72008-08-18 13:23:53 +0200145 hci_dev_put(hdev);
146}
147
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100148static inline char *host_bustostr(int bus)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149{
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100150 switch (bus) {
Marcel Holtmann0ac53932006-07-08 13:57:15 +0200151 case HCI_VIRTUAL:
Marcel Holtmann4d0eb002006-07-06 12:34:41 +0200152 return "VIRTUAL";
153 case HCI_USB:
154 return "USB";
155 case HCI_PCCARD:
156 return "PCCARD";
157 case HCI_UART:
158 return "UART";
159 case HCI_RS232:
160 return "RS232";
161 case HCI_PCI:
162 return "PCI";
Marcel Holtmann0ac53932006-07-08 13:57:15 +0200163 case HCI_SDIO:
164 return "SDIO";
Marcel Holtmann4d0eb002006-07-06 12:34:41 +0200165 default:
166 return "UNKNOWN";
167 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168}
169
Marcel Holtmann943da252010-02-13 02:28:41 +0100170static inline char *host_typetostr(int type)
171{
172 switch (type) {
173 case HCI_BREDR:
174 return "BR/EDR";
David Vrabel8f1e1742010-08-09 17:38:10 -0400175 case HCI_AMP:
176 return "AMP";
Marcel Holtmann943da252010-02-13 02:28:41 +0100177 default:
178 return "UNKNOWN";
179 }
180}
181
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300182static ssize_t show_bus(struct device *dev,
183 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100185 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100186 return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187}
188
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300189static ssize_t show_type(struct device *dev,
190 struct device_attribute *attr, char *buf)
Marcel Holtmann943da252010-02-13 02:28:41 +0100191{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100192 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmann943da252010-02-13 02:28:41 +0100193 return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
194}
195
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300196static ssize_t show_name(struct device *dev,
197 struct device_attribute *attr, char *buf)
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200198{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100199 struct hci_dev *hdev = to_hci_dev(dev);
Johan Hedberg1f6c6372011-03-16 14:29:35 +0200200 char name[HCI_MAX_NAME_LENGTH + 1];
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200201 int i;
202
Johan Hedberg1f6c6372011-03-16 14:29:35 +0200203 for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200204 name[i] = hdev->dev_name[i];
205
Johan Hedberg1f6c6372011-03-16 14:29:35 +0200206 name[HCI_MAX_NAME_LENGTH] = '\0';
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200207 return sprintf(buf, "%s\n", name);
208}
209
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300210static ssize_t show_class(struct device *dev,
211 struct device_attribute *attr, char *buf)
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200212{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100213 struct hci_dev *hdev = to_hci_dev(dev);
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300214 return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
215 hdev->dev_class[1], hdev->dev_class[0]);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200216}
217
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300218static ssize_t show_address(struct device *dev,
219 struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100221 struct hci_dev *hdev = to_hci_dev(dev);
Andrei Emeltchenkofcb73332012-09-25 12:49:44 +0300222 return sprintf(buf, "%pMR\n", &hdev->bdaddr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223}
224
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300225static ssize_t show_features(struct device *dev,
226 struct device_attribute *attr, char *buf)
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200227{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100228 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200229
230 return sprintf(buf, "0x%02x%02x%02x%02x%02x%02x%02x%02x\n",
Johan Hedbergcad718e2013-04-17 15:00:51 +0300231 hdev->features[0][0], hdev->features[0][1],
232 hdev->features[0][2], hdev->features[0][3],
233 hdev->features[0][4], hdev->features[0][5],
234 hdev->features[0][6], hdev->features[0][7]);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200235}
236
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300237static ssize_t show_manufacturer(struct device *dev,
238 struct device_attribute *attr, char *buf)
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200239{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100240 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200241 return sprintf(buf, "%d\n", hdev->manufacturer);
242}
243
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300244static ssize_t show_hci_version(struct device *dev,
245 struct device_attribute *attr, char *buf)
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200246{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100247 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200248 return sprintf(buf, "%d\n", hdev->hci_ver);
249}
250
Gustavo Padovanb80f0212012-05-17 00:36:23 -0300251static ssize_t show_hci_revision(struct device *dev,
252 struct device_attribute *attr, char *buf)
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200253{
David Herrmannaa2b86d2012-02-09 21:58:30 +0100254 struct hci_dev *hdev = to_hci_dev(dev);
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200255 return sprintf(buf, "%d\n", hdev->hci_rev);
256}
257
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100258static DEVICE_ATTR(bus, S_IRUGO, show_bus, NULL);
Marcel Holtmann943da252010-02-13 02:28:41 +0100259static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200260static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
261static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
Marcel Holtmanna91f2e32006-07-03 10:02:41 +0200262static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200263static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
Marcel Holtmann1143e5a2006-09-23 09:57:20 +0200264static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
265static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
266static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267
Marcel Holtmann90855d72008-08-18 13:23:53 +0200268static struct attribute *bt_host_attrs[] = {
Marcel Holtmannc13854c2010-02-08 15:27:07 +0100269 &dev_attr_bus.attr,
Marcel Holtmann943da252010-02-13 02:28:41 +0100270 &dev_attr_type.attr,
Marcel Holtmann90855d72008-08-18 13:23:53 +0200271 &dev_attr_name.attr,
272 &dev_attr_class.attr,
273 &dev_attr_address.attr,
274 &dev_attr_features.attr,
275 &dev_attr_manufacturer.attr,
276 &dev_attr_hci_version.attr,
277 &dev_attr_hci_revision.attr,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700278 NULL
279};
280
Marcel Holtmann90855d72008-08-18 13:23:53 +0200281static struct attribute_group bt_host_group = {
282 .attrs = bt_host_attrs,
283};
Marcel Holtmannb219e3a2006-07-06 12:38:46 +0200284
David Brownella4dbd672009-06-24 10:06:31 -0700285static const struct attribute_group *bt_host_groups[] = {
Marcel Holtmann90855d72008-08-18 13:23:53 +0200286 &bt_host_group,
Marcel Holtmannb219e3a2006-07-06 12:38:46 +0200287 NULL
288};
289
Marcel Holtmann90855d72008-08-18 13:23:53 +0200290static void bt_host_release(struct device *dev)
Marcel Holtmanna91f2e32006-07-03 10:02:41 +0200291{
David Herrmann2dd10682012-02-09 21:58:34 +0100292 struct hci_dev *hdev = to_hci_dev(dev);
293 kfree(hdev);
David Herrmann46e06532012-01-07 15:47:21 +0100294 module_put(THIS_MODULE);
Marcel Holtmannb219e3a2006-07-06 12:38:46 +0200295}
296
Marcel Holtmann90855d72008-08-18 13:23:53 +0200297static struct device_type bt_host = {
298 .name = "host",
299 .groups = bt_host_groups,
300 .release = bt_host_release,
301};
Marcel Holtmanna91f2e32006-07-03 10:02:41 +0200302
David Herrmann0ac7e702011-10-08 14:58:47 +0200303void hci_init_sysfs(struct hci_dev *hdev)
304{
305 struct device *dev = &hdev->dev;
306
307 dev->type = &bt_host;
308 dev->class = bt_class;
309
David Herrmann46e06532012-01-07 15:47:21 +0100310 __module_get(THIS_MODULE);
David Herrmann0ac7e702011-10-08 14:58:47 +0200311 device_initialize(dev);
312}
313
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314int __init bt_sysfs_init(void)
315{
Marcel Holtmanna91f2e32006-07-03 10:02:41 +0200316 bt_class = class_create(THIS_MODULE, "bluetooth");
Marcel Holtmann27d35282006-07-03 10:02:37 +0200317
Rusty Russell8c6ffba2013-07-15 11:20:32 +0930318 return PTR_ERR_OR_ZERO(bt_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319}
320
Arnaud Patard860e13b2006-09-28 15:29:37 -0700321void bt_sysfs_cleanup(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700322{
Marcel Holtmanna91f2e32006-07-03 10:02:41 +0200323 class_destroy(bt_class);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324}