Skip to content

Commit 3bb6040

Browse files
committed
Merge remote-tracking branch 'remotes/kraxel/tags/input-20210910-pull-request' into staging
input: ps2 fixes. # gpg: Signature made Fri 10 Sep 2021 11:22:47 BST # gpg: using RSA key A0328CFFB93A17A79901FE7D4CB6D8EED3E87138 # gpg: Good signature from "Gerd Hoffmann (work) <[email protected]>" [full] # gpg: aka "Gerd Hoffmann <[email protected]>" [full] # gpg: aka "Gerd Hoffmann (private) <[email protected]>" [full] # Primary key fingerprint: A032 8CFF B93A 17A7 9901 FE7D 4CB6 D8EE D3E8 7138 * remotes/kraxel/tags/input-20210910-pull-request: ps2: migration support for command reply queue ps2: use a separate keyboard command reply queue ps2: use the whole ps2 buffer but keep queue size Signed-off-by: Peter Maydell <[email protected]>
2 parents 6d1272d + 4e9bddc commit 3bb6040

File tree

1 file changed

+133
-81
lines changed

1 file changed

+133
-81
lines changed

hw/input/ps2.c

Lines changed: 133 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,13 @@
7474
#define MOUSE_STATUS_ENABLED 0x20
7575
#define MOUSE_STATUS_SCALE21 0x10
7676

77-
#define PS2_QUEUE_SIZE 16 /* Buffer size required by PS/2 protocol */
77+
/*
78+
* PS/2 buffer size. Keep 256 bytes for compatibility with
79+
* older QEMU versions.
80+
*/
81+
#define PS2_BUFFER_SIZE 256
82+
#define PS2_QUEUE_SIZE 16 /* Queue size required by PS/2 protocol */
83+
#define PS2_QUEUE_HEADROOM 8 /* Queue size for keyboard command replies */
7884

7985
/* Bits for 'modifiers' field in PS2KbdState */
8086
#define MOD_CTRL_L (1 << 0)
@@ -85,10 +91,8 @@
8591
#define MOD_ALT_R (1 << 5)
8692

8793
typedef struct {
88-
/* Keep the data array 256 bytes long, which compatibility
89-
with older qemu versions. */
90-
uint8_t data[256];
91-
int rptr, wptr, count;
94+
uint8_t data[PS2_BUFFER_SIZE];
95+
int rptr, wptr, cwptr, count;
9296
} PS2Queue;
9397

9498
struct PS2State {
@@ -183,6 +187,7 @@ static void ps2_reset_queue(PS2State *s)
183187

184188
q->rptr = 0;
185189
q->wptr = 0;
190+
q->cwptr = -1;
186191
q->count = 0;
187192
}
188193

@@ -195,13 +200,14 @@ void ps2_queue_noirq(PS2State *s, int b)
195200
{
196201
PS2Queue *q = &s->queue;
197202

198-
if (q->count == PS2_QUEUE_SIZE) {
203+
if (q->count >= PS2_QUEUE_SIZE) {
199204
return;
200205
}
201206

202207
q->data[q->wptr] = b;
203-
if (++q->wptr == PS2_QUEUE_SIZE)
208+
if (++q->wptr == PS2_BUFFER_SIZE) {
204209
q->wptr = 0;
210+
}
205211
q->count++;
206212
}
207213

@@ -256,6 +262,63 @@ void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
256262
ps2_raise_irq(s);
257263
}
258264

265+
static void ps2_cqueue_data(PS2Queue *q, int b)
266+
{
267+
q->data[q->cwptr] = b;
268+
if (++q->cwptr >= PS2_BUFFER_SIZE) {
269+
q->cwptr = 0;
270+
}
271+
q->count++;
272+
}
273+
274+
static void ps2_cqueue_1(PS2State *s, int b1)
275+
{
276+
PS2Queue *q = &s->queue;
277+
278+
q->rptr = (q->rptr - 1) & (PS2_BUFFER_SIZE - 1);
279+
q->cwptr = q->rptr;
280+
ps2_cqueue_data(q, b1);
281+
ps2_raise_irq(s);
282+
}
283+
284+
static void ps2_cqueue_2(PS2State *s, int b1, int b2)
285+
{
286+
PS2Queue *q = &s->queue;
287+
288+
q->rptr = (q->rptr - 2) & (PS2_BUFFER_SIZE - 1);
289+
q->cwptr = q->rptr;
290+
ps2_cqueue_data(q, b1);
291+
ps2_cqueue_data(q, b2);
292+
ps2_raise_irq(s);
293+
}
294+
295+
static void ps2_cqueue_3(PS2State *s, int b1, int b2, int b3)
296+
{
297+
PS2Queue *q = &s->queue;
298+
299+
q->rptr = (q->rptr - 3) & (PS2_BUFFER_SIZE - 1);
300+
q->cwptr = q->rptr;
301+
ps2_cqueue_data(q, b1);
302+
ps2_cqueue_data(q, b2);
303+
ps2_cqueue_data(q, b3);
304+
ps2_raise_irq(s);
305+
}
306+
307+
static void ps2_cqueue_reset(PS2State *s)
308+
{
309+
PS2Queue *q = &s->queue;
310+
int ccount;
311+
312+
if (q->cwptr == -1) {
313+
return;
314+
}
315+
316+
ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
317+
q->count -= ccount;
318+
q->rptr = q->cwptr;
319+
q->cwptr = -1;
320+
}
321+
259322
/* keycode is the untranslated scancode in the current scancode set. */
260323
static void ps2_put_keycode(void *opaque, int keycode)
261324
{
@@ -509,14 +572,20 @@ uint32_t ps2_read_data(PS2State *s)
509572
(needed for EMM386) */
510573
/* XXX: need a timer to do things correctly */
511574
index = q->rptr - 1;
512-
if (index < 0)
513-
index = PS2_QUEUE_SIZE - 1;
575+
if (index < 0) {
576+
index = PS2_BUFFER_SIZE - 1;
577+
}
514578
val = q->data[index];
515579
} else {
516580
val = q->data[q->rptr];
517-
if (++q->rptr == PS2_QUEUE_SIZE)
581+
if (++q->rptr == PS2_BUFFER_SIZE) {
518582
q->rptr = 0;
583+
}
519584
q->count--;
585+
if (q->rptr == q->cwptr) {
586+
/* command reply queue is empty */
587+
q->cwptr = -1;
588+
}
520589
/* reading deasserts IRQ */
521590
s->update_irq(s->update_arg, 0);
522591
/* reassert IRQs if data left */
@@ -548,92 +617,83 @@ void ps2_write_keyboard(void *opaque, int val)
548617
PS2KbdState *s = (PS2KbdState *)opaque;
549618

550619
trace_ps2_write_keyboard(opaque, val);
620+
ps2_cqueue_reset(&s->common);
551621
switch(s->common.write_cmd) {
552622
default:
553623
case -1:
554624
switch(val) {
555625
case 0x00:
556-
ps2_queue(&s->common, KBD_REPLY_ACK);
626+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
557627
break;
558628
case 0x05:
559-
ps2_queue(&s->common, KBD_REPLY_RESEND);
629+
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
560630
break;
561631
case KBD_CMD_GET_ID:
562632
/* We emulate a MF2 AT keyboard here */
563-
if (s->translate)
564-
ps2_queue_3(&s->common,
565-
KBD_REPLY_ACK,
566-
KBD_REPLY_ID,
567-
0x41);
568-
else
569-
ps2_queue_3(&s->common,
570-
KBD_REPLY_ACK,
571-
KBD_REPLY_ID,
572-
0x83);
633+
ps2_cqueue_3(&s->common, KBD_REPLY_ACK, KBD_REPLY_ID,
634+
s->translate ? 0x41 : 0x83);
573635
break;
574636
case KBD_CMD_ECHO:
575-
ps2_queue(&s->common, KBD_CMD_ECHO);
637+
ps2_cqueue_1(&s->common, KBD_CMD_ECHO);
576638
break;
577639
case KBD_CMD_ENABLE:
578640
s->scan_enabled = 1;
579-
ps2_queue(&s->common, KBD_REPLY_ACK);
641+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
580642
break;
581643
case KBD_CMD_SCANCODE:
582644
case KBD_CMD_SET_LEDS:
583645
case KBD_CMD_SET_RATE:
584646
case KBD_CMD_SET_MAKE_BREAK:
585647
s->common.write_cmd = val;
586-
ps2_queue(&s->common, KBD_REPLY_ACK);
648+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
587649
break;
588650
case KBD_CMD_RESET_DISABLE:
589651
ps2_reset_keyboard(s);
590652
s->scan_enabled = 0;
591-
ps2_queue(&s->common, KBD_REPLY_ACK);
653+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
592654
break;
593655
case KBD_CMD_RESET_ENABLE:
594656
ps2_reset_keyboard(s);
595657
s->scan_enabled = 1;
596-
ps2_queue(&s->common, KBD_REPLY_ACK);
658+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
597659
break;
598660
case KBD_CMD_RESET:
599661
ps2_reset_keyboard(s);
600-
ps2_queue_2(&s->common,
662+
ps2_cqueue_2(&s->common,
601663
KBD_REPLY_ACK,
602664
KBD_REPLY_POR);
603665
break;
604666
case KBD_CMD_SET_TYPEMATIC:
605-
ps2_queue(&s->common, KBD_REPLY_ACK);
667+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
606668
break;
607669
default:
608-
ps2_queue(&s->common, KBD_REPLY_RESEND);
670+
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
609671
break;
610672
}
611673
break;
612674
case KBD_CMD_SET_MAKE_BREAK:
613-
ps2_queue(&s->common, KBD_REPLY_ACK);
675+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
614676
s->common.write_cmd = -1;
615677
break;
616678
case KBD_CMD_SCANCODE:
617679
if (val == 0) {
618-
if (s->common.queue.count <= PS2_QUEUE_SIZE - 2) {
619-
ps2_queue(&s->common, KBD_REPLY_ACK);
620-
ps2_put_keycode(s, s->scancode_set);
621-
}
680+
ps2_cqueue_2(&s->common, KBD_REPLY_ACK, s->translate ?
681+
translate_table[s->scancode_set] : s->scancode_set);
622682
} else if (val >= 1 && val <= 3) {
623683
s->scancode_set = val;
624-
ps2_queue(&s->common, KBD_REPLY_ACK);
684+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
625685
} else {
626-
ps2_queue(&s->common, KBD_REPLY_RESEND);
686+
ps2_cqueue_1(&s->common, KBD_REPLY_RESEND);
627687
}
628688
s->common.write_cmd = -1;
629689
break;
630690
case KBD_CMD_SET_LEDS:
631691
ps2_set_ledstate(s, val);
632-
ps2_queue(&s->common, KBD_REPLY_ACK);
692+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
633693
s->common.write_cmd = -1;
634694
break;
635695
case KBD_CMD_SET_RATE:
636-
ps2_queue(&s->common, KBD_REPLY_ACK);
696+
ps2_cqueue_1(&s->common, KBD_REPLY_ACK);
637697
s->common.write_cmd = -1;
638698
break;
639699
}
@@ -926,30 +986,27 @@ static void ps2_common_reset(PS2State *s)
926986
static void ps2_common_post_load(PS2State *s)
927987
{
928988
PS2Queue *q = &s->queue;
929-
uint8_t i, size;
930-
uint8_t tmp_data[PS2_QUEUE_SIZE];
931-
932-
/* set the useful data buffer queue size, < PS2_QUEUE_SIZE */
933-
size = q->count;
934-
if (q->count < 0) {
935-
size = 0;
936-
} else if (q->count > PS2_QUEUE_SIZE) {
937-
size = PS2_QUEUE_SIZE;
938-
}
989+
int ccount = 0;
939990

940-
/* move the queue elements to the start of data array */
941-
for (i = 0; i < size; i++) {
942-
if (q->rptr < 0 || q->rptr >= sizeof(q->data)) {
943-
q->rptr = 0;
991+
/* limit the number of queued command replies to PS2_QUEUE_HEADROOM */
992+
if (q->cwptr != -1) {
993+
ccount = (q->cwptr - q->rptr) & (PS2_BUFFER_SIZE - 1);
994+
if (ccount > PS2_QUEUE_HEADROOM) {
995+
ccount = PS2_QUEUE_HEADROOM;
944996
}
945-
tmp_data[i] = q->data[q->rptr++];
946997
}
947-
memcpy(q->data, tmp_data, size);
948998

949-
/* reset rptr/wptr/count */
950-
q->rptr = 0;
951-
q->wptr = (size == PS2_QUEUE_SIZE) ? 0 : size;
952-
q->count = size;
999+
/* limit the scancode queue size to PS2_QUEUE_SIZE */
1000+
if (q->count < ccount) {
1001+
q->count = ccount;
1002+
} else if (q->count > ccount + PS2_QUEUE_SIZE) {
1003+
q->count = ccount + PS2_QUEUE_SIZE;
1004+
}
1005+
1006+
/* sanitize rptr and recalculate wptr and cwptr */
1007+
q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1);
1008+
q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1);
1009+
q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1;
9531010
}
9541011

9551012
static void ps2_kbd_reset(void *opaque)
@@ -1040,6 +1097,22 @@ static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
10401097
}
10411098
};
10421099

1100+
static bool ps2_keyboard_cqueue_needed(void *opaque)
1101+
{
1102+
PS2KbdState *s = opaque;
1103+
1104+
return s->common.queue.cwptr != -1; /* the queue is mostly empty */
1105+
}
1106+
1107+
static const VMStateDescription vmstate_ps2_keyboard_cqueue = {
1108+
.name = "ps2kbd/command_reply_queue",
1109+
.needed = ps2_keyboard_cqueue_needed,
1110+
.fields = (VMStateField[]) {
1111+
VMSTATE_INT32(common.queue.cwptr, PS2KbdState),
1112+
VMSTATE_END_OF_LIST()
1113+
}
1114+
};
1115+
10431116
static int ps2_kbd_post_load(void* opaque, int version_id)
10441117
{
10451118
PS2KbdState *s = (PS2KbdState*)opaque;
@@ -1053,22 +1126,11 @@ static int ps2_kbd_post_load(void* opaque, int version_id)
10531126
return 0;
10541127
}
10551128

1056-
static int ps2_kbd_pre_save(void *opaque)
1057-
{
1058-
PS2KbdState *s = (PS2KbdState *)opaque;
1059-
PS2State *ps2 = &s->common;
1060-
1061-
ps2_common_post_load(ps2);
1062-
1063-
return 0;
1064-
}
1065-
10661129
static const VMStateDescription vmstate_ps2_keyboard = {
10671130
.name = "ps2kbd",
10681131
.version_id = 3,
10691132
.minimum_version_id = 2,
10701133
.post_load = ps2_kbd_post_load,
1071-
.pre_save = ps2_kbd_pre_save,
10721134
.fields = (VMStateField[]) {
10731135
VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
10741136
VMSTATE_INT32(scan_enabled, PS2KbdState),
@@ -1079,6 +1141,7 @@ static const VMStateDescription vmstate_ps2_keyboard = {
10791141
.subsections = (const VMStateDescription*[]) {
10801142
&vmstate_ps2_keyboard_ledstate,
10811143
&vmstate_ps2_keyboard_need_high_bit,
1144+
&vmstate_ps2_keyboard_cqueue,
10821145
NULL
10831146
}
10841147
};
@@ -1093,22 +1156,11 @@ static int ps2_mouse_post_load(void *opaque, int version_id)
10931156
return 0;
10941157
}
10951158

1096-
static int ps2_mouse_pre_save(void *opaque)
1097-
{
1098-
PS2MouseState *s = (PS2MouseState *)opaque;
1099-
PS2State *ps2 = &s->common;
1100-
1101-
ps2_common_post_load(ps2);
1102-
1103-
return 0;
1104-
}
1105-
11061159
static const VMStateDescription vmstate_ps2_mouse = {
11071160
.name = "ps2mouse",
11081161
.version_id = 2,
11091162
.minimum_version_id = 2,
11101163
.post_load = ps2_mouse_post_load,
1111-
.pre_save = ps2_mouse_pre_save,
11121164
.fields = (VMStateField[]) {
11131165
VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
11141166
VMSTATE_UINT8(mouse_status, PS2MouseState),

0 commit comments

Comments
 (0)