|
80 | 80 | */
|
81 | 81 | #define PS2_BUFFER_SIZE 256
|
82 | 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 */ |
83 | 84 |
|
84 | 85 | /* Bits for 'modifiers' field in PS2KbdState */
|
85 | 86 | #define MOD_CTRL_L (1 << 0)
|
@@ -985,17 +986,27 @@ static void ps2_common_reset(PS2State *s)
|
985 | 986 | static void ps2_common_post_load(PS2State *s)
|
986 | 987 | {
|
987 | 988 | PS2Queue *q = &s->queue;
|
| 989 | + int ccount = 0; |
988 | 990 |
|
989 |
| - /* set the useful data buffer queue size <= PS2_QUEUE_SIZE */ |
990 |
| - if (q->count < 0) { |
991 |
| - q->count = 0; |
992 |
| - } else if (q->count > PS2_QUEUE_SIZE) { |
993 |
| - q->count = PS2_QUEUE_SIZE; |
| 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; |
| 996 | + } |
| 997 | + } |
| 998 | + |
| 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; |
994 | 1004 | }
|
995 | 1005 |
|
996 |
| - /* sanitize rptr and recalculate wptr */ |
| 1006 | + /* sanitize rptr and recalculate wptr and cwptr */ |
997 | 1007 | q->rptr = q->rptr & (PS2_BUFFER_SIZE - 1);
|
998 | 1008 | q->wptr = (q->rptr + q->count) & (PS2_BUFFER_SIZE - 1);
|
| 1009 | + q->cwptr = ccount ? (q->rptr + ccount) & (PS2_BUFFER_SIZE - 1) : -1; |
999 | 1010 | }
|
1000 | 1011 |
|
1001 | 1012 | static void ps2_kbd_reset(void *opaque)
|
@@ -1086,6 +1097,22 @@ static const VMStateDescription vmstate_ps2_keyboard_need_high_bit = {
|
1086 | 1097 | }
|
1087 | 1098 | };
|
1088 | 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 | + |
1089 | 1116 | static int ps2_kbd_post_load(void* opaque, int version_id)
|
1090 | 1117 | {
|
1091 | 1118 | PS2KbdState *s = (PS2KbdState*)opaque;
|
@@ -1114,6 +1141,7 @@ static const VMStateDescription vmstate_ps2_keyboard = {
|
1114 | 1141 | .subsections = (const VMStateDescription*[]) {
|
1115 | 1142 | &vmstate_ps2_keyboard_ledstate,
|
1116 | 1143 | &vmstate_ps2_keyboard_need_high_bit,
|
| 1144 | + &vmstate_ps2_keyboard_cqueue, |
1117 | 1145 | NULL
|
1118 | 1146 | }
|
1119 | 1147 | };
|
|
0 commit comments