0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/pci.h>
0013
0014 #include <drm/drm_drv.h>
0015 #include <drm/drm_probe_helper.h>
0016
0017 #include "vbox_drv.h"
0018 #include "vboxvideo.h"
0019
0020 static void vbox_clear_irq(void)
0021 {
0022 outl((u32)~0, VGA_PORT_HGSMI_HOST);
0023 }
0024
0025 static u32 vbox_get_flags(struct vbox_private *vbox)
0026 {
0027 return readl(vbox->guest_heap + HOST_FLAGS_OFFSET);
0028 }
0029
0030 void vbox_report_hotplug(struct vbox_private *vbox)
0031 {
0032 schedule_work(&vbox->hotplug_work);
0033 }
0034
0035 static irqreturn_t vbox_irq_handler(int irq, void *arg)
0036 {
0037 struct drm_device *dev = (struct drm_device *)arg;
0038 struct vbox_private *vbox = to_vbox_dev(dev);
0039 u32 host_flags = vbox_get_flags(vbox);
0040
0041 if (!(host_flags & HGSMIHOSTFLAGS_IRQ))
0042 return IRQ_NONE;
0043
0044
0045
0046
0047
0048
0049
0050 if (host_flags &
0051 (HGSMIHOSTFLAGS_HOTPLUG | HGSMIHOSTFLAGS_CURSOR_CAPABILITIES) &&
0052 !(host_flags & HGSMIHOSTFLAGS_VSYNC))
0053 vbox_report_hotplug(vbox);
0054
0055 vbox_clear_irq();
0056
0057 return IRQ_HANDLED;
0058 }
0059
0060
0061
0062
0063
0064
0065
0066 static void validate_or_set_position_hints(struct vbox_private *vbox)
0067 {
0068 struct vbva_modehint *hintsi, *hintsj;
0069 bool valid = true;
0070 u16 currentx = 0;
0071 int i, j;
0072
0073 for (i = 0; i < vbox->num_crtcs; ++i) {
0074 for (j = 0; j < i; ++j) {
0075 hintsi = &vbox->last_mode_hints[i];
0076 hintsj = &vbox->last_mode_hints[j];
0077
0078 if (hintsi->enabled && hintsj->enabled) {
0079 if (hintsi->dx >= 0xffff ||
0080 hintsi->dy >= 0xffff ||
0081 hintsj->dx >= 0xffff ||
0082 hintsj->dy >= 0xffff ||
0083 (hintsi->dx <
0084 hintsj->dx + (hintsj->cx & 0x8fff) &&
0085 hintsi->dx + (hintsi->cx & 0x8fff) >
0086 hintsj->dx) ||
0087 (hintsi->dy <
0088 hintsj->dy + (hintsj->cy & 0x8fff) &&
0089 hintsi->dy + (hintsi->cy & 0x8fff) >
0090 hintsj->dy))
0091 valid = false;
0092 }
0093 }
0094 }
0095 if (!valid)
0096 for (i = 0; i < vbox->num_crtcs; ++i) {
0097 if (vbox->last_mode_hints[i].enabled) {
0098 vbox->last_mode_hints[i].dx = currentx;
0099 vbox->last_mode_hints[i].dy = 0;
0100 currentx +=
0101 vbox->last_mode_hints[i].cx & 0x8fff;
0102 }
0103 }
0104 }
0105
0106
0107 static void vbox_update_mode_hints(struct vbox_private *vbox)
0108 {
0109 struct drm_connector_list_iter conn_iter;
0110 struct drm_device *dev = &vbox->ddev;
0111 struct drm_connector *connector;
0112 struct vbox_connector *vbox_conn;
0113 struct vbva_modehint *hints;
0114 u16 flags;
0115 bool disconnected;
0116 unsigned int crtc_id;
0117 int ret;
0118
0119 ret = hgsmi_get_mode_hints(vbox->guest_pool, vbox->num_crtcs,
0120 vbox->last_mode_hints);
0121 if (ret) {
0122 DRM_ERROR("vboxvideo: hgsmi_get_mode_hints failed: %d\n", ret);
0123 return;
0124 }
0125
0126 validate_or_set_position_hints(vbox);
0127
0128 drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
0129 drm_connector_list_iter_begin(dev, &conn_iter);
0130 drm_for_each_connector_iter(connector, &conn_iter) {
0131 vbox_conn = to_vbox_connector(connector);
0132
0133 hints = &vbox->last_mode_hints[vbox_conn->vbox_crtc->crtc_id];
0134 if (hints->magic != VBVAMODEHINT_MAGIC)
0135 continue;
0136
0137 disconnected = !(hints->enabled);
0138 crtc_id = vbox_conn->vbox_crtc->crtc_id;
0139 vbox_conn->mode_hint.width = hints->cx;
0140 vbox_conn->mode_hint.height = hints->cy;
0141 vbox_conn->vbox_crtc->x_hint = hints->dx;
0142 vbox_conn->vbox_crtc->y_hint = hints->dy;
0143 vbox_conn->mode_hint.disconnected = disconnected;
0144
0145 if (vbox_conn->vbox_crtc->disconnected == disconnected)
0146 continue;
0147
0148 if (disconnected)
0149 flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_DISABLED;
0150 else
0151 flags = VBVA_SCREEN_F_ACTIVE | VBVA_SCREEN_F_BLANK;
0152
0153 hgsmi_process_display_info(vbox->guest_pool, crtc_id, 0, 0, 0,
0154 hints->cx * 4, hints->cx,
0155 hints->cy, 0, flags);
0156
0157 vbox_conn->vbox_crtc->disconnected = disconnected;
0158 }
0159 drm_connector_list_iter_end(&conn_iter);
0160 drm_modeset_unlock(&dev->mode_config.connection_mutex);
0161 }
0162
0163 static void vbox_hotplug_worker(struct work_struct *work)
0164 {
0165 struct vbox_private *vbox = container_of(work, struct vbox_private,
0166 hotplug_work);
0167
0168 vbox_update_mode_hints(vbox);
0169 drm_kms_helper_hotplug_event(&vbox->ddev);
0170 }
0171
0172 int vbox_irq_init(struct vbox_private *vbox)
0173 {
0174 struct drm_device *dev = &vbox->ddev;
0175 struct pci_dev *pdev = to_pci_dev(dev->dev);
0176
0177 INIT_WORK(&vbox->hotplug_work, vbox_hotplug_worker);
0178 vbox_update_mode_hints(vbox);
0179
0180
0181 return request_irq(pdev->irq, vbox_irq_handler, IRQF_SHARED, dev->driver->name, dev);
0182 }
0183
0184 void vbox_irq_fini(struct vbox_private *vbox)
0185 {
0186 struct drm_device *dev = &vbox->ddev;
0187 struct pci_dev *pdev = to_pci_dev(dev->dev);
0188
0189 free_irq(pdev->irq, dev);
0190 flush_work(&vbox->hotplug_work);
0191 }