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 strlcpy(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
);