1/*
2 * Copyright (C) 2016 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 *
13 */
14
15#include "goldfish_dma.h"
16#include "qemu_pipe.h"
17
18#include <cutils/log.h>
19#include <sys/mman.h>
20#include <stdlib.h>
21#include <string.h>
22
23int goldfish_dma_lock(struct goldfish_dma_context* cxt) {
24    struct goldfish_dma_ioctl_info info;
25
26    return ioctl(cxt->fd, GOLDFISH_DMA_IOC_LOCK, &info);
27}
28
29int goldfish_dma_unlock(struct goldfish_dma_context* cxt) {
30    struct goldfish_dma_ioctl_info info;
31
32    return ioctl(cxt->fd, GOLDFISH_DMA_IOC_UNLOCK, &info);
33}
34
35int goldfish_dma_create_region(uint32_t sz, struct goldfish_dma_context* res) {
36
37    res->fd = qemu_pipe_open("opengles");
38    res->mapped = NULL;
39    res->sz = 0;
40
41    if (res->fd > 0) {
42        // now alloc
43        struct goldfish_dma_ioctl_info info;
44        info.size = sz;
45        int alloc_res = ioctl(res->fd, GOLDFISH_DMA_IOC_CREATE_REGION, &info);
46
47        if (alloc_res) {
48            ALOGE("%s: failed to allocate DMA region. errno=%d",
49                  __FUNCTION__, errno);
50            close(res->fd);
51            res->fd = -1;
52            return alloc_res;
53        }
54
55        res->sz = sz;
56        ALOGV("%s: successfully allocated goldfish DMA region with size %lu cxt=%p",
57              __FUNCTION__, sz, res);
58        return 0;
59    } else {
60        ALOGE("%s: could not obtain fd to device! fd %d errno=%d\n",
61              __FUNCTION__, res->fd, errno);
62        return ENODEV;
63    }
64}
65
66void* goldfish_dma_map(struct goldfish_dma_context* cxt) {
67    ALOGV("%s: on fd %d errno=%d", __FUNCTION__, cxt->fd, errno);
68    cxt->mapped = mmap(0, cxt->sz, PROT_WRITE, MAP_SHARED, cxt->fd, 0);
69    ALOGV("%s: mapped addr=%p errno=%d", __FUNCTION__, cxt->mapped, errno);
70
71    if (cxt->mapped == MAP_FAILED) {
72        cxt->mapped = NULL;
73    }
74    return cxt->mapped;
75}
76
77int goldfish_dma_unmap(struct goldfish_dma_context* cxt) {
78    munmap(cxt->mapped, cxt->sz);
79    cxt->mapped = NULL;
80    cxt->sz = 0;
81    return 0;
82}
83
84void goldfish_dma_write(struct goldfish_dma_context* cxt,
85                               void* to_write,
86                               uint32_t sz) {
87    ALOGV("%s: mapped addr=%p", __FUNCTION__, cxt->mapped);
88    memcpy(cxt->mapped, to_write, sz);
89}
90
91void goldfish_dma_free(goldfish_dma_context* cxt) {
92    struct goldfish_dma_ioctl_info info;
93    close(cxt->fd);
94}
95
96uint64_t goldfish_dma_guest_paddr(struct goldfish_dma_context* cxt) {
97    struct goldfish_dma_ioctl_info info;
98    ioctl(cxt->fd, GOLDFISH_DMA_IOC_GETOFF, &info);
99    return info.phys_begin;
100}
101