1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_INCLUDE_HARDWARE_QEMUD_H
18#define ANDROID_INCLUDE_HARDWARE_QEMUD_H
19
20#include <cutils/sockets.h>
21#include "qemu_pipe.h"
22
23/* the following is helper code that is used by the QEMU-specific
24 * hardware HAL modules to communicate with the emulator program
25 * through the 'qemud' multiplexing daemon, or through the qemud
26 * pipe.
27 *
28 * see the documentation comments for details in
29 * development/emulator/qemud/qemud.c
30 *
31 * all definitions here are built into the HAL module to avoid
32 * having to write a tiny shared library for this.
33 */
34
35/* we expect the D macro to be defined to a function macro
36 * that sends its formatted string argument(s) to the log.
37 * If not, ignore the traces.
38 */
39#ifndef D
40#  define  D(...)  ((void)0)
41#endif
42
43static __inline__ int
44qemud_fd_write(int  fd, const void*  buff, int  len)
45{
46    int  len2;
47    do {
48        len2 = write(fd, buff, len);
49    } while (len2 < 0 && errno == EINTR);
50    return len2;
51}
52
53static __inline__ int
54qemud_fd_read(int  fd, void*  buff, int  len)
55{
56    int  len2;
57    do {
58        len2 = read(fd, buff, len);
59    } while (len2 < 0 && errno == EINTR);
60    return len2;
61}
62
63static __inline__ int
64qemud_channel_open(const char*  name)
65{
66    int  fd;
67    int  namelen = strlen(name);
68    char answer[2];
69    char pipe_name[256];
70
71    /* First, try to connect to the pipe. */
72    snprintf(pipe_name, sizeof(pipe_name), "qemud:%s", name);
73    fd = qemu_pipe_open(pipe_name);
74    if (fd < 0) {
75        D("QEMUD pipe is not available for %s: %s", name, strerror(errno));
76        /* If pipe is not available, connect to qemud control socket */
77        fd = socket_local_client( "qemud",
78                                  ANDROID_SOCKET_NAMESPACE_RESERVED,
79                                  SOCK_STREAM );
80        if (fd < 0) {
81            D("no qemud control socket: %s", strerror(errno));
82            return -1;
83        }
84
85        /* send service name to connect */
86        if (qemud_fd_write(fd, name, namelen) != namelen) {
87            D("can't send service name to qemud: %s",
88               strerror(errno));
89            close(fd);
90            return -1;
91        }
92
93        /* read answer from daemon */
94        if (qemud_fd_read(fd, answer, 2) != 2 ||
95            answer[0] != 'O' || answer[1] != 'K') {
96            D("cant' connect to %s service through qemud", name);
97            close(fd);
98            return -1;
99        }
100    }
101    return fd;
102}
103
104static __inline__ int
105qemud_channel_send(int  fd, const void*  msg, int  msglen)
106{
107    char  header[5];
108
109    if (msglen < 0)
110        msglen = strlen((const char*)msg);
111
112    if (msglen == 0)
113        return 0;
114
115    snprintf(header, sizeof header, "%04x", msglen);
116    if (qemud_fd_write(fd, header, 4) != 4) {
117        D("can't write qemud frame header: %s", strerror(errno));
118        return -1;
119    }
120
121    if (qemud_fd_write(fd, msg, msglen) != msglen) {
122        D("can4t write qemud frame payload: %s", strerror(errno));
123        return -1;
124    }
125    return 0;
126}
127
128static __inline__ int
129qemud_channel_recv(int  fd, void*  msg, int  msgsize)
130{
131    char  header[5];
132    int   size, avail;
133
134    if (qemud_fd_read(fd, header, 4) != 4) {
135        D("can't read qemud frame header: %s", strerror(errno));
136        return -1;
137    }
138    header[4] = 0;
139    if (sscanf(header, "%04x", &size) != 1) {
140        D("malformed qemud frame header: '%.*s'", 4, header);
141        return -1;
142    }
143    if (size > msgsize)
144        return -1;
145
146    if (qemud_fd_read(fd, msg, size) != size) {
147        D("can't read qemud frame payload: %s", strerror(errno));
148        return -1;
149    }
150    return size;
151}
152
153#endif /* ANDROID_INCLUDE_HARDWARE_QEMUD_H */
154