162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Bluetooth HCI driver model support. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
762306a36Sopenharmony_ci#include <net/bluetooth/hci_core.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_cistatic const struct class bt_class = {
1062306a36Sopenharmony_ci	.name = "bluetooth",
1162306a36Sopenharmony_ci};
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistatic void bt_link_release(struct device *dev)
1462306a36Sopenharmony_ci{
1562306a36Sopenharmony_ci	struct hci_conn *conn = to_hci_conn(dev);
1662306a36Sopenharmony_ci	kfree(conn);
1762306a36Sopenharmony_ci}
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic const struct device_type bt_link = {
2062306a36Sopenharmony_ci	.name    = "link",
2162306a36Sopenharmony_ci	.release = bt_link_release,
2262306a36Sopenharmony_ci};
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci/*
2562306a36Sopenharmony_ci * The rfcomm tty device will possibly retain even when conn
2662306a36Sopenharmony_ci * is down, and sysfs doesn't support move zombie device,
2762306a36Sopenharmony_ci * so we should move the device before conn device is destroyed.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistatic int __match_tty(struct device *dev, void *data)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	return !strncmp(dev_name(dev), "rfcomm", 6);
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_civoid hci_conn_init_sysfs(struct hci_conn *conn)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	conn->dev.type = &bt_link;
4162306a36Sopenharmony_ci	conn->dev.class = &bt_class;
4262306a36Sopenharmony_ci	conn->dev.parent = &hdev->dev;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	device_initialize(&conn->dev);
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_civoid hci_conn_add_sysfs(struct hci_conn *conn)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	if (device_is_registered(&conn->dev))
5462306a36Sopenharmony_ci		return;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (device_add(&conn->dev) < 0)
5962306a36Sopenharmony_ci		bt_dev_err(hdev, "failed to register connection device");
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_civoid hci_conn_del_sysfs(struct hci_conn *conn)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	if (!device_is_registered(&conn->dev)) {
6962306a36Sopenharmony_ci		/* If device_add() has *not* succeeded, use *only* put_device()
7062306a36Sopenharmony_ci		 * to drop the reference count.
7162306a36Sopenharmony_ci		 */
7262306a36Sopenharmony_ci		put_device(&conn->dev);
7362306a36Sopenharmony_ci		return;
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	while (1) {
7762306a36Sopenharmony_ci		struct device *dev;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		dev = device_find_child(&conn->dev, NULL, __match_tty);
8062306a36Sopenharmony_ci		if (!dev)
8162306a36Sopenharmony_ci			break;
8262306a36Sopenharmony_ci		device_move(dev, NULL, DPM_ORDER_DEV_LAST);
8362306a36Sopenharmony_ci		put_device(dev);
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	device_unregister(&conn->dev);
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_cistatic void bt_host_release(struct device *dev)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	struct hci_dev *hdev = to_hci_dev(dev);
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
9462306a36Sopenharmony_ci		hci_release_dev(hdev);
9562306a36Sopenharmony_ci	else
9662306a36Sopenharmony_ci		kfree(hdev);
9762306a36Sopenharmony_ci	module_put(THIS_MODULE);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic const struct device_type bt_host = {
10162306a36Sopenharmony_ci	.name    = "host",
10262306a36Sopenharmony_ci	.release = bt_host_release,
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_civoid hci_init_sysfs(struct hci_dev *hdev)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	struct device *dev = &hdev->dev;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	dev->type = &bt_host;
11062306a36Sopenharmony_ci	dev->class = &bt_class;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	__module_get(THIS_MODULE);
11362306a36Sopenharmony_ci	device_initialize(dev);
11462306a36Sopenharmony_ci}
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ciint __init bt_sysfs_init(void)
11762306a36Sopenharmony_ci{
11862306a36Sopenharmony_ci	return class_register(&bt_class);
11962306a36Sopenharmony_ci}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_civoid bt_sysfs_cleanup(void)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	class_unregister(&bt_class);
12462306a36Sopenharmony_ci}
125