74
74
#define MOUSE_STATUS_ENABLED 0x20
75
75
#define MOUSE_STATUS_SCALE21 0x10
76
76
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 */
78
84
79
85
/* Bits for 'modifiers' field in PS2KbdState */
80
86
#define MOD_CTRL_L (1 << 0)
85
91
#define MOD_ALT_R (1 << 5)
86
92
87
93
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 ;
92
96
} PS2Queue ;
93
97
94
98
struct PS2State {
@@ -183,6 +187,7 @@ static void ps2_reset_queue(PS2State *s)
183
187
184
188
q -> rptr = 0 ;
185
189
q -> wptr = 0 ;
190
+ q -> cwptr = -1 ;
186
191
q -> count = 0 ;
187
192
}
188
193
@@ -195,13 +200,14 @@ void ps2_queue_noirq(PS2State *s, int b)
195
200
{
196
201
PS2Queue * q = & s -> queue ;
197
202
198
- if (q -> count = = PS2_QUEUE_SIZE ) {
203
+ if (q -> count > = PS2_QUEUE_SIZE ) {
199
204
return ;
200
205
}
201
206
202
207
q -> data [q -> wptr ] = b ;
203
- if (++ q -> wptr == PS2_QUEUE_SIZE )
208
+ if (++ q -> wptr == PS2_BUFFER_SIZE ) {
204
209
q -> wptr = 0 ;
210
+ }
205
211
q -> count ++ ;
206
212
}
207
213
@@ -256,6 +262,63 @@ void ps2_queue_4(PS2State *s, int b1, int b2, int b3, int b4)
256
262
ps2_raise_irq (s );
257
263
}
258
264
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
+
259
322
/* keycode is the untranslated scancode in the current scancode set. */
260
323
static void ps2_put_keycode (void * opaque , int keycode )
261
324
{
@@ -509,14 +572,20 @@ uint32_t ps2_read_data(PS2State *s)
509
572
(needed for EMM386) */
510
573
/* XXX: need a timer to do things correctly */
511
574
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
+ }
514
578
val = q -> data [index ];
515
579
} else {
516
580
val = q -> data [q -> rptr ];
517
- if (++ q -> rptr == PS2_QUEUE_SIZE )
581
+ if (++ q -> rptr == PS2_BUFFER_SIZE ) {
518
582
q -> rptr = 0 ;
583
+ }
519
584
q -> count -- ;
585
+ if (q -> rptr == q -> cwptr ) {
586
+ /* command reply queue is empty */
587
+ q -> cwptr = -1 ;
588
+ }
520
589
/* reading deasserts IRQ */
521
590
s -> update_irq (s -> update_arg , 0 );
522
591
/* reassert IRQs if data left */
@@ -548,92 +617,83 @@ void ps2_write_keyboard(void *opaque, int val)
548
617
PS2KbdState * s = (PS2KbdState * )opaque ;
549
618
550
619
trace_ps2_write_keyboard (opaque , val );
620
+ ps2_cqueue_reset (& s -> common );
551
621
switch (s -> common .write_cmd ) {
552
622
default :
553
623
case -1 :
554
624
switch (val ) {
555
625
case 0x00 :
556
- ps2_queue (& s -> common , KBD_REPLY_ACK );
626
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
557
627
break ;
558
628
case 0x05 :
559
- ps2_queue (& s -> common , KBD_REPLY_RESEND );
629
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_RESEND );
560
630
break ;
561
631
case KBD_CMD_GET_ID :
562
632
/* 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 );
573
635
break ;
574
636
case KBD_CMD_ECHO :
575
- ps2_queue (& s -> common , KBD_CMD_ECHO );
637
+ ps2_cqueue_1 (& s -> common , KBD_CMD_ECHO );
576
638
break ;
577
639
case KBD_CMD_ENABLE :
578
640
s -> scan_enabled = 1 ;
579
- ps2_queue (& s -> common , KBD_REPLY_ACK );
641
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
580
642
break ;
581
643
case KBD_CMD_SCANCODE :
582
644
case KBD_CMD_SET_LEDS :
583
645
case KBD_CMD_SET_RATE :
584
646
case KBD_CMD_SET_MAKE_BREAK :
585
647
s -> common .write_cmd = val ;
586
- ps2_queue (& s -> common , KBD_REPLY_ACK );
648
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
587
649
break ;
588
650
case KBD_CMD_RESET_DISABLE :
589
651
ps2_reset_keyboard (s );
590
652
s -> scan_enabled = 0 ;
591
- ps2_queue (& s -> common , KBD_REPLY_ACK );
653
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
592
654
break ;
593
655
case KBD_CMD_RESET_ENABLE :
594
656
ps2_reset_keyboard (s );
595
657
s -> scan_enabled = 1 ;
596
- ps2_queue (& s -> common , KBD_REPLY_ACK );
658
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
597
659
break ;
598
660
case KBD_CMD_RESET :
599
661
ps2_reset_keyboard (s );
600
- ps2_queue_2 (& s -> common ,
662
+ ps2_cqueue_2 (& s -> common ,
601
663
KBD_REPLY_ACK ,
602
664
KBD_REPLY_POR );
603
665
break ;
604
666
case KBD_CMD_SET_TYPEMATIC :
605
- ps2_queue (& s -> common , KBD_REPLY_ACK );
667
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
606
668
break ;
607
669
default :
608
- ps2_queue (& s -> common , KBD_REPLY_RESEND );
670
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_RESEND );
609
671
break ;
610
672
}
611
673
break ;
612
674
case KBD_CMD_SET_MAKE_BREAK :
613
- ps2_queue (& s -> common , KBD_REPLY_ACK );
675
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
614
676
s -> common .write_cmd = -1 ;
615
677
break ;
616
678
case KBD_CMD_SCANCODE :
617
679
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 );
622
682
} else if (val >= 1 && val <= 3 ) {
623
683
s -> scancode_set = val ;
624
- ps2_queue (& s -> common , KBD_REPLY_ACK );
684
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
625
685
} else {
626
- ps2_queue (& s -> common , KBD_REPLY_RESEND );
686
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_RESEND );
627
687
}
628
688
s -> common .write_cmd = -1 ;
629
689
break ;
630
690
case KBD_CMD_SET_LEDS :
631
691
ps2_set_ledstate (s , val );
632
- ps2_queue (& s -> common , KBD_REPLY_ACK );
692
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
633
693
s -> common .write_cmd = -1 ;
634
694
break ;
635
695
case KBD_CMD_SET_RATE :
636
- ps2_queue (& s -> common , KBD_REPLY_ACK );
696
+ ps2_cqueue_1 (& s -> common , KBD_REPLY_ACK );
637
697
s -> common .write_cmd = -1 ;
638
698
break ;
639
699
}
@@ -926,30 +986,27 @@ static void ps2_common_reset(PS2State *s)
926
986
static void ps2_common_post_load (PS2State * s )
927
987
{
928
988
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 ;
939
990
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 ;
944
996
}
945
- tmp_data [i ] = q -> data [q -> rptr ++ ];
946
997
}
947
- memcpy (q -> data , tmp_data , size );
948
998
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 ;
953
1010
}
954
1011
955
1012
static void ps2_kbd_reset (void * opaque )
@@ -1040,6 +1097,22 @@ static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
1040
1097
}
1041
1098
};
1042
1099
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
+
1043
1116
static int ps2_kbd_post_load (void * opaque , int version_id )
1044
1117
{
1045
1118
PS2KbdState * s = (PS2KbdState * )opaque ;
@@ -1053,22 +1126,11 @@ static int ps2_kbd_post_load(void* opaque, int version_id)
1053
1126
return 0 ;
1054
1127
}
1055
1128
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
-
1066
1129
static const VMStateDescription vmstate_ps2_keyboard = {
1067
1130
.name = "ps2kbd" ,
1068
1131
.version_id = 3 ,
1069
1132
.minimum_version_id = 2 ,
1070
1133
.post_load = ps2_kbd_post_load ,
1071
- .pre_save = ps2_kbd_pre_save ,
1072
1134
.fields = (VMStateField []) {
1073
1135
VMSTATE_STRUCT (common , PS2KbdState , 0 , vmstate_ps2_common , PS2State ),
1074
1136
VMSTATE_INT32 (scan_enabled , PS2KbdState ),
@@ -1079,6 +1141,7 @@ static const VMStateDescription vmstate_ps2_keyboard = {
1079
1141
.subsections = (const VMStateDescription * []) {
1080
1142
& vmstate_ps2_keyboard_ledstate ,
1081
1143
& vmstate_ps2_keyboard_need_high_bit ,
1144
+ & vmstate_ps2_keyboard_cqueue ,
1082
1145
NULL
1083
1146
}
1084
1147
};
@@ -1093,22 +1156,11 @@ static int ps2_mouse_post_load(void *opaque, int version_id)
1093
1156
return 0 ;
1094
1157
}
1095
1158
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
-
1106
1159
static const VMStateDescription vmstate_ps2_mouse = {
1107
1160
.name = "ps2mouse" ,
1108
1161
.version_id = 2 ,
1109
1162
.minimum_version_id = 2 ,
1110
1163
.post_load = ps2_mouse_post_load ,
1111
- .pre_save = ps2_mouse_pre_save ,
1112
1164
.fields = (VMStateField []) {
1113
1165
VMSTATE_STRUCT (common , PS2MouseState , 0 , vmstate_ps2_common , PS2State ),
1114
1166
VMSTATE_UINT8 (mouse_status , PS2MouseState ),
0 commit comments