Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b219e3ac authored by Marcel Holtmann's avatar Marcel Holtmann Committed by David S. Miller
Browse files

[Bluetooth] Integrate low-level connections into the driver model



This patch integrates the low-level connections (ACL and SCO) into the
driver model. Every connection is presented as device with the parent
set to its host controller device.

Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 4d0eb004
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -165,6 +165,10 @@ struct hci_conn {
	struct timer_list disc_timer;
	struct timer_list idle_timer;

	struct work_struct work;

	struct device	dev;

	struct hci_dev	*hdev;
	void		*l2cap_data;
	void		*sco_data;
@@ -412,6 +416,8 @@ static inline int hci_recv_frame(struct sk_buff *skb)

int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);

#define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->parent = (pdev))

+7 −1
Original line number Diff line number Diff line
@@ -179,6 +179,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);

	hci_conn_add_sysfs(conn);

	tasklet_enable(&hdev->tx_task);

	return conn;
@@ -211,6 +213,8 @@ int hci_conn_del(struct hci_conn *conn)

	tasklet_disable(&hdev->tx_task);

	hci_conn_del_sysfs(conn);

	hci_conn_hash_del(hdev, conn);
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
@@ -221,7 +225,9 @@ int hci_conn_del(struct hci_conn *conn)

	hci_dev_put(hdev);

	kfree(conn);
	/* will free via device release */
	put_device(&conn->dev);

	return 0;
}

+77 −2
Original line number Diff line number Diff line
@@ -170,6 +170,32 @@ static struct device_attribute *bt_attrs[] = {
	NULL
};

static ssize_t show_conn_type(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct hci_conn *conn = dev_get_drvdata(dev);
	return sprintf(buf, "%s\n", conn->type == ACL_LINK ? "ACL" : "SCO");
}

static ssize_t show_conn_address(struct device *dev, struct device_attribute *attr, char *buf)
{
	struct hci_conn *conn = dev_get_drvdata(dev);
	bdaddr_t bdaddr;
	baswap(&bdaddr, &conn->dst);
	return sprintf(buf, "%s\n", batostr(&bdaddr));
}

#define CONN_ATTR(_name,_mode,_show,_store) \
struct device_attribute conn_attr_##_name = __ATTR(_name,_mode,_show,_store)

static CONN_ATTR(type, S_IRUGO, show_conn_type, NULL);
static CONN_ATTR(address, S_IRUGO, show_conn_address, NULL);

static struct device_attribute *conn_attrs[] = {
	&conn_attr_type,
	&conn_attr_address,
	NULL
};

struct class *bt_class = NULL;
EXPORT_SYMBOL_GPL(bt_class);

@@ -181,8 +207,57 @@ static struct platform_device *bt_platform;

static void bt_release(struct device *dev)
{
	struct hci_dev *hdev = dev_get_drvdata(dev);
	kfree(hdev);
	void *data = dev_get_drvdata(dev);
	kfree(data);
}

static void add_conn(void *data)
{
	struct hci_conn *conn = data;
	int i;

	device_register(&conn->dev);

	for (i = 0; conn_attrs[i]; i++)
		device_create_file(&conn->dev, conn_attrs[i]);
}

void hci_conn_add_sysfs(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;
	bdaddr_t *ba = &conn->dst;

	BT_DBG("conn %p", conn);

	conn->dev.parent  = &hdev->dev;
	conn->dev.release = bt_release;

	snprintf(conn->dev.bus_id, BUS_ID_SIZE,
			"%s%2.2X%2.2X%2.2X%2.2X%2.2X%2.2X",
			conn->type == ACL_LINK ? "acl" : "sco",
			ba->b[5], ba->b[4], ba->b[3],
			ba->b[2], ba->b[1], ba->b[0]);

	dev_set_drvdata(&conn->dev, conn);

	INIT_WORK(&conn->work, add_conn, (void *) conn);

	schedule_work(&conn->work);
}

static void del_conn(void *data)
{
	struct hci_conn *conn = data;
	device_del(&conn->dev);
}

void hci_conn_del_sysfs(struct hci_conn *conn)
{
	BT_DBG("conn %p", conn);

	INIT_WORK(&conn->work, del_conn, (void *) conn);

	schedule_work(&conn->work);
}

int hci_register_sysfs(struct hci_dev *hdev)