1 // SPDX-License-Identifier: GPL-2.0-only
3 * TQC PS/2 Multiplexer driver
5 * Copyright (C) 2010 Dmitry Eremin-Solenikov
9 #include <linux/kernel.h>
10 #include <linux/slab.h>
11 #include <linux/module.h>
12 #include <linux/serio.h>
14 MODULE_AUTHOR("Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>");
15 MODULE_DESCRIPTION("TQC PS/2 Multiplexer driver");
16 MODULE_LICENSE("GPL");
18 #define PS2MULT_KB_SELECTOR 0xA0
19 #define PS2MULT_MS_SELECTOR 0xA1
20 #define PS2MULT_ESCAPE 0x7D
21 #define PS2MULT_BSYNC 0x7E
22 #define PS2MULT_SESSION_START 0x55
23 #define PS2MULT_SESSION_END 0x56
31 #define PS2MULT_NUM_PORTS 2
32 #define PS2MULT_KBD_PORT 0
33 #define PS2MULT_MOUSE_PORT 1
36 struct serio *mx_serio;
37 struct ps2mult_port ports[PS2MULT_NUM_PORTS];
40 struct ps2mult_port *in_port;
41 struct ps2mult_port *out_port;
45 /* First MUST come PS2MULT_NUM_PORTS selectors */
46 static const unsigned char ps2mult_controls[] = {
47 PS2MULT_KB_SELECTOR, PS2MULT_MS_SELECTOR,
48 PS2MULT_ESCAPE, PS2MULT_BSYNC,
49 PS2MULT_SESSION_START, PS2MULT_SESSION_END,
52 static const struct serio_device_id ps2mult_serio_ids[] = {
55 .proto = SERIO_PS2MULT,
62 MODULE_DEVICE_TABLE(serio, ps2mult_serio_ids);
64 static void ps2mult_select_port(struct ps2mult *psm, struct ps2mult_port *port)
66 struct serio *mx_serio = psm->mx_serio;
68 serio_write(mx_serio, port->sel);
70 dev_dbg(&mx_serio->dev, "switched to sel %02x\n", port->sel);
73 static int ps2mult_serio_write(struct serio *serio, unsigned char data)
75 struct serio *mx_port = serio->parent;
76 struct ps2mult *psm = serio_get_drvdata(mx_port);
77 struct ps2mult_port *port = serio->port_data;
81 spin_lock_irqsave(&psm->lock, flags);
83 if (psm->out_port != port)
84 ps2mult_select_port(psm, port);
86 need_escape = memchr(ps2mult_controls, data, sizeof(ps2mult_controls));
89 "write: %s%02x\n", need_escape ? "ESC " : "", data);
92 serio_write(mx_port, PS2MULT_ESCAPE);
94 serio_write(mx_port, data);
96 spin_unlock_irqrestore(&psm->lock, flags);
101 static int ps2mult_serio_start(struct serio *serio)
103 struct ps2mult *psm = serio_get_drvdata(serio->parent);
104 struct ps2mult_port *port = serio->port_data;
107 spin_lock_irqsave(&psm->lock, flags);
108 port->registered = true;
109 spin_unlock_irqrestore(&psm->lock, flags);
114 static void ps2mult_serio_stop(struct serio *serio)
116 struct ps2mult *psm = serio_get_drvdata(serio->parent);
117 struct ps2mult_port *port = serio->port_data;
120 spin_lock_irqsave(&psm->lock, flags);
121 port->registered = false;
122 spin_unlock_irqrestore(&psm->lock, flags);
125 static int ps2mult_create_port(struct ps2mult *psm, int i)
127 struct serio *mx_serio = psm->mx_serio;
130 serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
134 strscpy(serio->name, "TQC PS/2 Multiplexer", sizeof(serio->name));
135 snprintf(serio->phys, sizeof(serio->phys),
136 "%s/port%d", mx_serio->phys, i);
137 serio->id.type = SERIO_8042;
138 serio->write = ps2mult_serio_write;
139 serio->start = ps2mult_serio_start;
140 serio->stop = ps2mult_serio_stop;
141 serio->parent = psm->mx_serio;
142 serio->port_data = &psm->ports[i];
144 psm->ports[i].serio = serio;
149 static void ps2mult_reset(struct ps2mult *psm)
153 spin_lock_irqsave(&psm->lock, flags);
155 serio_write(psm->mx_serio, PS2MULT_SESSION_END);
156 serio_write(psm->mx_serio, PS2MULT_SESSION_START);
158 ps2mult_select_port(psm, &psm->ports[PS2MULT_KBD_PORT]);
160 spin_unlock_irqrestore(&psm->lock, flags);
163 static int ps2mult_connect(struct serio *serio, struct serio_driver *drv)
172 psm = kzalloc(sizeof(*psm), GFP_KERNEL);
176 spin_lock_init(&psm->lock);
177 psm->mx_serio = serio;
179 for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
180 psm->ports[i].sel = ps2mult_controls[i];
181 error = ps2mult_create_port(psm, i);
186 psm->in_port = psm->out_port = &psm->ports[PS2MULT_KBD_PORT];
188 serio_set_drvdata(serio, psm);
189 error = serio_open(serio, drv);
195 for (i = 0; i < PS2MULT_NUM_PORTS; i++) {
196 struct serio *s = psm->ports[i].serio;
198 dev_info(&serio->dev, "%s port at %s\n", s->name, serio->phys);
199 serio_register_port(s);
206 kfree(psm->ports[i].serio);
211 static void ps2mult_disconnect(struct serio *serio)
213 struct ps2mult *psm = serio_get_drvdata(serio);
215 /* Note that serio core already take care of children ports */
216 serio_write(serio, PS2MULT_SESSION_END);
220 serio_set_drvdata(serio, NULL);
223 static int ps2mult_reconnect(struct serio *serio)
225 struct ps2mult *psm = serio_get_drvdata(serio);
232 static irqreturn_t ps2mult_interrupt(struct serio *serio,
233 unsigned char data, unsigned int dfl)
235 struct ps2mult *psm = serio_get_drvdata(serio);
236 struct ps2mult_port *in_port;
239 dev_dbg(&serio->dev, "Received %02x flags %02x\n", data, dfl);
241 spin_lock_irqsave(&psm->lock, flags);
245 in_port = psm->in_port;
246 if (in_port->registered)
247 serio_interrupt(in_port->serio, data, dfl);
253 dev_dbg(&serio->dev, "ESCAPE\n");
258 dev_dbg(&serio->dev, "BSYNC\n");
259 psm->in_port = psm->out_port;
262 case PS2MULT_SESSION_START:
263 dev_dbg(&serio->dev, "SS\n");
266 case PS2MULT_SESSION_END:
267 dev_dbg(&serio->dev, "SE\n");
270 case PS2MULT_KB_SELECTOR:
271 dev_dbg(&serio->dev, "KB\n");
272 psm->in_port = &psm->ports[PS2MULT_KBD_PORT];
275 case PS2MULT_MS_SELECTOR:
276 dev_dbg(&serio->dev, "MS\n");
277 psm->in_port = &psm->ports[PS2MULT_MOUSE_PORT];
281 in_port = psm->in_port;
282 if (in_port->registered)
283 serio_interrupt(in_port->serio, data, dfl);
288 spin_unlock_irqrestore(&psm->lock, flags);
292 static struct serio_driver ps2mult_drv = {
296 .description = "TQC PS/2 Multiplexer driver",
297 .id_table = ps2mult_serio_ids,
298 .interrupt = ps2mult_interrupt,
299 .connect = ps2mult_connect,
300 .disconnect = ps2mult_disconnect,
301 .reconnect = ps2mult_reconnect,
304 module_serio_driver(ps2mult_drv);