xref: /openbmc/linux/net/bluetooth/hci_sysfs.c (revision ecc23d0a422a3118fcf6e4f0a46e17a6c2047b02)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /* Bluetooth HCI driver model support. */
31da177e4SLinus Torvalds 
43a9a231dSPaul Gortmaker #include <linux/module.h>
51da177e4SLinus Torvalds 
61da177e4SLinus Torvalds #include <net/bluetooth/bluetooth.h>
71da177e4SLinus Torvalds #include <net/bluetooth/hci_core.h>
81da177e4SLinus Torvalds 
9d40d6f52SIvan Orlov static const struct class bt_class = {
10d40d6f52SIvan Orlov 	.name = "bluetooth",
11d40d6f52SIvan Orlov };
1290855d7bSMarcel Holtmann 
bt_link_release(struct device * dev)1390855d7bSMarcel Holtmann static void bt_link_release(struct device *dev)
1490855d7bSMarcel Holtmann {
152dd10688SDavid Herrmann 	struct hci_conn *conn = to_hci_conn(dev);
162dd10688SDavid Herrmann 	kfree(conn);
1790855d7bSMarcel Holtmann }
1890855d7bSMarcel Holtmann 
199374bf18SBhumika Goyal static const struct device_type bt_link = {
2090855d7bSMarcel Holtmann 	.name    = "link",
2190855d7bSMarcel Holtmann 	.release = bt_link_release,
2290855d7bSMarcel Holtmann };
2390855d7bSMarcel Holtmann 
hci_conn_init_sysfs(struct hci_conn * conn)246d438e33SGustavo F. Padovan void hci_conn_init_sysfs(struct hci_conn *conn)
256d438e33SGustavo F. Padovan {
26457ca7bbSMarcel Holtmann 	struct hci_dev *hdev = conn->hdev;
2790855d7bSMarcel Holtmann 
2856a4fddeSZhengHan Wang 	bt_dev_dbg(hdev, "conn %p", conn);
296d438e33SGustavo F. Padovan 
306d438e33SGustavo F. Padovan 	conn->dev.type = &bt_link;
31d40d6f52SIvan Orlov 	conn->dev.class = &bt_class;
326d438e33SGustavo F. Padovan 	conn->dev.parent = &hdev->dev;
336d438e33SGustavo F. Padovan 
346d438e33SGustavo F. Padovan 	device_initialize(&conn->dev);
356d438e33SGustavo F. Padovan }
366d438e33SGustavo F. Padovan 
hci_conn_add_sysfs(struct hci_conn * conn)376d438e33SGustavo F. Padovan void hci_conn_add_sysfs(struct hci_conn *conn)
386d438e33SGustavo F. Padovan {
396d438e33SGustavo F. Padovan 	struct hci_dev *hdev = conn->hdev;
406d438e33SGustavo F. Padovan 
4156a4fddeSZhengHan Wang 	bt_dev_dbg(hdev, "conn %p", conn);
426d438e33SGustavo F. Padovan 
43448a496fSLuiz Augusto von Dentz 	if (device_is_registered(&conn->dev))
44448a496fSLuiz Augusto von Dentz 		return;
45448a496fSLuiz Augusto von Dentz 
46457ca7bbSMarcel Holtmann 	dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle);
47457ca7bbSMarcel Holtmann 
4856a4fddeSZhengHan Wang 	if (device_add(&conn->dev) < 0)
492064ee33SMarcel Holtmann 		bt_dev_err(hdev, "failed to register connection device");
5090855d7bSMarcel Holtmann }
5190855d7bSMarcel Holtmann 
hci_conn_del_sysfs(struct hci_conn * conn)526d438e33SGustavo F. Padovan void hci_conn_del_sysfs(struct hci_conn *conn)
5390855d7bSMarcel Holtmann {
5490855d7bSMarcel Holtmann 	struct hci_dev *hdev = conn->hdev;
5590855d7bSMarcel Holtmann 
5656a4fddeSZhengHan Wang 	bt_dev_dbg(hdev, "conn %p", conn);
5756a4fddeSZhengHan Wang 
5856a4fddeSZhengHan Wang 	if (!device_is_registered(&conn->dev)) {
5956a4fddeSZhengHan Wang 		/* If device_add() has *not* succeeded, use *only* put_device()
6056a4fddeSZhengHan Wang 		 * to drop the reference count.
6156a4fddeSZhengHan Wang 		 */
6256a4fddeSZhengHan Wang 		put_device(&conn->dev);
63a67e899cSMarcel Holtmann 		return;
6456a4fddeSZhengHan Wang 	}
65f3784d83SRoger Quadros 
66*de5a44f3SDmitry Antipov 	/* If there are devices using the connection as parent reset it to NULL
67*de5a44f3SDmitry Antipov 	 * before unregistering the device.
68*de5a44f3SDmitry Antipov 	 */
6990855d7bSMarcel Holtmann 	while (1) {
7090855d7bSMarcel Holtmann 		struct device *dev;
7190855d7bSMarcel Holtmann 
72*de5a44f3SDmitry Antipov 		dev = device_find_any_child(&conn->dev);
7390855d7bSMarcel Holtmann 		if (!dev)
7490855d7bSMarcel Holtmann 			break;
75ffa6a705SCornelia Huck 		device_move(dev, NULL, DPM_ORDER_DEV_LAST);
7690855d7bSMarcel Holtmann 		put_device(dev);
7790855d7bSMarcel Holtmann 	}
7890855d7bSMarcel Holtmann 
7956a4fddeSZhengHan Wang 	device_unregister(&conn->dev);
8090855d7bSMarcel Holtmann }
8190855d7bSMarcel Holtmann 
bt_host_release(struct device * dev)8290855d7bSMarcel Holtmann static void bt_host_release(struct device *dev)
83a91f2e39SMarcel Holtmann {
842dd10688SDavid Herrmann 	struct hci_dev *hdev = to_hci_dev(dev);
85e0448092STetsuo Handa 
86e0448092STetsuo Handa 	if (hci_dev_test_flag(hdev, HCI_UNREGISTER))
8758ce6d5bSTetsuo Handa 		hci_release_dev(hdev);
8875d9b855SWei Yongjun 	else
8975d9b855SWei Yongjun 		kfree(hdev);
9046e06531SDavid Herrmann 	module_put(THIS_MODULE);
91b219e3acSMarcel Holtmann }
92b219e3acSMarcel Holtmann 
939374bf18SBhumika Goyal static const struct device_type bt_host = {
9490855d7bSMarcel Holtmann 	.name    = "host",
9590855d7bSMarcel Holtmann 	.release = bt_host_release,
9690855d7bSMarcel Holtmann };
97a91f2e39SMarcel Holtmann 
hci_init_sysfs(struct hci_dev * hdev)980ac7e700SDavid Herrmann void hci_init_sysfs(struct hci_dev *hdev)
990ac7e700SDavid Herrmann {
1000ac7e700SDavid Herrmann 	struct device *dev = &hdev->dev;
1010ac7e700SDavid Herrmann 
1020ac7e700SDavid Herrmann 	dev->type = &bt_host;
103d40d6f52SIvan Orlov 	dev->class = &bt_class;
1040ac7e700SDavid Herrmann 
10546e06531SDavid Herrmann 	__module_get(THIS_MODULE);
1060ac7e700SDavid Herrmann 	device_initialize(dev);
1070ac7e700SDavid Herrmann }
1080ac7e700SDavid Herrmann 
bt_sysfs_init(void)1091da177e4SLinus Torvalds int __init bt_sysfs_init(void)
1101da177e4SLinus Torvalds {
111d40d6f52SIvan Orlov 	return class_register(&bt_class);
1121da177e4SLinus Torvalds }
1131da177e4SLinus Torvalds 
bt_sysfs_cleanup(void)114860e13b5SArnaud Patard void bt_sysfs_cleanup(void)
1151da177e4SLinus Torvalds {
116d40d6f52SIvan Orlov 	class_unregister(&bt_class);
1171da177e4SLinus Torvalds }
118