From c27f813900a3c114562efbb8df1065e94766fc48 Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 10 Feb 2009 15:43:59 -0800 Subject: auto import from //branches/cupcake/...@130745 --- android/hw-control.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 android/hw-control.c (limited to 'android/hw-control.c') diff --git a/android/hw-control.c b/android/hw-control.c new file mode 100644 index 0000000..681e85b --- /dev/null +++ b/android/hw-control.c @@ -0,0 +1,204 @@ +/* Copyright (C) 2007-2008 The Android Open Source Project +** +** This software is licensed under the terms of the GNU General Public +** License version 2, as published by the Free Software Foundation, and +** may be copied, distributed, and modified under those terms. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +*/ + +/* this file implements the support of the new 'hardware control' + * qemud communication channel, which is used by libs/hardware on + * the system image to communicate with the emulator program for + * emulating the following: + * + * - power management + * - led(s) brightness + * - vibrator + * - flashlight + */ +#include "android/hw-control.h" +#include "cbuffer.h" +#include "android/qemud.h" +#include "android/utils/misc.h" +#include "android/utils/debug.h" +#include "qemu-char.h" +#include +#include + +#define D(...) VERBOSE_PRINT(hw_control,__VA_ARGS__) + +/* define T_ACTIVE to 1 to debug transport communications */ +#define T_ACTIVE 0 + +#if T_ACTIVE +#define T(...) VERBOSE_PRINT(hw_control,__VA_ARGS__) +#else +#define T(...) ((void)0) +#endif + +static void* hw_control_client; +static AndroidHwControlFuncs hw_control_funcs; + +#define BUFFER_SIZE 512 + +typedef struct { + CharDriverState* cs; + int overflow; + int wanted; + CBuffer input[1]; + char input_0[ BUFFER_SIZE ]; + /* note: 1 more byte to zero-terminate the query */ + char query[ BUFFER_SIZE+1 ]; +} HwControl; + +/* forward */ +static void hw_control_do_query( HwControl* h, + uint8_t* query, + int querylen ); + +static void +hw_control_init( HwControl* h, CharDriverState* cs ) +{ + h->cs = cs; + h->overflow = 0; + h->wanted = 0; + cbuffer_reset( h->input, h->input_0, sizeof h->input_0 ); +} + +static int +hw_control_can_read( void* _hw ) +{ + HwControl* h = _hw; + return cbuffer_write_avail( h->input ); +} + +static void +hw_control_read( void* _hw, const uint8_t* data, int len ) +{ + HwControl* h = _hw; + CBuffer* input = h->input; + + T("%s: %4d '%.*s'", __FUNCTION__, len, len, data); + + cbuffer_write( input, data, len ); + + while ( input->count > 0 ) + { + /* skip over unwanted data, if any */ + while (h->overflow > 0) { + uint8_t* dummy; + int avail = cbuffer_read_peek( input, &dummy ); + + if (avail == 0) + return; + + if (avail > h->overflow) + avail = h->overflow; + + cbuffer_read_step( input, avail ); + h->overflow -= avail; + } + + /* all incoming messages are made of a 4-byte hexchar sequence giving */ + /* the length of the following payload */ + if (h->wanted == 0) + { + char header[4]; + int len; + + if (input->count < 4) + return; + + cbuffer_read( input, header, 4 ); + len = hex2int( (uint8_t*)header, 4 ); + if (len >= 0) { + /* if the message is too long, skip it */ + if (len > input->size) { + T("%s: skipping oversized message (%d > %d)", + __FUNCTION__, len, input->size); + h->overflow = len; + } else { + T("%s: waiting for %d bytes", __FUNCTION__, len); + h->wanted = len; + } + } + } + else + { + if (input->count < h->wanted) + break; + + cbuffer_read( input, h->query, h->wanted ); + h->query[h->wanted] = 0; + hw_control_do_query( h, (uint8_t*)h->query, h->wanted ); + h->wanted = 0; + } + } +} + + +static uint8_t* +if_starts_with( uint8_t* buf, int buflen, const char* prefix ) +{ + int prefixlen = strlen(prefix); + + if (buflen < prefixlen || memcmp(buf, prefix, prefixlen)) + return NULL; + + return (uint8_t*)buf + prefixlen; +} + + +static void +hw_control_do_query( HwControl* h, + uint8_t* query, + int querylen ) +{ + uint8_t* q; + + D("%s: query %4d '%.*s'", __FUNCTION__, querylen, querylen, query ); + + q = if_starts_with( query, querylen, "power:light:brightness:" ); + if (q != NULL) { + if (hw_control_funcs.light_brightness) { + char* qq = strchr((const char*)q, ':'); + int value; + if (qq == NULL) { + D("%s: badly formatted", __FUNCTION__ ); + return; + } + *qq++ = 0; + value = atoi(qq); + hw_control_funcs.light_brightness( hw_control_client, (char*)q, value ); + } + return; + } +} + + +void +android_hw_control_init( void* opaque, const AndroidHwControlFuncs* funcs ) +{ + static CharDriverState* hw_control_cs; + static HwControl hwstate[1]; + + if (hw_control_cs == NULL) { + CharDriverState* cs; + if ( android_qemud_get_channel( ANDROID_QEMUD_CONTROL, &cs ) < 0 ) { + derror( "could not create hardware control charpipe" ); + exit(1); + } + + hw_control_cs = cs; + hw_control_init( hwstate, cs ); + qemu_chr_add_handlers( cs, hw_control_can_read, hw_control_read, NULL, hwstate ); + + D("%s: hw-control char pipe initialized", __FUNCTION__); + } + hw_control_client = opaque; + hw_control_funcs = funcs[0]; +} -- cgit v1.1