blob: ad71a5e768dc46432b18b84fb344a7bb514bb56c [file] [log] [blame]
Lyude Paulc5e88482016-12-02 16:59:07 -08001/*
2 * Copyright (C) 2015-2016 Red Hat
3 * Copyright (C) 2015 Lyude Paul <thatslyude@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 */
9
10#include <linux/kernel.h>
11#include <linux/slab.h>
12#include <linux/serio.h>
13#include <linux/notifier.h>
14#include "rmi_driver.h"
15
16#define RMI_F03_RX_DATA_OFB 0x01
17#define RMI_F03_OB_SIZE 2
18
19#define RMI_F03_OB_OFFSET 2
20#define RMI_F03_OB_DATA_OFFSET 1
21#define RMI_F03_OB_FLAG_TIMEOUT BIT(6)
22#define RMI_F03_OB_FLAG_PARITY BIT(7)
23
24#define RMI_F03_DEVICE_COUNT 0x07
25#define RMI_F03_BYTES_PER_DEVICE 0x07
26#define RMI_F03_BYTES_PER_DEVICE_SHIFT 4
27#define RMI_F03_QUEUE_LENGTH 0x0F
28
Benjamin Tissoires81dec802017-02-08 00:26:45 -080029#define PSMOUSE_OOB_EXTRA_BTNS 0x01
30
Lyude Paulc5e88482016-12-02 16:59:07 -080031struct f03_data {
32 struct rmi_function *fn;
33
34 struct serio *serio;
35
Benjamin Tissoires81dec802017-02-08 00:26:45 -080036 unsigned int overwrite_buttons;
37
Lyude Paulc5e88482016-12-02 16:59:07 -080038 u8 device_count;
39 u8 rx_queue_length;
40};
41
Benjamin Tissoires81dec802017-02-08 00:26:45 -080042int rmi_f03_overwrite_button(struct rmi_function *fn, unsigned int button,
43 int value)
44{
45 struct f03_data *f03 = dev_get_drvdata(&fn->dev);
46 unsigned int bit;
47
48 if (button < BTN_LEFT || button > BTN_MIDDLE)
49 return -EINVAL;
50
51 bit = BIT(button - BTN_LEFT);
52
53 if (value)
54 f03->overwrite_buttons |= bit;
55 else
56 f03->overwrite_buttons &= ~bit;
57
58 return 0;
59}
60
61void rmi_f03_commit_buttons(struct rmi_function *fn)
62{
63 struct f03_data *f03 = dev_get_drvdata(&fn->dev);
64 struct serio *serio = f03->serio;
65
66 serio_pause_rx(serio);
67 if (serio->drv) {
68 serio->drv->interrupt(serio, PSMOUSE_OOB_EXTRA_BTNS,
69 SERIO_OOB_DATA);
70 serio->drv->interrupt(serio, f03->overwrite_buttons,
71 SERIO_OOB_DATA);
72 }
73 serio_continue_rx(serio);
74}
75
Lyude Paulc5e88482016-12-02 16:59:07 -080076static int rmi_f03_pt_write(struct serio *id, unsigned char val)
77{
78 struct f03_data *f03 = id->port_data;
79 int error;
80
81 rmi_dbg(RMI_DEBUG_FN, &f03->fn->dev,
82 "%s: Wrote %.2hhx to PS/2 passthrough address",
83 __func__, val);
84
85 error = rmi_write(f03->fn->rmi_dev, f03->fn->fd.data_base_addr, val);
86 if (error) {
87 dev_err(&f03->fn->dev,
88 "%s: Failed to write to F03 TX register (%d).\n",
89 __func__, error);
90 return error;
91 }
92
93 return 0;
94}
95
96static int rmi_f03_initialize(struct f03_data *f03)
97{
98 struct rmi_function *fn = f03->fn;
99 struct device *dev = &fn->dev;
100 int error;
101 u8 bytes_per_device;
102 u8 query1;
103 u8 query2[RMI_F03_DEVICE_COUNT * RMI_F03_BYTES_PER_DEVICE];
104 size_t query2_len;
105
106 error = rmi_read(fn->rmi_dev, fn->fd.query_base_addr, &query1);
107 if (error) {
108 dev_err(dev, "Failed to read query register (%d).\n", error);
109 return error;
110 }
111
112 f03->device_count = query1 & RMI_F03_DEVICE_COUNT;
113 bytes_per_device = (query1 >> RMI_F03_BYTES_PER_DEVICE_SHIFT) &
114 RMI_F03_BYTES_PER_DEVICE;
115
116 query2_len = f03->device_count * bytes_per_device;
117
118 /*
119 * The first generation of image sensors don't have a second part to
120 * their f03 query, as such we have to set some of these values manually
121 */
122 if (query2_len < 1) {
123 f03->device_count = 1;
124 f03->rx_queue_length = 7;
125 } else {
126 error = rmi_read_block(fn->rmi_dev, fn->fd.query_base_addr + 1,
127 query2, query2_len);
128 if (error) {
129 dev_err(dev,
130 "Failed to read second set of query registers (%d).\n",
131 error);
132 return error;
133 }
134
135 f03->rx_queue_length = query2[0] & RMI_F03_QUEUE_LENGTH;
136 }
137
138 return 0;
139}
140
141static int rmi_f03_register_pt(struct f03_data *f03)
142{
143 struct serio *serio;
144
145 serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
146 if (!serio)
147 return -ENOMEM;
148
Dmitry Torokhova0897d52017-06-06 13:05:03 -0700149 serio->id.type = SERIO_PS_PSTHRU;
Lyude Paulc5e88482016-12-02 16:59:07 -0800150 serio->write = rmi_f03_pt_write;
151 serio->port_data = f03;
152
153 strlcpy(serio->name, "Synaptics RMI4 PS/2 pass-through",
154 sizeof(serio->name));
155 strlcpy(serio->phys, "synaptics-rmi4-pt/serio1",
156 sizeof(serio->phys));
157 serio->dev.parent = &f03->fn->dev;
158
159 f03->serio = serio;
160
161 serio_register_port(serio);
162
163 return 0;
164}
165
166static int rmi_f03_probe(struct rmi_function *fn)
167{
168 struct device *dev = &fn->dev;
169 struct f03_data *f03;
170 int error;
171
172 f03 = devm_kzalloc(dev, sizeof(struct f03_data), GFP_KERNEL);
173 if (!f03)
174 return -ENOMEM;
175
176 f03->fn = fn;
177
178 error = rmi_f03_initialize(f03);
179 if (error < 0)
180 return error;
181
182 if (f03->device_count != 1)
183 dev_warn(dev, "found %d devices on PS/2 passthrough",
184 f03->device_count);
185
186 dev_set_drvdata(dev, f03);
187
188 error = rmi_f03_register_pt(f03);
189 if (error)
190 return error;
191
192 return 0;
193}
194
195static int rmi_f03_config(struct rmi_function *fn)
196{
197 fn->rmi_dev->driver->set_irq_bits(fn->rmi_dev, fn->irq_mask);
198
199 return 0;
200}
201
202static int rmi_f03_attention(struct rmi_function *fn, unsigned long *irq_bits)
203{
Dennis Wassenberge6211322016-12-02 17:45:29 -0800204 struct rmi_device *rmi_dev = fn->rmi_dev;
Benjamin Tissoiresae9979c2016-12-02 17:49:10 -0800205 struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
Lyude Paulc5e88482016-12-02 16:59:07 -0800206 struct f03_data *f03 = dev_get_drvdata(&fn->dev);
207 u16 data_addr = fn->fd.data_base_addr;
208 const u8 ob_len = f03->rx_queue_length * RMI_F03_OB_SIZE;
209 u8 obs[RMI_F03_QUEUE_LENGTH * RMI_F03_OB_SIZE];
210 u8 ob_status;
211 u8 ob_data;
212 unsigned int serio_flags;
213 int i;
214 int error;
215
Benjamin Tissoiresae9979c2016-12-02 17:49:10 -0800216 if (drvdata->attn_data.data) {
Dennis Wassenberge6211322016-12-02 17:45:29 -0800217 /* First grab the data passed by the transport device */
Benjamin Tissoiresae9979c2016-12-02 17:49:10 -0800218 if (drvdata->attn_data.size < ob_len) {
Dennis Wassenberge6211322016-12-02 17:45:29 -0800219 dev_warn(&fn->dev, "F03 interrupted, but data is missing!\n");
220 return 0;
221 }
222
Benjamin Tissoiresae9979c2016-12-02 17:49:10 -0800223 memcpy(obs, drvdata->attn_data.data, ob_len);
Dennis Wassenberge6211322016-12-02 17:45:29 -0800224
Benjamin Tissoiresae9979c2016-12-02 17:49:10 -0800225 drvdata->attn_data.data += ob_len;
226 drvdata->attn_data.size -= ob_len;
Dennis Wassenberge6211322016-12-02 17:45:29 -0800227 } else {
228 /* Grab all of the data registers, and check them for data */
229 error = rmi_read_block(fn->rmi_dev, data_addr + RMI_F03_OB_OFFSET,
230 &obs, ob_len);
231 if (error) {
232 dev_err(&fn->dev,
233 "%s: Failed to read F03 output buffers: %d\n",
234 __func__, error);
235 serio_interrupt(f03->serio, 0, SERIO_TIMEOUT);
236 return error;
237 }
Lyude Paulc5e88482016-12-02 16:59:07 -0800238 }
239
240 for (i = 0; i < ob_len; i += RMI_F03_OB_SIZE) {
241 ob_status = obs[i];
242 ob_data = obs[i + RMI_F03_OB_DATA_OFFSET];
243 serio_flags = 0;
244
245 if (!(ob_status & RMI_F03_RX_DATA_OFB))
246 continue;
247
248 if (ob_status & RMI_F03_OB_FLAG_TIMEOUT)
249 serio_flags |= SERIO_TIMEOUT;
250 if (ob_status & RMI_F03_OB_FLAG_PARITY)
251 serio_flags |= SERIO_PARITY;
252
253 rmi_dbg(RMI_DEBUG_FN, &fn->dev,
254 "%s: Received %.2hhx from PS2 guest T: %c P: %c\n",
255 __func__, ob_data,
256 serio_flags & SERIO_TIMEOUT ? 'Y' : 'N',
257 serio_flags & SERIO_PARITY ? 'Y' : 'N');
258
259 serio_interrupt(f03->serio, ob_data, serio_flags);
260 }
261
262 return 0;
263}
264
265static void rmi_f03_remove(struct rmi_function *fn)
266{
267 struct f03_data *f03 = dev_get_drvdata(&fn->dev);
268
269 serio_unregister_port(f03->serio);
270}
271
272struct rmi_function_handler rmi_f03_handler = {
273 .driver = {
274 .name = "rmi4_f03",
275 },
276 .func = 0x03,
277 .probe = rmi_f03_probe,
278 .config = rmi_f03_config,
279 .attention = rmi_f03_attention,
280 .remove = rmi_f03_remove,
281};
282
283MODULE_AUTHOR("Lyude Paul <thatslyude@gmail.com>");
284MODULE_DESCRIPTION("RMI F03 module");
285MODULE_LICENSE("GPL");