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
;
80 guard(spinlock_irqsave
)(&psm
->lock
);
82 if (psm
->out_port
!= port
)
83 ps2mult_select_port(psm
, port
);
85 need_escape
= memchr(ps2mult_controls
, data
, sizeof(ps2mult_controls
));
88 "write: %s%02x\n", need_escape
? "ESC " : "", data
);
91 serio_write(mx_port
, PS2MULT_ESCAPE
);
93 serio_write(mx_port
, data
);
98 static int ps2mult_serio_start(struct serio
*serio
)
100 struct ps2mult
*psm
= serio_get_drvdata(serio
->parent
);
101 struct ps2mult_port
*port
= serio
->port_data
;
103 guard(spinlock_irqsave
)(&psm
->lock
);
105 port
->registered
= true;
110 static void ps2mult_serio_stop(struct serio
*serio
)
112 struct ps2mult
*psm
= serio_get_drvdata(serio
->parent
);
113 struct ps2mult_port
*port
= serio
->port_data
;
115 guard(spinlock_irqsave
)(&psm
->lock
);
117 port
->registered
= false;
120 static int ps2mult_create_port(struct ps2mult
*psm
, int i
)
122 struct serio
*mx_serio
= psm
->mx_serio
;
125 serio
= kzalloc(sizeof(*serio
), GFP_KERNEL
);
129 strscpy(serio
->name
, "TQC PS/2 Multiplexer", sizeof(serio
->name
));
130 snprintf(serio
->phys
, sizeof(serio
->phys
),
131 "%s/port%d", mx_serio
->phys
, i
);
132 serio
->id
.type
= SERIO_8042
;
133 serio
->write
= ps2mult_serio_write
;
134 serio
->start
= ps2mult_serio_start
;
135 serio
->stop
= ps2mult_serio_stop
;
136 serio
->parent
= psm
->mx_serio
;
137 serio
->port_data
= &psm
->ports
[i
];
139 psm
->ports
[i
].serio
= serio
;
144 static void ps2mult_reset(struct ps2mult
*psm
)
146 guard(spinlock_irqsave
)(&psm
->lock
);
148 serio_write(psm
->mx_serio
, PS2MULT_SESSION_END
);
149 serio_write(psm
->mx_serio
, PS2MULT_SESSION_START
);
151 ps2mult_select_port(psm
, &psm
->ports
[PS2MULT_KBD_PORT
]);
154 static int ps2mult_connect(struct serio
*serio
, struct serio_driver
*drv
)
163 psm
= kzalloc(sizeof(*psm
), GFP_KERNEL
);
167 spin_lock_init(&psm
->lock
);
168 psm
->mx_serio
= serio
;
170 for (i
= 0; i
< PS2MULT_NUM_PORTS
; i
++) {
171 psm
->ports
[i
].sel
= ps2mult_controls
[i
];
172 error
= ps2mult_create_port(psm
, i
);
177 psm
->in_port
= psm
->out_port
= &psm
->ports
[PS2MULT_KBD_PORT
];
179 serio_set_drvdata(serio
, psm
);
180 error
= serio_open(serio
, drv
);
186 for (i
= 0; i
< PS2MULT_NUM_PORTS
; i
++) {
187 struct serio
*s
= psm
->ports
[i
].serio
;
189 dev_info(&serio
->dev
, "%s port at %s\n", s
->name
, serio
->phys
);
190 serio_register_port(s
);
197 kfree(psm
->ports
[i
].serio
);
202 static void ps2mult_disconnect(struct serio
*serio
)
204 struct ps2mult
*psm
= serio_get_drvdata(serio
);
206 /* Note that serio core already take care of children ports */
207 serio_write(serio
, PS2MULT_SESSION_END
);
211 serio_set_drvdata(serio
, NULL
);
214 static int ps2mult_reconnect(struct serio
*serio
)
216 struct ps2mult
*psm
= serio_get_drvdata(serio
);
223 static irqreturn_t
ps2mult_interrupt(struct serio
*serio
,
224 unsigned char data
, unsigned int dfl
)
226 struct ps2mult
*psm
= serio_get_drvdata(serio
);
227 struct ps2mult_port
*in_port
;
229 dev_dbg(&serio
->dev
, "Received %02x flags %02x\n", data
, dfl
);
231 guard(spinlock_irqsave
)(&psm
->lock
);
235 in_port
= psm
->in_port
;
236 if (in_port
->registered
)
237 serio_interrupt(in_port
->serio
, data
, dfl
);
243 dev_dbg(&serio
->dev
, "ESCAPE\n");
248 dev_dbg(&serio
->dev
, "BSYNC\n");
249 psm
->in_port
= psm
->out_port
;
252 case PS2MULT_SESSION_START
:
253 dev_dbg(&serio
->dev
, "SS\n");
256 case PS2MULT_SESSION_END
:
257 dev_dbg(&serio
->dev
, "SE\n");
260 case PS2MULT_KB_SELECTOR
:
261 dev_dbg(&serio
->dev
, "KB\n");
262 psm
->in_port
= &psm
->ports
[PS2MULT_KBD_PORT
];
265 case PS2MULT_MS_SELECTOR
:
266 dev_dbg(&serio
->dev
, "MS\n");
267 psm
->in_port
= &psm
->ports
[PS2MULT_MOUSE_PORT
];
271 in_port
= psm
->in_port
;
272 if (in_port
->registered
)
273 serio_interrupt(in_port
->serio
, data
, dfl
);
281 static struct serio_driver ps2mult_drv
= {
285 .description
= "TQC PS/2 Multiplexer driver",
286 .id_table
= ps2mult_serio_ids
,
287 .interrupt
= ps2mult_interrupt
,
288 .connect
= ps2mult_connect
,
289 .disconnect
= ps2mult_disconnect
,
290 .reconnect
= ps2mult_reconnect
,
293 module_serio_driver(ps2mult_drv
);