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