OSDN Git Service

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