The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/hyperv/input/hv_kbdc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2017 Microsoft Corp.
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice unmodified, this list of conditions, and the following
   10  *    disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/kernel.h>
   32 #include <sys/conf.h>
   33 #include <sys/uio.h>
   34 #include <sys/bus.h>
   35 #include <sys/malloc.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/module.h>
   38 #include <sys/lock.h>
   39 #include <sys/taskqueue.h>
   40 #include <sys/selinfo.h>
   41 #include <sys/sysctl.h>
   42 #include <sys/poll.h>
   43 #include <sys/proc.h>
   44 #include <sys/queue.h>
   45 #include <sys/syscallsubr.h>
   46 #include <sys/sysproto.h>
   47 #include <sys/systm.h>
   48 #include <sys/mutex.h>
   49 
   50 #include <sys/kbio.h>
   51 #include <dev/kbd/kbdreg.h>
   52 
   53 #include <dev/hyperv/include/hyperv.h>
   54 #include <dev/hyperv/utilities/hv_utilreg.h>
   55 #include <dev/hyperv/utilities/vmbus_icreg.h>
   56 #include <dev/hyperv/utilities/vmbus_icvar.h>
   57 #include <dev/hyperv/include/vmbus_xact.h>
   58 
   59 #include "dev/hyperv/input/hv_kbdc.h"
   60 #include "vmbus_if.h"
   61 
   62 #define HV_KBD_VER_MAJOR        (1)
   63 #define HV_KBD_VER_MINOR        (0)
   64 
   65 #define HV_KBD_VER              (HV_KBD_VER_MINOR | (HV_KBD_VER_MAJOR) << 16)
   66 
   67 #define HV_KBD_PROTO_ACCEPTED   (1)
   68 
   69 #define HV_BUFF_SIZE            (4*PAGE_SIZE)
   70 #define HV_KBD_RINGBUFF_SEND_SZ (10*PAGE_SIZE)
   71 #define HV_KBD_RINGBUFF_RECV_SZ (10*PAGE_SIZE)
   72 
   73 enum hv_kbd_msg_type_t {
   74         HV_KBD_PROTO_REQUEST        = 1,
   75         HV_KBD_PROTO_RESPONSE       = 2,
   76         HV_KBD_PROTO_EVENT          = 3,
   77         HV_KBD_PROTO_LED_INDICATORS = 4,
   78 };
   79 
   80 typedef struct hv_kbd_msg_hdr_t {
   81         uint32_t type;
   82 } hv_kbd_msg_hdr;
   83 
   84 typedef struct hv_kbd_msg_t {
   85         hv_kbd_msg_hdr hdr;
   86         char data[];
   87 } hv_kbd_msg;
   88 
   89 typedef struct hv_kbd_proto_req_t {
   90         hv_kbd_msg_hdr  hdr;
   91         uint32_t        ver;
   92 } hv_kbd_proto_req;
   93 
   94 typedef struct hv_kbd_proto_resp_t {
   95         hv_kbd_msg_hdr  hdr;
   96         uint32_t        status;
   97 } hv_kbd_proto_resp;
   98 
   99 #define HV_KBD_PROTO_REQ_SZ     (sizeof(hv_kbd_proto_req))
  100 #define HV_KBD_PROTO_RESP_SZ    (sizeof(hv_kbd_proto_resp))
  101 
  102 /**
  103  * the struct in win host:
  104  * typedef struct _HK_MESSAGE_KEYSTROKE
  105  * {
  106  *     HK_MESSAGE_HEADER Header;
  107  *     UINT16 MakeCode;
  108  *     UINT32 IsUnicode:1;
  109  *     UINT32 IsBreak:1;
  110  *     UINT32 IsE0:1;
  111  *     UINT32 IsE1:1;
  112  *     UINT32 Reserved:28;
  113  * } HK_MESSAGE_KEYSTROKE
  114  */
  115 typedef struct hv_kbd_keystroke_t {
  116         hv_kbd_msg_hdr  hdr;
  117         keystroke       ks;
  118 } hv_kbd_keystroke;
  119 
  120 static const struct vmbus_ic_desc vmbus_kbd_descs[] = {
  121         {
  122                 .ic_guid = { .hv_guid = {
  123                     0x6d, 0xad, 0x12, 0xf9, 0x17, 0x2b, 0xea, 0x48,
  124                     0xbd, 0x65, 0xf9, 0x27, 0xa6, 0x1c, 0x76,  0x84} },
  125                 .ic_desc = "Hyper-V KBD"
  126         },
  127         VMBUS_IC_DESC_END
  128 };
  129 
  130 static int hv_kbd_attach(device_t dev);
  131 static int hv_kbd_detach(device_t dev);
  132 
  133 /**
  134  * return 1 if producer is ready
  135  */
  136 int
  137 hv_kbd_prod_is_ready(hv_kbd_sc *sc)
  138 {
  139         int ret;
  140         mtx_lock(&sc->ks_mtx);
  141         ret = !STAILQ_EMPTY(&sc->ks_queue);
  142         mtx_unlock(&sc->ks_mtx);
  143         return (ret);
  144 }
  145 
  146 int
  147 hv_kbd_produce_ks(hv_kbd_sc *sc, const keystroke *ks)
  148 {
  149         int ret = 0;
  150         keystroke_info *ksi;
  151         mtx_lock(&sc->ks_mtx);
  152         if (LIST_EMPTY(&sc->ks_free_list)) {
  153                 DEBUG_HVSC(sc, "NO buffer!\n");
  154                 ret = 1;
  155         } else {
  156                 ksi = LIST_FIRST(&sc->ks_free_list);
  157                 LIST_REMOVE(ksi, link);
  158                 ksi->ks = *ks;
  159                 STAILQ_INSERT_TAIL(&sc->ks_queue, ksi, slink);
  160         }
  161         mtx_unlock(&sc->ks_mtx);
  162         return (ret);
  163 }
  164 
  165 /**
  166  * return 0 if successfully get the 1st item of queue without removing it
  167  */
  168 int
  169 hv_kbd_fetch_top(hv_kbd_sc *sc, keystroke *result)
  170 {
  171         int ret = 0;
  172         keystroke_info *ksi = NULL;
  173         mtx_lock(&sc->ks_mtx);
  174         if (STAILQ_EMPTY(&sc->ks_queue)) {
  175                 DEBUG_HVSC(sc, "Empty queue!\n");
  176                 ret = 1;
  177         } else {
  178                 ksi = STAILQ_FIRST(&sc->ks_queue);
  179                 *result = ksi->ks;
  180         }
  181         mtx_unlock(&sc->ks_mtx);
  182         return (ret);
  183 }
  184 
  185 /**
  186  * return 0 if successfully removing the top item
  187  */
  188 int
  189 hv_kbd_remove_top(hv_kbd_sc *sc)
  190 {
  191         int ret = 0;
  192         keystroke_info *ksi = NULL;
  193         mtx_lock(&sc->ks_mtx);
  194         if (STAILQ_EMPTY(&sc->ks_queue)) {
  195                 DEBUG_HVSC(sc, "Empty queue!\n");
  196                 ret = 1;
  197         } else {
  198                 ksi = STAILQ_FIRST(&sc->ks_queue);
  199                 STAILQ_REMOVE_HEAD(&sc->ks_queue, slink);
  200                 LIST_INSERT_HEAD(&sc->ks_free_list, ksi, link);
  201         }
  202         mtx_unlock(&sc->ks_mtx);
  203         return (ret);
  204 }
  205 
  206 /**
  207  * return 0 if successfully modify the 1st item of queue
  208  */
  209 int
  210 hv_kbd_modify_top(hv_kbd_sc *sc, keystroke *top)
  211 {
  212         int ret = 0;
  213         keystroke_info *ksi = NULL;
  214         mtx_lock(&sc->ks_mtx);
  215         if (STAILQ_EMPTY(&sc->ks_queue)) {
  216                 DEBUG_HVSC(sc, "Empty queue!\n");
  217                 ret = 1;
  218         } else {
  219                 ksi = STAILQ_FIRST(&sc->ks_queue);
  220                 ksi->ks = *top;
  221         }
  222         mtx_unlock(&sc->ks_mtx);
  223         return (ret);
  224 }
  225 
  226 static int
  227 hv_kbd_probe(device_t dev)
  228 {
  229         device_t bus = device_get_parent(dev);
  230         const struct vmbus_ic_desc *d;
  231 
  232         if (resource_disabled(device_get_name(dev), 0))
  233                 return (ENXIO);
  234 
  235         for (d = vmbus_kbd_descs; d->ic_desc != NULL; ++d) {
  236                 if (VMBUS_PROBE_GUID(bus, dev, &d->ic_guid) == 0) {
  237                         device_set_desc(dev, d->ic_desc);
  238                         return (BUS_PROBE_DEFAULT);
  239                 }
  240         }
  241         return (ENXIO);
  242 }
  243 
  244 static void
  245 hv_kbd_on_response(hv_kbd_sc *sc, struct vmbus_chanpkt_hdr *pkt)
  246 {
  247         struct vmbus_xact_ctx *xact = sc->hs_xact_ctx;
  248         if (xact != NULL) {
  249                 DEBUG_HVSC(sc, "hvkbd is ready\n");
  250                 vmbus_xact_ctx_wakeup(xact, VMBUS_CHANPKT_CONST_DATA(pkt),
  251                     VMBUS_CHANPKT_DATALEN(pkt));
  252         }
  253 }
  254 
  255 static void
  256 hv_kbd_on_received(hv_kbd_sc *sc, struct vmbus_chanpkt_hdr *pkt)
  257 {
  258 
  259         const hv_kbd_msg *msg = VMBUS_CHANPKT_CONST_DATA(pkt);
  260         const hv_kbd_proto_resp *resp =
  261             VMBUS_CHANPKT_CONST_DATA(pkt);
  262         const hv_kbd_keystroke *keystroke =
  263             VMBUS_CHANPKT_CONST_DATA(pkt);
  264         uint32_t msg_len = VMBUS_CHANPKT_DATALEN(pkt);
  265         enum hv_kbd_msg_type_t msg_type;
  266         uint32_t info;
  267         uint16_t scan_code;
  268 
  269         if (msg_len <= sizeof(hv_kbd_msg)) {
  270                 device_printf(sc->dev, "Illegal packet\n");
  271                 return;
  272         }
  273         msg_type = msg->hdr.type;
  274         switch (msg_type) {
  275                 case HV_KBD_PROTO_RESPONSE:
  276                         hv_kbd_on_response(sc, pkt);
  277                         DEBUG_HVSC(sc, "keyboard resp: 0x%x\n",
  278                             resp->status);
  279                         break;
  280                 case HV_KBD_PROTO_EVENT:
  281                         info = keystroke->ks.info;
  282                         scan_code = keystroke->ks.makecode;
  283                         DEBUG_HVSC(sc, "keystroke info: 0x%x, scan: 0x%x\n",
  284                             info, scan_code);
  285                         hv_kbd_produce_ks(sc, &keystroke->ks);
  286                         hv_kbd_intr(sc);
  287                 default:
  288                         break;
  289         }
  290 }
  291 
  292 void 
  293 hv_kbd_read_channel(struct vmbus_channel *channel, void *context)
  294 {
  295         uint8_t *buf;
  296         uint32_t buflen = 0;
  297         int ret = 0;
  298 
  299         hv_kbd_sc *sc = (hv_kbd_sc*)context;
  300         buf = sc->buf;
  301         buflen = sc->buflen;
  302         for (;;) {
  303                 struct vmbus_chanpkt_hdr *pkt = (struct vmbus_chanpkt_hdr *)buf;
  304                 uint32_t rxed = buflen;
  305 
  306                 ret = vmbus_chan_recv_pkt(channel, pkt, &rxed);
  307                 if (__predict_false(ret == ENOBUFS)) {
  308                         buflen = sc->buflen * 2;
  309                         while (buflen < rxed)
  310                                 buflen *= 2;
  311                         buf = malloc(buflen, M_DEVBUF, M_WAITOK | M_ZERO);
  312                         device_printf(sc->dev, "expand recvbuf %d -> %d\n",
  313                             sc->buflen, buflen);
  314                         free(sc->buf, M_DEVBUF);
  315                         sc->buf = buf;
  316                         sc->buflen = buflen;
  317                         continue;
  318                 } else if (__predict_false(ret == EAGAIN)) {
  319                         /* No more channel packets; done! */
  320                         break;
  321                 }
  322                 KASSERT(!ret, ("vmbus_chan_recv_pkt failed: %d", ret));
  323 
  324                 DEBUG_HVSC(sc, "event: 0x%x\n", pkt->cph_type);
  325                 switch (pkt->cph_type) {
  326                 case VMBUS_CHANPKT_TYPE_COMP:
  327                 case VMBUS_CHANPKT_TYPE_RXBUF:
  328                         device_printf(sc->dev, "unhandled event: %d\n",
  329                             pkt->cph_type);
  330                         break;
  331                 case VMBUS_CHANPKT_TYPE_INBAND:
  332                         hv_kbd_on_received(sc, pkt);
  333                         break;
  334                 default:
  335                         device_printf(sc->dev, "unknown event: %d\n",
  336                             pkt->cph_type);
  337                         break;
  338                 }
  339         }
  340 }
  341 
  342 static int
  343 hv_kbd_connect_vsp(hv_kbd_sc *sc)
  344 {
  345         int ret;
  346         size_t resplen;
  347         struct vmbus_xact *xact;
  348         hv_kbd_proto_req *req;
  349         const hv_kbd_proto_resp *resp;
  350 
  351         xact = vmbus_xact_get(sc->hs_xact_ctx, sizeof(*req));
  352         if (xact == NULL) {
  353                 device_printf(sc->dev, "no xact for kbd init");
  354                 return (ENODEV);
  355         }
  356         req = vmbus_xact_req_data(xact);
  357         req->hdr.type = HV_KBD_PROTO_REQUEST;
  358         req->ver = HV_KBD_VER;
  359 
  360         vmbus_xact_activate(xact);
  361         ret = vmbus_chan_send(sc->hs_chan,
  362                 VMBUS_CHANPKT_TYPE_INBAND,
  363                 VMBUS_CHANPKT_FLAG_RC,
  364                 req, sizeof(hv_kbd_proto_req),
  365                 (uint64_t)(uintptr_t)xact);
  366         if (ret) {
  367                 device_printf(sc->dev, "fail to send\n");
  368                 vmbus_xact_deactivate(xact);
  369                 return (ret);
  370         }
  371         resp = vmbus_chan_xact_wait(sc->hs_chan, xact, &resplen, true);
  372         if (resplen < HV_KBD_PROTO_RESP_SZ) {
  373                 device_printf(sc->dev, "hv_kbd init communicate failed\n");
  374                 ret = ENODEV;
  375                 goto clean;
  376         }
  377 
  378         if (!(resp->status & HV_KBD_PROTO_ACCEPTED)) {
  379                 device_printf(sc->dev, "hv_kbd protocol request failed\n");
  380                 ret = ENODEV;
  381         }
  382 clean:
  383         vmbus_xact_put(xact);
  384         DEBUG_HVSC(sc, "finish connect vsp\n");
  385         return (ret);
  386 }
  387 
  388 static int
  389 hv_kbd_attach1(device_t dev, vmbus_chan_callback_t cb)
  390 {
  391         int ret;
  392         hv_kbd_sc *sc;
  393 
  394         sc = device_get_softc(dev);
  395         sc->buflen = HV_BUFF_SIZE;
  396         sc->buf = malloc(sc->buflen, M_DEVBUF, M_WAITOK | M_ZERO);
  397         vmbus_chan_set_readbatch(sc->hs_chan, false);
  398         ret = vmbus_chan_open(
  399                 sc->hs_chan,
  400                 HV_KBD_RINGBUFF_SEND_SZ,
  401                 HV_KBD_RINGBUFF_RECV_SZ,
  402                 NULL, 0,
  403                 cb,
  404                 sc);
  405         if (ret != 0) {
  406                 free(sc->buf, M_DEVBUF);
  407         }
  408         return (ret);
  409 }
  410 
  411 static int
  412 hv_kbd_detach1(device_t dev)
  413 {
  414         hv_kbd_sc *sc = device_get_softc(dev);
  415         vmbus_chan_close(vmbus_get_channel(dev));
  416         free(sc->buf, M_DEVBUF);
  417         return (0);
  418 }
  419 
  420 static void
  421 hv_kbd_init(hv_kbd_sc *sc)
  422 {
  423         const int max_list = 16;
  424         int i;
  425         keystroke_info *ksi;
  426 
  427         mtx_init(&sc->ks_mtx, "hv_kbdc mutex", NULL, MTX_DEF);
  428         LIST_INIT(&sc->ks_free_list);
  429         STAILQ_INIT(&sc->ks_queue);
  430         for (i = 0; i < max_list; i++) {
  431                 ksi = malloc(sizeof(keystroke_info),
  432                     M_DEVBUF, M_WAITOK|M_ZERO);
  433                 LIST_INSERT_HEAD(&sc->ks_free_list, ksi, link);
  434         }
  435 }
  436 
  437 static void
  438 hv_kbd_fini(hv_kbd_sc *sc)
  439 {
  440         keystroke_info *ksi;
  441         while (!LIST_EMPTY(&sc->ks_free_list)) {
  442                 ksi = LIST_FIRST(&sc->ks_free_list);
  443                 LIST_REMOVE(ksi, link);
  444                 free(ksi, M_DEVBUF);
  445         }
  446         while (!STAILQ_EMPTY(&sc->ks_queue)) {
  447                 ksi = STAILQ_FIRST(&sc->ks_queue);
  448                 STAILQ_REMOVE_HEAD(&sc->ks_queue, slink);
  449                 free(ksi, M_DEVBUF);
  450         }
  451         mtx_destroy(&sc->ks_mtx);
  452 }
  453 
  454 static void
  455 hv_kbd_sysctl(device_t dev)
  456 {
  457         struct sysctl_oid_list *child;
  458         struct sysctl_ctx_list *ctx;
  459         hv_kbd_sc *sc;
  460 
  461         sc = device_get_softc(dev);
  462         ctx = device_get_sysctl_ctx(dev);
  463         child = SYSCTL_CHILDREN(device_get_sysctl_tree(dev));
  464         SYSCTL_ADD_INT(ctx, child, OID_AUTO, "debug", CTLFLAG_RW,
  465             &sc->debug, 0, "debug hyperv keyboard");
  466 }
  467 
  468 static int
  469 hv_kbd_attach(device_t dev)
  470 {
  471         int error = 0;
  472         hv_kbd_sc *sc;
  473 
  474         sc = device_get_softc(dev);
  475         sc->hs_chan = vmbus_get_channel(dev);
  476         sc->dev = dev;
  477         hv_kbd_init(sc);
  478         sc->hs_xact_ctx = vmbus_xact_ctx_create(bus_get_dma_tag(dev),
  479             HV_KBD_PROTO_REQ_SZ, HV_KBD_PROTO_RESP_SZ, 0);
  480         if (sc->hs_xact_ctx == NULL) {
  481                 error = ENOMEM;
  482                 goto failed;
  483         }
  484 
  485         error = hv_kbd_attach1(dev, hv_kbd_read_channel);
  486         if (error)
  487                 goto failed;
  488         error = hv_kbd_connect_vsp(sc);
  489         if (error)
  490                 goto failed;
  491 
  492         error = hv_kbd_drv_attach(dev);
  493         if (error)
  494                 goto failed;
  495         hv_kbd_sysctl(dev);
  496         return (0);
  497 failed:
  498         hv_kbd_detach(dev);
  499         return (error);
  500 }
  501 
  502 static int
  503 hv_kbd_detach(device_t dev)
  504 {
  505         int ret;
  506         hv_kbd_sc *sc = device_get_softc(dev);
  507         hv_kbd_fini(sc);
  508         if (sc->hs_xact_ctx != NULL)
  509                 vmbus_xact_ctx_destroy(sc->hs_xact_ctx);
  510         ret = hv_kbd_detach1(dev);
  511         if (!ret)
  512                 device_printf(dev, "Fail to detach\n");
  513         return hv_kbd_drv_detach(dev);
  514 }
  515 
  516 static device_method_t kbd_methods[] = {
  517         /* Device interface */
  518         DEVMETHOD(device_probe, hv_kbd_probe),
  519         DEVMETHOD(device_attach, hv_kbd_attach),
  520         DEVMETHOD(device_detach, hv_kbd_detach),
  521         { 0, 0 }
  522 };
  523 
  524 static driver_t kbd_driver = {HVKBD_DRIVER_NAME , kbd_methods, sizeof(hv_kbd_sc)};
  525 
  526 DRIVER_MODULE(hv_kbd, vmbus, kbd_driver, hvkbd_driver_load, NULL);
  527 MODULE_VERSION(hv_kbd, 1);
  528 MODULE_DEPEND(hv_kbd, vmbus, 1, 1, 1);

Cache object: 3f35426dd73377cfc5a7c7cd44d7ab3f


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.