hci_sysfs.c 5.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/* Bluetooth HCI driver model support. */

3
#include <linux/module.h>
L
Linus Torvalds 已提交
4 5 6 7

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

8
static struct class *bt_class;
9 10 11 12 13 14 15 16 17 18

static inline char *link_typetostr(int type)
{
	switch (type) {
	case ACL_LINK:
		return "ACL";
	case SCO_LINK:
		return "SCO";
	case ESCO_LINK:
		return "eSCO";
19 20
	case LE_LINK:
		return "LE";
21 22 23 24 25
	default:
		return "UNKNOWN";
	}
}

26 27
static ssize_t show_link_type(struct device *dev,
			      struct device_attribute *attr, char *buf)
28
{
29
	struct hci_conn *conn = to_hci_conn(dev);
30 31 32
	return sprintf(buf, "%s\n", link_typetostr(conn->type));
}

33 34
static ssize_t show_link_address(struct device *dev,
				 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 41
#define LINK_ATTR(_name, _mode, _show, _store) \
struct device_attribute link_attr_##_name = __ATTR(_name, _mode, _show, _store)
42 43 44 45 46 47 48 49 50 51 52 53 54 55

static LINK_ATTR(type, S_IRUGO, show_link_type, NULL);
static LINK_ATTR(address, S_IRUGO, show_link_address, NULL);

static struct attribute *bt_link_attrs[] = {
	&link_attr_type.attr,
	&link_attr_address.attr,
	NULL
};

static struct attribute_group bt_link_group = {
	.attrs = bt_link_attrs,
};

56
static const struct attribute_group *bt_link_groups[] = {
57 58 59 60 61 62
	&bt_link_group,
	NULL
};

static void bt_link_release(struct device *dev)
{
63 64
	struct hci_conn *conn = to_hci_conn(dev);
	kfree(conn);
65 66 67 68 69 70 71 72
}

static struct device_type bt_link = {
	.name    = "link",
	.groups  = bt_link_groups,
	.release = bt_link_release,
};

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/*
 * The rfcomm tty device will possibly retain even when conn
 * is down, and sysfs doesn't support move zombie device,
 * so we should move the device before conn device is destroyed.
 */
static int __match_tty(struct device *dev, void *data)
{
	return !strncmp(dev_name(dev), "rfcomm", 6);
}

void hci_conn_init_sysfs(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("conn %p", conn);

	conn->dev.type = &bt_link;
	conn->dev.class = bt_class;
	conn->dev.parent = &hdev->dev;

	device_initialize(&conn->dev);
}

void hci_conn_add_sysfs(struct hci_conn *conn)
97
{
98
	struct hci_dev *hdev = conn->hdev;
99

100 101
	BT_DBG("conn %p", conn);

102 103
	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);

104 105 106 107
	if (device_add(&conn->dev) < 0) {
		BT_ERR("Failed to register connection device");
		return;
	}
108 109

	hci_dev_hold(hdev);
110 111
}

112
void hci_conn_del_sysfs(struct hci_conn *conn)
113 114 115
{
	struct hci_dev *hdev = conn->hdev;

116 117
	if (!device_is_registered(&conn->dev))
		return;
118

119 120 121 122 123 124
	while (1) {
		struct device *dev;

		dev = device_find_child(&conn->dev, NULL, __match_tty);
		if (!dev)
			break;
125
		device_move(dev, NULL, DPM_ORDER_DEV_LAST);
126 127 128 129
		put_device(dev);
	}

	device_del(&conn->dev);
130

131 132 133
	hci_dev_put(hdev);
}

134
static inline char *host_bustostr(int bus)
L
Linus Torvalds 已提交
135
{
136
	switch (bus) {
137
	case HCI_VIRTUAL:
138 139 140 141 142 143 144 145 146 147 148
		return "VIRTUAL";
	case HCI_USB:
		return "USB";
	case HCI_PCCARD:
		return "PCCARD";
	case HCI_UART:
		return "UART";
	case HCI_RS232:
		return "RS232";
	case HCI_PCI:
		return "PCI";
149 150
	case HCI_SDIO:
		return "SDIO";
151 152 153
	default:
		return "UNKNOWN";
	}
L
Linus Torvalds 已提交
154 155
}

156 157 158 159 160
static inline char *host_typetostr(int type)
{
	switch (type) {
	case HCI_BREDR:
		return "BR/EDR";
161 162
	case HCI_AMP:
		return "AMP";
163 164 165 166 167
	default:
		return "UNKNOWN";
	}
}

168 169
static ssize_t show_bus(struct device *dev,
			struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
170
{
171
	struct hci_dev *hdev = to_hci_dev(dev);
172
	return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
L
Linus Torvalds 已提交
173 174
}

175 176
static ssize_t show_type(struct device *dev,
			 struct device_attribute *attr, char *buf)
177
{
178
	struct hci_dev *hdev = to_hci_dev(dev);
179 180 181
	return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
}

182 183
static ssize_t show_name(struct device *dev,
			 struct device_attribute *attr, char *buf)
184
{
185
	struct hci_dev *hdev = to_hci_dev(dev);
186
	char name[HCI_MAX_NAME_LENGTH + 1];
187 188
	int i;

189
	for (i = 0; i < HCI_MAX_NAME_LENGTH; i++)
190 191
		name[i] = hdev->dev_name[i];

192
	name[HCI_MAX_NAME_LENGTH] = '\0';
193 194 195
	return sprintf(buf, "%s\n", name);
}

196 197
static ssize_t show_address(struct device *dev,
			    struct device_attribute *attr, char *buf)
L
Linus Torvalds 已提交
198
{
199
	struct hci_dev *hdev = to_hci_dev(dev);
200
	return sprintf(buf, "%pMR\n", &hdev->bdaddr);
L
Linus Torvalds 已提交
201 202
}

203
static DEVICE_ATTR(bus, S_IRUGO, show_bus, NULL);
204
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
205
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
206
static DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
L
Linus Torvalds 已提交
207

208
static struct attribute *bt_host_attrs[] = {
209
	&dev_attr_bus.attr,
210
	&dev_attr_type.attr,
211 212
	&dev_attr_name.attr,
	&dev_attr_address.attr,
L
Linus Torvalds 已提交
213 214 215
	NULL
};

216 217
static struct attribute_group bt_host_group = {
	.attrs = bt_host_attrs,
218 219
};

220
static const struct attribute_group *bt_host_groups[] = {
221 222
	&bt_host_group,
	NULL
223 224
};

225
static void bt_host_release(struct device *dev)
226
{
227 228
	struct hci_dev *hdev = to_hci_dev(dev);
	kfree(hdev);
229
	module_put(THIS_MODULE);
230 231
}

232 233 234 235 236
static struct device_type bt_host = {
	.name    = "host",
	.groups  = bt_host_groups,
	.release = bt_host_release,
};
237

238 239 240 241 242 243 244
void hci_init_sysfs(struct hci_dev *hdev)
{
	struct device *dev = &hdev->dev;

	dev->type = &bt_host;
	dev->class = bt_class;

245
	__module_get(THIS_MODULE);
246 247 248
	device_initialize(dev);
}

L
Linus Torvalds 已提交
249 250
int __init bt_sysfs_init(void)
{
251
	bt_class = class_create(THIS_MODULE, "bluetooth");
252

253
	return PTR_ERR_OR_ZERO(bt_class);
L
Linus Torvalds 已提交
254 255
}

256
void bt_sysfs_cleanup(void)
L
Linus Torvalds 已提交
257
{
258
	class_destroy(bt_class);
L
Linus Torvalds 已提交
259
}