ati-vga: Support unaligned access to hardware cursor registers
This fixes horizontal mouse movement and pointer color with MacOS that writes these registers with access size less than 4 so previously only the last portion of access was effective overwriting previous partial writes. Signed-off-by: BALATON Zoltan <balaton@eik.bme.hu> Message-id: ba1d5ba97f246e8807f86f1243c2bdc6497dc8f2.1592737958.git.balaton@eik.bme.hu Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
parent
9982c605a7
commit
d634c883ca
@ -389,22 +389,28 @@ static uint64_t ati_mm_read(void *opaque, hwaddr addr, unsigned int size)
|
|||||||
case 0xf00 ... 0xfff:
|
case 0xf00 ... 0xfff:
|
||||||
val = pci_default_read_config(&s->dev, addr - 0xf00, size);
|
val = pci_default_read_config(&s->dev, addr - 0xf00, size);
|
||||||
break;
|
break;
|
||||||
case CUR_OFFSET:
|
case CUR_OFFSET ... CUR_OFFSET + 3:
|
||||||
val = s->regs.cur_offset;
|
val = ati_reg_read_offs(s->regs.cur_offset, addr - CUR_OFFSET, size);
|
||||||
break;
|
break;
|
||||||
case CUR_HORZ_VERT_POSN:
|
case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
|
||||||
val = s->regs.cur_hv_pos;
|
val = ati_reg_read_offs(s->regs.cur_hv_pos,
|
||||||
val |= s->regs.cur_offset & BIT(31);
|
addr - CUR_HORZ_VERT_POSN, size);
|
||||||
|
if (addr + size > CUR_HORZ_VERT_POSN + 3) {
|
||||||
|
val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CUR_HORZ_VERT_OFF:
|
case CUR_HORZ_VERT_OFF ... CUR_HORZ_VERT_OFF + 3:
|
||||||
val = s->regs.cur_hv_offs;
|
val = ati_reg_read_offs(s->regs.cur_hv_offs,
|
||||||
val |= s->regs.cur_offset & BIT(31);
|
addr - CUR_HORZ_VERT_OFF, size);
|
||||||
|
if (addr + size > CUR_HORZ_VERT_OFF + 3) {
|
||||||
|
val |= (s->regs.cur_offset & BIT(31)) >> (4 - size);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CUR_CLR0:
|
case CUR_CLR0 ... CUR_CLR0 + 3:
|
||||||
val = s->regs.cur_color0;
|
val = ati_reg_read_offs(s->regs.cur_color0, addr - CUR_CLR0, size);
|
||||||
break;
|
break;
|
||||||
case CUR_CLR1:
|
case CUR_CLR1 ... CUR_CLR1 + 3:
|
||||||
val = s->regs.cur_color1;
|
val = ati_reg_read_offs(s->regs.cur_color1, addr - CUR_CLR1, size);
|
||||||
break;
|
break;
|
||||||
case DST_OFFSET:
|
case DST_OFFSET:
|
||||||
val = s->regs.dst_offset;
|
val = s->regs.dst_offset;
|
||||||
@ -679,48 +685,71 @@ static void ati_mm_write(void *opaque, hwaddr addr,
|
|||||||
case 0xf00 ... 0xfff:
|
case 0xf00 ... 0xfff:
|
||||||
/* read-only copy of PCI config space so ignore writes */
|
/* read-only copy of PCI config space so ignore writes */
|
||||||
break;
|
break;
|
||||||
case CUR_OFFSET:
|
case CUR_OFFSET ... CUR_OFFSET + 3:
|
||||||
if (s->regs.cur_offset != (data & 0x87fffff0)) {
|
{
|
||||||
s->regs.cur_offset = data & 0x87fffff0;
|
uint32_t t = s->regs.cur_offset;
|
||||||
|
|
||||||
|
ati_reg_write_offs(&t, addr - CUR_OFFSET, data, size);
|
||||||
|
t &= 0x87fffff0;
|
||||||
|
if (s->regs.cur_offset != t) {
|
||||||
|
s->regs.cur_offset = t;
|
||||||
ati_cursor_define(s);
|
ati_cursor_define(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CUR_HORZ_VERT_POSN:
|
}
|
||||||
s->regs.cur_hv_pos = data & 0x3fff0fff;
|
case CUR_HORZ_VERT_POSN ... CUR_HORZ_VERT_POSN + 3:
|
||||||
if (data & BIT(31)) {
|
{
|
||||||
s->regs.cur_offset |= data & BIT(31);
|
uint32_t t = s->regs.cur_hv_pos | (s->regs.cur_offset & BIT(31));
|
||||||
|
|
||||||
|
ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_POSN, data, size);
|
||||||
|
s->regs.cur_hv_pos = t & 0x3fff0fff;
|
||||||
|
if (t & BIT(31)) {
|
||||||
|
s->regs.cur_offset |= t & BIT(31);
|
||||||
} else if (s->regs.cur_offset & BIT(31)) {
|
} else if (s->regs.cur_offset & BIT(31)) {
|
||||||
s->regs.cur_offset &= ~BIT(31);
|
s->regs.cur_offset &= ~BIT(31);
|
||||||
ati_cursor_define(s);
|
ati_cursor_define(s);
|
||||||
}
|
}
|
||||||
if (!s->cursor_guest_mode &&
|
if (!s->cursor_guest_mode &&
|
||||||
(s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(data & BIT(31))) {
|
(s->regs.crtc_gen_cntl & CRTC2_CUR_EN) && !(t & BIT(31))) {
|
||||||
dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
|
dpy_mouse_set(s->vga.con, s->regs.cur_hv_pos >> 16,
|
||||||
s->regs.cur_hv_pos & 0xffff, 1);
|
s->regs.cur_hv_pos & 0xffff, 1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case CUR_HORZ_VERT_OFF:
|
case CUR_HORZ_VERT_OFF:
|
||||||
s->regs.cur_hv_offs = data & 0x3f003f;
|
{
|
||||||
if (data & BIT(31)) {
|
uint32_t t = s->regs.cur_hv_offs | (s->regs.cur_offset & BIT(31));
|
||||||
s->regs.cur_offset |= data & BIT(31);
|
|
||||||
|
ati_reg_write_offs(&t, addr - CUR_HORZ_VERT_OFF, data, size);
|
||||||
|
s->regs.cur_hv_offs = t & 0x3f003f;
|
||||||
|
if (t & BIT(31)) {
|
||||||
|
s->regs.cur_offset |= t & BIT(31);
|
||||||
} else if (s->regs.cur_offset & BIT(31)) {
|
} else if (s->regs.cur_offset & BIT(31)) {
|
||||||
s->regs.cur_offset &= ~BIT(31);
|
s->regs.cur_offset &= ~BIT(31);
|
||||||
ati_cursor_define(s);
|
ati_cursor_define(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CUR_CLR0:
|
}
|
||||||
if (s->regs.cur_color0 != (data & 0xffffff)) {
|
case CUR_CLR0 ... CUR_CLR0 + 3:
|
||||||
s->regs.cur_color0 = data & 0xffffff;
|
{
|
||||||
|
uint32_t t = s->regs.cur_color0;
|
||||||
|
|
||||||
|
ati_reg_write_offs(&t, addr - CUR_CLR0, data, size);
|
||||||
|
t &= 0xffffff;
|
||||||
|
if (s->regs.cur_color0 != t) {
|
||||||
|
s->regs.cur_color0 = t;
|
||||||
ati_cursor_define(s);
|
ati_cursor_define(s);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CUR_CLR1:
|
}
|
||||||
|
case CUR_CLR1 ... CUR_CLR1 + 3:
|
||||||
/*
|
/*
|
||||||
* Update cursor unconditionally here because some clients set up
|
* Update cursor unconditionally here because some clients set up
|
||||||
* other registers before actually writing cursor data to memory at
|
* other registers before actually writing cursor data to memory at
|
||||||
* offset so we would miss cursor change unless always updating here
|
* offset so we would miss cursor change unless always updating here
|
||||||
*/
|
*/
|
||||||
s->regs.cur_color1 = data & 0xffffff;
|
ati_reg_write_offs(&s->regs.cur_color1, addr - CUR_CLR1, data, size);
|
||||||
|
s->regs.cur_color1 &= 0xffffff;
|
||||||
ati_cursor_define(s);
|
ati_cursor_define(s);
|
||||||
break;
|
break;
|
||||||
case DST_OFFSET:
|
case DST_OFFSET:
|
||||||
|
Loading…
Reference in New Issue
Block a user