1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Bluetooth HCI driver model support. */ |
3 | |
4 | #include <linux/module.h> |
5 | |
6 | #include <net/bluetooth/bluetooth.h> |
7 | #include <net/bluetooth/hci_core.h> |
8 | |
9 | static const struct class bt_class = { |
10 | .name = "bluetooth" , |
11 | }; |
12 | |
13 | static void bt_link_release(struct device *dev) |
14 | { |
15 | struct hci_conn *conn = to_hci_conn(dev); |
16 | kfree(objp: conn); |
17 | } |
18 | |
19 | static const struct device_type bt_link = { |
20 | .name = "link" , |
21 | .release = bt_link_release, |
22 | }; |
23 | |
24 | /* |
25 | * The rfcomm tty device will possibly retain even when conn |
26 | * is down, and sysfs doesn't support move zombie device, |
27 | * so we should move the device before conn device is destroyed. |
28 | */ |
29 | static int __match_tty(struct device *dev, void *data) |
30 | { |
31 | return !strncmp(dev_name(dev), "rfcomm" , 6); |
32 | } |
33 | |
34 | void hci_conn_init_sysfs(struct hci_conn *conn) |
35 | { |
36 | struct hci_dev *hdev = conn->hdev; |
37 | |
38 | bt_dev_dbg(hdev, "conn %p" , conn); |
39 | |
40 | conn->dev.type = &bt_link; |
41 | conn->dev.class = &bt_class; |
42 | conn->dev.parent = &hdev->dev; |
43 | |
44 | device_initialize(dev: &conn->dev); |
45 | } |
46 | |
47 | void hci_conn_add_sysfs(struct hci_conn *conn) |
48 | { |
49 | struct hci_dev *hdev = conn->hdev; |
50 | |
51 | bt_dev_dbg(hdev, "conn %p" , conn); |
52 | |
53 | if (device_is_registered(dev: &conn->dev)) |
54 | return; |
55 | |
56 | dev_set_name(dev: &conn->dev, name: "%s:%d" , hdev->name, conn->handle); |
57 | |
58 | if (device_add(dev: &conn->dev) < 0) |
59 | bt_dev_err(hdev, "failed to register connection device" ); |
60 | } |
61 | |
62 | void hci_conn_del_sysfs(struct hci_conn *conn) |
63 | { |
64 | struct hci_dev *hdev = conn->hdev; |
65 | |
66 | bt_dev_dbg(hdev, "conn %p" , conn); |
67 | |
68 | if (!device_is_registered(dev: &conn->dev)) { |
69 | /* If device_add() has *not* succeeded, use *only* put_device() |
70 | * to drop the reference count. |
71 | */ |
72 | put_device(dev: &conn->dev); |
73 | return; |
74 | } |
75 | |
76 | while (1) { |
77 | struct device *dev; |
78 | |
79 | dev = device_find_child(dev: &conn->dev, NULL, match: __match_tty); |
80 | if (!dev) |
81 | break; |
82 | device_move(dev, NULL, dpm_order: DPM_ORDER_DEV_LAST); |
83 | put_device(dev); |
84 | } |
85 | |
86 | device_unregister(dev: &conn->dev); |
87 | } |
88 | |
89 | static void bt_host_release(struct device *dev) |
90 | { |
91 | struct hci_dev *hdev = to_hci_dev(dev); |
92 | |
93 | if (hci_dev_test_flag(hdev, HCI_UNREGISTER)) |
94 | hci_release_dev(hdev); |
95 | else |
96 | kfree(objp: hdev); |
97 | module_put(THIS_MODULE); |
98 | } |
99 | |
100 | static const struct device_type bt_host = { |
101 | .name = "host" , |
102 | .release = bt_host_release, |
103 | }; |
104 | |
105 | void hci_init_sysfs(struct hci_dev *hdev) |
106 | { |
107 | struct device *dev = &hdev->dev; |
108 | |
109 | dev->type = &bt_host; |
110 | dev->class = &bt_class; |
111 | |
112 | __module_get(THIS_MODULE); |
113 | device_initialize(dev); |
114 | } |
115 | |
116 | int __init bt_sysfs_init(void) |
117 | { |
118 | return class_register(class: &bt_class); |
119 | } |
120 | |
121 | void bt_sysfs_cleanup(void) |
122 | { |
123 | class_unregister(class: &bt_class); |
124 | } |
125 | |