Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-only
2 : /*
3 : * Copyright (c) 2017 Red Hat, Inc
4 : */
5 :
6 : #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7 :
8 : #include <linux/kernel.h>
9 : #include <linux/module.h>
10 : #include <linux/libps2.h>
11 : #include <linux/i2c.h>
12 : #include <linux/serio.h>
13 : #include <linux/slab.h>
14 : #include <linux/workqueue.h>
15 : #include "psmouse.h"
16 :
17 : struct psmouse_smbus_dev {
18 : struct i2c_board_info board;
19 : struct psmouse *psmouse;
20 : struct i2c_client *client;
21 : struct list_head node;
22 : bool dead;
23 : bool need_deactivate;
24 : };
25 :
26 : static LIST_HEAD(psmouse_smbus_list);
27 : static DEFINE_MUTEX(psmouse_smbus_mutex);
28 :
29 0 : static void psmouse_smbus_check_adapter(struct i2c_adapter *adapter)
30 : {
31 : struct psmouse_smbus_dev *smbdev;
32 :
33 0 : if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY))
34 : return;
35 :
36 0 : mutex_lock(&psmouse_smbus_mutex);
37 :
38 0 : list_for_each_entry(smbdev, &psmouse_smbus_list, node) {
39 0 : if (smbdev->dead)
40 0 : continue;
41 :
42 0 : if (smbdev->client)
43 0 : continue;
44 :
45 : /*
46 : * Here would be a good place to check if device is actually
47 : * present, but it seems that SMBus will not respond unless we
48 : * fully reset PS/2 connection. So cross our fingers, and try
49 : * to switch over, hopefully our system will not have too many
50 : * "host notify" I2C adapters.
51 : */
52 : psmouse_dbg(smbdev->psmouse,
53 : "SMBus candidate adapter appeared, triggering rescan\n");
54 0 : serio_rescan(smbdev->psmouse->ps2dev.serio);
55 : }
56 :
57 0 : mutex_unlock(&psmouse_smbus_mutex);
58 : }
59 :
60 0 : static void psmouse_smbus_detach_i2c_client(struct i2c_client *client)
61 : {
62 : struct psmouse_smbus_dev *smbdev, *tmp;
63 :
64 0 : mutex_lock(&psmouse_smbus_mutex);
65 :
66 0 : list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) {
67 0 : if (smbdev->client != client)
68 0 : continue;
69 :
70 0 : kfree(client->dev.platform_data);
71 0 : client->dev.platform_data = NULL;
72 :
73 0 : if (!smbdev->dead) {
74 : psmouse_dbg(smbdev->psmouse,
75 : "Marking SMBus companion %s as gone\n",
76 : dev_name(&smbdev->client->dev));
77 0 : smbdev->dead = true;
78 0 : device_link_remove(&smbdev->client->dev,
79 0 : &smbdev->psmouse->ps2dev.serio->dev);
80 0 : serio_rescan(smbdev->psmouse->ps2dev.serio);
81 : } else {
82 0 : list_del(&smbdev->node);
83 0 : kfree(smbdev);
84 : }
85 : }
86 :
87 0 : mutex_unlock(&psmouse_smbus_mutex);
88 0 : }
89 :
90 0 : static int psmouse_smbus_notifier_call(struct notifier_block *nb,
91 : unsigned long action, void *data)
92 : {
93 0 : struct device *dev = data;
94 :
95 0 : switch (action) {
96 : case BUS_NOTIFY_ADD_DEVICE:
97 0 : if (dev->type == &i2c_adapter_type)
98 0 : psmouse_smbus_check_adapter(to_i2c_adapter(dev));
99 : break;
100 :
101 : case BUS_NOTIFY_REMOVED_DEVICE:
102 0 : if (dev->type == &i2c_client_type)
103 0 : psmouse_smbus_detach_i2c_client(to_i2c_client(dev));
104 : break;
105 : }
106 :
107 0 : return 0;
108 : }
109 :
110 : static struct notifier_block psmouse_smbus_notifier = {
111 : .notifier_call = psmouse_smbus_notifier_call,
112 : };
113 :
114 0 : static psmouse_ret_t psmouse_smbus_process_byte(struct psmouse *psmouse)
115 : {
116 0 : return PSMOUSE_FULL_PACKET;
117 : }
118 :
119 0 : static int psmouse_smbus_reconnect(struct psmouse *psmouse)
120 : {
121 0 : struct psmouse_smbus_dev *smbdev = psmouse->private;
122 :
123 0 : if (smbdev->need_deactivate)
124 0 : psmouse_deactivate(psmouse);
125 :
126 0 : return 0;
127 : }
128 :
129 : struct psmouse_smbus_removal_work {
130 : struct work_struct work;
131 : struct i2c_client *client;
132 : };
133 :
134 0 : static void psmouse_smbus_remove_i2c_device(struct work_struct *work)
135 : {
136 0 : struct psmouse_smbus_removal_work *rwork =
137 0 : container_of(work, struct psmouse_smbus_removal_work, work);
138 :
139 : dev_dbg(&rwork->client->dev, "destroying SMBus companion device\n");
140 0 : i2c_unregister_device(rwork->client);
141 :
142 0 : kfree(rwork);
143 0 : }
144 :
145 : /*
146 : * This schedules removal of SMBus companion device. We have to do
147 : * it in a separate tread to avoid deadlocking on psmouse_mutex in
148 : * case the device has a trackstick (which is also driven by psmouse).
149 : *
150 : * Note that this may be racing with i2c adapter removal, but we
151 : * can't do anything about that: i2c automatically destroys clients
152 : * attached to an adapter that is being removed. This has to be
153 : * fixed in i2c core.
154 : */
155 0 : static void psmouse_smbus_schedule_remove(struct i2c_client *client)
156 : {
157 : struct psmouse_smbus_removal_work *rwork;
158 :
159 0 : rwork = kzalloc(sizeof(*rwork), GFP_KERNEL);
160 0 : if (rwork) {
161 0 : INIT_WORK(&rwork->work, psmouse_smbus_remove_i2c_device);
162 0 : rwork->client = client;
163 :
164 0 : schedule_work(&rwork->work);
165 : }
166 0 : }
167 :
168 0 : static void psmouse_smbus_disconnect(struct psmouse *psmouse)
169 : {
170 0 : struct psmouse_smbus_dev *smbdev = psmouse->private;
171 :
172 0 : mutex_lock(&psmouse_smbus_mutex);
173 :
174 0 : if (smbdev->dead) {
175 0 : list_del(&smbdev->node);
176 0 : kfree(smbdev);
177 : } else {
178 0 : smbdev->dead = true;
179 0 : device_link_remove(&smbdev->client->dev,
180 0 : &psmouse->ps2dev.serio->dev);
181 : psmouse_dbg(smbdev->psmouse,
182 : "posting removal request for SMBus companion %s\n",
183 : dev_name(&smbdev->client->dev));
184 0 : psmouse_smbus_schedule_remove(smbdev->client);
185 : }
186 :
187 0 : mutex_unlock(&psmouse_smbus_mutex);
188 :
189 0 : psmouse->private = NULL;
190 0 : }
191 :
192 0 : static int psmouse_smbus_create_companion(struct device *dev, void *data)
193 : {
194 0 : struct psmouse_smbus_dev *smbdev = data;
195 0 : unsigned short addr_list[] = { smbdev->board.addr, I2C_CLIENT_END };
196 : struct i2c_adapter *adapter;
197 : struct i2c_client *client;
198 :
199 0 : adapter = i2c_verify_adapter(dev);
200 0 : if (!adapter)
201 : return 0;
202 :
203 0 : if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_HOST_NOTIFY))
204 : return 0;
205 :
206 0 : client = i2c_new_scanned_device(adapter, &smbdev->board,
207 : addr_list, NULL);
208 0 : if (IS_ERR(client))
209 : return 0;
210 :
211 : /* We have our(?) device, stop iterating i2c bus. */
212 0 : smbdev->client = client;
213 0 : return 1;
214 : }
215 :
216 0 : void psmouse_smbus_cleanup(struct psmouse *psmouse)
217 : {
218 : struct psmouse_smbus_dev *smbdev, *tmp;
219 :
220 0 : mutex_lock(&psmouse_smbus_mutex);
221 :
222 0 : list_for_each_entry_safe(smbdev, tmp, &psmouse_smbus_list, node) {
223 0 : if (psmouse == smbdev->psmouse) {
224 0 : list_del(&smbdev->node);
225 0 : kfree(smbdev);
226 : }
227 : }
228 :
229 0 : mutex_unlock(&psmouse_smbus_mutex);
230 0 : }
231 :
232 0 : int psmouse_smbus_init(struct psmouse *psmouse,
233 : const struct i2c_board_info *board,
234 : const void *pdata, size_t pdata_size,
235 : bool need_deactivate,
236 : bool leave_breadcrumbs)
237 : {
238 : struct psmouse_smbus_dev *smbdev;
239 : int error;
240 :
241 0 : smbdev = kzalloc(sizeof(*smbdev), GFP_KERNEL);
242 0 : if (!smbdev)
243 : return -ENOMEM;
244 :
245 0 : smbdev->psmouse = psmouse;
246 0 : smbdev->board = *board;
247 0 : smbdev->need_deactivate = need_deactivate;
248 :
249 0 : if (pdata) {
250 0 : smbdev->board.platform_data = kmemdup(pdata, pdata_size,
251 : GFP_KERNEL);
252 0 : if (!smbdev->board.platform_data) {
253 0 : kfree(smbdev);
254 0 : return -ENOMEM;
255 : }
256 : }
257 :
258 0 : if (need_deactivate)
259 0 : psmouse_deactivate(psmouse);
260 :
261 0 : psmouse->private = smbdev;
262 0 : psmouse->protocol_handler = psmouse_smbus_process_byte;
263 0 : psmouse->reconnect = psmouse_smbus_reconnect;
264 0 : psmouse->fast_reconnect = psmouse_smbus_reconnect;
265 0 : psmouse->disconnect = psmouse_smbus_disconnect;
266 0 : psmouse->resync_time = 0;
267 :
268 0 : mutex_lock(&psmouse_smbus_mutex);
269 0 : list_add_tail(&smbdev->node, &psmouse_smbus_list);
270 0 : mutex_unlock(&psmouse_smbus_mutex);
271 :
272 : /* Bind to already existing adapters right away */
273 0 : error = i2c_for_each_dev(smbdev, psmouse_smbus_create_companion);
274 :
275 0 : if (smbdev->client) {
276 : /* We have our companion device */
277 0 : if (!device_link_add(&smbdev->client->dev,
278 0 : &psmouse->ps2dev.serio->dev,
279 : DL_FLAG_STATELESS))
280 0 : psmouse_warn(psmouse,
281 : "failed to set up link with iSMBus companion %s\n",
282 : dev_name(&smbdev->client->dev));
283 : return 0;
284 : }
285 :
286 : /*
287 : * If we did not create i2c device we will not need platform
288 : * data even if we are leaving breadcrumbs.
289 : */
290 0 : kfree(smbdev->board.platform_data);
291 0 : smbdev->board.platform_data = NULL;
292 :
293 0 : if (error < 0 || !leave_breadcrumbs) {
294 0 : mutex_lock(&psmouse_smbus_mutex);
295 0 : list_del(&smbdev->node);
296 0 : mutex_unlock(&psmouse_smbus_mutex);
297 :
298 0 : kfree(smbdev);
299 : }
300 :
301 0 : return error < 0 ? error : -EAGAIN;
302 : }
303 :
304 1 : int __init psmouse_smbus_module_init(void)
305 : {
306 : int error;
307 :
308 1 : error = bus_register_notifier(&i2c_bus_type, &psmouse_smbus_notifier);
309 1 : if (error) {
310 0 : pr_err("failed to register i2c bus notifier: %d\n", error);
311 0 : return error;
312 : }
313 :
314 : return 0;
315 : }
316 :
317 0 : void psmouse_smbus_module_exit(void)
318 : {
319 0 : bus_unregister_notifier(&i2c_bus_type, &psmouse_smbus_notifier);
320 : flush_scheduled_work();
321 0 : }
|