1d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang/*
2d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * Copyright (C) 2008 The Android Open Source Project
3d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang *
4d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * Licensed under the Apache License, Version 2.0 (the "License");
5d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * you may not use this file except in compliance with the License.
6d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * You may obtain a copy of the License at
7d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang *
8d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang *      http://www.apache.org/licenses/LICENSE-2.0
9d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang *
10d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * Unless required by applicable law or agreed to in writing, software
11d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * distributed under the License is distributed on an "AS IS" BASIS,
12d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * See the License for the specific language governing permissions and
14d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * limitations under the License.
15d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang */
16d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
17d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang/* this file contains various functions used by all libhardware modules
18d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang * that support QEMU emulation
19d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang */
20d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include "qemu.h"
21d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#define  LOG_TAG  "hardware-qemu"
22d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <cutils/log.h>
23d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <cutils/properties.h>
24d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <cutils/sockets.h>
25d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <errno.h>
26d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <fcntl.h>
27d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <termios.h>
28d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <stdio.h>
29d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#include <stdarg.h>
30d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
31d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#define  QEMU_DEBUG  0
32d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
33d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#if QEMU_DEBUG
34d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#  define  D(...)   ALOGD(__VA_ARGS__)
35d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#else
36d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#  define  D(...)   ((void)0)
37d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang#endif
38d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
397165d3b5faf3d7a18bcb48bcb6a1afb863474ad3bohu#include "qemu_pipe.h"
40d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
41d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangint
42d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_check(void)
43d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
44d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    static int  in_qemu = -1;
45d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
46d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (__builtin_expect(in_qemu < 0,0)) {
47d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        char  propBuf[PROPERTY_VALUE_MAX];
48d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        property_get("ro.kernel.qemu", propBuf, "");
49d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        in_qemu = (propBuf[0] == '1');
50d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
51d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return in_qemu;
52d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
53d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
54d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
55d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_fd_write( int  fd, const char*  cmd, int  len )
56d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
57d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int  len2;
58d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    do {
59d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        len2 = write(fd, cmd, len);
60d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    } while (len2 < 0 && errno == EINTR);
61d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return len2;
62d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
63d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
64d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
65d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_fd_read( int  fd, char*  buff, int  len )
66d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
67d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int  len2;
68d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    do {
69d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        len2 = read(fd, buff, len);
70d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    } while (len2 < 0 && errno == EINTR);
71d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return len2;
72d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
73d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
74d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
75d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_channel_open_qemud_pipe( QemuChannel*  channel,
76d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                              const char*   name )
77d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
78d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int   fd;
79d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char  pipe_name[512];
80d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
81d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    snprintf(pipe_name, sizeof(pipe_name), "qemud:%s", name);
82d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = qemu_pipe_open(pipe_name);
83d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0) {
84d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("no qemud pipe: %s", strerror(errno));
85d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
86d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
87d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
88d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->is_qemud = 1;
89d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->fd       = fd;
90d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return 0;
91d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
92d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
93d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
94d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_channel_open_qemud( QemuChannel*  channel,
95d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                         const char*   name )
96d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
97d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int   fd, ret, namelen = strlen(name);
98d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char  answer[2];
99d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
100d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = socket_local_client( "qemud",
101d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                              ANDROID_SOCKET_NAMESPACE_RESERVED,
102d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                              SOCK_STREAM );
103d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0) {
104d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("no qemud control socket: %s", strerror(errno));
105d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
106d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
107d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
108d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* send service name to connect */
109d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (qemu_fd_write(fd, name, namelen) != namelen) {
110d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("can't send service name to qemud: %s",
111d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang           strerror(errno));
112d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        close(fd);
113d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
114d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
115d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
116d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* read answer from daemon */
117d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (qemu_fd_read(fd, answer, 2) != 2 ||
118d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        answer[0] != 'O' || answer[1] != 'K') {
119d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("cant' connect to %s service through qemud", name);
120d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        close(fd);
121d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
122d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
123d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
124d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->is_qemud = 1;
125d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->fd       = fd;
126d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return 0;
127d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
128d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
129d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
130d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
131d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_channel_open_qemud_old( QemuChannel*  channel,
132d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                             const char*   name )
133d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
134d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int  fd;
135d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
136d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    snprintf(channel->device, sizeof channel->device,
137d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                "qemud_%s", name);
138d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
139d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = socket_local_client( channel->device,
140d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                              ANDROID_SOCKET_NAMESPACE_RESERVED,
141d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                              SOCK_STREAM );
142d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0) {
143d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("no '%s' control socket available: %s",
144d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            channel->device, strerror(errno));
145d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
146d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
147d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
148d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    close(fd);
149d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->is_qemud_old = 1;
150d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return 0;
151d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
152d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
153d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
154d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
155d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_channel_open_tty( QemuChannel*  channel,
156d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                       const char*   name,
157d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                       int           mode )
158d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
159d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char   key[PROPERTY_KEY_MAX];
160d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char   prop[PROPERTY_VALUE_MAX];
161d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int    ret;
162d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
163d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = snprintf(key, sizeof key, "ro.kernel.android.%s", name);
164d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (ret >= (int)sizeof key)
165d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
166d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
167d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (property_get(key, prop, "") == 0) {
168d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("no kernel-provided %s device name", name);
169d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
170d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
171d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
172d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = snprintf(channel->device, sizeof channel->device,
173d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                    "/dev/%s", prop);
174d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (ret >= (int)sizeof channel->device) {
175d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s device name too long: '%s'", name, prop);
176d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
177d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
178d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
179d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    channel->is_tty = !memcmp("/dev/tty", channel->device, 8);
180d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return 0;
181d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
182d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
183d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangint
184d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_channel_open( QemuChannel*  channel,
185d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                   const char*   name,
186d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                   int           mode )
187d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
188d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int  fd = -1;
189d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
190d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* initialize the channel is needed */
191d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (!channel->is_inited)
192d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    {
193d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        channel->is_inited = 1;
194d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
195d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        do {
196d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            if (qemu_channel_open_qemud_pipe(channel, name) == 0)
197d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                break;
198d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
199d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            if (qemu_channel_open_qemud(channel, name) == 0)
200d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                break;
201d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
202d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            if (qemu_channel_open_qemud_old(channel, name) == 0)
203d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                break;
204d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
205d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            if (qemu_channel_open_tty(channel, name, mode) == 0)
206d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                break;
207d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
208d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            channel->is_available = 0;
209d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            return -1;
210d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        } while (0);
211d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
212d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        channel->is_available = 1;
213d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
214d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
215d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* try to open the file */
216d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (!channel->is_available) {
217d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        errno = ENOENT;
218d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
219d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
220d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
221d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (channel->is_qemud) {
222d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return dup(channel->fd);
223d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
224d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
225d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (channel->is_qemud_old) {
226d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        do {
227d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            fd = socket_local_client( channel->device,
228d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                                      ANDROID_SOCKET_NAMESPACE_RESERVED,
229d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                                      SOCK_STREAM );
230d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        } while (fd < 0 && errno == EINTR);
231d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
232d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    else /* /dev/ttySn ? */
233d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    {
234d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        do {
235d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            fd = open(channel->device, mode);
236d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        } while (fd < 0 && errno == EINTR);
237d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
238d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        /* disable ECHO on serial lines */
239d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        if (fd >= 0 && channel->is_tty) {
240d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            struct termios  ios;
241d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            tcgetattr( fd, &ios );
242d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            ios.c_lflag = 0;  /* disable ECHO, ICANON, etc... */
243d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            tcsetattr( fd, TCSANOW, &ios );
244d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        }
245d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
246d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return fd;
247d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
248d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
249d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
250d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
251d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_command_vformat( char*        buffer,
252d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                      int          buffer_size,
253d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                      const char*  format,
254d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                      va_list      args )
255d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
256d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char     header[5];
257d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int      len;
258d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
259d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (buffer_size < 6)
260d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
261d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
262d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    len = vsnprintf(buffer+4, buffer_size-4, format, args);
263d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (len >= buffer_size-4)
264d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
265d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
266d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    snprintf(header, sizeof header, "%04x", len);
267d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    memcpy(buffer, header, 4);
268d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return len + 4;
269d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
270d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
271d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangextern int
272d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_command_format( char*        buffer,
273d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                     int          buffer_size,
274d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                     const char*  format,
275d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                     ... )
276d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
277d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_list  args;
278d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int      ret;
279d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
280d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_start(args, format);
281d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = qemu_command_vformat(buffer, buffer_size, format, args);
282d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_end(args);
283d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return ret;
284d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
285d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
286d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
287d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
288d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_control_fd(void)
289d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
290d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    static QemuChannel  channel[1];
291d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int                 fd;
292d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
293d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = qemu_channel_open( channel, "hw-control", O_RDWR );
294d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0) {
295d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not open control channel: %s", __FUNCTION__,
296d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          strerror(errno));
297d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
298d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return fd;
299d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
300d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
301d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangstatic int
302d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_control_send(const char*  cmd, int  len)
303d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
304d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int  fd, len2;
305d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
306d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (len < 0) {
307d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        errno = EINVAL;
308d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
309d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
310d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
311d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = qemu_control_fd();
312d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0)
313d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
314d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
315d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    len2 = qemu_fd_write(fd, cmd, len);
316d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    close(fd);
317d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (len2 != len) {
318d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not send everything %d < %d",
319d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          __FUNCTION__, len2, len);
320d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
321d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
322d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return 0;
323d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
324d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
325d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
326d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangint
327d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangqemu_control_command( const char*  fmt, ... )
328d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
329d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_list  args;
330d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char     command[256];
331d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int      len, fd;
332d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
333d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_start(args, fmt);
334d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    len = qemu_command_vformat( command, sizeof command, fmt, args );
335d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    va_end(args);
336d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
337d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (len < 0 || len >= (int)sizeof command) {
338d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        if (len < 0) {
339d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            D("%s: could not send: %s", __FUNCTION__, strerror(errno));
340d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        } else {
341d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang            D("%s: too large %d > %d", __FUNCTION__, len, (int)(sizeof command));
342d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        }
343d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        errno = EINVAL;
344d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
345d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
346d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
347d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return qemu_control_send( command, len );
348d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
349d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
350d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yangextern int  qemu_control_query( const char*  question, int  questionlen,
351d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang                                char*        answer,   int  answersize )
352d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang{
353d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    int   ret, fd, len, result = -1;
354d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    char  header[5], *end;
355d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
356d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (questionlen <= 0) {
357d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        errno = EINVAL;
358d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
359d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
360d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
361d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    fd = qemu_control_fd();
362d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (fd < 0)
363d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        return -1;
364d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
365d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = qemu_fd_write( fd, question, questionlen );
366d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (ret != questionlen) {
367d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not write all: %d < %d", __FUNCTION__,
368d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          ret, questionlen);
369d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        goto Exit;
370d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
371d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
372d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* read a 4-byte header giving the length of the following content */
373d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = qemu_fd_read( fd, header, 4 );
374d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (ret != 4) {
375d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not read header (%d != 4)",
376d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          __FUNCTION__, ret);
377d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        goto Exit;
378d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
379d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
380d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    header[4] = 0;
381d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    len = strtol( header, &end,  16 );
382d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if ( len < 0 || end == NULL || end != header+4 || len > answersize ) {
383d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not parse header: '%s'",
384d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          __FUNCTION__, header);
385d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        goto Exit;
386d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
387d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
388d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    /* read the answer */
389d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    ret = qemu_fd_read( fd, answer, len );
390d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    if (ret != len) {
391d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        D("%s: could not read all of answer %d < %d",
392d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang          __FUNCTION__, ret, len);
393d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang        goto Exit;
394d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    }
395d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
396d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    result = len;
397d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang
398d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng YangExit:
399d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    close(fd);
400d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang    return result;
401d0dc61679414c81f211da4ad1eb54c3ee7e95c0bLingfeng Yang}
402