1 // SPDX-License-Identifier: MIT
3 * Copyright (C) 2016-2017 Oracle Corporation
4 * This file is based on qxl_irq.c
5 * Copyright 2013 Red Hat Inc.
8 * Michael Thayer <michael.thayer@oracle.com,
9 * Hans de Goede <hdegoede@redhat.com>
12 #include <linux/pci.h>
13 #include <drm/drm_irq.h>
14 #include <drm/drm_probe_helper.h>
17 #include "vboxvideo.h"
19 static void vbox_clear_irq(void)
21 outl((u32
)~0, VGA_PORT_HGSMI_HOST
);
24 static u32
vbox_get_flags(struct vbox_private
*vbox
)
26 return readl(vbox
->guest_heap
+ HOST_FLAGS_OFFSET
);
29 void vbox_report_hotplug(struct vbox_private
*vbox
)
31 schedule_work(&vbox
->hotplug_work
);
34 irqreturn_t
vbox_irq_handler(int irq
, void *arg
)
36 struct drm_device
*dev
= (struct drm_device
*)arg
;
37 struct vbox_private
*vbox
= (struct vbox_private
*)dev
->dev_private
;
38 u32 host_flags
= vbox_get_flags(vbox
);
40 if (!(host_flags
& HGSMIHOSTFLAGS_IRQ
))
44 * Due to a bug in the initial host implementation of hot-plug irqs,
45 * the hot-plug and cursor capability flags were never cleared.
46 * Fortunately we can tell when they would have been set by checking
47 * that the VSYNC flag is not set.
50 (HGSMIHOSTFLAGS_HOTPLUG
| HGSMIHOSTFLAGS_CURSOR_CAPABILITIES
) &&
51 !(host_flags
& HGSMIHOSTFLAGS_VSYNC
))
52 vbox_report_hotplug(vbox
);
60 * Check that the position hints provided by the host are suitable for GNOME
61 * shell (i.e. all screens disjoint and hints for all enabled screens) and if
62 * not replace them with default ones. Providing valid hints improves the
63 * chances that we will get a known screen layout for pointer mapping.
65 static void validate_or_set_position_hints(struct vbox_private
*vbox
)
67 struct vbva_modehint
*hintsi
, *hintsj
;
72 for (i
= 0; i
< vbox
->num_crtcs
; ++i
) {
73 for (j
= 0; j
< i
; ++j
) {
74 hintsi
= &vbox
->last_mode_hints
[i
];
75 hintsj
= &vbox
->last_mode_hints
[j
];
77 if (hintsi
->enabled
&& hintsj
->enabled
) {
78 if (hintsi
->dx
>= 0xffff ||
79 hintsi
->dy
>= 0xffff ||
80 hintsj
->dx
>= 0xffff ||
81 hintsj
->dy
>= 0xffff ||
83 hintsj
->dx
+ (hintsj
->cx
& 0x8fff) &&
84 hintsi
->dx
+ (hintsi
->cx
& 0x8fff) >
87 hintsj
->dy
+ (hintsj
->cy
& 0x8fff) &&
88 hintsi
->dy
+ (hintsi
->cy
& 0x8fff) >
95 for (i
= 0; i
< vbox
->num_crtcs
; ++i
) {
96 if (vbox
->last_mode_hints
[i
].enabled
) {
97 vbox
->last_mode_hints
[i
].dx
= currentx
;
98 vbox
->last_mode_hints
[i
].dy
= 0;
100 vbox
->last_mode_hints
[i
].cx
& 0x8fff;
105 /* Query the host for the most recent video mode hints. */
106 static void vbox_update_mode_hints(struct vbox_private
*vbox
)
108 struct drm_device
*dev
= &vbox
->ddev
;
109 struct drm_connector
*connector
;
110 struct vbox_connector
*vbox_conn
;
111 struct vbva_modehint
*hints
;
114 unsigned int crtc_id
;
117 ret
= hgsmi_get_mode_hints(vbox
->guest_pool
, vbox
->num_crtcs
,
118 vbox
->last_mode_hints
);
120 DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret
);
124 validate_or_set_position_hints(vbox
);
125 drm_modeset_lock_all(dev
);
126 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
127 vbox_conn
= to_vbox_connector(connector
);
129 hints
= &vbox
->last_mode_hints
[vbox_conn
->vbox_crtc
->crtc_id
];
130 if (hints
->magic
!= VBVAMODEHINT_MAGIC
)
133 disconnected
= !(hints
->enabled
);
134 crtc_id
= vbox_conn
->vbox_crtc
->crtc_id
;
135 vbox_conn
->mode_hint
.width
= hints
->cx
;
136 vbox_conn
->mode_hint
.height
= hints
->cy
;
137 vbox_conn
->vbox_crtc
->x_hint
= hints
->dx
;
138 vbox_conn
->vbox_crtc
->y_hint
= hints
->dy
;
139 vbox_conn
->mode_hint
.disconnected
= disconnected
;
141 if (vbox_conn
->vbox_crtc
->disconnected
== disconnected
)
145 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_DISABLED
;
147 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_BLANK
;
149 hgsmi_process_display_info(vbox
->guest_pool
, crtc_id
, 0, 0, 0,
150 hints
->cx
* 4, hints
->cx
,
151 hints
->cy
, 0, flags
);
153 vbox_conn
->vbox_crtc
->disconnected
= disconnected
;
155 drm_modeset_unlock_all(dev
);
158 static void vbox_hotplug_worker(struct work_struct
*work
)
160 struct vbox_private
*vbox
= container_of(work
, struct vbox_private
,
163 vbox_update_mode_hints(vbox
);
164 drm_kms_helper_hotplug_event(&vbox
->ddev
);
167 int vbox_irq_init(struct vbox_private
*vbox
)
169 INIT_WORK(&vbox
->hotplug_work
, vbox_hotplug_worker
);
170 vbox_update_mode_hints(vbox
);
172 return drm_irq_install(&vbox
->ddev
, vbox
->ddev
.pdev
->irq
);
175 void vbox_irq_fini(struct vbox_private
*vbox
)
177 drm_irq_uninstall(&vbox
->ddev
);
178 flush_work(&vbox
->hotplug_work
);