18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/* Bluetooth HCI driver model support. */
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/module.h>
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <net/bluetooth/bluetooth.h>
78c2ecf20Sopenharmony_ci#include <net/bluetooth/hci_core.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_cistatic struct class *bt_class;
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_cistatic void bt_link_release(struct device *dev)
128c2ecf20Sopenharmony_ci{
138c2ecf20Sopenharmony_ci	struct hci_conn *conn = to_hci_conn(dev);
148c2ecf20Sopenharmony_ci	kfree(conn);
158c2ecf20Sopenharmony_ci}
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_cistatic const struct device_type bt_link = {
188c2ecf20Sopenharmony_ci	.name    = "link",
198c2ecf20Sopenharmony_ci	.release = bt_link_release,
208c2ecf20Sopenharmony_ci};
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/*
238c2ecf20Sopenharmony_ci * The rfcomm tty device will possibly retain even when conn
248c2ecf20Sopenharmony_ci * is down, and sysfs doesn't support move zombie device,
258c2ecf20Sopenharmony_ci * so we should move the device before conn device is destroyed.
268c2ecf20Sopenharmony_ci */
278c2ecf20Sopenharmony_cistatic int __match_tty(struct device *dev, void *data)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	return !strncmp(dev_name(dev), "rfcomm", 6);
308c2ecf20Sopenharmony_ci}
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_civoid hci_conn_init_sysfs(struct hci_conn *conn)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	conn->dev.type = &bt_link;
398c2ecf20Sopenharmony_ci	conn->dev.class = bt_class;
408c2ecf20Sopenharmony_ci	conn->dev.parent = &hdev->dev;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	device_initialize(&conn->dev);
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_civoid hci_conn_add_sysfs(struct hci_conn *conn)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	if (device_is_registered(&conn->dev))
528c2ecf20Sopenharmony_ci		return;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci	if (device_add(&conn->dev) < 0)
578c2ecf20Sopenharmony_ci		bt_dev_err(hdev, "failed to register connection device");
588c2ecf20Sopenharmony_ci}
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_civoid hci_conn_del_sysfs(struct hci_conn *conn)
618c2ecf20Sopenharmony_ci{
628c2ecf20Sopenharmony_ci	struct hci_dev *hdev = conn->hdev;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	bt_dev_dbg(hdev, "conn %p", conn);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (!device_is_registered(&conn->dev)) {
678c2ecf20Sopenharmony_ci		/* If device_add() has *not* succeeded, use *only* put_device()
688c2ecf20Sopenharmony_ci		 * to drop the reference count.
698c2ecf20Sopenharmony_ci		 */
708c2ecf20Sopenharmony_ci		put_device(&conn->dev);
718c2ecf20Sopenharmony_ci		return;
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci	while (1) {
758c2ecf20Sopenharmony_ci		struct device *dev;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci		dev = device_find_child(&conn->dev, NULL, __match_tty);
788c2ecf20Sopenharmony_ci		if (!dev)
798c2ecf20Sopenharmony_ci			break;
808c2ecf20Sopenharmony_ci		device_move(dev, NULL, DPM_ORDER_DEV_LAST);
818c2ecf20Sopenharmony_ci		put_device(dev);
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	device_unregister(&conn->dev);
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic void bt_host_release(struct device *dev)
888c2ecf20Sopenharmony_ci{
898c2ecf20Sopenharmony_ci	struct hci_dev *hdev = to_hci_dev(dev);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
928c2ecf20Sopenharmony_ci		hci_cleanup_dev(hdev);
938c2ecf20Sopenharmony_ci	kfree(hdev);
948c2ecf20Sopenharmony_ci	module_put(THIS_MODULE);
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic const struct device_type bt_host = {
988c2ecf20Sopenharmony_ci	.name    = "host",
998c2ecf20Sopenharmony_ci	.release = bt_host_release,
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_civoid hci_init_sysfs(struct hci_dev *hdev)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	struct device *dev = &hdev->dev;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	dev->type = &bt_host;
1078c2ecf20Sopenharmony_ci	dev->class = bt_class;
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	__module_get(THIS_MODULE);
1108c2ecf20Sopenharmony_ci	device_initialize(dev);
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciint __init bt_sysfs_init(void)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	bt_class = class_create(THIS_MODULE, "bluetooth");
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(bt_class);
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_civoid bt_sysfs_cleanup(void)
1218c2ecf20Sopenharmony_ci{
1228c2ecf20Sopenharmony_ci	class_destroy(bt_class);
1238c2ecf20Sopenharmony_ci}
124