Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[sfrench/cifs-2.6.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 ATTRIBUTE_GROUPS(bt_link);
53
54 static void bt_link_release(struct device *dev)
55 {
56         struct hci_conn *conn = to_hci_conn(dev);
57         kfree(conn);
58 }
59
60 static struct device_type bt_link = {
61         .name    = "link",
62         .groups  = bt_link_groups,
63         .release = bt_link_release,
64 };
65
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)
90 {
91         struct hci_dev *hdev = conn->hdev;
92
93         BT_DBG("conn %p", conn);
94
95         dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
96
97         if (device_add(&conn->dev) < 0) {
98                 BT_ERR("Failed to register connection device");
99                 return;
100         }
101
102         hci_dev_hold(hdev);
103 }
104
105 void hci_conn_del_sysfs(struct hci_conn *conn)
106 {
107         struct hci_dev *hdev = conn->hdev;
108
109         if (!device_is_registered(&conn->dev))
110                 return;
111
112         while (1) {
113                 struct device *dev;
114
115                 dev = device_find_child(&conn->dev, NULL, __match_tty);
116                 if (!dev)
117                         break;
118                 device_move(dev, NULL, DPM_ORDER_DEV_LAST);
119                 put_device(dev);
120         }
121
122         device_del(&conn->dev);
123
124         hci_dev_put(hdev);
125 }
126
127 static inline char *host_typetostr(int type)
128 {
129         switch (type) {
130         case HCI_BREDR:
131                 return "BR/EDR";
132         case HCI_AMP:
133                 return "AMP";
134         default:
135                 return "UNKNOWN";
136         }
137 }
138
139 static ssize_t show_type(struct device *dev,
140                          struct device_attribute *attr, char *buf)
141 {
142         struct hci_dev *hdev = to_hci_dev(dev);
143         return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
144 }
145
146 static ssize_t show_name(struct device *dev,
147                          struct device_attribute *attr, char *buf)
148 {
149         struct hci_dev *hdev = to_hci_dev(dev);
150         char name[HCI_MAX_NAME_LENGTH + 1];
151         int i;
152
153         for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
154                 name[i] = hdev->dev_name[i];
155
156         name[HCI_MAX_NAME_LENGTH] = '\0';
157         return sprintf(buf, "%s\n", name);
158 }
159
160 static ssize_t show_address(struct device *dev,
161                             struct device_attribute *attr, char *buf)
162 {
163         struct hci_dev *hdev = to_hci_dev(dev);
164         return sprintf(buf, "%pMR\n", &hdev->bdaddr);
165 }
166
167 static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
168 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
169 static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
170
171 static struct attribute *bt_host_attrs[] = {
172         &dev_attr_type.attr,
173         &dev_attr_name.attr,
174         &dev_attr_address.attr,
175         NULL
176 };
177
178 ATTRIBUTE_GROUPS(bt_host);
179
180 static void bt_host_release(struct device *dev)
181 {
182         struct hci_dev *hdev = to_hci_dev(dev);
183         kfree(hdev);
184         module_put(THIS_MODULE);
185 }
186
187 static struct device_type bt_host = {
188         .name    = "host",
189         .groups  = bt_host_groups,
190         .release = bt_host_release,
191 };
192
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
200         __module_get(THIS_MODULE);
201         device_initialize(dev);
202 }
203
204 int __init bt_sysfs_init(void)
205 {
206         bt_class = class_create(THIS_MODULE, "bluetooth");
207
208         return PTR_ERR_OR_ZERO(bt_class);
209 }
210
211 void bt_sysfs_cleanup(void)
212 {
213         class_destroy(bt_class);
214 }