aboutsummaryrefslogtreecommitdiffstats
path: root/tmk_core/protocol/adb.h
blob: b4b3633cf450a5bd6ba37a3a952f692ce3e313a1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/*
Copyright 2011 Jun WAKO <wakojun@gmail.com>

This software is licensed with a Modified BSD License.
All of this is supposed to be Free Software, Open Source, DFSG-free,
GPL-compatible, and OK to use in both free and proprietary applications.
Additions and corrections to this file are welcome.


Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

* Redistributions of source code must retain the above copyright
  notice, this list of conditions and the following disclaimer.

* 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.

* Neither the name of the copyright holders nor the names of
  contributors may be used to endorse or promote products derived
  from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
*/

#ifndef ADB_H
#define ADB_H

#include <stdint.h>
#include <stdbool.h>

#if !(defined(ADB_PORT) && \
      defined(ADB_PIN)  && \
      defined(ADB_DDR)  && \
      defined(ADB_DATA_BIT))
#   error "ADB port setting is required in config.h"
#endif

#define ADB_POWER       0x7F
#define ADB_CAPS        0x39


// ADB host
void     adb_host_init(void);
bool     adb_host_psw(void);
uint16_t adb_host_kbd_recv(void);
uint16_t adb_host_mouse_recv(void);
void     adb_host_listen(uint8_t cmd, uint8_t data_h, uint8_t data_l);
void     adb_host_kbd_led(uint8_t led);
void     adb_mouse_task(void);
void     adb_mouse_init(void);


#endif
d='n367' href='#n367'>367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
/******************************************************************************
 *
 * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 * xc_gnttab functions:
 * Copyright (c) 2007-2008, D G Murray <Derek.Murray@cl.cam.ac.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation;
 * version 2.1 of the License.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <sys/mman.h>
#include <sys/ioctl.h>

#include <xen/memory.h>
#include <xen/sys/evtchn.h>
#include <xen/sys/gntdev.h>

#include "xenctrl.h"
#include "xenctrlosdep.h"

#define ERROR(_m, _a...)  xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m , ## _a )
#define PERROR(_m, _a...) xc_osdep_log(xch,XTL_ERROR,XC_INTERNAL_ERROR,_m \
                  " (%d = %s)", ## _a , errno, xc_strerror(xch, errno))

static xc_osdep_handle linux_privcmd_open(xc_interface *xch)
{
    int flags, saved_errno;
    int fd = open("/proc/xen/privcmd", O_RDWR);

    if ( fd == -1 )
    {
        PERROR("Could not obtain handle on privileged command interface");
        return XC_OSDEP_OPEN_ERROR;
    }

    /* Although we return the file handle as the 'xc handle' the API
       does not specify / guarentee that this integer is in fact
       a file handle. Thus we must take responsiblity to ensure
       it doesn't propagate (ie leak) outside the process */
    if ( (flags = fcntl(fd, F_GETFD)) < 0 )
    {
        PERROR("Could not get file handle flags");
        goto error;
    }

    flags |= FD_CLOEXEC;

    if ( fcntl(fd, F_SETFD, flags) < 0 )
    {
        PERROR("Could not set file handle flags");
        goto error;
    }

    return (xc_osdep_handle)fd;

 error:
    saved_errno = errno;
    close(fd);
    errno = saved_errno;
    return XC_OSDEP_OPEN_ERROR;
}

static int linux_privcmd_close(xc_interface *xch, xc_osdep_handle h)
{
    int fd = (int)h;
    return close(fd);
}

static void *linux_privcmd_alloc_hypercall_buffer(xc_interface *xch, xc_osdep_handle h, int npages)
{
    size_t size = npages * XC_PAGE_SIZE;
    void *p;
    int ret;

    ret = posix_memalign(&p, XC_PAGE_SIZE, size);
    if (ret != 0 || !p)
        return NULL;

    if ( mlock(p, size) < 0 )
    {
        free(p);
        return NULL;
    }
    return p;
}

static void linux_privcmd_free_hypercall_buffer(xc_interface *xch, xc_osdep_handle h, void *ptr, int npages)
{
    (void) munlock(ptr, npages * XC_PAGE_SIZE);
    free(ptr);
}

static int linux_privcmd_hypercall(xc_interface *xch, xc_osdep_handle h, privcmd_hypercall_t *hypercall)
{
    int fd = (int)h;
    return ioctl(fd, IOCTL_PRIVCMD_HYPERCALL, hypercall);
}

static int xc_map_foreign_batch_single(int fd, uint32_t dom,
                                       xen_pfn_t *mfn, unsigned long addr)
{
    privcmd_mmapbatch_t ioctlx;
    int rc;

    ioctlx.num = 1;
    ioctlx.dom = dom;
    ioctlx.addr = addr;
    ioctlx.arr = mfn;

    do
    {
        *mfn ^= XEN_DOMCTL_PFINFO_PAGEDTAB;
        usleep(100);
        rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
    }
    while ( (rc < 0) && (errno == ENOENT) );

    return rc;
}

static void *linux_privcmd_map_foreign_batch(xc_interface *xch, xc_osdep_handle h,
                                             uint32_t dom, int prot,
                                             xen_pfn_t *arr, int num)
{
    int fd = (int)h;
    privcmd_mmapbatch_t ioctlx;
    void *addr;
    int rc;

    addr = mmap(NULL, num << XC_PAGE_SHIFT, prot, MAP_SHARED, fd, 0);
    if ( addr == MAP_FAILED )
    {
        PERROR("xc_map_foreign_batch: mmap failed");
        return NULL;
    }

    ioctlx.num = num;
    ioctlx.dom = dom;
    ioctlx.addr = (unsigned long)addr;
    ioctlx.arr = arr;

    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);
    if ( (rc < 0) && (errno == ENOENT) )
    {
        int i;

        for ( i = 0; i < num; i++ )
        {
            if ( (arr[i] & XEN_DOMCTL_PFINFO_LTAB_MASK) ==
                 XEN_DOMCTL_PFINFO_PAGEDTAB )
            {
                unsigned long paged_addr = (unsigned long)addr + (i << XC_PAGE_SHIFT);
                rc = xc_map_foreign_batch_single(fd, dom, &arr[i],
                                                 paged_addr);
                if ( rc < 0 )
                    goto out;
            }
        }
    }

 out:
    if ( rc < 0 )
    {
        int saved_errno = errno;
        PERROR("xc_map_foreign_batch: ioctl failed");
        (void)munmap(addr, num << XC_PAGE_SHIFT);
        errno = saved_errno;
        return NULL;
    }

    return addr;
}

static void *linux_privcmd_map_foreign_bulk(xc_interface *xch, xc_osdep_handle h,
                                            uint32_t dom, int prot,
                                            const xen_pfn_t *arr, int *err, unsigned int num)
{
    int fd = (int)h;
    privcmd_mmapbatch_v2_t ioctlx;
    void *addr;
    unsigned int i;
    int rc;

    addr = mmap(NULL, (unsigned long)num << XC_PAGE_SHIFT, prot, MAP_SHARED,
                fd, 0);
    if ( addr == MAP_FAILED )
    {
        PERROR("xc_map_foreign_batch: mmap failed");
        return NULL;
    }

    ioctlx.num = num;
    ioctlx.dom = dom;
    ioctlx.addr = (unsigned long)addr;
    ioctlx.arr = arr;
    ioctlx.err = err;

    rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);

    if ( rc < 0 && errno == ENOENT )
    {
        for ( i = rc = 0; rc == 0 && i < num; i++ )
        {
            if ( err[i] != -ENOENT )
                continue;

            ioctlx.num = 1;
            ioctlx.dom = dom;
            ioctlx.addr = (unsigned long)addr + ((unsigned long)i<<XC_PAGE_SHIFT);
            ioctlx.arr = arr + i;
            ioctlx.err = err + i;
            do {
                usleep(100);
                rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH_V2, &ioctlx);
            } while ( rc < 0 && err[i] == -ENOENT );
        }
    }

    if ( rc < 0 && errno == EINVAL && (int)num > 0 )
    {
        /*
         * IOCTL_PRIVCMD_MMAPBATCH_V2 is not supported - fall back to
         * IOCTL_PRIVCMD_MMAPBATCH.
         */
        xen_pfn_t *pfn = malloc(num * sizeof(*pfn));

        if ( pfn )
        {
            privcmd_mmapbatch_t ioctlx;

            memcpy(pfn, arr, num * sizeof(*arr));

            ioctlx.num = num;
            ioctlx.dom = dom;
            ioctlx.addr = (unsigned long)addr;
            ioctlx.arr = pfn;

            rc = ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, &ioctlx);

            rc = rc < 0 ? -errno : 0;

            for ( i = 0; i < num; ++i )
            {
                switch ( pfn[i] ^ arr[i] )
                {
                case 0:
                    err[i] = rc != -ENOENT ? rc : 0;
                    continue;
                default:
                    err[i] = -EINVAL;
                    continue;
                case XEN_DOMCTL_PFINFO_PAGEDTAB:
                    if ( rc != -ENOENT )
                    {
                        err[i] = rc ?: -EINVAL;
                        continue;
                    }
                    rc = xc_map_foreign_batch_single(fd, dom, pfn + i,
                        (unsigned long)addr + ((unsigned long)i<<XC_PAGE_SHIFT));
                    if ( rc < 0 )
                    {
                        rc = -errno;
                        break;
                    }
                    rc = -ENOENT;
                    continue;
                }
                break;
            }

            free(pfn);

            if ( rc == -ENOENT && i == num )
                rc = 0;
            else if ( rc )
            {
                errno = -rc;
                rc = -1;
            }
        }
        else
        {
            errno = -ENOMEM;
            rc = -1;
        }
    }

    if ( rc < 0 )
    {
        int saved_errno = errno;

        PERROR("xc_map_foreign_bulk: ioctl failed");
        (void)munmap(addr, (unsigned long)num << XC_PAGE_SHIFT);
        errno = saved_errno;
        return NULL;
    }

    return addr;
}

static void *linux_privcmd_map_foreign_range(xc_interface *xch, xc_osdep_handle h,
                                             uint32_t dom, int size, int prot,
                                             unsigned long mfn)
{
    xen_pfn_t *arr;
    int num;
    int i;
    void *ret;

    num = (size + XC_PAGE_SIZE - 1) >> XC_PAGE_SHIFT;
    arr = calloc(num, sizeof(xen_pfn_t));

    for ( i = 0; i < num; i++ )
        arr[i] = mfn + i;

    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
    free(arr);
    return ret;
}

static void *linux_privcmd_map_foreign_ranges(xc_interface *xch, xc_osdep_handle h,
                                              uint32_t dom, size_t size, int prot,
                                              size_t chunksize, privcmd_mmap_entry_t entries[],
                                              int nentries)
{
    xen_pfn_t *arr;
    int num_per_entry;
    int num;
    int i;
    int j;
    void *ret;

    num_per_entry = chunksize >> XC_PAGE_SHIFT;
    num = num_per_entry * nentries;
    arr = calloc(num, sizeof(xen_pfn_t));

    for ( i = 0; i < nentries; i++ )
        for ( j = 0; j < num_per_entry; j++ )
            arr[i * num_per_entry + j] = entries[i].mfn + j;

    ret = xc_map_foreign_pages(xch, dom, prot, arr, num);
    free(arr);
    return ret;
}

static struct xc_osdep_ops linux_privcmd_ops = {
    .open = &linux_privcmd_open,
    .close = &linux_privcmd_close,

    .u.privcmd = {
        .alloc_hypercall_buffer = &linux_privcmd_alloc_hypercall_buffer,
        .free_hypercall_buffer = &linux_privcmd_free_hypercall_buffer,

        .hypercall = &linux_privcmd_hypercall,

        .map_foreign_batch = &linux_privcmd_map_foreign_batch,
        .map_foreign_bulk = &linux_privcmd_map_foreign_bulk,
        .map_foreign_range = &linux_privcmd_map_foreign_range,
        .map_foreign_ranges = &linux_privcmd_map_foreign_ranges,
    },
};

#define DEVXEN "/dev/xen/"

static xc_osdep_handle linux_evtchn_open(xc_evtchn *xce)
{
    int fd = open(DEVXEN "evtchn", O_RDWR);
    if ( fd == -1 )
        return XC_OSDEP_OPEN_ERROR;

    return (xc_osdep_handle)fd;
}

static int linux_evtchn_close(xc_evtchn *xce, xc_osdep_handle h)
{
    int fd = (int)h;
    return close(fd);
}

static int linux_evtchn_fd(xc_evtchn *xce, xc_osdep_handle h)
{
    return (int)h;
}

static int linux_evtchn_notify(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port)
{
    int fd = (int)h;
    struct ioctl_evtchn_notify notify;

    notify.port = port;

    return ioctl(fd, IOCTL_EVTCHN_NOTIFY, &notify);
}

static evtchn_port_or_error_t
linux_evtchn_bind_unbound_port(xc_evtchn *xce, xc_osdep_handle h, int domid)
{
    int fd = (int)h;
    struct ioctl_evtchn_bind_unbound_port bind;

    bind.remote_domain = domid;

    return ioctl(fd, IOCTL_EVTCHN_BIND_UNBOUND_PORT, &bind);
}

static evtchn_port_or_error_t
linux_evtchn_bind_interdomain(xc_evtchn *xce, xc_osdep_handle h, int domid,
                              evtchn_port_t remote_port)
{
    int fd = (int)h;
    struct ioctl_evtchn_bind_interdomain bind;

    bind.remote_domain = domid;
    bind.remote_port = remote_port;

    return ioctl(fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
}

static evtchn_port_or_error_t
linux_evtchn_bind_virq(xc_evtchn *xce, xc_osdep_handle h, unsigned int virq)
{
    int fd = (int)h;
    struct ioctl_evtchn_bind_virq bind;

    bind.virq = virq;

    return ioctl(fd, IOCTL_EVTCHN_BIND_VIRQ, &bind);
}

static int linux_evtchn_unbind(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port)
{
    int fd = (int)h;
    struct ioctl_evtchn_unbind unbind;

    unbind.port = port;

    return ioctl(fd, IOCTL_EVTCHN_UNBIND, &unbind);
}

static evtchn_port_or_error_t linux_evtchn_pending(xc_evtchn *xce, xc_osdep_handle h)
{
    int fd = (int)h;
    evtchn_port_t port;

    if ( read(fd, &port, sizeof(port)) != sizeof(port) )
        return -1;

    return port;
}

static int linux_evtchn_unmask(xc_evtchn *xce, xc_osdep_handle h, evtchn_port_t port)
{
    int fd = (int)h;

    if ( write(fd, &port, sizeof(port)) != sizeof(port) )
        return -1;
    return 0;
}

static struct xc_osdep_ops linux_evtchn_ops = {
    .open = &linux_evtchn_open,
    .close = &linux_evtchn_close,

    .u.evtchn = {
        .fd = &linux_evtchn_fd,
        .notify = &linux_evtchn_notify,
        .bind_unbound_port = &linux_evtchn_bind_unbound_port,
        .bind_interdomain = &linux_evtchn_bind_interdomain,
        .bind_virq = &linux_evtchn_bind_virq,
        .unbind = &linux_evtchn_unbind,
        .pending = &linux_evtchn_pending,
        .unmask = &linux_evtchn_unmask,
    },
};

static xc_osdep_handle linux_gnttab_open(xc_gnttab *xcg)
{
    int fd = open(DEVXEN "gntdev", O_RDWR);

    if ( fd == -1 )
        return XC_OSDEP_OPEN_ERROR;

    return (xc_osdep_handle)fd;
}

static int linux_gnttab_close(xc_gnttab *xcg, xc_osdep_handle h)
{
    int fd = (int)h;
    return close(fd);
}

static void *linux_gnttab_map_grant_ref(xc_gnttab *xch, xc_osdep_handle h,
                                        uint32_t domid, uint32_t ref, int prot)
{
    int fd = (int)h;
    struct ioctl_gntdev_map_grant_ref map;
    void *addr;

    map.count = 1;
    map.refs[0].domid = domid;
    map.refs[0].ref = ref;

    if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, &map) ) {
        PERROR("xc_gnttab_map_grant_ref: ioctl MAP_GRANT_REF failed");
        return NULL;
    }

mmap_again:    
    addr = mmap(NULL, XC_PAGE_SIZE, prot, MAP_SHARED, fd, map.index);
    if ( addr == MAP_FAILED )
    {
        int saved_errno = errno;
        struct ioctl_gntdev_unmap_grant_ref unmap_grant;

        if(saved_errno == EAGAIN)
        {
            usleep(1000);
            goto mmap_again;
        }
         /* Unmap the driver slots used to store the grant information. */
        PERROR("xc_gnttab_map_grant_ref: mmap failed");
        unmap_grant.index = map.index;
        unmap_grant.count = 1;
        ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
        errno = saved_errno;
        return NULL;
    }

    return addr;
}

static void *do_gnttab_map_grant_refs(xc_gnttab *xch, xc_osdep_handle h,
                                      uint32_t count,
                                      uint32_t *domids, int domids_stride,
                                      uint32_t *refs, int prot)
{
    int fd = (int)h;
    struct ioctl_gntdev_map_grant_ref *map;
    void *addr = NULL;
    int i;

    map = malloc(sizeof(*map) +
                 (count - 1) * sizeof(struct ioctl_gntdev_map_grant_ref));
    if ( map == NULL )
        return NULL;

    for ( i = 0; i < count; i++ )
    {
        map->refs[i].domid = domids[i * domids_stride];
        map->refs[i].ref = refs[i];
    }

    map->count = count;

    if ( ioctl(fd, IOCTL_GNTDEV_MAP_GRANT_REF, map) ) {
        PERROR("xc_gnttab_map_grant_refs: ioctl MAP_GRANT_REF failed");
        goto out;
    }

    addr = mmap(NULL, XC_PAGE_SIZE * count, prot, MAP_SHARED, fd,
                map->index);
    if ( addr == MAP_FAILED )
    {
        int saved_errno = errno;
        struct ioctl_gntdev_unmap_grant_ref unmap_grant;

        /* Unmap the driver slots used to store the grant information. */
        PERROR("xc_gnttab_map_grant_refs: mmap failed");
        unmap_grant.index = map->index;
        unmap_grant.count = count;
        ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant);
        errno = saved_errno;
        addr = NULL;
    }

 out:
    free(map);

    return addr;
}

static void *linux_gnttab_map_grant_refs(xc_gnttab *xcg, xc_osdep_handle h,
                                         uint32_t count, uint32_t *domids,
                                         uint32_t *refs, int prot)
{
    return do_gnttab_map_grant_refs(xcg, h, count, domids, 1, refs, prot);
}

static void *linux_gnttab_map_domain_grant_refs(xc_gnttab *xcg, xc_osdep_handle h,
                                                uint32_t count,
                                                uint32_t domid, uint32_t *refs, int prot)
{
    return do_gnttab_map_grant_refs(xcg, h, count, &domid, 0, refs, prot);
}

static int linux_gnttab_munmap(xc_gnttab *xcg, xc_osdep_handle h,
                               void *start_address, uint32_t count)
{
    int fd = (int)h;
    struct ioctl_gntdev_get_offset_for_vaddr get_offset;
    struct ioctl_gntdev_unmap_grant_ref unmap_grant;
    int rc;

    if ( start_address == NULL )
    {
        errno = EINVAL;
        return -1;
    }

    /* First, it is necessary to get the offset which was initially used to
     * mmap() the pages.
     */
    get_offset.vaddr = (unsigned long)start_address;
    if ( (rc = ioctl(fd, IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR,
                     &get_offset)) )
        return rc;

    if ( get_offset.count != count )
    {
        errno = EINVAL;
        return -1;
    }

    /* Next, unmap the memory. */
    if ( (rc = munmap(start_address, count * getpagesize())) )
        return rc;

    /* Finally, unmap the driver slots used to store the grant information. */
    unmap_grant.index = get_offset.offset;
    unmap_grant.count = count;
    if ( (rc = ioctl(fd, IOCTL_GNTDEV_UNMAP_GRANT_REF, &unmap_grant)) )
        return rc;

    return 0;
}

static struct xc_osdep_ops linux_gnttab_ops = {
    .open = &linux_gnttab_open,
    .close = &linux_gnttab_close,

    .u.gnttab = {
        .map_grant_ref = &linux_gnttab_map_grant_ref,
        .map_grant_refs = &linux_gnttab_map_grant_refs,
        .map_domain_grant_refs = &linux_gnttab_map_domain_grant_refs,
        .munmap = &linux_gnttab_munmap,
    },
};

static struct xc_osdep_ops *linux_osdep_init(xc_interface *xch, enum xc_osdep_type type)
{
    switch ( type )
    {
    case XC_OSDEP_PRIVCMD:
        return &linux_privcmd_ops;
    case XC_OSDEP_EVTCHN:
        return &linux_evtchn_ops;
    case XC_OSDEP_GNTTAB:
        return &linux_gnttab_ops;
    default:
        return NULL;
    }
}

xc_osdep_info_t xc_osdep_info = {
    .name = "Linux Native OS interface",
    .init = &linux_osdep_init,
    .fake = 0,
};

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */