aboutsummaryrefslogtreecommitdiff
path: root/net/bluetooth/hci_sysfs.c
blob: 19b234c86f33ac686e1f63b9924db9cd967513f2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
/* Bluetooth HCI driver model support. */

#include <linux/kernel.h>
#include <linux/init.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

#ifndef CONFIG_BT_HCI_CORE_DEBUG
#undef  BT_DBG
#define BT_DBG(D...)
#endif

static ssize_t show_name(struct class_device *cdev, char *buf)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	return sprintf(buf, "%s\n", hdev->name);
}

static ssize_t show_type(struct class_device *cdev, char *buf)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	return sprintf(buf, "%d\n", hdev->type);
}

static ssize_t show_address(struct class_device *cdev, char *buf)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	bdaddr_t bdaddr;
	baswap(&bdaddr, &hdev->bdaddr);
	return sprintf(buf, "%s\n", batostr(&bdaddr));
}

static ssize_t show_flags(struct class_device *cdev, char *buf)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	return sprintf(buf, "0x%lx\n", hdev->flags);
}

static ssize_t show_inquiry_cache(struct class_device *cdev, char *buf)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	struct inquiry_cache *cache = &hdev->inq_cache;
	struct inquiry_entry *e;
	int n = 0;

	hci_dev_lock_bh(hdev);

	for (e = cache->list; e; e = e->next) {
		struct inquiry_data *data = &e->data;
		bdaddr_t bdaddr;
		baswap(&bdaddr, &data->bdaddr);
		n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %u\n",
				batostr(&bdaddr),
				data->pscan_rep_mode, data->pscan_period_mode, data->pscan_mode,
				data->dev_class[2], data->dev_class[1], data->dev_class[0],
				__le16_to_cpu(data->clock_offset), data->rssi, e->timestamp);
	}

	hci_dev_unlock_bh(hdev);
	return n;
}

static CLASS_DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static CLASS_DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
static CLASS_DEVICE_ATTR(flags, S_IRUGO, show_flags, NULL);
static CLASS_DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);

static struct class_device_attribute *bt_attrs[] = {
	&class_device_attr_name,
	&class_device_attr_type,
	&class_device_attr_address,
	&class_device_attr_flags,
	&class_device_attr_inquiry_cache,
	NULL
};

#ifdef CONFIG_HOTPLUG
static int bt_uevent(struct class_device *cdev, char **envp, int num_envp, char *buf, int size)
{
	struct hci_dev *hdev = class_get_devdata(cdev);
	int n, i = 0;

	envp[i++] = buf;
	n = snprintf(buf, size, "INTERFACE=%s", hdev->name) + 1;
	buf += n;
	size -= n;

	if ((size <= 0) || (i >= num_envp))
		return -ENOMEM;

	envp[i] = NULL;
	return 0;
}
#endif

static void bt_release(struct class_device *cdev)
{
	struct hci_dev *hdev = class_get_devdata(cdev);

	kfree(hdev);
}

struct class bt_class = {
	.name		= "bluetooth",
	.release	= bt_release,
#ifdef CONFIG_HOTPLUG
	.uevent		= bt_uevent,
#endif
};

EXPORT_SYMBOL_GPL(bt_class);

int hci_register_sysfs(struct hci_dev *hdev)
{
	struct class_device *cdev = &hdev->class_dev;
	unsigned int i;
	int err;

	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);

	cdev->class = &bt_class;
	class_set_devdata(cdev, hdev);

	strlcpy(cdev->class_id, hdev->name, BUS_ID_SIZE);
	err = class_device_register(cdev);
	if (err < 0)
		return err;

	for (i = 0; bt_attrs[i]; i++)
		class_device_create_file(cdev, bt_attrs[i]);

	return 0;
}

void hci_unregister_sysfs(struct hci_dev *hdev)
{
	struct class_device * cdev = &hdev->class_dev;

	BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);

	class_device_del(cdev);
}

int __init bt_sysfs_init(void)
{
	return class_register(&bt_class);
}

void __exit bt_sysfs_cleanup(void)
{
	class_unregister(&bt_class);
}