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