Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* Bluetooth HCI driver model support. */ |
2 | ||
3a9a231d | 3 | #include <linux/module.h> |
1da177e4 LT |
4 | |
5 | #include <net/bluetooth/bluetooth.h> | |
6 | #include <net/bluetooth/hci_core.h> | |
7 | ||
aef7d97c | 8 | static struct class *bt_class; |
90855d7b | 9 | |
90855d7b MH |
10 | static 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"; | |
21061df3 PH |
19 | case LE_LINK: |
20 | return "LE"; | |
90855d7b MH |
21 | default: |
22 | return "UNKNOWN"; | |
23 | } | |
24 | } | |
25 | ||
b80f021f GP |
26 | static ssize_t show_link_type(struct device *dev, |
27 | struct device_attribute *attr, char *buf) | |
90855d7b | 28 | { |
3dc07322 | 29 | struct hci_conn *conn = to_hci_conn(dev); |
90855d7b MH |
30 | return sprintf(buf, "%s\n", link_typetostr(conn->type)); |
31 | } | |
32 | ||
b80f021f GP |
33 | static ssize_t show_link_address(struct device *dev, |
34 | struct device_attribute *attr, char *buf) | |
90855d7b | 35 | { |
3dc07322 | 36 | struct hci_conn *conn = to_hci_conn(dev); |
fcb73338 | 37 | return sprintf(buf, "%pMR\n", &conn->dst); |
90855d7b MH |
38 | } |
39 | ||
602f9887 GP |
40 | #define LINK_ATTR(_name, _mode, _show, _store) \ |
41 | struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store) | |
90855d7b MH |
42 | |
43 | static LINK_ATTR(type, S_IRUGO, show_link_type, NULL); | |
44 | static LINK_ATTR(address, S_IRUGO, show_link_address, NULL); | |
90855d7b MH |
45 | |
46 | static struct attribute *bt_link_attrs[] = { | |
47 | &link_attr_type.attr, | |
48 | &link_attr_address.attr, | |
90855d7b MH |
49 | NULL |
50 | }; | |
51 | ||
b848079a | 52 | ATTRIBUTE_GROUPS(bt_link); |
90855d7b MH |
53 | |
54 | static void bt_link_release(struct device *dev) | |
55 | { | |
2dd10688 DH |
56 | struct hci_conn *conn = to_hci_conn(dev); |
57 | kfree(conn); | |
90855d7b MH |
58 | } |
59 | ||
60 | static struct device_type bt_link = { | |
61 | .name = "link", | |
62 | .groups = bt_link_groups, | |
63 | .release = bt_link_release, | |
64 | }; | |
65 | ||
6d438e33 GP |
66 | /* |
67 | * The rfcomm tty device will possibly retain even when conn | |
68 | * is down, and sysfs doesn't support move zombie device, | |
69 | * so we should move the device before conn device is destroyed. | |
70 | */ | |
71 | static int __match_tty(struct device *dev, void *data) | |
72 | { | |
73 | return !strncmp(dev_name(dev), "rfcomm", 6); | |
74 | } | |
75 | ||
76 | void hci_conn_init_sysfs(struct hci_conn *conn) | |
77 | { | |
78 | struct hci_dev *hdev = conn->hdev; | |
79 | ||
80 | BT_DBG("conn %p", conn); | |
81 | ||
82 | conn->dev.type = &bt_link; | |
83 | conn->dev.class = bt_class; | |
84 | conn->dev.parent = &hdev->dev; | |
85 | ||
86 | device_initialize(&conn->dev); | |
87 | } | |
88 | ||
89 | void hci_conn_add_sysfs(struct hci_conn *conn) | |
90855d7b | 90 | { |
457ca7bb | 91 | struct hci_dev *hdev = conn->hdev; |
90855d7b | 92 | |
6d438e33 GP |
93 | BT_DBG("conn %p", conn); |
94 | ||
457ca7bb MH |
95 | dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); |
96 | ||
90855d7b MH |
97 | if (device_add(&conn->dev) < 0) { |
98 | BT_ERR("Failed to register connection device"); | |
99 | return; | |
100 | } | |
384943ec MH |
101 | |
102 | hci_dev_hold(hdev); | |
90855d7b MH |
103 | } |
104 | ||
6d438e33 | 105 | void hci_conn_del_sysfs(struct hci_conn *conn) |
90855d7b | 106 | { |
90855d7b MH |
107 | struct hci_dev *hdev = conn->hdev; |
108 | ||
a67e899c MH |
109 | if (!device_is_registered(&conn->dev)) |
110 | return; | |
f3784d83 | 111 | |
90855d7b MH |
112 | while (1) { |
113 | struct device *dev; | |
114 | ||
115 | dev = device_find_child(&conn->dev, NULL, __match_tty); | |
116 | if (!dev) | |
117 | break; | |
ffa6a705 | 118 | device_move(dev, NULL, DPM_ORDER_DEV_LAST); |
90855d7b MH |
119 | put_device(dev); |
120 | } | |
121 | ||
122 | device_del(&conn->dev); | |
384943ec | 123 | |
90855d7b MH |
124 | hci_dev_put(hdev); |
125 | } | |
126 | ||
943da25d MH |
127 | static inline char *host_typetostr(int type) |
128 | { | |
129 | switch (type) { | |
130 | case HCI_BREDR: | |
131 | return "BR/EDR"; | |
8f1e1742 DV |
132 | case HCI_AMP: |
133 | return "AMP"; | |
943da25d MH |
134 | default: |
135 | return "UNKNOWN"; | |
136 | } | |
137 | } | |
138 | ||
b80f021f GP |
139 | static ssize_t show_type(struct device *dev, |
140 | struct device_attribute *attr, char *buf) | |
943da25d | 141 | { |
aa2b86d7 | 142 | struct hci_dev *hdev = to_hci_dev(dev); |
943da25d MH |
143 | return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type)); |
144 | } | |
145 | ||
b80f021f GP |
146 | static ssize_t show_name(struct device *dev, |
147 | struct device_attribute *attr, char *buf) | |
a9de9248 | 148 | { |
aa2b86d7 | 149 | struct hci_dev *hdev = to_hci_dev(dev); |
1f6c6378 | 150 | char name[HCI_MAX_NAME_LENGTH + 1]; |
a9de9248 MH |
151 | int i; |
152 | ||
1f6c6378 | 153 | for (i = 0; i < HCI_MAX_NAME_LENGTH; i++) |
a9de9248 MH |
154 | name[i] = hdev->dev_name[i]; |
155 | ||
1f6c6378 | 156 | name[HCI_MAX_NAME_LENGTH] = '\0'; |
a9de9248 MH |
157 | return sprintf(buf, "%s\n", name); |
158 | } | |
159 | ||
b80f021f GP |
160 | static ssize_t show_address(struct device *dev, |
161 | struct device_attribute *attr, char *buf) | |
1da177e4 | 162 | { |
aa2b86d7 | 163 | struct hci_dev *hdev = to_hci_dev(dev); |
fcb73338 | 164 | return sprintf(buf, "%pMR\n", &hdev->bdaddr); |
1da177e4 LT |
165 | } |
166 | ||
943da25d | 167 | static DEVICE_ATTR(type, S_IRUGO, show_type, NULL); |
a9de9248 | 168 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); |
a91f2e39 | 169 | static DEVICE_ATTR(address, S_IRUGO, show_address, NULL); |
1da177e4 | 170 | |
90855d7b | 171 | static struct attribute *bt_host_attrs[] = { |
943da25d | 172 | &dev_attr_type.attr, |
90855d7b | 173 | &dev_attr_name.attr, |
90855d7b | 174 | &dev_attr_address.attr, |
1da177e4 LT |
175 | NULL |
176 | }; | |
177 | ||
b848079a | 178 | ATTRIBUTE_GROUPS(bt_host); |
27d35284 | 179 | |
90855d7b | 180 | static void bt_host_release(struct device *dev) |
a91f2e39 | 181 | { |
2dd10688 DH |
182 | struct hci_dev *hdev = to_hci_dev(dev); |
183 | kfree(hdev); | |
46e06531 | 184 | module_put(THIS_MODULE); |
b219e3ac MH |
185 | } |
186 | ||
90855d7b MH |
187 | static struct device_type bt_host = { |
188 | .name = "host", | |
189 | .groups = bt_host_groups, | |
190 | .release = bt_host_release, | |
191 | }; | |
a91f2e39 | 192 | |
0ac7e700 DH |
193 | void hci_init_sysfs(struct hci_dev *hdev) |
194 | { | |
195 | struct device *dev = &hdev->dev; | |
196 | ||
197 | dev->type = &bt_host; | |
198 | dev->class = bt_class; | |
199 | ||
46e06531 | 200 | __module_get(THIS_MODULE); |
0ac7e700 DH |
201 | device_initialize(dev); |
202 | } | |
203 | ||
1da177e4 LT |
204 | int __init bt_sysfs_init(void) |
205 | { | |
a91f2e39 | 206 | bt_class = class_create(THIS_MODULE, "bluetooth"); |
27d35284 | 207 | |
8c6ffba0 | 208 | return PTR_ERR_OR_ZERO(bt_class); |
1da177e4 LT |
209 | } |
210 | ||
860e13b5 | 211 | void bt_sysfs_cleanup(void) |
1da177e4 | 212 | { |
a91f2e39 | 213 | class_destroy(bt_class); |
1da177e4 | 214 | } |