2 * Copyright (C) 2016-2017 Oracle Corporation
3 * This file is based on qxl_irq.c
4 * Copyright 2013 Red Hat Inc.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
24 * Authors: Dave Airlie
26 * Michael Thayer <michael.thayer@oracle.com,
27 * Hans de Goede <hdegoede@redhat.com>
30 #include <drm/drm_crtc_helper.h>
33 #include "vboxvideo.h"
35 static void vbox_clear_irq(void)
37 outl((u32
)~0, VGA_PORT_HGSMI_HOST
);
40 static u32
vbox_get_flags(struct vbox_private
*vbox
)
42 return readl(vbox
->guest_heap
+ HOST_FLAGS_OFFSET
);
45 void vbox_report_hotplug(struct vbox_private
*vbox
)
47 schedule_work(&vbox
->hotplug_work
);
50 irqreturn_t
vbox_irq_handler(int irq
, void *arg
)
52 struct drm_device
*dev
= (struct drm_device
*)arg
;
53 struct vbox_private
*vbox
= (struct vbox_private
*)dev
->dev_private
;
54 u32 host_flags
= vbox_get_flags(vbox
);
56 if (!(host_flags
& HGSMIHOSTFLAGS_IRQ
))
60 * Due to a bug in the initial host implementation of hot-plug irqs,
61 * the hot-plug and cursor capability flags were never cleared.
62 * Fortunately we can tell when they would have been set by checking
63 * that the VSYNC flag is not set.
66 (HGSMIHOSTFLAGS_HOTPLUG
| HGSMIHOSTFLAGS_CURSOR_CAPABILITIES
) &&
67 !(host_flags
& HGSMIHOSTFLAGS_VSYNC
))
68 vbox_report_hotplug(vbox
);
76 * Check that the position hints provided by the host are suitable for GNOME
77 * shell (i.e. all screens disjoint and hints for all enabled screens) and if
78 * not replace them with default ones. Providing valid hints improves the
79 * chances that we will get a known screen layout for pointer mapping.
81 static void validate_or_set_position_hints(struct vbox_private
*vbox
)
83 struct vbva_modehint
*hintsi
, *hintsj
;
88 for (i
= 0; i
< vbox
->num_crtcs
; ++i
) {
89 for (j
= 0; j
< i
; ++j
) {
90 hintsi
= &vbox
->last_mode_hints
[i
];
91 hintsj
= &vbox
->last_mode_hints
[j
];
93 if (hintsi
->enabled
&& hintsj
->enabled
) {
94 if (hintsi
->dx
>= 0xffff ||
95 hintsi
->dy
>= 0xffff ||
96 hintsj
->dx
>= 0xffff ||
97 hintsj
->dy
>= 0xffff ||
99 hintsj
->dx
+ (hintsj
->cx
& 0x8fff) &&
100 hintsi
->dx
+ (hintsi
->cx
& 0x8fff) >
103 hintsj
->dy
+ (hintsj
->cy
& 0x8fff) &&
104 hintsi
->dy
+ (hintsi
->cy
& 0x8fff) >
111 for (i
= 0; i
< vbox
->num_crtcs
; ++i
) {
112 if (vbox
->last_mode_hints
[i
].enabled
) {
113 vbox
->last_mode_hints
[i
].dx
= currentx
;
114 vbox
->last_mode_hints
[i
].dy
= 0;
116 vbox
->last_mode_hints
[i
].cx
& 0x8fff;
122 * Query the host for the most recent video mode hints.
124 static void vbox_update_mode_hints(struct vbox_private
*vbox
)
126 struct drm_device
*dev
= vbox
->dev
;
127 struct drm_connector
*connector
;
128 struct vbox_connector
*vbox_conn
;
129 struct vbva_modehint
*hints
;
132 unsigned int crtc_id
;
135 ret
= hgsmi_get_mode_hints(vbox
->guest_pool
, vbox
->num_crtcs
,
136 vbox
->last_mode_hints
);
138 DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret
);
142 validate_or_set_position_hints(vbox
);
143 drm_modeset_lock_all(dev
);
144 list_for_each_entry(connector
, &dev
->mode_config
.connector_list
, head
) {
145 vbox_conn
= to_vbox_connector(connector
);
147 hints
= &vbox
->last_mode_hints
[vbox_conn
->vbox_crtc
->crtc_id
];
148 if (hints
->magic
!= VBVAMODEHINT_MAGIC
)
151 disconnected
= !(hints
->enabled
);
152 crtc_id
= vbox_conn
->vbox_crtc
->crtc_id
;
153 vbox_conn
->mode_hint
.width
= hints
->cx
& 0x8fff;
154 vbox_conn
->mode_hint
.height
= hints
->cy
& 0x8fff;
155 vbox_conn
->vbox_crtc
->x_hint
= hints
->dx
;
156 vbox_conn
->vbox_crtc
->y_hint
= hints
->dy
;
157 vbox_conn
->mode_hint
.disconnected
= disconnected
;
159 if (vbox_conn
->vbox_crtc
->disconnected
== disconnected
)
163 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_DISABLED
;
165 flags
= VBVA_SCREEN_F_ACTIVE
| VBVA_SCREEN_F_BLANK
;
167 hgsmi_process_display_info(vbox
->guest_pool
, crtc_id
, 0, 0, 0,
168 hints
->cx
* 4, hints
->cx
,
169 hints
->cy
, 0, flags
);
171 vbox_conn
->vbox_crtc
->disconnected
= disconnected
;
173 drm_modeset_unlock_all(dev
);
176 static void vbox_hotplug_worker(struct work_struct
*work
)
178 struct vbox_private
*vbox
= container_of(work
, struct vbox_private
,
181 vbox_update_mode_hints(vbox
);
182 drm_kms_helper_hotplug_event(vbox
->dev
);
185 int vbox_irq_init(struct vbox_private
*vbox
)
187 INIT_WORK(&vbox
->hotplug_work
, vbox_hotplug_worker
);
188 vbox_update_mode_hints(vbox
);
190 return drm_irq_install(vbox
->dev
, vbox
->dev
->pdev
->irq
);
193 void vbox_irq_fini(struct vbox_private
*vbox
)
195 drm_irq_uninstall(vbox
->dev
);
196 flush_work(&vbox
->hotplug_work
);