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
= to_vbox_dev(dev
);
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_connector_list_iter conn_iter
;
109 struct drm_device
*dev
= &vbox
->ddev
;
110 struct drm_connector
*connector
;
111 struct vbox_connector
*vbox_conn
;
112 struct vbva_modehint
*hints
;
115 unsigned int crtc_id
;
118 ret
= hgsmi_get_mode_hints(vbox
->guest_pool
, vbox
->num_crtcs
,
119 vbox
->last_mode_hints
);
121 DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret
);
125 validate_or_set_position_hints(vbox
);
127 drm_modeset_lock(&dev
->mode_config
.connection_mutex
, NULL
);
128 drm_connector_list_iter_begin(dev
, &conn_iter
);
129 drm_for_each_connector_iter(connector
, &conn_iter
) {
130 vbox_conn
= to_vbox_connector(connector
);
132 hints
= &vbox
->last_mode_hints
[vbox_conn
->vbox_crtc
->crtc_id
];
133 if (hints
->magic
!= VBVAMODEHINT_MAGIC
)
136 disconnected
= !(hints
->enabled
);
137 crtc_id
= vbox_conn
->vbox_crtc
->crtc_id
;
138 vbox_conn
->mode_hint
.width
= hints
->cx
;
139 vbox_conn
->mode_hint
.height
= hints
->cy
;
140 vbox_conn
->vbox_crtc
->x_hint
= hints
->dx
;
141 vbox_conn
->vbox_crtc
->y_hint
= hints
->dy
;
142 vbox_conn
->mode_hint
.disconnected
= disconnected
;
144 if (vbox_conn
->vbox_crtc
->disconnected
== disconnected
)
148 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_DISABLED
;
150 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_BLANK
;
152 hgsmi_process_display_info(vbox
->guest_pool
, crtc_id
, 0, 0, 0,
153 hints
->cx
* 4, hints
->cx
,
154 hints
->cy
, 0, flags
);
156 vbox_conn
->vbox_crtc
->disconnected
= disconnected
;
158 drm_connector_list_iter_end(&conn_iter
);
159 drm_modeset_unlock(&dev
->mode_config
.connection_mutex
);
162 static void vbox_hotplug_worker(struct work_struct
*work
)
164 struct vbox_private
*vbox
= container_of(work
, struct vbox_private
,
167 vbox_update_mode_hints(vbox
);
168 drm_kms_helper_hotplug_event(&vbox
->ddev
);
171 int vbox_irq_init(struct vbox_private
*vbox
)
173 INIT_WORK(&vbox
->hotplug_work
, vbox_hotplug_worker
);
174 vbox_update_mode_hints(vbox
);
176 return drm_irq_install(&vbox
->ddev
, vbox
->ddev
.pdev
->irq
);
179 void vbox_irq_fini(struct vbox_private
*vbox
)
181 drm_irq_uninstall(&vbox
->ddev
);
182 flush_work(&vbox
->hotplug_work
);