hci_sysfs.c revision 4d0eb0049ce94101f7f169f89216ba58475219e2
1/* Bluetooth HCI driver model support. */
2
3#include <linux/kernel.h>
4#include <linux/init.h>
5
6#include <linux/platform_device.h>
7
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 inline char *typetostr(int type)
17{
18	switch (type) {
19	case HCI_VHCI:
20		return "VIRTUAL";
21	case HCI_USB:
22		return "USB";
23	case HCI_PCCARD:
24		return "PCCARD";
25	case HCI_UART:
26		return "UART";
27	case HCI_RS232:
28		return "RS232";
29	case HCI_PCI:
30		return "PCI";
31	default:
32		return "UNKNOWN";
33	}
34}
35
36static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
37{
38	struct hci_dev *hdev = dev_get_drvdata(dev);
39	return sprintf(buf, "%s\n", typetostr(hdev->type));
40}
41
42static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
43{
44	struct hci_dev *hdev = dev_get_drvdata(dev);
45	bdaddr_t bdaddr;
46	baswap(&bdaddr, &hdev->bdaddr);
47	return sprintf(buf, "%s\n", batostr(&bdaddr));
48}
49
50static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
51{
52	struct hci_dev *hdev = dev_get_drvdata(dev);
53	struct inquiry_cache *cache = &hdev->inq_cache;
54	struct inquiry_entry *e;
55	int n = 0;
56
57	hci_dev_lock_bh(hdev);
58
59	for (e = cache->list; e; e = e->next) {
60		struct inquiry_data *data = &e->data;
61		bdaddr_t bdaddr;
62		baswap(&bdaddr, &data->bdaddr);
63		n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n",
64				batostr(&bdaddr),
65				data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode,
66				data->dev_class[2], data->dev_class[1], data->dev_class[0],
67				__le16_to_cpu(data->clock_offset), data->rssi, e->timestamp);
68	}
69
70	hci_dev_unlock_bh(hdev);
71	return n;
72}
73
74static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
75{
76	struct hci_dev *hdev = dev_get_drvdata(dev);
77	return sprintf(buf, "%d\n", hdev->idle_timeout);
78}
79
80static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
81{
82	struct hci_dev *hdev = dev_get_drvdata(dev);
83	char *ptr;
84	__u32 val;
85
86	val = simple_strtoul(buf, &ptr, 10);
87	if (ptr == buf)
88		return -EINVAL;
89
90	if (val != 0 && (val < 500 || val > 3600000))
91		return -EINVAL;
92
93	hdev->idle_timeout = val;
94
95	return count;
96}
97
98static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
99{
100	struct hci_dev *hdev = dev_get_drvdata(dev);
101	return sprintf(buf, "%d\n", hdev->sniff_max_interval);
102}
103
104static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
105{
106	struct hci_dev *hdev = dev_get_drvdata(dev);
107	char *ptr;
108	__u16 val;
109
110	val = simple_strtoul(buf, &ptr, 10);
111	if (ptr == buf)
112		return -EINVAL;
113
114	if (val < 0x0002 || val > 0xFFFE || val % 2)
115		return -EINVAL;
116
117	if (val < hdev->sniff_min_interval)
118		return -EINVAL;
119
120	hdev->sniff_max_interval = val;
121
122	return count;
123}
124
125static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
126{
127	struct hci_dev *hdev = dev_get_drvdata(dev);
128	return sprintf(buf, "%d\n", hdev->sniff_min_interval);
129}
130
131static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
132{
133	struct hci_dev *hdev = dev_get_drvdata(dev);
134	char *ptr;
135	__u16 val;
136
137	val = simple_strtoul(buf, &ptr, 10);
138	if (ptr == buf)
139		return -EINVAL;
140
141	if (val < 0x0002 || val > 0xFFFE || val % 2)
142		return -EINVAL;
143
144	if (val > hdev->sniff_max_interval)
145		return -EINVAL;
146
147	hdev->sniff_min_interval = val;
148
149	return count;
150}
151
152static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
153static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
154static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
155
156static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
157				show_idle_timeout, store_idle_timeout);
158static DEVICE_ATTR(sniff_max_interval, S_IRUGO | S_IWUSR,
159				show_sniff_max_interval, store_sniff_max_interval);
160static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
161				show_sniff_min_interval, store_sniff_min_interval);
162
163static struct device_attribute *bt_attrs[] = {
164	&dev_attr_type,
165	&dev_attr_address,
166	&dev_attr_inquiry_cache,
167	&dev_attr_idle_timeout,
168	&dev_attr_sniff_max_interval,
169	&dev_attr_sniff_min_interval,
170	NULL
171};
172
173struct class *bt_class = NULL;
174EXPORT_SYMBOL_GPL(bt_class);
175
176static struct bus_type bt_bus = {
177	.name	= "bluetooth",
178};
179
180static struct platform_device *bt_platform;
181
182static void bt_release(struct device *dev)
183{
184	struct hci_dev *hdev = dev_get_drvdata(dev);
185	kfree(hdev);
186}
187
188int hci_register_sysfs(struct hci_dev *hdev)
189{
190	struct device *dev = &hdev->dev;
191	unsigned int i;
192	int err;
193
194	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
195
196	dev->class = bt_class;
197
198	if (hdev->parent)
199		dev->parent = hdev->parent;
200	else
201		dev->parent = &bt_platform->dev;
202
203	strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE);
204
205	dev->release = bt_release;
206
207	dev_set_drvdata(dev, hdev);
208
209	err = device_register(dev);
210	if (err < 0)
211		return err;
212
213	for (i = 0; bt_attrs[i]; i++)
214		device_create_file(dev, bt_attrs[i]);
215
216	return 0;
217}
218
219void hci_unregister_sysfs(struct hci_dev *hdev)
220{
221	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
222
223	device_del(&hdev->dev);
224}
225
226int __init bt_sysfs_init(void)
227{
228	int err;
229
230	bt_platform = platform_device_register_simple("bluetooth", -1, NULL, 0);
231	if (IS_ERR(bt_platform))
232		return PTR_ERR(bt_platform);
233
234	err = bus_register(&bt_bus);
235	if (err < 0) {
236		platform_device_unregister(bt_platform);
237		return err;
238	}
239
240	bt_class = class_create(THIS_MODULE, "bluetooth");
241	if (IS_ERR(bt_class)) {
242		bus_unregister(&bt_bus);
243		platform_device_unregister(bt_platform);
244		return PTR_ERR(bt_class);
245	}
246
247	return 0;
248}
249
250void __exit bt_sysfs_cleanup(void)
251{
252	class_destroy(bt_class);
253
254	bus_unregister(&bt_bus);
255
256	platform_device_unregister(bt_platform);
257}
258