+++ /dev/null
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# We're moving the emulator-specific platform libs to
-# development.git/tools/emulator/. The following test is to ensure
-# smooth builds even if the tree contains both versions.
-#
-ifndef BUILD_EMULATOR_GPS_MODULE
-BUILD_EMULATOR_GPS_MODULE := true
-
-LOCAL_PATH := $(call my-dir)
-
-ifneq ($(TARGET_PRODUCT),sim)
-# HAL module implemenation, not prelinked and stored in
-# hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
-include $(CLEAR_VARS)
-LOCAL_PRELINK_MODULE := false
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-LOCAL_CFLAGS += -DQEMU_HARDWARE
-LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
-LOCAL_SRC_FILES := gps_qemu.c
-LOCAL_MODULE := gps.goldfish
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_SHARED_LIBRARY)
-endif
-
-endif # BUILD_EMULATOR_GPS_MODULE
+++ /dev/null
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* this implements a GPS hardware library for the Android emulator.
- * the following code should be built as a shared library that will be
- * placed into /system/lib/hw/gps.goldfish.so
- *
- * it will be loaded by the code in hardware/libhardware/hardware.c
- * which is itself called from android_location_GpsLocationProvider.cpp
- */
-
-
-#include <errno.h>
-#include <pthread.h>
-#include <fcntl.h>
-#include <sys/epoll.h>
-#include <math.h>
-#include <time.h>
-
-#define LOG_TAG "gps_qemu"
-#include <cutils/log.h>
-#include <cutils/sockets.h>
-#include <hardware/gps.h>
-#include <hardware/qemud.h>
-
-/* the name of the qemud-controlled socket */
-#define QEMU_CHANNEL_NAME "gps"
-
-#define GPS_DEBUG 0
-
-#if GPS_DEBUG
-# define D(...) LOGD(__VA_ARGS__)
-#else
-# define D(...) ((void)0)
-#endif
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** N M E A T O K E N I Z E R *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-typedef struct {
- const char* p;
- const char* end;
-} Token;
-
-#define MAX_NMEA_TOKENS 16
-
-typedef struct {
- int count;
- Token tokens[ MAX_NMEA_TOKENS ];
-} NmeaTokenizer;
-
-static int
-nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
-{
- int count = 0;
- char* q;
-
- // the initial '$' is optional
- if (p < end && p[0] == '$')
- p += 1;
-
- // remove trailing newline
- if (end > p && end[-1] == '\n') {
- end -= 1;
- if (end > p && end[-1] == '\r')
- end -= 1;
- }
-
- // get rid of checksum at the end of the sentecne
- if (end >= p+3 && end[-3] == '*') {
- end -= 3;
- }
-
- while (p < end) {
- const char* q = p;
-
- q = memchr(p, ',', end-p);
- if (q == NULL)
- q = end;
-
- if (q > p) {
- if (count < MAX_NMEA_TOKENS) {
- t->tokens[count].p = p;
- t->tokens[count].end = q;
- count += 1;
- }
- }
- if (q < end)
- q += 1;
-
- p = q;
- }
-
- t->count = count;
- return count;
-}
-
-static Token
-nmea_tokenizer_get( NmeaTokenizer* t, int index )
-{
- Token tok;
- static const char* dummy = "";
-
- if (index < 0 || index >= t->count) {
- tok.p = tok.end = dummy;
- } else
- tok = t->tokens[index];
-
- return tok;
-}
-
-
-static int
-str2int( const char* p, const char* end )
-{
- int result = 0;
- int len = end - p;
-
- for ( ; len > 0; len--, p++ )
- {
- int c;
-
- if (p >= end)
- goto Fail;
-
- c = *p - '0';
- if ((unsigned)c >= 10)
- goto Fail;
-
- result = result*10 + c;
- }
- return result;
-
-Fail:
- return -1;
-}
-
-static double
-str2float( const char* p, const char* end )
-{
- int result = 0;
- int len = end - p;
- char temp[16];
-
- if (len >= (int)sizeof(temp))
- return 0.;
-
- memcpy( temp, p, len );
- temp[len] = 0;
- return strtod( temp, NULL );
-}
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** N M E A P A R S E R *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-#define NMEA_MAX_SIZE 83
-
-typedef struct {
- int pos;
- int overflow;
- int utc_year;
- int utc_mon;
- int utc_day;
- int utc_diff;
- GpsLocation fix;
- gps_location_callback callback;
- char in[ NMEA_MAX_SIZE+1 ];
-} NmeaReader;
-
-
-static void
-nmea_reader_update_utc_diff( NmeaReader* r )
-{
- time_t now = time(NULL);
- struct tm tm_local;
- struct tm tm_utc;
- long time_local, time_utc;
-
- gmtime_r( &now, &tm_utc );
- localtime_r( &now, &tm_local );
-
- time_local = tm_local.tm_sec +
- 60*(tm_local.tm_min +
- 60*(tm_local.tm_hour +
- 24*(tm_local.tm_yday +
- 365*tm_local.tm_year)));
-
- time_utc = tm_utc.tm_sec +
- 60*(tm_utc.tm_min +
- 60*(tm_utc.tm_hour +
- 24*(tm_utc.tm_yday +
- 365*tm_utc.tm_year)));
-
- r->utc_diff = time_utc - time_local;
-}
-
-
-static void
-nmea_reader_init( NmeaReader* r )
-{
- memset( r, 0, sizeof(*r) );
-
- r->pos = 0;
- r->overflow = 0;
- r->utc_year = -1;
- r->utc_mon = -1;
- r->utc_day = -1;
- r->callback = NULL;
- r->fix.size = sizeof(r->fix);
-
- nmea_reader_update_utc_diff( r );
-}
-
-
-static void
-nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
-{
- r->callback = cb;
- if (cb != NULL && r->fix.flags != 0) {
- D("%s: sending latest fix to new callback", __FUNCTION__);
- r->callback( &r->fix );
- r->fix.flags = 0;
- }
-}
-
-
-static int
-nmea_reader_update_time( NmeaReader* r, Token tok )
-{
- int hour, minute;
- double seconds;
- struct tm tm;
- time_t fix_time;
-
- if (tok.p + 6 > tok.end)
- return -1;
-
- if (r->utc_year < 0) {
- // no date yet, get current one
- time_t now = time(NULL);
- gmtime_r( &now, &tm );
- r->utc_year = tm.tm_year + 1900;
- r->utc_mon = tm.tm_mon + 1;
- r->utc_day = tm.tm_mday;
- }
-
- hour = str2int(tok.p, tok.p+2);
- minute = str2int(tok.p+2, tok.p+4);
- seconds = str2float(tok.p+4, tok.end);
-
- tm.tm_hour = hour;
- tm.tm_min = minute;
- tm.tm_sec = (int) seconds;
- tm.tm_year = r->utc_year - 1900;
- tm.tm_mon = r->utc_mon - 1;
- tm.tm_mday = r->utc_day;
- tm.tm_isdst = -1;
-
- fix_time = mktime( &tm ) + r->utc_diff;
- r->fix.timestamp = (long long)fix_time * 1000;
- return 0;
-}
-
-static int
-nmea_reader_update_date( NmeaReader* r, Token date, Token time )
-{
- Token tok = date;
- int day, mon, year;
-
- if (tok.p + 6 != tok.end) {
- D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- day = str2int(tok.p, tok.p+2);
- mon = str2int(tok.p+2, tok.p+4);
- year = str2int(tok.p+4, tok.p+6) + 2000;
-
- if ((day|mon|year) < 0) {
- D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
-
- r->utc_year = year;
- r->utc_mon = mon;
- r->utc_day = day;
-
- return nmea_reader_update_time( r, time );
-}
-
-
-static double
-convert_from_hhmm( Token tok )
-{
- double val = str2float(tok.p, tok.end);
- int degrees = (int)(floor(val) / 100);
- double minutes = val - degrees*100.;
- double dcoord = degrees + minutes / 60.0;
- return dcoord;
-}
-
-
-static int
-nmea_reader_update_latlong( NmeaReader* r,
- Token latitude,
- char latitudeHemi,
- Token longitude,
- char longitudeHemi )
-{
- double lat, lon;
- Token tok;
-
- tok = latitude;
- if (tok.p + 6 > tok.end) {
- D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- lat = convert_from_hhmm(tok);
- if (latitudeHemi == 'S')
- lat = -lat;
-
- tok = longitude;
- if (tok.p + 6 > tok.end) {
- D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
- return -1;
- }
- lon = convert_from_hhmm(tok);
- if (longitudeHemi == 'W')
- lon = -lon;
-
- r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
- r->fix.latitude = lat;
- r->fix.longitude = lon;
- return 0;
-}
-
-
-static int
-nmea_reader_update_altitude( NmeaReader* r,
- Token altitude,
- Token units )
-{
- double alt;
- Token tok = altitude;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
- r->fix.altitude = str2float(tok.p, tok.end);
- return 0;
-}
-
-
-static int
-nmea_reader_update_bearing( NmeaReader* r,
- Token bearing )
-{
- double alt;
- Token tok = bearing;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_BEARING;
- r->fix.bearing = str2float(tok.p, tok.end);
- return 0;
-}
-
-
-static int
-nmea_reader_update_speed( NmeaReader* r,
- Token speed )
-{
- double alt;
- Token tok = speed;
-
- if (tok.p >= tok.end)
- return -1;
-
- r->fix.flags |= GPS_LOCATION_HAS_SPEED;
- r->fix.speed = str2float(tok.p, tok.end);
- return 0;
-}
-
-
-static void
-nmea_reader_parse( NmeaReader* r )
-{
- /* we received a complete sentence, now parse it to generate
- * a new GPS fix...
- */
- NmeaTokenizer tzer[1];
- Token tok;
-
- D("Received: '%.*s'", r->pos, r->in);
- if (r->pos < 9) {
- D("Too short. discarded.");
- return;
- }
-
- nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
-#if GPS_DEBUG
- {
- int n;
- D("Found %d tokens", tzer->count);
- for (n = 0; n < tzer->count; n++) {
- Token tok = nmea_tokenizer_get(tzer,n);
- D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
- }
- }
-#endif
-
- tok = nmea_tokenizer_get(tzer, 0);
- if (tok.p + 5 > tok.end) {
- D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
- return;
- }
-
- // ignore first two characters.
- tok.p += 2;
- if ( !memcmp(tok.p, "GGA", 3) ) {
- // GPS fix
- Token tok_time = nmea_tokenizer_get(tzer,1);
- Token tok_latitude = nmea_tokenizer_get(tzer,2);
- Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
- Token tok_longitude = nmea_tokenizer_get(tzer,4);
- Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
- Token tok_altitude = nmea_tokenizer_get(tzer,9);
- Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
-
- nmea_reader_update_time(r, tok_time);
- nmea_reader_update_latlong(r, tok_latitude,
- tok_latitudeHemi.p[0],
- tok_longitude,
- tok_longitudeHemi.p[0]);
- nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
-
- } else if ( !memcmp(tok.p, "GSA", 3) ) {
- // do something ?
- } else if ( !memcmp(tok.p, "RMC", 3) ) {
- Token tok_time = nmea_tokenizer_get(tzer,1);
- Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
- Token tok_latitude = nmea_tokenizer_get(tzer,3);
- Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
- Token tok_longitude = nmea_tokenizer_get(tzer,5);
- Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
- Token tok_speed = nmea_tokenizer_get(tzer,7);
- Token tok_bearing = nmea_tokenizer_get(tzer,8);
- Token tok_date = nmea_tokenizer_get(tzer,9);
-
- D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
- if (tok_fixStatus.p[0] == 'A')
- {
- nmea_reader_update_date( r, tok_date, tok_time );
-
- nmea_reader_update_latlong( r, tok_latitude,
- tok_latitudeHemi.p[0],
- tok_longitude,
- tok_longitudeHemi.p[0] );
-
- nmea_reader_update_bearing( r, tok_bearing );
- nmea_reader_update_speed ( r, tok_speed );
- }
- } else {
- tok.p -= 2;
- D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
- }
- if (r->fix.flags != 0) {
-#if GPS_DEBUG
- char temp[256];
- char* p = temp;
- char* end = p + sizeof(temp);
- struct tm utc;
-
- p += snprintf( p, end-p, "sending fix" );
- if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
- p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
- p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
- p += snprintf(p, end-p, " speed=%g", r->fix.speed);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
- p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
- }
- if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
- p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
- }
- gmtime_r( (time_t*) &r->fix.timestamp, &utc );
- p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
- D(temp);
-#endif
- if (r->callback) {
- r->callback( &r->fix );
- r->fix.flags = 0;
- }
- else {
- D("no callback, keeping data until needed !");
- }
- }
-}
-
-
-static void
-nmea_reader_addc( NmeaReader* r, int c )
-{
- if (r->overflow) {
- r->overflow = (c != '\n');
- return;
- }
-
- if (r->pos >= (int) sizeof(r->in)-1 ) {
- r->overflow = 1;
- r->pos = 0;
- return;
- }
-
- r->in[r->pos] = (char)c;
- r->pos += 1;
-
- if (c == '\n') {
- nmea_reader_parse( r );
- r->pos = 0;
- }
-}
-
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** C O N N E C T I O N S T A T E *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-/* commands sent to the gps thread */
-enum {
- CMD_QUIT = 0,
- CMD_START = 1,
- CMD_STOP = 2
-};
-
-
-/* this is the state of our connection to the qemu_gpsd daemon */
-typedef struct {
- int init;
- int fd;
- GpsCallbacks callbacks;
- pthread_t thread;
- int control[2];
-} GpsState;
-
-static GpsState _gps_state[1];
-
-
-static void
-gps_state_done( GpsState* s )
-{
- // tell the thread to quit, and wait for it
- char cmd = CMD_QUIT;
- void* dummy;
- write( s->control[0], &cmd, 1 );
- pthread_join(s->thread, &dummy);
-
- // close the control socket pair
- close( s->control[0] ); s->control[0] = -1;
- close( s->control[1] ); s->control[1] = -1;
-
- // close connection to the QEMU GPS daemon
- close( s->fd ); s->fd = -1;
- s->init = 0;
-}
-
-
-static void
-gps_state_start( GpsState* s )
-{
- char cmd = CMD_START;
- int ret;
-
- do { ret=write( s->control[0], &cmd, 1 ); }
- while (ret < 0 && errno == EINTR);
-
- if (ret != 1)
- D("%s: could not send CMD_START command: ret=%d: %s",
- __FUNCTION__, ret, strerror(errno));
-}
-
-
-static void
-gps_state_stop( GpsState* s )
-{
- char cmd = CMD_STOP;
- int ret;
-
- do { ret=write( s->control[0], &cmd, 1 ); }
- while (ret < 0 && errno == EINTR);
-
- if (ret != 1)
- D("%s: could not send CMD_STOP command: ret=%d: %s",
- __FUNCTION__, ret, strerror(errno));
-}
-
-
-static int
-epoll_register( int epoll_fd, int fd )
-{
- struct epoll_event ev;
- int ret, flags;
-
- /* important: make the fd non-blocking */
- flags = fcntl(fd, F_GETFL);
- fcntl(fd, F_SETFL, flags | O_NONBLOCK);
-
- ev.events = EPOLLIN;
- ev.data.fd = fd;
- do {
- ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-
-static int
-epoll_deregister( int epoll_fd, int fd )
-{
- int ret;
- do {
- ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
- } while (ret < 0 && errno == EINTR);
- return ret;
-}
-
-/* this is the main thread, it waits for commands from gps_state_start/stop and,
- * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
- * that must be parsed to be converted into GPS fixes sent to the framework
- */
-static void
-gps_state_thread( void* arg )
-{
- GpsState* state = (GpsState*) arg;
- NmeaReader reader[1];
- int epoll_fd = epoll_create(2);
- int started = 0;
- int gps_fd = state->fd;
- int control_fd = state->control[1];
-
- nmea_reader_init( reader );
-
- // register control file descriptors for polling
- epoll_register( epoll_fd, control_fd );
- epoll_register( epoll_fd, gps_fd );
-
- D("gps thread running");
-
- // now loop
- for (;;) {
- struct epoll_event events[2];
- int ne, nevents;
-
- nevents = epoll_wait( epoll_fd, events, 2, -1 );
- if (nevents < 0) {
- if (errno != EINTR)
- LOGE("epoll_wait() unexpected error: %s", strerror(errno));
- continue;
- }
- D("gps thread received %d events", nevents);
- for (ne = 0; ne < nevents; ne++) {
- if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
- LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
- return;
- }
- if ((events[ne].events & EPOLLIN) != 0) {
- int fd = events[ne].data.fd;
-
- if (fd == control_fd)
- {
- char cmd = 255;
- int ret;
- D("gps control fd event");
- do {
- ret = read( fd, &cmd, 1 );
- } while (ret < 0 && errno == EINTR);
-
- if (cmd == CMD_QUIT) {
- D("gps thread quitting on demand");
- return;
- }
- else if (cmd == CMD_START) {
- if (!started) {
- D("gps thread starting location_cb=%p", state->callbacks.location_cb);
- started = 1;
- nmea_reader_set_callback( reader, state->callbacks.location_cb );
- }
- }
- else if (cmd == CMD_STOP) {
- if (started) {
- D("gps thread stopping");
- started = 0;
- nmea_reader_set_callback( reader, NULL );
- }
- }
- }
- else if (fd == gps_fd)
- {
- char buff[32];
- D("gps fd event");
- for (;;) {
- int nn, ret;
-
- ret = read( fd, buff, sizeof(buff) );
- if (ret < 0) {
- if (errno == EINTR)
- continue;
- if (errno != EWOULDBLOCK)
- LOGE("error while reading from gps daemon socket: %s:", strerror(errno));
- break;
- }
- D("received %d bytes: %.*s", ret, ret, buff);
- for (nn = 0; nn < ret; nn++)
- nmea_reader_addc( reader, buff[nn] );
- }
- D("gps fd event end");
- }
- else
- {
- LOGE("epoll_wait() returned unkown fd %d ?", fd);
- }
- }
- }
- }
-}
-
-
-static void
-gps_state_init( GpsState* state, GpsCallbacks* callbacks )
-{
- state->init = 1;
- state->control[0] = -1;
- state->control[1] = -1;
- state->fd = -1;
-
- state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
-
- if (state->fd < 0) {
- D("no gps emulation detected");
- return;
- }
-
- D("gps emulation will read from '%s' qemud channel", QEMU_CHANNEL_NAME );
-
- if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
- LOGE("could not create thread control socket pair: %s", strerror(errno));
- goto Fail;
- }
-
- state->thread = callbacks->create_thread_cb( "gps_state_thread", gps_state_thread, state );
-
- if ( !state->thread ) {
- LOGE("could not create gps thread: %s", strerror(errno));
- goto Fail;
- }
-
- state->callbacks = *callbacks;
-
- D("gps state initialized");
- return;
-
-Fail:
- gps_state_done( state );
-}
-
-
-/*****************************************************************/
-/*****************************************************************/
-/***** *****/
-/***** I N T E R F A C E *****/
-/***** *****/
-/*****************************************************************/
-/*****************************************************************/
-
-
-static int
-qemu_gps_init(GpsCallbacks* callbacks)
-{
- GpsState* s = _gps_state;
-
- if (!s->init)
- gps_state_init(s, callbacks);
-
- if (s->fd < 0)
- return -1;
-
- return 0;
-}
-
-static void
-qemu_gps_cleanup(void)
-{
- GpsState* s = _gps_state;
-
- if (s->init)
- gps_state_done(s);
-}
-
-
-static int
-qemu_gps_start()
-{
- GpsState* s = _gps_state;
-
- if (!s->init) {
- D("%s: called with uninitialized state !!", __FUNCTION__);
- return -1;
- }
-
- D("%s: called", __FUNCTION__);
- gps_state_start(s);
- return 0;
-}
-
-
-static int
-qemu_gps_stop()
-{
- GpsState* s = _gps_state;
-
- if (!s->init) {
- D("%s: called with uninitialized state !!", __FUNCTION__);
- return -1;
- }
-
- D("%s: called", __FUNCTION__);
- gps_state_stop(s);
- return 0;
-}
-
-
-static int
-qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
-{
- return 0;
-}
-
-static int
-qemu_gps_inject_location(double latitude, double longitude, float accuracy)
-{
- return 0;
-}
-
-static void
-qemu_gps_delete_aiding_data(GpsAidingData flags)
-{
-}
-
-static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
-{
- // FIXME - support fix_frequency
- return 0;
-}
-
-static const void*
-qemu_gps_get_extension(const char* name)
-{
- // no extensions supported
- return NULL;
-}
-
-static const GpsInterface qemuGpsInterface = {
- sizeof(GpsInterface),
- qemu_gps_init,
- qemu_gps_start,
- qemu_gps_stop,
- qemu_gps_cleanup,
- qemu_gps_inject_time,
- qemu_gps_inject_location,
- qemu_gps_delete_aiding_data,
- qemu_gps_set_position_mode,
- qemu_gps_get_extension,
-};
-
-const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
-{
- return &qemuGpsInterface;
-}
-
-static int open_gps(const struct hw_module_t* module, char const* name,
- struct hw_device_t** device)
-{
- struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
- memset(dev, 0, sizeof(*dev));
-
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (struct hw_module_t*)module;
-// dev->common.close = (int (*)(struct hw_device_t*))close_lights;
- dev->get_gps_interface = gps__get_gps_interface;
-
- *device = (struct hw_device_t*)dev;
- return 0;
-}
-
-
-static struct hw_module_methods_t gps_module_methods = {
- .open = open_gps
-};
-
-const struct hw_module_t HAL_MODULE_INFO_SYM = {
- .tag = HARDWARE_MODULE_TAG,
- .version_major = 1,
- .version_minor = 0,
- .id = GPS_HARDWARE_MODULE_ID,
- .name = "Goldfish GPS Module",
- .author = "The Android Open Source Project",
- .methods = &gps_module_methods,
-};
+++ /dev/null
-# Copyright 2008 The Android Open Source Project
-
-# We're moving the emulator-specific platform libs to
-# development.git/tools/emulator/. The following test is to ensure
-# smooth builds even if the tree contains both versions.
-#
-ifndef BUILD_EMULATOR_QEMUD
-BUILD_EMULATOR_QEMUD := true
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- qemud.c
-
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
-
-LOCAL_MODULE:= qemud
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-endif # BUILD_EMULATOR_QEMUD
\ No newline at end of file
+++ /dev/null
-#include <stdint.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <termios.h>
-#include <cutils/sockets.h>
-
-/*
- * the qemud daemon program is only used within Android as a bridge
- * between the emulator program and the emulated system. it really works as
- * a simple stream multiplexer that works as follows:
- *
- * - qemud is started by init following instructions in
- * /system/etc/init.goldfish.rc (i.e. it is never started on real devices)
- *
- * - qemud communicates with the emulator program through a single serial
- * port, whose name is passed through a kernel boot parameter
- * (e.g. android.qemud=ttyS1)
- *
- * - qemud binds one unix local stream socket (/dev/socket/qemud, created
- * by init through /system/etc/init.goldfish.rc).
- *
- *
- * emulator <==serial==> qemud <---> /dev/socket/qemud <-+--> client1
- * |
- * +--> client2
- *
- * - the special channel index 0 is used by the emulator and qemud only.
- * other channel numbers correspond to clients. More specifically,
- * connection are created like this:
- *
- * * the client connects to /dev/socket/qemud
- *
- * * the client sends the service name through the socket, as
- * <service-name>
- *
- * * qemud creates a "Client" object internally, assigns it an
- * internal unique channel number > 0, then sends a connection
- * initiation request to the emulator (i.e. through channel 0):
- *
- * connect:<id>:<name>
- *
- * where <name> is the service name, and <id> is a 2-hexchar
- * number corresponding to the channel number.
- *
- * * in case of success, the emulator responds through channel 0
- * with:
- *
- * ok:connect:<id>
- *
- * after this, all messages between the client and the emulator
- * are passed in pass-through mode.
- *
- * * if the emulator refuses the service connection, it will
- * send the following through channel 0:
- *
- * ko:connect:<id>:reason-for-failure
- *
- * * If the client closes the connection, qemud sends the following
- * to the emulator:
- *
- * disconnect:<id>
- *
- * The same message is the opposite direction if the emulator
- * chooses to close the connection.
- *
- * * any command sent through channel 0 to the emulator that is
- * not properly recognized will be answered by:
- *
- * ko:unknown command
- *
- *
- * Internally, the daemon maintains a "Client" object for each client
- * connection (i.e. accepting socket connection).
- */
-
-/* name of the single control socket used by the daemon */
-#define CONTROL_SOCKET_NAME "qemud"
-
-#define DEBUG 1
-#define T_ACTIVE 0 /* set to 1 to dump traffic */
-
-#if DEBUG
-# define LOG_TAG "qemud"
-# include <cutils/log.h>
-# define D(...) LOGD(__VA_ARGS__)
-#else
-# define D(...) ((void)0)
-# define T(...) ((void)0)
-#endif
-
-#if T_ACTIVE
-# define T(...) D(__VA_ARGS__)
-#else
-# define T(...) ((void)0)
-#endif
-
-/** UTILITIES
- **/
-
-static void
-fatal( const char* fmt, ... )
-{
- va_list args;
- va_start(args, fmt);
- fprintf(stderr, "PANIC: ");
- vfprintf(stderr, fmt, args);
- fprintf(stderr, "\n" );
- va_end(args);
- exit(1);
-}
-
-static void*
-xalloc( size_t sz )
-{
- void* p;
-
- if (sz == 0)
- return NULL;
-
- p = malloc(sz);
- if (p == NULL)
- fatal( "not enough memory" );
-
- return p;
-}
-
-#define xnew(p) (p) = xalloc(sizeof(*(p)))
-
-static void*
-xalloc0( size_t sz )
-{
- void* p = xalloc(sz);
- memset( p, 0, sz );
- return p;
-}
-
-#define xnew0(p) (p) = xalloc0(sizeof(*(p)))
-
-#define xfree(p) (free((p)), (p) = NULL)
-
-static void*
-xrealloc( void* block, size_t size )
-{
- void* p = realloc( block, size );
-
- if (p == NULL && size > 0)
- fatal( "not enough memory" );
-
- return p;
-}
-
-#define xrenew(p,count) (p) = xrealloc((p),sizeof(*(p))*(count))
-
-static int
-hex2int( const uint8_t* data, int len )
-{
- int result = 0;
- while (len > 0) {
- int c = *data++;
- unsigned d;
-
- result <<= 4;
- do {
- d = (unsigned)(c - '0');
- if (d < 10)
- break;
-
- d = (unsigned)(c - 'a');
- if (d < 6) {
- d += 10;
- break;
- }
-
- d = (unsigned)(c - 'A');
- if (d < 6) {
- d += 10;
- break;
- }
-
- return -1;
- }
- while (0);
-
- result |= d;
- len -= 1;
- }
- return result;
-}
-
-
-static void
-int2hex( int value, uint8_t* to, int width )
-{
- int nn = 0;
- static const char hexchars[16] = "0123456789abcdef";
-
- for ( --width; width >= 0; width--, nn++ ) {
- to[nn] = hexchars[(value >> (width*4)) & 15];
- }
-}
-
-static int
-fd_read(int fd, void* to, int len)
-{
- int ret;
-
- do {
- ret = read(fd, to, len);
- } while (ret < 0 && errno == EINTR);
-
- return ret;
-}
-
-static int
-fd_write(int fd, const void* from, int len)
-{
- int ret;
-
- do {
- ret = write(fd, from, len);
- } while (ret < 0 && errno == EINTR);
-
- return ret;
-}
-
-static void
-fd_setnonblock(int fd)
-{
- int ret, flags;
-
- do {
- flags = fcntl(fd, F_GETFD);
- } while (flags < 0 && errno == EINTR);
-
- if (flags < 0) {
- fatal( "%s: could not get flags for fd %d: %s",
- __FUNCTION__, fd, strerror(errno) );
- }
-
- do {
- ret = fcntl(fd, F_SETFD, flags | O_NONBLOCK);
- } while (ret < 0 && errno == EINTR);
-
- if (ret < 0) {
- fatal( "%s: could not set fd %d to non-blocking: %s",
- __FUNCTION__, fd, strerror(errno) );
- }
-}
-
-
-static int
-fd_accept(int fd)
-{
- struct sockaddr from;
- socklen_t fromlen = sizeof(from);
- int ret;
-
- do {
- ret = accept(fd, &from, &fromlen);
- } while (ret < 0 && errno == EINTR);
-
- return ret;
-}
-
-/** FD EVENT LOOP
- **/
-
-/* A Looper object is used to monitor activity on one or more
- * file descriptors (e.g sockets).
- *
- * - call looper_add() to register a function that will be
- * called when events happen on the file descriptor.
- *
- * - call looper_enable() or looper_disable() to enable/disable
- * the set of monitored events for a given file descriptor.
- *
- * - call looper_del() to unregister a file descriptor.
- * this does *not* close the file descriptor.
- *
- * Note that you can only provide a single function to handle
- * all events related to a given file descriptor.
-
- * You can call looper_enable/_disable/_del within a function
- * callback.
- */
-
-/* the current implementation uses Linux's epoll facility
- * the event mask we use are simply combinations of EPOLLIN
- * EPOLLOUT, EPOLLHUP and EPOLLERR
- */
-#include <sys/epoll.h>
-
-#define MAX_CHANNELS 16
-#define MAX_EVENTS (MAX_CHANNELS+1) /* each channel + the serial fd */
-
-/* the event handler function type, 'user' is a user-specific
- * opaque pointer passed to looper_add().
- */
-typedef void (*EventFunc)( void* user, int events );
-
-/* bit flags for the LoopHook structure.
- *
- * HOOK_PENDING means that an event happened on the
- * corresponding file descriptor.
- *
- * HOOK_CLOSING is used to delay-close monitored
- * file descriptors.
- */
-enum {
- HOOK_PENDING = (1 << 0),
- HOOK_CLOSING = (1 << 1),
-};
-
-/* A LoopHook structure is used to monitor a given
- * file descriptor and record its event handler.
- */
-typedef struct {
- int fd;
- int wanted; /* events we are monitoring */
- int events; /* events that occured */
- int state; /* see HOOK_XXX constants */
- void* ev_user; /* user-provided handler parameter */
- EventFunc ev_func; /* event handler callback */
-} LoopHook;
-
-/* Looper is the main object modeling a looper object
- */
-typedef struct {
- int epoll_fd;
- int num_fds;
- int max_fds;
- struct epoll_event* events;
- LoopHook* hooks;
-} Looper;
-
-/* initialize a looper object */
-static void
-looper_init( Looper* l )
-{
- l->epoll_fd = epoll_create(4);
- l->num_fds = 0;
- l->max_fds = 0;
- l->events = NULL;
- l->hooks = NULL;
-}
-
-/* finalize a looper object */
-static void
-looper_done( Looper* l )
-{
- xfree(l->events);
- xfree(l->hooks);
- l->max_fds = 0;
- l->num_fds = 0;
-
- close(l->epoll_fd);
- l->epoll_fd = -1;
-}
-
-/* return the LoopHook corresponding to a given
- * monitored file descriptor, or NULL if not found
- */
-static LoopHook*
-looper_find( Looper* l, int fd )
-{
- LoopHook* hook = l->hooks;
- LoopHook* end = hook + l->num_fds;
-
- for ( ; hook < end; hook++ ) {
- if (hook->fd == fd)
- return hook;
- }
- return NULL;
-}
-
-/* grow the arrays in the looper object */
-static void
-looper_grow( Looper* l )
-{
- int old_max = l->max_fds;
- int new_max = old_max + (old_max >> 1) + 4;
- int n;
-
- xrenew( l->events, new_max );
- xrenew( l->hooks, new_max );
- l->max_fds = new_max;
-
- /* now change the handles to all events */
- for (n = 0; n < l->num_fds; n++) {
- struct epoll_event ev;
- LoopHook* hook = l->hooks + n;
-
- ev.events = hook->wanted;
- ev.data.ptr = hook;
- epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev );
- }
-}
-
-/* register a file descriptor and its event handler.
- * no event mask will be enabled
- */
-static void
-looper_add( Looper* l, int fd, EventFunc func, void* user )
-{
- struct epoll_event ev;
- LoopHook* hook;
-
- if (l->num_fds >= l->max_fds)
- looper_grow(l);
-
- hook = l->hooks + l->num_fds;
-
- hook->fd = fd;
- hook->ev_user = user;
- hook->ev_func = func;
- hook->state = 0;
- hook->wanted = 0;
- hook->events = 0;
-
- fd_setnonblock(fd);
-
- ev.events = 0;
- ev.data.ptr = hook;
- epoll_ctl( l->epoll_fd, EPOLL_CTL_ADD, fd, &ev );
-
- l->num_fds += 1;
-}
-
-/* unregister a file descriptor and its event handler
- */
-static void
-looper_del( Looper* l, int fd )
-{
- LoopHook* hook = looper_find( l, fd );
-
- if (!hook) {
- D( "%s: invalid fd: %d", __FUNCTION__, fd );
- return;
- }
- /* don't remove the hook yet */
- hook->state |= HOOK_CLOSING;
-
- epoll_ctl( l->epoll_fd, EPOLL_CTL_DEL, fd, NULL );
-}
-
-/* enable monitoring of certain events for a file
- * descriptor. This adds 'events' to the current
- * event mask
- */
-static void
-looper_enable( Looper* l, int fd, int events )
-{
- LoopHook* hook = looper_find( l, fd );
-
- if (!hook) {
- D("%s: invalid fd: %d", __FUNCTION__, fd );
- return;
- }
-
- if (events & ~hook->wanted) {
- struct epoll_event ev;
-
- hook->wanted |= events;
- ev.events = hook->wanted;
- ev.data.ptr = hook;
-
- epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
- }
-}
-
-/* disable monitoring of certain events for a file
- * descriptor. This ignores events that are not
- * currently enabled.
- */
-static void
-looper_disable( Looper* l, int fd, int events )
-{
- LoopHook* hook = looper_find( l, fd );
-
- if (!hook) {
- D("%s: invalid fd: %d", __FUNCTION__, fd );
- return;
- }
-
- if (events & hook->wanted) {
- struct epoll_event ev;
-
- hook->wanted &= ~events;
- ev.events = hook->wanted;
- ev.data.ptr = hook;
-
- epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, fd, &ev );
- }
-}
-
-/* wait until an event occurs on one of the registered file
- * descriptors. Only returns in case of error !!
- */
-static void
-looper_loop( Looper* l )
-{
- for (;;) {
- int n, count;
-
- do {
- count = epoll_wait( l->epoll_fd, l->events, l->num_fds, -1 );
- } while (count < 0 && errno == EINTR);
-
- if (count < 0) {
- D("%s: error: %s", __FUNCTION__, strerror(errno) );
- return;
- }
-
- if (count == 0) {
- D("%s: huh ? epoll returned count=0", __FUNCTION__);
- continue;
- }
-
- /* mark all pending hooks */
- for (n = 0; n < count; n++) {
- LoopHook* hook = l->events[n].data.ptr;
- hook->state = HOOK_PENDING;
- hook->events = l->events[n].events;
- }
-
- /* execute hook callbacks. this may change the 'hooks'
- * and 'events' array, as well as l->num_fds, so be careful */
- for (n = 0; n < l->num_fds; n++) {
- LoopHook* hook = l->hooks + n;
- if (hook->state & HOOK_PENDING) {
- hook->state &= ~HOOK_PENDING;
- hook->ev_func( hook->ev_user, hook->events );
- }
- }
-
- /* now remove all the hooks that were closed by
- * the callbacks */
- for (n = 0; n < l->num_fds;) {
- struct epoll_event ev;
- LoopHook* hook = l->hooks + n;
-
- if (!(hook->state & HOOK_CLOSING)) {
- n++;
- continue;
- }
-
- hook[0] = l->hooks[l->num_fds-1];
- l->num_fds -= 1;
- ev.events = hook->wanted;
- ev.data.ptr = hook;
- epoll_ctl( l->epoll_fd, EPOLL_CTL_MOD, hook->fd, &ev );
- }
- }
-}
-
-#if T_ACTIVE
-char*
-quote( const void* data, int len )
-{
- const char* p = data;
- const char* end = p + len;
- int count = 0;
- int phase = 0;
- static char* buff = NULL;
-
- for (phase = 0; phase < 2; phase++) {
- if (phase != 0) {
- xfree(buff);
- buff = xalloc(count+1);
- }
- count = 0;
- for (p = data; p < end; p++) {
- int c = *p;
-
- if (c == '\\') {
- if (phase != 0) {
- buff[count] = buff[count+1] = '\\';
- }
- count += 2;
- continue;
- }
-
- if (c >= 32 && c < 127) {
- if (phase != 0)
- buff[count] = c;
- count += 1;
- continue;
- }
-
-
- if (c == '\t') {
- if (phase != 0) {
- memcpy(buff+count, "<TAB>", 5);
- }
- count += 5;
- continue;
- }
- if (c == '\n') {
- if (phase != 0) {
- memcpy(buff+count, "<LN>", 4);
- }
- count += 4;
- continue;
- }
- if (c == '\r') {
- if (phase != 0) {
- memcpy(buff+count, "<CR>", 4);
- }
- count += 4;
- continue;
- }
-
- if (phase != 0) {
- buff[count+0] = '\\';
- buff[count+1] = 'x';
- buff[count+2] = "0123456789abcdef"[(c >> 4) & 15];
- buff[count+3] = "0123456789abcdef"[ (c) & 15];
- }
- count += 4;
- }
- }
- buff[count] = 0;
- return buff;
-}
-#endif /* T_ACTIVE */
-
-/** PACKETS
- **
- ** We need a way to buffer data before it can be sent to the
- ** corresponding file descriptor. We use linked list of Packet
- ** objects to do this.
- **/
-
-typedef struct Packet Packet;
-
-#define MAX_PAYLOAD 4000
-
-struct Packet {
- Packet* next;
- int len;
- int channel;
- uint8_t data[ MAX_PAYLOAD ];
-};
-
-/* we expect to alloc/free a lot of packets during
- * operations so use a single linked list of free packets
- * to keep things speedy and simple.
- */
-static Packet* _free_packets;
-
-/* Allocate a packet */
-static Packet*
-packet_alloc(void)
-{
- Packet* p = _free_packets;
- if (p != NULL) {
- _free_packets = p->next;
- } else {
- xnew(p);
- }
- p->next = NULL;
- p->len = 0;
- p->channel = -1;
- return p;
-}
-
-/* Release a packet. This takes the address of a packet
- * pointer that will be set to NULL on exit (avoids
- * referencing dangling pointers in case of bugs)
- */
-static void
-packet_free( Packet* *ppacket )
-{
- Packet* p = *ppacket;
- if (p) {
- p->next = _free_packets;
- _free_packets = p;
- *ppacket = NULL;
- }
-}
-
-/** PACKET RECEIVER
- **
- ** Simple abstraction for something that can receive a packet
- ** from a FDHandler (see below) or something else.
- **
- ** Send a packet to it with 'receiver_post'
- **
- ** Call 'receiver_close' to indicate that the corresponding
- ** packet source was closed.
- **/
-
-typedef void (*PostFunc) ( void* user, Packet* p );
-typedef void (*CloseFunc)( void* user );
-
-typedef struct {
- PostFunc post;
- CloseFunc close;
- void* user;
-} Receiver;
-
-/* post a packet to a receiver. Note that this transfers
- * ownership of the packet to the receiver.
- */
-static __inline__ void
-receiver_post( Receiver* r, Packet* p )
-{
- if (r->post)
- r->post( r->user, p );
- else
- packet_free(&p);
-}
-
-/* tell a receiver the packet source was closed.
- * this will also prevent further posting to the
- * receiver.
- */
-static __inline__ void
-receiver_close( Receiver* r )
-{
- if (r->close) {
- r->close( r->user );
- r->close = NULL;
- }
- r->post = NULL;
-}
-
-
-/** FD HANDLERS
- **
- ** these are smart listeners that send incoming packets to a receiver
- ** and can queue one or more outgoing packets and send them when
- ** possible to the FD.
- **
- ** note that we support clean shutdown of file descriptors,
- ** i.e. we try to send all outgoing packets before destroying
- ** the FDHandler.
- **/
-
-typedef struct FDHandler FDHandler;
-typedef struct FDHandlerList FDHandlerList;
-
-struct FDHandler {
- int fd;
- FDHandlerList* list;
- char closing;
- Receiver receiver[1];
-
- /* queue of outgoing packets */
- int out_pos;
- Packet* out_first;
- Packet** out_ptail;
-
- FDHandler* next;
- FDHandler** pref;
-
-};
-
-struct FDHandlerList {
- /* the looper that manages the fds */
- Looper* looper;
-
- /* list of active FDHandler objects */
- FDHandler* active;
-
- /* list of closing FDHandler objects.
- * these are waiting to push their
- * queued packets to the fd before
- * freeing themselves.
- */
- FDHandler* closing;
-
-};
-
-/* remove a FDHandler from its current list */
-static void
-fdhandler_remove( FDHandler* f )
-{
- f->pref[0] = f->next;
- if (f->next)
- f->next->pref = f->pref;
-}
-
-/* add a FDHandler to a given list */
-static void
-fdhandler_prepend( FDHandler* f, FDHandler** list )
-{
- f->next = list[0];
- f->pref = list;
- list[0] = f;
- if (f->next)
- f->next->pref = &f->next;
-}
-
-/* initialize a FDHandler list */
-static void
-fdhandler_list_init( FDHandlerList* list, Looper* looper )
-{
- list->looper = looper;
- list->active = NULL;
- list->closing = NULL;
-}
-
-
-/* close a FDHandler (and free it). Note that this will not
- * perform a graceful shutdown, i.e. all packets in the
- * outgoing queue will be immediately free.
- *
- * this *will* notify the receiver that the file descriptor
- * was closed.
- *
- * you should call fdhandler_shutdown() if you want to
- * notify the FDHandler that its packet source is closed.
- */
-static void
-fdhandler_close( FDHandler* f )
-{
- /* notify receiver */
- receiver_close(f->receiver);
-
- /* remove the handler from its list */
- fdhandler_remove(f);
-
- /* get rid of outgoing packet queue */
- if (f->out_first != NULL) {
- Packet* p;
- while ((p = f->out_first) != NULL) {
- f->out_first = p->next;
- packet_free(&p);
- }
- }
-
- /* get rid of file descriptor */
- if (f->fd >= 0) {
- looper_del( f->list->looper, f->fd );
- close(f->fd);
- f->fd = -1;
- }
-
- f->list = NULL;
- xfree(f);
-}
-
-/* Ask the FDHandler to cleanly shutdown the connection,
- * i.e. send any pending outgoing packets then auto-free
- * itself.
- */
-static void
-fdhandler_shutdown( FDHandler* f )
-{
- /* prevent later fdhandler_close() to
- * call the receiver's close.
- */
- f->receiver->close = NULL;
-
- if (f->out_first != NULL && !f->closing)
- {
- /* move the handler to the 'closing' list */
- f->closing = 1;
- fdhandler_remove(f);
- fdhandler_prepend(f, &f->list->closing);
- return;
- }
-
- fdhandler_close(f);
-}
-
-/* Enqueue a new packet that the FDHandler will
- * send through its file descriptor.
- */
-static void
-fdhandler_enqueue( FDHandler* f, Packet* p )
-{
- Packet* first = f->out_first;
-
- p->next = NULL;
- f->out_ptail[0] = p;
- f->out_ptail = &p->next;
-
- if (first == NULL) {
- f->out_pos = 0;
- looper_enable( f->list->looper, f->fd, EPOLLOUT );
- }
-}
-
-
-/* FDHandler file descriptor event callback for read/write ops */
-static void
-fdhandler_event( FDHandler* f, int events )
-{
- int len;
-
- /* in certain cases, it's possible to have both EPOLLIN and
- * EPOLLHUP at the same time. This indicates that there is incoming
- * data to read, but that the connection was nonetheless closed
- * by the sender. Be sure to read the data before closing
- * the receiver to avoid packet loss.
- */
-
- if (events & EPOLLIN) {
- Packet* p = packet_alloc();
- int len;
-
- if ((len = fd_read(f->fd, p->data, MAX_PAYLOAD)) < 0) {
- D("%s: can't recv: %s", __FUNCTION__, strerror(errno));
- packet_free(&p);
- } else if (len > 0) {
- p->len = len;
- p->channel = -101; /* special debug value, not used */
- receiver_post( f->receiver, p );
- }
- }
-
- if (events & (EPOLLHUP|EPOLLERR)) {
- /* disconnection */
- D("%s: disconnect on fd %d", __FUNCTION__, f->fd);
- fdhandler_close(f);
- return;
- }
-
- if (events & EPOLLOUT && f->out_first) {
- Packet* p = f->out_first;
- int avail, len;
-
- avail = p->len - f->out_pos;
- if ((len = fd_write(f->fd, p->data + f->out_pos, avail)) < 0) {
- D("%s: can't send: %s", __FUNCTION__, strerror(errno));
- } else {
- f->out_pos += len;
- if (f->out_pos >= p->len) {
- f->out_pos = 0;
- f->out_first = p->next;
- packet_free(&p);
- if (f->out_first == NULL) {
- f->out_ptail = &f->out_first;
- looper_disable( f->list->looper, f->fd, EPOLLOUT );
- }
- }
- }
- }
-}
-
-
-/* Create a new FDHandler that monitors read/writes */
-static FDHandler*
-fdhandler_new( int fd,
- FDHandlerList* list,
- Receiver* receiver )
-{
- FDHandler* f = xalloc0(sizeof(*f));
-
- f->fd = fd;
- f->list = list;
- f->receiver[0] = receiver[0];
- f->out_first = NULL;
- f->out_ptail = &f->out_first;
- f->out_pos = 0;
-
- fdhandler_prepend(f, &list->active);
-
- looper_add( list->looper, fd, (EventFunc) fdhandler_event, f );
- looper_enable( list->looper, fd, EPOLLIN );
-
- return f;
-}
-
-
-/* event callback function to monitor accepts() on server sockets.
- * the convention used here is that the receiver will receive a
- * dummy packet with the new client socket in p->channel
- */
-static void
-fdhandler_accept_event( FDHandler* f, int events )
-{
- if (events & EPOLLIN) {
- /* this is an accept - send a dummy packet to the receiver */
- Packet* p = packet_alloc();
-
- D("%s: accepting on fd %d", __FUNCTION__, f->fd);
- p->data[0] = 1;
- p->len = 1;
- p->channel = fd_accept(f->fd);
- if (p->channel < 0) {
- D("%s: accept failed ?: %s", __FUNCTION__, strerror(errno));
- packet_free(&p);
- return;
- }
- receiver_post( f->receiver, p );
- }
-
- if (events & (EPOLLHUP|EPOLLERR)) {
- /* disconnecting !! */
- D("%s: closing accept fd %d", __FUNCTION__, f->fd);
- fdhandler_close(f);
- return;
- }
-}
-
-
-/* Create a new FDHandler used to monitor new connections on a
- * server socket. The receiver must expect the new connection
- * fd in the 'channel' field of a dummy packet.
- */
-static FDHandler*
-fdhandler_new_accept( int fd,
- FDHandlerList* list,
- Receiver* receiver )
-{
- FDHandler* f = xalloc0(sizeof(*f));
-
- f->fd = fd;
- f->list = list;
- f->receiver[0] = receiver[0];
-
- fdhandler_prepend(f, &list->active);
-
- looper_add( list->looper, fd, (EventFunc) fdhandler_accept_event, f );
- looper_enable( list->looper, fd, EPOLLIN );
- listen( fd, 5 );
-
- return f;
-}
-
-/** SERIAL CONNECTION STATE
- **
- ** The following is used to handle the framing protocol
- ** used on the serial port connection.
- **/
-
-/* each packet is made of a 6 byte header followed by a payload
- * the header looks like:
- *
- * offset size description
- * 0 2 a 2-byte hex string for the channel number
- * 4 4 a 4-char hex string for the size of the payload
- * 6 n the payload itself
- */
-#define HEADER_SIZE 6
-#define CHANNEL_OFFSET 0
-#define LENGTH_OFFSET 2
-#define CHANNEL_SIZE 2
-#define LENGTH_SIZE 4
-
-#define CHANNEL_CONTROL 0
-
-/* The Serial object receives data from the serial port,
- * extracts the payload size and channel index, then sends
- * the resulting messages as a packet to a generic receiver.
- *
- * You can also use serial_send to send a packet through
- * the serial port.
- */
-typedef struct Serial {
- FDHandler* fdhandler; /* used to monitor serial port fd */
- Receiver receiver[1]; /* send payload there */
- int in_len; /* current bytes in input packet */
- int in_datalen; /* payload size, or 0 when reading header */
- int in_channel; /* extracted channel number */
- Packet* in_packet; /* used to read incoming packets */
-} Serial;
-
-
-/* a callback called when the serial port's fd is closed */
-static void
-serial_fd_close( Serial* s )
-{
- fatal("unexpected serial port close !!");
-}
-
-static void
-serial_dump( Packet* p, const char* funcname )
-{
- T("%s: %03d bytes: '%s'",
- funcname, p->len, quote(p->data, p->len));
-}
-
-/* a callback called when a packet arrives from the serial port's FDHandler.
- *
- * This will essentially parse the header, extract the channel number and
- * the payload size and store them in 'in_datalen' and 'in_channel'.
- *
- * After that, the payload is sent to the receiver once completed.
- */
-static void
-serial_fd_receive( Serial* s, Packet* p )
-{
- int rpos = 0, rcount = p->len;
- Packet* inp = s->in_packet;
- int inpos = s->in_len;
-
- serial_dump( p, __FUNCTION__ );
-
- while (rpos < rcount)
- {
- int avail = rcount - rpos;
-
- /* first, try to read the header */
- if (s->in_datalen == 0) {
- int wanted = HEADER_SIZE - inpos;
- if (avail > wanted)
- avail = wanted;
-
- memcpy( inp->data + inpos, p->data + rpos, avail );
- inpos += avail;
- rpos += avail;
-
- if (inpos == HEADER_SIZE) {
- s->in_datalen = hex2int( inp->data + LENGTH_OFFSET, LENGTH_SIZE );
- s->in_channel = hex2int( inp->data + CHANNEL_OFFSET, CHANNEL_SIZE );
-
- if (s->in_datalen <= 0) {
- D("ignoring %s packet from serial port",
- s->in_datalen ? "empty" : "malformed");
- s->in_datalen = 0;
- }
-
- //D("received %d bytes packet for channel %d", s->in_datalen, s->in_channel);
- inpos = 0;
- }
- }
- else /* then, populate the packet itself */
- {
- int wanted = s->in_datalen - inpos;
-
- if (avail > wanted)
- avail = wanted;
-
- memcpy( inp->data + inpos, p->data + rpos, avail );
- inpos += avail;
- rpos += avail;
-
- if (inpos == s->in_datalen) {
- if (s->in_channel < 0) {
- D("ignoring %d bytes addressed to channel %d",
- inpos, s->in_channel);
- } else {
- inp->len = inpos;
- inp->channel = s->in_channel;
- receiver_post( s->receiver, inp );
- s->in_packet = inp = packet_alloc();
- }
- s->in_datalen = 0;
- inpos = 0;
- }
- }
- }
- s->in_len = inpos;
- packet_free(&p);
-}
-
-
-/* send a packet to the serial port.
- * this assumes that p->len and p->channel contain the payload's
- * size and channel and will add the appropriate header.
- */
-static void
-serial_send( Serial* s, Packet* p )
-{
- Packet* h = packet_alloc();
-
- //D("sending to serial %d bytes from channel %d: '%.*s'", p->len, p->channel, p->len, p->data);
-
- /* insert a small header before this packet */
- h->len = HEADER_SIZE;
- int2hex( p->len, h->data + LENGTH_OFFSET, LENGTH_SIZE );
- int2hex( p->channel, h->data + CHANNEL_OFFSET, CHANNEL_SIZE );
-
- serial_dump( h, __FUNCTION__ );
- serial_dump( p, __FUNCTION__ );
-
- fdhandler_enqueue( s->fdhandler, h );
- fdhandler_enqueue( s->fdhandler, p );
-}
-
-
-/* initialize serial reader */
-static void
-serial_init( Serial* s,
- int fd,
- FDHandlerList* list,
- Receiver* receiver )
-{
- Receiver recv;
-
- recv.user = s;
- recv.post = (PostFunc) serial_fd_receive;
- recv.close = (CloseFunc) serial_fd_close;
-
- s->receiver[0] = receiver[0];
-
- s->fdhandler = fdhandler_new( fd, list, &recv );
- s->in_len = 0;
- s->in_datalen = 0;
- s->in_channel = 0;
- s->in_packet = packet_alloc();
-}
-
-
-/** CLIENTS
- **/
-
-typedef struct Client Client;
-typedef struct Multiplexer Multiplexer;
-
-/* A Client object models a single qemud client socket
- * connection in the emulated system.
- *
- * the client first sends the name of the system service
- * it wants to contact (no framing), then waits for a 2
- * byte answer from qemud.
- *
- * the answer is either "OK" or "KO" to indicate
- * success or failure.
- *
- * In case of success, the client can send messages
- * to the service.
- *
- * In case of failure, it can disconnect or try sending
- * the name of another service.
- */
-struct Client {
- Client* next;
- Client** pref;
- int channel;
- char registered;
- FDHandler* fdhandler;
- Multiplexer* multiplexer;
-};
-
-struct Multiplexer {
- Client* clients;
- int last_channel;
- Serial serial[1];
- Looper looper[1];
- FDHandlerList fdhandlers[1];
-};
-
-
-static int multiplexer_open_channel( Multiplexer* mult, Packet* p );
-static void multiplexer_close_channel( Multiplexer* mult, int channel );
-static void multiplexer_serial_send( Multiplexer* mult, int channel, Packet* p );
-
-static void
-client_dump( Client* c, Packet* p, const char* funcname )
-{
- T("%s: client %p (%d): %3d bytes: '%s'",
- funcname, c, c->fdhandler->fd,
- p->len, quote(p->data, p->len));
-}
-
-/* destroy a client */
-static void
-client_free( Client* c )
-{
- /* remove from list */
- c->pref[0] = c->next;
- if (c->next)
- c->next->pref = c->pref;
-
- c->channel = -1;
- c->registered = 0;
-
- /* gently ask the FDHandler to shutdown to
- * avoid losing queued outgoing packets */
- if (c->fdhandler != NULL) {
- fdhandler_shutdown(c->fdhandler);
- c->fdhandler = NULL;
- }
-
- xfree(c);
-}
-
-
-/* a function called when a client socket receives data */
-static void
-client_fd_receive( Client* c, Packet* p )
-{
- client_dump(c, p, __FUNCTION__);
-
- if (c->registered) {
- /* the client is registered, just send the
- * data through the serial port
- */
- multiplexer_serial_send(c->multiplexer, c->channel, p);
- return;
- }
-
- if (c->channel > 0) {
- /* the client is waiting registration results.
- * this should not happen because the client
- * should wait for our 'ok' or 'ko'.
- * close the connection.
- */
- D("%s: bad client sending data before end of registration",
- __FUNCTION__);
- BAD_CLIENT:
- packet_free(&p);
- client_free(c);
- return;
- }
-
- /* the client hasn't registered a service yet,
- * so this must be the name of a service, call
- * the multiplexer to start registration for
- * it.
- */
- D("%s: attempting registration for service '%.*s'",
- __FUNCTION__, p->len, p->data);
- c->channel = multiplexer_open_channel(c->multiplexer, p);
- if (c->channel < 0) {
- D("%s: service name too long", __FUNCTION__);
- goto BAD_CLIENT;
- }
- D("%s: -> received channel id %d", __FUNCTION__, c->channel);
- packet_free(&p);
-}
-
-
-/* a function called when the client socket is closed. */
-static void
-client_fd_close( Client* c )
-{
- T("%s: client %p (%d)", __FUNCTION__, c, c->fdhandler->fd);
-
- /* no need to shutdown the FDHandler */
- c->fdhandler = NULL;
-
- /* tell the emulator we're out */
- if (c->channel > 0)
- multiplexer_close_channel(c->multiplexer, c->channel);
-
- /* free the client */
- client_free(c);
-}
-
-/* a function called when the multiplexer received a registration
- * response from the emulator for a given client.
- */
-static void
-client_registration( Client* c, int registered )
-{
- Packet* p = packet_alloc();
-
- /* sends registration status to client */
- if (!registered) {
- D("%s: registration failed for client %d", __FUNCTION__, c->channel);
- memcpy( p->data, "KO", 2 );
- p->len = 2;
- } else {
- D("%s: registration succeeded for client %d", __FUNCTION__, c->channel);
- memcpy( p->data, "OK", 2 );
- p->len = 2;
- }
- client_dump(c, p, __FUNCTION__);
- fdhandler_enqueue(c->fdhandler, p);
-
- /* now save registration state
- */
- c->registered = registered;
- if (!registered) {
- /* allow the client to try registering another service */
- c->channel = -1;
- }
-}
-
-/* send data to a client */
-static void
-client_send( Client* c, Packet* p )
-{
- client_dump(c, p, __FUNCTION__);
- fdhandler_enqueue(c->fdhandler, p);
-}
-
-
-/* Create new client socket handler */
-static Client*
-client_new( Multiplexer* mult,
- int fd,
- FDHandlerList* pfdhandlers,
- Client** pclients )
-{
- Client* c;
- Receiver recv;
-
- xnew(c);
-
- c->multiplexer = mult;
- c->next = NULL;
- c->pref = &c->next;
- c->channel = -1;
- c->registered = 0;
-
- recv.user = c;
- recv.post = (PostFunc) client_fd_receive;
- recv.close = (CloseFunc) client_fd_close;
-
- c->fdhandler = fdhandler_new( fd, pfdhandlers, &recv );
-
- /* add to client list */
- c->next = *pclients;
- c->pref = pclients;
- *pclients = c;
- if (c->next)
- c->next->pref = &c->next;
-
- return c;
-}
-
-/** GLOBAL MULTIPLEXER
- **/
-
-/* find a client by its channel */
-static Client*
-multiplexer_find_client( Multiplexer* mult, int channel )
-{
- Client* c = mult->clients;
-
- for ( ; c != NULL; c = c->next ) {
- if (c->channel == channel)
- return c;
- }
- return NULL;
-}
-
-/* handle control messages coming from the serial port
- * on CONTROL_CHANNEL.
- */
-static void
-multiplexer_handle_control( Multiplexer* mult, Packet* p )
-{
- /* connection registration success */
- if (p->len == 13 && !memcmp(p->data, "ok:connect:", 11)) {
- int channel = hex2int(p->data+11, 2);
- Client* client = multiplexer_find_client(mult, channel);
-
- /* note that 'client' can be NULL if the corresponding
- * socket was closed before the emulator response arrived.
- */
- if (client != NULL) {
- client_registration(client, 1);
- } else {
- D("%s: NULL client: '%.*s'", __FUNCTION__, p->len, p->data+11);
- }
- goto EXIT;
- }
-
- /* connection registration failure */
- if (p->len == 13 && !memcmp(p->data, "ko:connect:",11)) {
- int channel = hex2int(p->data+11, 2);
- Client* client = multiplexer_find_client(mult, channel);
-
- if (client != NULL)
- client_registration(client, 0);
-
- goto EXIT;
- }
-
- /* emulator-induced client disconnection */
- if (p->len == 13 && !memcmp(p->data, "disconnect:",11)) {
- int channel = hex2int(p->data+11, 2);
- Client* client = multiplexer_find_client(mult, channel);
-
- if (client != NULL)
- client_free(client);
-
- goto EXIT;
- }
-
- /* A message that begins with "X00" is a probe sent by
- * the emulator used to detect which version of qemud it runs
- * against (in order to detect 1.0/1.1 system images. Just
- * silently ignore it there instead of printing an error
- * message.
- */
- if (p->len >= 3 && !memcmp(p->data,"X00",3)) {
- goto EXIT;
- }
-
- D("%s: unknown control message (%d bytes): '%.*s'",
- __FUNCTION__, p->len, p->len, p->data);
-
-EXIT:
- packet_free(&p);
-}
-
-/* a function called when an incoming packet comes from the serial port */
-static void
-multiplexer_serial_receive( Multiplexer* mult, Packet* p )
-{
- Client* client;
-
- T("%s: channel=%d '%.*s'", __FUNCTION__, p->channel, p->len, p->data);
-
- if (p->channel == CHANNEL_CONTROL) {
- multiplexer_handle_control(mult, p);
- return;
- }
-
- client = multiplexer_find_client(mult, p->channel);
- if (client != NULL) {
- client_send(client, p);
- return;
- }
-
- D("%s: discarding packet for unknown channel %d", __FUNCTION__, p->channel);
- packet_free(&p);
-}
-
-/* a function called when the serial reader closes */
-static void
-multiplexer_serial_close( Multiplexer* mult )
-{
- fatal("unexpected close of serial reader");
-}
-
-/* a function called to send a packet to the serial port */
-static void
-multiplexer_serial_send( Multiplexer* mult, int channel, Packet* p )
-{
- p->channel = channel;
- serial_send( mult->serial, p );
-}
-
-
-
-/* a function used by a client to allocate a new channel id and
- * ask the emulator to open it. 'service' must be a packet containing
- * the name of the service in its payload.
- *
- * returns -1 if the service name is too long.
- *
- * notice that client_registration() will be called later when
- * the answer arrives.
- */
-static int
-multiplexer_open_channel( Multiplexer* mult, Packet* service )
-{
- Packet* p = packet_alloc();
- int len, channel;
-
- /* find a free channel number, assume we don't have many
- * clients here. */
- {
- Client* c;
- TRY_AGAIN:
- channel = (++mult->last_channel) & 0xff;
-
- for (c = mult->clients; c != NULL; c = c->next)
- if (c->channel == channel)
- goto TRY_AGAIN;
- }
-
- len = snprintf((char*)p->data, sizeof p->data, "connect:%.*s:%02x", service->len, service->data, channel);
- if (len >= (int)sizeof(p->data)) {
- D("%s: weird, service name too long (%d > %d)", __FUNCTION__, len, sizeof(p->data));
- packet_free(&p);
- return -1;
- }
- p->channel = CHANNEL_CONTROL;
- p->len = len;
-
- serial_send(mult->serial, p);
- return channel;
-}
-
-/* used to tell the emulator a channel was closed by a client */
-static void
-multiplexer_close_channel( Multiplexer* mult, int channel )
-{
- Packet* p = packet_alloc();
- int len = snprintf((char*)p->data, sizeof(p->data), "disconnect:%02x", channel);
-
- if (len > (int)sizeof(p->data)) {
- /* should not happen */
- return;
- }
-
- p->channel = CHANNEL_CONTROL;
- p->len = len;
-
- serial_send(mult->serial, p);
-}
-
-/* this function is used when a new connection happens on the control
- * socket.
- */
-static void
-multiplexer_control_accept( Multiplexer* m, Packet* p )
-{
- /* the file descriptor for the new socket connection is
- * in p->channel. See fdhandler_accept_event() */
- int fd = p->channel;
- Client* client = client_new( m, fd, m->fdhandlers, &m->clients );
-
- D("created client %p listening on fd %d", client, fd);
-
- /* free dummy packet */
- packet_free(&p);
-}
-
-static void
-multiplexer_control_close( Multiplexer* m )
-{
- fatal("unexpected multiplexer control close");
-}
-
-static void
-multiplexer_init( Multiplexer* m, const char* serial_dev )
-{
- int fd, control_fd;
- Receiver recv;
-
- /* initialize looper and fdhandlers list */
- looper_init( m->looper );
- fdhandler_list_init( m->fdhandlers, m->looper );
-
- /* open the serial port */
- do {
- fd = open(serial_dev, O_RDWR);
- } while (fd < 0 && errno == EINTR);
-
- if (fd < 0) {
- fatal( "%s: could not open '%s': %s", __FUNCTION__, serial_dev,
- strerror(errno) );
- }
- // disable echo on serial lines
- if ( !memcmp( serial_dev, "/dev/ttyS", 9 ) ) {
- struct termios ios;
- tcgetattr( fd, &ios );
- ios.c_lflag = 0; /* disable ECHO, ICANON, etc... */
- tcsetattr( fd, TCSANOW, &ios );
- }
-
- /* initialize the serial reader/writer */
- recv.user = m;
- recv.post = (PostFunc) multiplexer_serial_receive;
- recv.close = (CloseFunc) multiplexer_serial_close;
-
- serial_init( m->serial, fd, m->fdhandlers, &recv );
-
- /* open the qemud control socket */
- recv.user = m;
- recv.post = (PostFunc) multiplexer_control_accept;
- recv.close = (CloseFunc) multiplexer_control_close;
-
- fd = android_get_control_socket(CONTROL_SOCKET_NAME);
- if (fd < 0) {
- fatal("couldn't get fd for control socket '%s'", CONTROL_SOCKET_NAME);
- }
-
- fdhandler_new_accept( fd, m->fdhandlers, &recv );
-
- /* initialize clients list */
- m->clients = NULL;
-}
-
-/** MAIN LOOP
- **/
-
-static Multiplexer _multiplexer[1];
-
-int main( void )
-{
- Multiplexer* m = _multiplexer;
-
- /* extract the name of our serial device from the kernel
- * boot options that are stored in /proc/cmdline
- */
-#define KERNEL_OPTION "android.qemud="
-
- {
- char buff[1024];
- int fd, len;
- char* p;
- char* q;
-
- fd = open( "/proc/cmdline", O_RDONLY );
- if (fd < 0) {
- D("%s: can't open /proc/cmdline !!: %s", __FUNCTION__,
- strerror(errno));
- exit(1);
- }
-
- len = fd_read( fd, buff, sizeof(buff)-1 );
- close(fd);
- if (len < 0) {
- D("%s: can't read /proc/cmdline: %s", __FUNCTION__,
- strerror(errno));
- exit(1);
- }
- buff[len] = 0;
-
- p = strstr( buff, KERNEL_OPTION );
- if (p == NULL) {
- D("%s: can't find '%s' in /proc/cmdline",
- __FUNCTION__, KERNEL_OPTION );
- exit(1);
- }
-
- p += sizeof(KERNEL_OPTION)-1; /* skip option */
- q = p;
- while ( *q && *q != ' ' && *q != '\t' )
- q += 1;
-
- snprintf( buff, sizeof(buff), "/dev/%.*s", q-p, p );
-
- multiplexer_init( m, buff );
- }
-
- D( "entering main loop");
- looper_loop( m->looper );
- D( "unexpected termination !!" );
- return 0;
-}
+++ /dev/null
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# We're moving the emulator-specific platform libs to
-# development.git/tools/emulator/. The following test is to ensure
-# smooth builds even if the tree contains both versions.
-#
-ifndef BUILD_EMULATOR_SENSORS_MODULE
-BUILD_EMULATOR_SENSORS_MODULE := true
-
-LOCAL_PATH := $(call my-dir)
-
-ifneq ($(TARGET_PRODUCT),sim)
-# HAL module implemenation, not prelinked and stored in
-# hw/<SENSORS_HARDWARE_MODULE_ID>.<ro.hardware>.so
-include $(CLEAR_VARS)
-LOCAL_PRELINK_MODULE := false
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-LOCAL_SHARED_LIBRARIES := liblog libcutils
-LOCAL_SRC_FILES := sensors_qemu.c
-LOCAL_MODULE := sensors.goldfish
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_SHARED_LIBRARY)
-endif
-
-endif # BUILD_EMULATOR_SENSORS_MODULE
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* this implements a sensors hardware library for the Android emulator.
- * the following code should be built as a shared library that will be
- * placed into /system/lib/hw/sensors.goldfish.so
- *
- * it will be loaded by the code in hardware/libhardware/hardware.c
- * which is itself called from com_android_server_SensorService.cpp
- */
-
-
-/* we connect with the emulator through the "sensors" qemud service
- */
-#define SENSORS_SERVICE_NAME "sensors"
-
-#define LOG_TAG "QemuSensors"
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <string.h>
-#include <cutils/log.h>
-#include <cutils/native_handle.h>
-#include <cutils/sockets.h>
-#include <hardware/sensors.h>
-
-#if 0
-#define D(...) LOGD(__VA_ARGS__)
-#else
-#define D(...) ((void)0)
-#endif
-
-#define E(...) LOGE(__VA_ARGS__)
-
-#include <hardware/qemud.h>
-
-/** SENSOR IDS AND NAMES
- **/
-
-#define MAX_NUM_SENSORS 5
-
-#define SUPPORTED_SENSORS ((1<<MAX_NUM_SENSORS)-1)
-
-#define ID_BASE SENSORS_HANDLE_BASE
-#define ID_ACCELERATION (ID_BASE+0)
-#define ID_MAGNETIC_FIELD (ID_BASE+1)
-#define ID_ORIENTATION (ID_BASE+2)
-#define ID_TEMPERATURE (ID_BASE+3)
-#define ID_PROXIMITY (ID_BASE+4)
-
-#define SENSORS_ACCELERATION (1 << ID_ACCELERATION)
-#define SENSORS_MAGNETIC_FIELD (1 << ID_MAGNETIC_FIELD)
-#define SENSORS_ORIENTATION (1 << ID_ORIENTATION)
-#define SENSORS_TEMPERATURE (1 << ID_TEMPERATURE)
-#define SENSORS_PROXIMITY (1 << ID_PROXIMITY)
-
-#define ID_CHECK(x) ((unsigned)((x)-ID_BASE) < MAX_NUM_SENSORS)
-
-#define SENSORS_LIST \
- SENSOR_(ACCELERATION,"acceleration") \
- SENSOR_(MAGNETIC_FIELD,"magnetic-field") \
- SENSOR_(ORIENTATION,"orientation") \
- SENSOR_(TEMPERATURE,"temperature") \
- SENSOR_(PROXIMITY,"proximity") \
-
-static const struct {
- const char* name;
- int id; } _sensorIds[MAX_NUM_SENSORS] =
-{
-#define SENSOR_(x,y) { y, ID_##x },
- SENSORS_LIST
-#undef SENSOR_
-};
-
-static const char*
-_sensorIdToName( int id )
-{
- int nn;
- for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
- if (id == _sensorIds[nn].id)
- return _sensorIds[nn].name;
- return "<UNKNOWN>";
-}
-
-static int
-_sensorIdFromName( const char* name )
-{
- int nn;
-
- if (name == NULL)
- return -1;
-
- for (nn = 0; nn < MAX_NUM_SENSORS; nn++)
- if (!strcmp(name, _sensorIds[nn].name))
- return _sensorIds[nn].id;
-
- return -1;
-}
-
-/** SENSORS POLL DEVICE
- **
- ** This one is used to read sensor data from the hardware.
- ** We implement this by simply reading the data from the
- ** emulator through the QEMUD channel.
- **/
-
-typedef struct SensorPoll {
- struct sensors_poll_device_t device;
- sensors_event_t sensors[MAX_NUM_SENSORS];
- int events_fd;
- uint32_t pendingSensors;
- int64_t timeStart;
- int64_t timeOffset;
- int fd;
- uint32_t active_sensors;
-} SensorPoll;
-
-/* this must return a file descriptor that will be used to read
- * the sensors data (it is passed to data__data_open() below
- */
-static native_handle_t*
-control__open_data_source(struct sensors_poll_device_t *dev)
-{
- SensorPoll* ctl = (void*)dev;
- native_handle_t* handle;
-
- if (ctl->fd < 0) {
- ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
- }
- D("%s: fd=%d", __FUNCTION__, ctl->fd);
- handle = native_handle_create(1, 0);
- handle->data[0] = dup(ctl->fd);
- return handle;
-}
-
-static int
-control__activate(struct sensors_poll_device_t *dev,
- int handle,
- int enabled)
-{
- SensorPoll* ctl = (void*)dev;
- uint32_t mask, sensors, active, new_sensors, changed;
- char command[128];
- int ret;
-
- D("%s: handle=%s (%d) fd=%d enabled=%d", __FUNCTION__,
- _sensorIdToName(handle), handle, ctl->fd, enabled);
-
- if (!ID_CHECK(handle)) {
- E("%s: bad handle ID", __FUNCTION__);
- return -1;
- }
-
- mask = (1<<handle);
- sensors = enabled ? mask : 0;
-
- active = ctl->active_sensors;
- new_sensors = (active & ~mask) | (sensors & mask);
- changed = active ^ new_sensors;
-
- if (!changed)
- return 0;
-
- snprintf(command, sizeof command, "set:%s:%d",
- _sensorIdToName(handle), enabled != 0);
-
- if (ctl->fd < 0) {
- ctl->fd = qemud_channel_open(SENSORS_SERVICE_NAME);
- }
-
- ret = qemud_channel_send(ctl->fd, command, -1);
- if (ret < 0) {
- E("%s: when sending command errno=%d: %s", __FUNCTION__, errno, strerror(errno));
- return -1;
- }
- ctl->active_sensors = new_sensors;
-
- return 0;
-}
-
-static int
-control__set_delay(struct sensors_poll_device_t *dev, int32_t ms)
-{
- SensorPoll* ctl = (void*)dev;
- char command[128];
-
- D("%s: dev=%p delay-ms=%d", __FUNCTION__, dev, ms);
-
- snprintf(command, sizeof command, "set-delay:%d", ms);
-
- return qemud_channel_send(ctl->fd, command, -1);
-}
-
-static int
-control__close(struct hw_device_t *dev)
-{
- SensorPoll* ctl = (void*)dev;
- close(ctl->fd);
- free(ctl);
- return 0;
-}
-
-/* return the current time in nanoseconds */
-static int64_t
-data__now_ns(void)
-{
- struct timespec ts;
-
- clock_gettime(CLOCK_MONOTONIC, &ts);
-
- return (int64_t)ts.tv_sec * 1000000000 + ts.tv_nsec;
-}
-
-static int
-data__data_open(struct sensors_poll_device_t *dev, native_handle_t* handle)
-{
- SensorPoll* data = (void*)dev;
- int i;
- D("%s: dev=%p fd=%d", __FUNCTION__, dev, handle->data[0]);
- memset(&data->sensors, 0, sizeof(data->sensors));
-
- for (i=0 ; i<MAX_NUM_SENSORS ; i++) {
- data->sensors[i].acceleration.status = SENSOR_STATUS_ACCURACY_HIGH;
- }
- data->pendingSensors = 0;
- data->timeStart = 0;
- data->timeOffset = 0;
-
- data->events_fd = dup(handle->data[0]);
- D("%s: dev=%p fd=%d (was %d)", __FUNCTION__, dev, data->events_fd, handle->data[0]);
- native_handle_close(handle);
- native_handle_delete(handle);
- return 0;
-}
-
-static int
-data__data_close(struct sensors_poll_device_t *dev)
-{
- SensorPoll* data = (void*)dev;
- D("%s: dev=%p", __FUNCTION__, dev);
- if (data->events_fd >= 0) {
- close(data->events_fd);
- data->events_fd = -1;
- }
- return 0;
-}
-
-static int
-pick_sensor(SensorPoll* data,
- sensors_event_t* values)
-{
- uint32_t mask = SUPPORTED_SENSORS;
- while (mask) {
- uint32_t i = 31 - __builtin_clz(mask);
- mask &= ~(1<<i);
- if (data->pendingSensors & (1<<i)) {
- data->pendingSensors &= ~(1<<i);
- *values = data->sensors[i];
- values->sensor = i;
- values->version = sizeof(*values);
-
- D("%s: %d [%f, %f, %f]", __FUNCTION__,
- i,
- values->data[0],
- values->data[1],
- values->data[2]);
- return i;
- }
- }
- LOGE("No sensor to return!!! pendingSensors=%08x", data->pendingSensors);
- // we may end-up in a busy loop, slow things down, just in case.
- usleep(100000);
- return -EINVAL;
-}
-
-static int
-data__poll(struct sensors_poll_device_t *dev, sensors_event_t* values)
-{
- SensorPoll* data = (void*)dev;
- int fd = data->events_fd;
-
- D("%s: data=%p", __FUNCTION__, dev);
-
- // there are pending sensors, returns them now...
- if (data->pendingSensors) {
- return pick_sensor(data, values);
- }
-
- // wait until we get a complete event for an enabled sensor
- uint32_t new_sensors = 0;
-
- while (1) {
- /* read the next event */
- char buff[256];
- int len = qemud_channel_recv(data->events_fd, buff, sizeof buff-1);
- float params[3];
- int64_t event_time;
-
- if (len < 0) {
- E("%s: len=%d, errno=%d: %s", __FUNCTION__, len, errno, strerror(errno));
- return -errno;
- }
-
- buff[len] = 0;
-
- /* "wake" is sent from the emulator to exit this loop. */
- if (!strcmp((const char*)data, "wake")) {
- return 0x7FFFFFFF;
- }
-
- /* "acceleration:<x>:<y>:<z>" corresponds to an acceleration event */
- if (sscanf(buff, "acceleration:%g:%g:%g", params+0, params+1, params+2) == 3) {
- new_sensors |= SENSORS_ACCELERATION;
- data->sensors[ID_ACCELERATION].acceleration.x = params[0];
- data->sensors[ID_ACCELERATION].acceleration.y = params[1];
- data->sensors[ID_ACCELERATION].acceleration.z = params[2];
- continue;
- }
-
- /* "orientation:<azimuth>:<pitch>:<roll>" is sent when orientation changes */
- if (sscanf(buff, "orientation:%g:%g:%g", params+0, params+1, params+2) == 3) {
- new_sensors |= SENSORS_ORIENTATION;
- data->sensors[ID_ORIENTATION].orientation.azimuth = params[0];
- data->sensors[ID_ORIENTATION].orientation.pitch = params[1];
- data->sensors[ID_ORIENTATION].orientation.roll = params[2];
- continue;
- }
-
- /* "magnetic:<x>:<y>:<z>" is sent for the params of the magnetic field */
- if (sscanf(buff, "magnetic:%g:%g:%g", params+0, params+1, params+2) == 3) {
- new_sensors |= SENSORS_MAGNETIC_FIELD;
- data->sensors[ID_MAGNETIC_FIELD].magnetic.x = params[0];
- data->sensors[ID_MAGNETIC_FIELD].magnetic.y = params[1];
- data->sensors[ID_MAGNETIC_FIELD].magnetic.z = params[2];
- continue;
- }
-
- /* "temperature:<celsius>" */
- if (sscanf(buff, "temperature:%g", params+0) == 2) {
- new_sensors |= SENSORS_TEMPERATURE;
- data->sensors[ID_TEMPERATURE].temperature = params[0];
- continue;
- }
-
- /* "proximity:<value>" */
- if (sscanf(buff, "proximity:%g", params+0) == 1) {
- new_sensors |= SENSORS_PROXIMITY;
- data->sensors[ID_PROXIMITY].distance = params[0];
- continue;
- }
-
- /* "sync:<time>" is sent after a series of sensor events.
- * where 'time' is expressed in micro-seconds and corresponds
- * to the VM time when the real poll occured.
- */
- if (sscanf(buff, "sync:%lld", &event_time) == 1) {
- if (new_sensors) {
- data->pendingSensors = new_sensors;
- int64_t t = event_time * 1000LL; /* convert to nano-seconds */
-
- /* use the time at the first sync: as the base for later
- * time values */
- if (data->timeStart == 0) {
- data->timeStart = data__now_ns();
- data->timeOffset = data->timeStart - t;
- }
- t += data->timeOffset;
-
- while (new_sensors) {
- uint32_t i = 31 - __builtin_clz(new_sensors);
- new_sensors &= ~(1<<i);
- data->sensors[i].timestamp = t;
- }
- return pick_sensor(data, values);
- } else {
- D("huh ? sync without any sensor data ?");
- }
- continue;
- }
- D("huh ? unsupported command");
- }
- return -1;
-}
-
-static int
-data__close(struct hw_device_t *dev)
-{
- SensorPoll* data = (SensorPoll*)dev;
- if (data) {
- if (data->events_fd >= 0) {
- //LOGD("(device close) about to close fd=%d", data->events_fd);
- close(data->events_fd);
- }
- free(data);
- }
- return 0;
-}
-
-/** SENSORS POLL DEVICE FUNCTIONS **/
-
-static int poll__close(struct hw_device_t* dev)
-{
- SensorPoll* ctl = (void*)dev;
- close(ctl->fd);
- if (ctl->fd >= 0) {
- close(ctl->fd);
- }
- if (ctl->events_fd >= 0) {
- close(ctl->events_fd);
- }
- free(ctl);
- return 0;
-}
-
-static int poll__poll(struct sensors_poll_device_t *dev,
- sensors_event_t* data, int count)
-{
- SensorPoll* datadev = (void*)dev;
- int ret;
- int i;
- D("%s: dev=%p data=%p count=%d ", __FUNCTION__, dev, data, count);
-
- for (i = 0; i < count; i++) {
- ret = data__poll(dev, data);
- data++;
- if (ret > MAX_NUM_SENSORS || ret < 0) {
- return i;
- }
- if (!datadev->pendingSensors) {
- return i + 1;
- }
- }
- return count;
-}
-
-static int poll__activate(struct sensors_poll_device_t *dev,
- int handle, int enabled)
-{
- int ret;
- native_handle_t* hdl;
- SensorPoll* ctl = (void*)dev;
- D("%s: dev=%p handle=%x enable=%d ", __FUNCTION__, dev, handle, enabled);
- if (ctl->fd < 0) {
- D("%s: OPEN CTRL and DATA ", __FUNCTION__);
- hdl = control__open_data_source(dev);
- ret = data__data_open(dev,hdl);
- }
- ret = control__activate(dev, handle, enabled);
- return ret;
-}
-
-static int poll__setDelay(struct sensors_poll_device_t *dev,
- int handle, int64_t ns)
-{
- // TODO
- return 0;
-}
-
-/** MODULE REGISTRATION SUPPORT
- **
- ** This is required so that hardware/libhardware/hardware.c
- ** will dlopen() this library appropriately.
- **/
-
-/*
- * the following is the list of all supported sensors.
- * this table is used to build sSensorList declared below
- * according to which hardware sensors are reported as
- * available from the emulator (see get_sensors_list below)
- *
- * note: numerical values for maxRange/resolution/power were
- * taken from the reference AK8976A implementation
- */
-static const struct sensor_t sSensorListInit[] = {
- { .name = "Goldfish 3-axis Accelerometer",
- .vendor = "The Android Open Source Project",
- .version = 1,
- .handle = ID_ACCELERATION,
- .type = SENSOR_TYPE_ACCELEROMETER,
- .maxRange = 2.8f,
- .resolution = 1.0f/4032.0f,
- .power = 3.0f,
- .reserved = {}
- },
-
- { .name = "Goldfish 3-axis Magnetic field sensor",
- .vendor = "The Android Open Source Project",
- .version = 1,
- .handle = ID_MAGNETIC_FIELD,
- .type = SENSOR_TYPE_MAGNETIC_FIELD,
- .maxRange = 2000.0f,
- .resolution = 1.0f,
- .power = 6.7f,
- .reserved = {}
- },
-
- { .name = "Goldfish Orientation sensor",
- .vendor = "The Android Open Source Project",
- .version = 1,
- .handle = ID_ORIENTATION,
- .type = SENSOR_TYPE_ORIENTATION,
- .maxRange = 360.0f,
- .resolution = 1.0f,
- .power = 9.7f,
- .reserved = {}
- },
-
- { .name = "Goldfish Temperature sensor",
- .vendor = "The Android Open Source Project",
- .version = 1,
- .handle = ID_TEMPERATURE,
- .type = SENSOR_TYPE_TEMPERATURE,
- .maxRange = 80.0f,
- .resolution = 1.0f,
- .power = 0.0f,
- .reserved = {}
- },
-
- { .name = "Goldfish Proximity sensor",
- .vendor = "The Android Open Source Project",
- .version = 1,
- .handle = ID_PROXIMITY,
- .type = SENSOR_TYPE_PROXIMITY,
- .maxRange = 1.0f,
- .resolution = 1.0f,
- .power = 20.0f,
- .reserved = {}
- },
-};
-
-static struct sensor_t sSensorList[MAX_NUM_SENSORS];
-
-static int sensors__get_sensors_list(struct sensors_module_t* module,
- struct sensor_t const** list)
-{
- int fd = qemud_channel_open(SENSORS_SERVICE_NAME);
- char buffer[12];
- int mask, nn, count;
-
- int ret;
- if (fd < 0) {
- E("%s: no qemud connection", __FUNCTION__);
- return 0;
- }
- ret = qemud_channel_send(fd, "list-sensors", -1);
- if (ret < 0) {
- E("%s: could not query sensor list: %s", __FUNCTION__,
- strerror(errno));
- close(fd);
- return 0;
- }
- ret = qemud_channel_recv(fd, buffer, sizeof buffer-1);
- if (ret < 0) {
- E("%s: could not receive sensor list: %s", __FUNCTION__,
- strerror(errno));
- close(fd);
- return 0;
- }
- buffer[ret] = 0;
- close(fd);
-
- /* the result is a integer used as a mask for available sensors */
- mask = atoi(buffer);
- count = 0;
- for (nn = 0; nn < MAX_NUM_SENSORS; nn++) {
- if (((1 << nn) & mask) == 0)
- continue;
-
- sSensorList[count++] = sSensorListInit[nn];
- }
- D("%s: returned %d sensors (mask=%d)", __FUNCTION__, count, mask);
- *list = sSensorList;
- return count;
-}
-
-
-static int
-open_sensors(const struct hw_module_t* module,
- const char* name,
- struct hw_device_t* *device)
-{
- int status = -EINVAL;
-
- D("%s: name=%s", __FUNCTION__, name);
-
- if (!strcmp(name, SENSORS_HARDWARE_POLL)) {
- SensorPoll *dev = malloc(sizeof(*dev));
-
- memset(dev, 0, sizeof(*dev));
-
- dev->device.common.tag = HARDWARE_DEVICE_TAG;
- dev->device.common.version = 0;
- dev->device.common.module = (struct hw_module_t*) module;
- dev->device.common.close = poll__close;
- dev->device.poll = poll__poll;
- dev->device.activate = poll__activate;
- dev->device.setDelay = poll__setDelay;
- dev->events_fd = -1;
- dev->fd = -1;
-
- *device = &dev->device.common;
- status = 0;
- }
- return status;
-}
-
-
-static struct hw_module_methods_t sensors_module_methods = {
- .open = open_sensors
-};
-
-const struct sensors_module_t HAL_MODULE_INFO_SYM = {
- .common = {
- .tag = HARDWARE_MODULE_TAG,
- .version_major = 1,
- .version_minor = 0,
- .id = SENSORS_HARDWARE_MODULE_ID,
- .name = "Goldfish SENSORS Module",
- .author = "The Android Open Source Project",
- .methods = &sensors_module_methods,
- },
- .get_sensors_list = sensors__get_sensors_list
-};
+++ /dev/null
-# Copyright (C) 2009 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# this file is used to build emulator-specific program tools
-# that should only run in the emulator.
-#
-
-# We're moving the emulator-specific platform libs to
-# development.git/tools/emulator/. The following test is to ensure
-# smooth builds even if the tree contains both versions.
-#
-ifndef BUILD_EMULATOR_QEMU_PROPS
-BUILD_EMULATOR_QEMU_PROPS := true
-
-LOCAL_PATH := $(call my-dir)
-
-ifneq ($(TARGET_PRODUCT),sim)
-
-# The 'qemu-props' program is run from /system/etc/init.goldfish.rc
-# to setup various system properties sent by the emulator program.
-#
-include $(CLEAR_VARS)
-LOCAL_MODULE := qemu-props
-LOCAL_SRC_FILES := qemu-props.c
-LOCAL_SHARED_LIBRARIES := libcutils
-# we don't want this in 'user' builds which don't have
-# emulator-specific binaries.
-LOCAL_MODULE_TAGS := debug
-include $(BUILD_EXECUTABLE)
-
-endif # TARGET_PRODUCT != sim
-
-endif # BUILD_EMULATOR_QEMU_PROPS
+++ /dev/null
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/* this program is used to read a set of system properties and their values
- * from the emulator program and set them in the currently-running emulated
- * system. It does so by connecting to the 'boot-properties' qemud service.
- *
- * This program should be run as root and called from
- * /system/etc/init.goldfish.rc exclusively.
- */
-
-#define LOG_TAG "qemu-props"
-
-#define DEBUG 1
-
-#if DEBUG
-# include <cutils/log.h>
-# define DD(...) LOGI(__VA_ARGS__)
-#else
-# define DD(...) ((void)0)
-#endif
-
-#include <cutils/properties.h>
-#include <unistd.h>
-#include <hardware/qemud.h>
-
-/* Name of the qemud service we want to connect to.
- */
-#define QEMUD_SERVICE "boot-properties"
-
-#define MAX_TRIES 5
-
-int main(void)
-{
- int qemud_fd, count = 0;
-
- /* try to connect to the qemud service */
- {
- int tries = MAX_TRIES;
-
- while (1) {
- qemud_fd = qemud_channel_open( "boot-properties" );
- if (qemud_fd >= 0)
- break;
-
- if (--tries <= 0) {
- DD("Could not connect after too many tries. Aborting");
- return 1;
- }
-
- DD("waiting 1s to wait for qemud.");
- sleep(1);
- }
- }
-
- DD("connected to '%s' qemud service.", QEMUD_SERVICE);
-
- /* send the 'list' command to the service */
- if (qemud_channel_send(qemud_fd, "list", -1) < 0) {
- DD("could not send command to '%s' service", QEMUD_SERVICE);
- return 1;
- }
-
- /* read each system property as a single line from the service,
- * until exhaustion.
- */
- for (;;)
- {
-#define BUFF_SIZE (PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 2)
- DD("receiving..");
- char* q;
- char temp[BUFF_SIZE];
- int len = qemud_channel_recv(qemud_fd, temp, sizeof temp - 1);
-
- /* lone NUL-byte signals end of properties */
- if (len < 0 || len > BUFF_SIZE-1 || temp[0] == '\0')
- break;
-
- temp[len] = '\0'; /* zero-terminate string */
-
- DD("received: %.*s", len, temp);
-
- /* separate propery name from value */
- q = strchr(temp, '=');
- if (q == NULL) {
- DD("invalid format, ignored.");
- continue;
- }
- *q++ = '\0';
-
- if (property_set(temp, q) < 0) {
- DD("could not set property '%s' to '%s'", temp, q);
- } else {
- count += 1;
- }
- }
-
-
- /* finally, close the channel and exit */
- close(qemud_fd);
- DD("exiting (%d properties set).", count);
- return 0;
-}