]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - net/bluetooth/hci_sysfs.c
[Bluetooth] Add platform device for virtual and serial devices
[mirror_ubuntu-jammy-kernel.git] / net / bluetooth / hci_sysfs.c
CommitLineData
1da177e4
LT
1/* Bluetooth HCI driver model support. */
2
1da177e4
LT
3#include <linux/kernel.h>
4#include <linux/init.h>
5
27d35284
MH
6#include <linux/platform_device.h>
7
1da177e4
LT
8#include <net/bluetooth/bluetooth.h>
9#include <net/bluetooth/hci_core.h>
10
11#ifndef CONFIG_BT_HCI_CORE_DEBUG
12#undef BT_DBG
13#define BT_DBG(D...)
14#endif
15
16static ssize_t show_name(struct class_device *cdev, char *buf)
17{
18 struct hci_dev *hdev = class_get_devdata(cdev);
19 return sprintf(buf, "%s\n", hdev->name);
20}
21
22static ssize_t show_type(struct class_device *cdev, char *buf)
23{
24 struct hci_dev *hdev = class_get_devdata(cdev);
25 return sprintf(buf, "%d\n", hdev->type);
26}
27
28static ssize_t show_address(struct class_device *cdev, char *buf)
29{
30 struct hci_dev *hdev = class_get_devdata(cdev);
31 bdaddr_t bdaddr;
32 baswap(&bdaddr, &hdev->bdaddr);
33 return sprintf(buf, "%s\n", batostr(&bdaddr));
34}
35
36static ssize_t show_flags(struct class_device *cdev, char *buf)
37{
38 struct hci_dev *hdev = class_get_devdata(cdev);
39 return sprintf(buf, "0x%lx\n", hdev->flags);
40}
41
42static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf)
43{
44 struct hci_dev *hdev = class_get_devdata(cdev);
45 struct inquiry_cache *cache = &hdev->inq_cache;
46 struct inquiry_entry *e;
47 int n = 0;
48
49 hci_dev_lock_bh(hdev);
50
51 for (e = cache->list; e; e = e->next) {
52 struct inquiry_data *data = &e->data;
53 bdaddr_t bdaddr;
54 baswap(&bdaddr, &data->bdaddr);
55 n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n",
56 batostr(&bdaddr),
57 data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode,
58 data->dev_class[2], data->dev_class[1], data->dev_class[0],
59 __le16_to_cpu(data->clock_offset), data->rssi, e->timestamp);
60 }
61
62 hci_dev_unlock_bh(hdev);
63 return n;
64}
65
04837f64
MH
66static ssize_t show_idle_timeout(struct class_device *cdev, char *buf)
67{
68 struct hci_dev *hdev = class_get_devdata(cdev);
69 return sprintf(buf, "%d\n", hdev->idle_timeout);
70}
71
72static ssize_t store_idle_timeout(struct class_device *cdev, const char *buf, size_t count)
73{
74 struct hci_dev *hdev = class_get_devdata(cdev);
75 char *ptr;
76 __u32 val;
77
78 val = simple_strtoul(buf, &ptr, 10);
79 if (ptr == buf)
80 return -EINVAL;
81
82 if (val != 0 && (val < 500 || val > 3600000))
83 return -EINVAL;
84
85 hdev->idle_timeout = val;
86
87 return count;
88}
89
90static ssize_t show_sniff_max_interval(struct class_device *cdev, char *buf)
91{
92 struct hci_dev *hdev = class_get_devdata(cdev);
93 return sprintf(buf, "%d\n", hdev->sniff_max_interval);
94}
95
96static ssize_t store_sniff_max_interval(struct class_device *cdev, const char *buf, size_t count)
97{
98 struct hci_dev *hdev = class_get_devdata(cdev);
99 char *ptr;
100 __u16 val;
101
102 val = simple_strtoul(buf, &ptr, 10);
103 if (ptr == buf)
104 return -EINVAL;
105
106 if (val < 0x0002 || val > 0xFFFE || val % 2)
107 return -EINVAL;
108
109 if (val < hdev->sniff_min_interval)
110 return -EINVAL;
111
112 hdev->sniff_max_interval = val;
113
114 return count;
115}
116
117static ssize_t show_sniff_min_interval(struct class_device *cdev, char *buf)
118{
119 struct hci_dev *hdev = class_get_devdata(cdev);
120 return sprintf(buf, "%d\n", hdev->sniff_min_interval);
121}
122
123static ssize_t store_sniff_min_interval(struct class_device *cdev, const char *buf, size_t count)
124{
125 struct hci_dev *hdev = class_get_devdata(cdev);
126 char *ptr;
127 __u16 val;
128
129 val = simple_strtoul(buf, &ptr, 10);
130 if (ptr == buf)
131 return -EINVAL;
132
133 if (val < 0x0002 || val > 0xFFFE || val % 2)
134 return -EINVAL;
135
136 if (val > hdev->sniff_max_interval)
137 return -EINVAL;
138
139 hdev->sniff_min_interval = val;
140
141 return count;
142}
143
1da177e4
LT
144static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
145static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
146static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
147static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
148static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
149
04837f64
MH
150static CLASS_DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
151 show_idle_timeout, store_idle_timeout);
152static CLASS_DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
153 show_sniff_max_interval, store_sniff_max_interval);
154static CLASS_DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
155 show_sniff_min_interval, store_sniff_min_interval);
156
1da177e4
LT
157static struct class_device_attribute *bt_attrs[] = {
158 &class_device_attr_name,
159 &class_device_attr_type,
160 &class_device_attr_address,
161 &class_device_attr_flags,
162 &class_device_attr_inquiry_cache,
04837f64
MH
163 &class_device_attr_idle_timeout,
164 &class_device_attr_sniff_max_interval,
165 &class_device_attr_sniff_min_interval,
1da177e4
LT
166 NULL
167};
168
169#ifdef CONFIG_HOTPLUG
312c004d 170static int bt_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
1da177e4
LT
171{
172 struct hci_dev *hdev = class_get_devdata(cdev);
173 int n, i = 0;
174
175 envp[i++] = buf;
176 n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1;
177 buf += n;
178 size -= n;
179
180 if ((size <= 0) || (i >= num_envp))
181 return -ENOMEM;
182
183 envp[i] = NULL;
184 return 0;
185}
186#endif
187
188static void bt_release(struct class_device *cdev)
189{
190 struct hci_dev *hdev = class_get_devdata(cdev);
191
192 kfree(hdev);
193}
194
be9d1227 195struct class bt_class = {
1da177e4
LT
196 .name = "bluetooth",
197 .release = bt_release,
198#ifdef CONFIG_HOTPLUG
312c004d 199 .uevent = bt_uevent,
1da177e4
LT
200#endif
201};
be9d1227
MH
202EXPORT_SYMBOL_GPL(bt_class);
203
27d35284
MH
204static struct bus_type bt_bus = {
205 .name = "bluetooth",
206};
207
208static struct platform_device *bt_platform;
209
1da177e4
LT
210int hci_register_sysfs(struct hci_dev *hdev)
211{
212 struct class_device *cdev = &hdev->class_dev;
213 unsigned int i;
214 int err;
215
216 BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
217
218 cdev->class = &bt_class;
219 class_set_devdata(cdev, hdev);
220
27d35284
MH
221 if (!cdev->dev)
222 cdev->dev = &bt_platform->dev;
223
224 hdev->dev = cdev->dev;
225
1da177e4
LT
226 strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE);
227 err = class_device_register(cdev);
228 if (err < 0)
229 return err;
230
231 for (i = 0; bt_attrs[i]; i++)
232 class_device_create_file(cdev, bt_attrs[i]);
233
234 return 0;
235}
236
237void hci_unregister_sysfs(struct hci_dev *hdev)
238{
239 struct class_device * cdev = &hdev->class_dev;
240
241 BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
242
243 class_device_del(cdev);
244}
245
246int __init bt_sysfs_init(void)
247{
27d35284
MH
248 int err;
249
250 bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
251 if (IS_ERR(bt_platform))
252 return PTR_ERR(bt_platform);
253
254 err = bus_register(&bt_bus);
255 if (err < 0) {
256 platform_device_unregister(bt_platform);
257 return err;
258 }
259
260 err = class_register(&bt_class);
261 if (err < 0) {
262 bus_unregister(&bt_bus);
263 platform_device_unregister(bt_platform);
264 return err;
265 }
266
267 return 0;
1da177e4
LT
268}
269
270void __exit bt_sysfs_cleanup(void)
271{
272 class_unregister(&bt_class);
27d35284
MH
273
274 bus_unregister(&bt_bus);
275
276 platform_device_unregister(bt_platform);
1da177e4 277}