Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F160416479
D39395.id119789.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D39395.id119789.diff
View Options
diff --git a/sys/dev/hyperv/hvfb/hv_fb.c b/sys/dev/hyperv/hvfb/hv_fb.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/hyperv/hvfb/hv_fb.c
@@ -0,0 +1,684 @@
+/*-
+ * Copyright (c) 2017 Microsoft Corp.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice unmodified, this list of conditions, and the following
+ * disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
+#include <sys/kernel.h>
+#include <sys/linker.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+
+#include <machine/metadata.h>
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/hyperv/include/hyperv.h>
+#include <dev/hyperv/include/vmbus_xact.h>
+#include <dev/hyperv/utilities/hv_utilreg.h>
+#include <dev/hyperv/utilities/vmbus_icreg.h>
+#include <dev/hyperv/utilities/vmbus_icvar.h>
+
+#include <dev/vt/vt.h>
+#include <dev/vt/hw/fb/vt_fb.h>
+
+#include "vmbus_if.h"
+
+/* Protocol details taken from linux hyperv_fb driver */
+
+#define SV_VER(major, minor) ((minor) << 16 | (major))
+#define SV_VER_MAJOR(ver) (ver & 0x0000ffff)
+#define SV_VER_MINOR(ver) ((ver & 0xffff0000) >> 16)
+
+#define SV_VER_WIN7 SV_VER(3, 0)
+#define SV_VER_WIN8 SV_VER(3, 2)
+#define SV_VER_WIN10 SV_VER(3, 5)
+
+#define HV_BUFSIZ (4 * PAGE_SIZE)
+#define HV_RINGBUFF_SZ (10 * PAGE_SIZE)
+
+typedef struct {
+ device_t dev;
+ struct mtx mtx;
+ bool ready;
+ /* vmbus */
+ struct vmbus_channel *hs_chan;
+ struct vmbus_xact_ctx *hs_xact_ctx;
+ uint8_t *buf;
+ int buflen;
+ /* fb */
+ struct fb_info fb;
+} hv_fb_sc;
+
+typedef enum {
+ SV_VER_REQ = 1,
+ SV_VER_RESP = 2,
+ SV_VRAM = 3,
+ SV_VRAM_ACK = 4,
+ SV_SITU = 5,
+ SV_SITU_ACK = 6,
+ SV_PTR_POS = 7,
+ SV_PTR_SHAPE = 8,
+ SV_FEAT_CHG = 9,
+ SV_DIRT = 10,
+ SV_RES_REQ = 13,
+ SV_RES_RESP = 14,
+} sv_msg_type;
+
+typedef struct {
+ sv_msg_type type;
+ uint32_t size; /* includes header size */
+} __packed sv_msg_hdr;
+
+typedef struct {
+ uint32_t ver;
+} __packed sv_ver_req;
+
+typedef struct {
+ uint32_t ver;
+ uint8_t is_acc;
+ uint8_t max_vo;
+} __packed sv_ver_resp;
+
+typedef struct {
+ uint8_t max_res_cnt;
+} __packed sv_res_req;
+
+typedef struct {
+ uint16_t width;
+ uint16_t height;
+} __packed sv_scr_info;
+
+#define SV_EDID_SZ 128
+#define SV_MAX_RES_CNT 64
+
+typedef struct {
+ uint8_t edid[SV_EDID_SZ];
+ uint8_t res_cnt;
+ uint8_t def_res_idx;
+ uint8_t is_std;
+ sv_scr_info res[SV_MAX_RES_CNT];
+} __packed sv_res_resp;
+
+typedef struct {
+ uint64_t ctx;
+ uint8_t is_gpa;
+ uint64_t gpa;
+} __packed sv_vram;
+
+typedef struct {
+ uint64_t ctx;
+} __packed sv_vram_ack;
+
+typedef struct {
+ uint8_t active;
+ uint32_t vram_off;
+ uint8_t depth;
+ uint32_t width;
+ uint32_t height;
+ uint32_t pitch;
+} __packed vo_situ;
+
+typedef struct {
+ uint64_t ctx;
+ uint8_t vo_cnt;
+ vo_situ vo[1];
+} __packed sv_situ;
+
+typedef struct {
+ uint64_t ctx;
+} __packed sv_situ_ack;
+
+typedef struct {
+ uint8_t is_visible;
+ uint8_t vo;
+ int32_t img_x;
+ int32_t img_y;
+} __packed sv_ptr_pos;
+
+typedef struct {
+ uint8_t part_idx;
+ uint8_t is_argb;
+ uint32_t width;
+ uint32_t height;
+ uint32_t hs_x;
+ uint32_t hs_y;
+ uint8_t data[4];
+} __packed sv_ptr_shape;
+
+typedef struct {
+ uint8_t dirt;
+ uint8_t ptr_pos;
+ uint8_t ptr_shape;
+ uint8_t situ;
+} __packed sv_feat_chg;
+
+typedef struct {
+ int32_t x1;
+ int32_t y1;
+ int32_t x2;
+ int32_t y2;
+} __packed sv_rect;
+
+typedef struct {
+ uint8_t vo;
+ uint8_t cnt;
+ sv_rect rect[1];
+} __packed sv_dirt;
+
+typedef enum {
+ HV_MSG_INVALID,
+ HV_MSG_DATA,
+} hv_msg_type;
+
+typedef struct {
+ hv_msg_type type;
+ uint32_t size; /* does not include header size */
+} hv_fb_hdr;
+
+typedef struct {
+ hv_fb_hdr hdr;
+ sv_msg_hdr sv_hdr;
+ union {
+ sv_ver_req ver_req;
+ sv_ver_resp ver_resp;
+ sv_vram vram;
+ sv_vram_ack vram_ack;
+ sv_situ situ;
+ sv_situ_ack situ_ack;
+ sv_ptr_pos ptr_pos;
+ sv_ptr_shape ptr_shape;
+ sv_feat_chg feat_chg;
+ sv_dirt dirt;
+ sv_res_req res_req;
+ sv_res_resp res_resp;
+ };
+} __packed hv_fb_msg;
+
+static inline int
+hv_fb_send(hv_fb_sc *sc, hv_fb_msg *req, const hv_fb_msg **resp)
+{
+ struct vmbus_xact *xact;
+ hv_fb_msg *xreq;
+ const hv_fb_msg *xresp;
+ size_t xreqlen;
+ size_t xresplen;
+ int ret;
+
+ xreqlen = sizeof(hv_fb_hdr) + req->sv_hdr.size;
+ xact = vmbus_xact_get(sc->hs_xact_ctx, xreqlen);
+ if (xact == NULL) {
+ device_printf(sc->dev, "failed to get xact");
+ return (ENOMEM);
+ }
+ xreq = vmbus_xact_req_data(xact);
+ memcpy(xreq, req, xreqlen);
+ xreq->hdr.type = HV_MSG_DATA;
+ xreq->hdr.size = req->sv_hdr.size;
+
+ vmbus_xact_activate(xact);
+ ret = vmbus_chan_send(sc->hs_chan, VMBUS_CHANPKT_TYPE_INBAND,
+ VMBUS_CHANPKT_FLAG_RC, xreq, xreqlen, (uint64_t)(uintptr_t)xact);
+ if (ret != 0 || resp == NULL) {
+ vmbus_xact_deactivate(xact);
+ vmbus_xact_put(xact);
+ return (ret);
+ }
+ xresp = vmbus_chan_xact_wait(sc->hs_chan, xact, &xresplen, true);
+ *resp = xresp;
+ vmbus_xact_put(xact);
+ return (0);
+}
+
+static int
+hv_fb_neg_ver(hv_fb_sc *sc, uint32_t ver)
+{
+ hv_fb_msg req = { 0 };
+ const hv_fb_msg *resp;
+
+ req.sv_hdr.type = SV_VER_REQ;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_ver_req);
+ req.ver_req.ver = ver;
+
+ if (hv_fb_send(sc, &req, &resp) != 0 ||
+ resp->ver_resp.is_acc == 0)
+ return (ENODEV);
+
+ device_printf(sc->dev, "version %d.%d\n",
+ SV_VER_MAJOR(ver), SV_VER_MINOR(ver));
+ return (0);
+}
+
+static int
+hv_fb_get_res(hv_fb_sc *sc)
+{
+ hv_fb_msg req = { 0 };
+ const hv_fb_msg *resp;
+ uint8_t idx;
+ uint8_t i;
+
+ req.sv_hdr.type = SV_RES_REQ;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_res_req);
+ req.res_req.max_res_cnt = SV_MAX_RES_CNT;
+
+ if (hv_fb_send(sc, &req, &resp) != 0)
+ return (ENODEV);
+ if (resp->res_resp.res_cnt == 0) {
+ device_printf(sc->dev, "no supported resolutions");
+ return (ENODEV);
+ }
+ idx = resp->res_resp.def_res_idx;
+ if (idx >= resp->res_resp.res_cnt) {
+ device_printf(sc->dev, "invalid resolution index: %d\n", idx);
+ return (ENODEV);
+ }
+ device_printf(sc->dev, "supported resolutions:\n");
+ for (i = 0; i < resp->res_resp.res_cnt; i++) {
+ device_printf(sc->dev, " (%s%2d) %dx%d\n",
+ i == idx ? "*" : " ", i,
+ resp->res_resp.res[i].width,
+ resp->res_resp.res[i].height);
+ }
+
+ sc->fb.fb_width = resp->res_resp.res[idx].width;
+ sc->fb.fb_height = resp->res_resp.res[idx].height;
+
+ return (0);
+}
+
+static int
+hv_fb_connect_vsp(hv_fb_sc *sc)
+{
+ int ret;
+
+ /*
+ * Negotiate version.
+ * Everything prior to WIN10 is already unsupported by Microsoft, more
+ * so I have no means of testing on previous versions.
+ */
+ switch (vmbus_current_version) {
+ default:
+ case VMBUS_VERSION_WIN10:
+ ret = hv_fb_neg_ver(sc, SV_VER_WIN10);
+ break;
+ }
+ if (ret != 0) {
+ device_printf(sc->dev, "failed to negotiate version\n");
+ return (ret);
+ }
+
+ /* Get supported resolution list */
+ ret = hv_fb_get_res(sc);
+
+ return (ret);
+}
+
+/* Essentially this hides the builtin pointer */
+static void
+hv_fb_send_ptr(hv_fb_sc *sc)
+{
+ hv_fb_msg req;
+
+ memset(&req, 0, sizeof(req));
+ req.sv_hdr.type = SV_PTR_POS;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_ptr_pos);
+ req.ptr_pos.is_visible = 1;
+ req.ptr_pos.vo = 0;
+ req.ptr_pos.img_x = 0;
+ req.ptr_pos.img_y = 0;
+ if (hv_fb_send(sc, &req, NULL) != 0)
+ device_printf(sc->dev, "failed to send ptr pos\n");
+
+ memset(&req, 0, sizeof(req));
+ req.sv_hdr.type = SV_PTR_SHAPE;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_ptr_shape);
+ req.ptr_shape.part_idx = -1;
+ req.ptr_shape.is_argb = 1;
+ req.ptr_shape.width = 1;
+ req.ptr_shape.height = 1;
+ req.ptr_shape.hs_x = 0;
+ req.ptr_shape.hs_y = 0;
+ req.ptr_shape.data[0] = 0;
+ req.ptr_shape.data[1] = 1;
+ req.ptr_shape.data[2] = 1;
+ req.ptr_shape.data[3] = 1;
+ if (hv_fb_send(sc, &req, NULL) != 0)
+ device_printf(sc->dev, "failed to send ptr shape\n");
+}
+
+static void
+hv_fb_send_situ(hv_fb_sc *sc)
+{
+ hv_fb_msg req;
+
+ memset(&req, 0, sizeof(req));
+ req.sv_hdr.type = SV_SITU;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_situ);
+ req.situ.ctx = 0;
+ req.situ.vo_cnt = 1;
+ req.situ.vo[0].active = 1;
+ req.situ.vo[0].vram_off = 0;
+ req.situ.vo[0].depth = sc->fb.fb_depth;
+ req.situ.vo[0].width = sc->fb.fb_width;
+ req.situ.vo[0].height = sc->fb.fb_height;
+ req.situ.vo[0].pitch = sc->fb.fb_stride;
+ if (hv_fb_send(sc, &req, NULL) != 0)
+ device_printf(sc->dev, "failed to send situ\n");
+}
+
+static int
+hv_fb_send_config(hv_fb_sc *sc)
+{
+ hv_fb_msg req;
+ const hv_fb_msg *resp;
+
+ memset(&req, 0, sizeof(req));
+ req.sv_hdr.type = SV_VRAM;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_vram);
+ req.vram.ctx = req.vram.gpa = sc->fb.fb_pbase;
+ req.vram.is_gpa = 1;
+
+ if (hv_fb_send(sc, &req, &resp) != 0 ||
+ resp->vram_ack.ctx != sc->fb.fb_pbase) {
+ device_printf(sc->dev, "failed to set vram\n");
+ return (ENODEV);
+ }
+
+ hv_fb_send_ptr(sc);
+ hv_fb_send_situ(sc);
+
+ return (0);
+}
+
+static void
+hv_fb_update(hv_fb_sc *sc, int x1, int y1, int x2, int y2)
+{
+ hv_fb_msg req;
+
+ if (x2 == -1)
+ x2 = sc->fb.fb_width;
+ if (y2 == -1)
+ y2 = sc->fb.fb_height;
+
+ memset(&req, 0, sizeof(req));
+ req.sv_hdr.type = SV_DIRT;
+ req.sv_hdr.size = sizeof(sv_msg_hdr) + sizeof(sv_dirt);
+ req.dirt.vo = 0;
+ req.dirt.cnt = 1;
+ req.dirt.rect[0].x1 = (x1 > x2) ? 0 : x1;
+ req.dirt.rect[0].y1 = (y1 > y2) ? 0 : y1;
+ req.dirt.rect[0].x2 =
+ (x2 < x1 || x2 > sc->fb.fb_width) ? sc->fb.fb_width : x2;
+ req.dirt.rect[0].y2 =
+ (y2 < y1 || y2 > sc->fb.fb_height) ? sc->fb.fb_height : y2;
+ hv_fb_send(sc, &req, NULL);
+}
+
+static void
+hv_fb_receive(hv_fb_sc *sc, struct vmbus_chanpkt_hdr *pkt)
+{
+ const hv_fb_msg *msg;
+ uint32_t msg_len;
+
+ msg = VMBUS_CHANPKT_CONST_DATA(pkt);
+ msg_len = VMBUS_CHANPKT_DATALEN(pkt);
+
+ if (msg->hdr.type != HV_MSG_DATA)
+ return;
+
+ switch (msg->sv_hdr.type) {
+ case SV_VER_RESP:
+ case SV_RES_RESP:
+ case SV_VRAM_ACK:
+ if (sc->hs_xact_ctx != NULL)
+ vmbus_xact_ctx_wakeup(sc->hs_xact_ctx, msg, msg_len);
+ break;
+ case SV_SITU_ACK:
+ /* Nothing interesting here */
+ break;
+ case SV_FEAT_CHG:
+ if (sc->ready) {
+ hv_fb_send_ptr(sc);
+ hv_fb_send_situ(sc);
+ }
+ break;
+ default:
+ device_printf(sc->dev, "unhandled type: %d\n",
+ msg->sv_hdr.type);
+ break;
+ }
+}
+
+static void
+hv_fb_read_channel(struct vmbus_channel *channel, void *ctx)
+{
+ hv_fb_sc *sc;
+ uint8_t *buf;
+ int buflen;
+ int ret;
+
+ sc = ctx;
+ buf = sc->buf;
+ buflen = sc->buflen;
+ for (;;) {
+ struct vmbus_chanpkt_hdr *pkt;
+ int rcvd;
+
+ pkt = (struct vmbus_chanpkt_hdr *)buf;
+ rcvd = buflen;
+ ret = vmbus_chan_recv_pkt(channel, pkt, &rcvd);
+ if (__predict_false(ret == ENOBUFS)) {
+ buflen = sc->buflen * 2;
+ while (buflen < rcvd)
+ buflen *= 2;
+ buf = malloc(buflen, M_DEVBUF, M_WAITOK | M_ZERO);
+ device_printf(sc->dev, "expand recvbuf %d -> %d\n",
+ sc->buflen, buflen);
+ free(sc->buf, M_DEVBUF);
+ sc->buf = buf;
+ sc->buflen = buflen;
+ continue;
+ } else if (__predict_false(ret == EAGAIN)) {
+ /* No more channel packets; done! */
+ break;
+ }
+ KASSERT(ret == 0, ("vmbus_chan_recv_pkt failed: %d", ret));
+
+ switch (pkt->cph_type) {
+ case VMBUS_CHANPKT_TYPE_COMP:
+ case VMBUS_CHANPKT_TYPE_RXBUF:
+ device_printf(sc->dev, "unhandled event: %d\n",
+ pkt->cph_type);
+ break;
+ case VMBUS_CHANPKT_TYPE_INBAND:
+ hv_fb_receive(sc, pkt);
+ break;
+ default:
+ device_printf(sc->dev, "unknown event: %d\n",
+ pkt->cph_type);
+ break;
+ }
+ }
+}
+
+static const struct vmbus_ic_desc vmbus_fb_descs[] = {
+ {
+ .ic_guid = { .hv_guid = {
+ 0x02, 0x78, 0x0a, 0xda, 0x77, 0xe3, 0xac, 0x4a,
+ 0x8e, 0x77, 0x05, 0x58, 0xeb, 0x10, 0x73, 0xf8} },
+ .ic_desc = "Hyper-V framebuffer device"
+ },
+ VMBUS_IC_DESC_END
+};
+
+/* TODO: add GUID support to devmatch(8) to export vmbus_fb_descs directly */
+const struct {
+ char *guid;
+} vmbus_fb_descs_pnp[] = { { "da0a7802-e377-4aac-8e77-0558eb1073f8" } };
+
+static int hv_fb_attach(device_t dev);
+static int hv_fb_detach(device_t dev);
+
+static int
+hv_fb_probe(device_t dev)
+{
+ device_t bus;
+ const struct vmbus_ic_desc *d;
+
+ if (resource_disabled(device_get_name(dev), 0))
+ return (ENXIO);
+
+ bus = device_get_parent(dev);
+ for (d = vmbus_fb_descs; d->ic_desc != NULL; ++d) {
+ if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
+ device_set_desc(dev, d->ic_desc);
+ return (BUS_PROBE_DEFAULT);
+ }
+ }
+
+ return (ENXIO);
+}
+
+static int
+hv_fb_attach(device_t dev)
+{
+ hv_fb_sc *sc;
+ struct efi_fb *efifb;
+ caddr_t kmdp;
+ int ret;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+ sc->ready = false;
+ sc->buflen = HV_BUFSIZ;
+ sc->buf = malloc(sc->buflen, M_DEVBUF, M_WAITOK | M_ZERO);
+ mtx_init(&sc->mtx, "hvfb lock", NULL, MTX_DEF);
+
+ ret = ENODEV;
+ sc->hs_chan = vmbus_get_channel(dev);
+ sc->hs_xact_ctx = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
+ HV_RINGBUFF_SZ, HV_RINGBUFF_SZ, 0);
+ if (sc->hs_xact_ctx == NULL) {
+ device_printf(sc->dev, "failed to create xact ctx\n");
+ ret = ENOMEM;
+ goto out;
+ }
+ vmbus_chan_set_readbatch(sc->hs_chan, false);
+ if (vmbus_chan_open(sc->hs_chan, HV_RINGBUFF_SZ, HV_RINGBUFF_SZ, NULL,
+ 0, hv_fb_read_channel, sc) != 0) {
+ device_printf(sc->dev, "failed to open vmbus chan\n");
+ goto out;
+ }
+
+ if (hv_fb_connect_vsp(sc) != 0)
+ goto out;
+
+ /* Get the framebuffer information from EFI loader */
+ kmdp = preload_search_by_type("elf kernel");
+ if (kmdp == NULL)
+ kmdp = preload_search_by_type("elf64 kernel");
+ efifb = (struct efi_fb *)preload_search_info(kmdp,
+ MODINFO_METADATA | MODINFOMD_EFI_FB);
+ if (efifb == NULL) {
+ device_printf(sc->dev,
+ "failed to find framebuffer information\n");
+ goto out;
+ }
+
+ sc->fb.fb_type = FBTYPE_PCIMISC;
+ sc->fb.fb_pbase = efifb->fb_addr;
+ sc->fb.fb_size = efifb->fb_size;
+ sc->fb.fb_vbase = (intptr_t)pmap_mapdev_attr(sc->fb.fb_pbase,
+ sc->fb.fb_size, VM_MEMATTR_WRITE_COMBINING);
+ sc->fb.fb_depth = 32; /* XXX */
+ sc->fb.fb_bpp = roundup2(sc->fb.fb_depth, NBBY);
+ sc->fb.fb_stride = sc->fb.fb_width * (sc->fb.fb_bpp / NBBY);
+ sc->fb.fb_cmsize = 0;
+
+ if (hv_fb_send_config(sc) != 0)
+ goto out;
+
+ sc->fb.fb_fbd_dev = device_add_child(dev, "fbd", -1);
+ if (sc->fb.fb_fbd_dev == NULL || vt_fb_attach(&sc->fb) != 0) {
+ device_printf(sc->dev, "failed to attach fbd");
+ goto out;
+ }
+
+ sc->ready = true;
+ ret = 0;
+
+ /* This allows updates for a minute on load */
+ for (int i = 0; i < 1200; i++) {
+ hv_fb_update(sc, 0, 0, -1, -1);
+ pause("test", hz / 20);
+ }
+out:
+ if (ret != 0)
+ hv_fb_detach(dev);
+ return (ret);
+}
+
+static int
+hv_fb_detach(device_t dev)
+{
+ hv_fb_sc *sc;
+
+ sc = device_get_softc(dev);
+ sc->ready = false;
+ if (sc->fb.fb_fbd_dev != NULL) {
+ mtx_lock(&Giant);
+ device_delete_child(dev, sc->fb.fb_fbd_dev);
+ mtx_unlock(&Giant);
+ sc->fb.fb_fbd_dev = NULL;
+ }
+ vt_fb_detach(&sc->fb);
+
+ if (sc->hs_xact_ctx != NULL)
+ vmbus_xact_ctx_destroy(sc->hs_xact_ctx);
+ vmbus_chan_close(vmbus_get_channel(dev));
+ free(sc->buf, M_DEVBUF);
+ mtx_destroy(&sc->mtx);
+
+ return (0);
+}
+
+static device_method_t hv_fb_methods[] = {
+ DEVMETHOD(device_probe, hv_fb_probe),
+ DEVMETHOD(device_attach, hv_fb_attach),
+ DEVMETHOD(device_detach, hv_fb_detach),
+ DEVMETHOD_END,
+};
+
+static driver_t hv_fb_driver = {
+ .name = "hvfb",
+ .methods = hv_fb_methods,
+ .size = sizeof(hv_fb_sc),
+};
+
+DRIVER_MODULE(hv_fb, vmbus, hv_fb_driver, NULL, NULL);
+MODULE_VERSION(hv_fb, 1);
+MODULE_DEPEND(hv_fb, vmbus, 1, 1, 1);
+MODULE_DEPEND(hv_fb, fbd, 1, 1, 1);
diff --git a/sys/modules/hyperv/fb/Makefile b/sys/modules/hyperv/fb/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/hyperv/fb/Makefile
@@ -0,0 +1,11 @@
+.PATH: ${SRCTOP}/sys/dev/hyperv/hvfb
+
+KMOD= hv_fb
+SRCS= hv_fb.c
+SRCS+= bus_if.h device_if.h vmbus_if.h
+SRCS+= opt_splash.h opt_syscons.h opt_teken.h
+
+CFLAGS+= -I${SRCTOP}/sys/dev/hyperv/include \
+ -I${SRCTOP}/sys/dev/hyperv/vmbus
+
+.include <bsd.kmod.mk>
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Jun 25, 6:53 AM (51 m, 45 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
34309519
Default Alt Text
D39395.id119789.diff (16 KB)
Attached To
Mode
D39395: Hyper-V framebuffer driver
Attached
Detach File
Event Timeline
Log In to Comment