Home | History | Annotate | Download | only in telephony
      1 /* Copyright (C) 2007-2008 The Android Open Source Project
      2 **
      3 ** This software is licensed under the terms of the GNU General Public
      4 ** License version 2, as published by the Free Software Foundation, and
      5 ** may be copied, distributed, and modified under those terms.
      6 **
      7 ** This program is distributed in the hope that it will be useful,
      8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
      9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     10 ** GNU General Public License for more details.
     11 */
     12 /* implement the modem character device for Android within the QEMU event loop.
     13  * it communicates through a serial port with "rild" (Radio Interface Layer Daemon)
     14  * on the emulated device.
     15  */
     16 #include "modem_driver.h"
     17 #include "sysemu/char.h"
     18 
     19 #define  xxDEBUG
     20 
     21 #ifdef DEBUG
     22 #  include <stdio.h>
     23 #  define  D(...)   ( fprintf( stderr, __VA_ARGS__ ) )
     24 #else
     25 #  define  D(...)   ((void)0)
     26 #endif
     27 
     28 AModem            android_modem;
     29 CharDriverState*  android_modem_cs;
     30 
     31 typedef struct {
     32     CharDriverState*  cs;
     33     AModem            modem;
     34     char              in_buff[ 1024 ];
     35     int               in_pos;
     36     int               in_sms;
     37 } ModemDriver;
     38 
     39 /* send unsollicited messages to the device */
     40 static void
     41 modem_driver_unsol( void*  _md, const char*  message)
     42 {
     43     ModemDriver*      md = _md;
     44     int               len = strlen(message);
     45 
     46     qemu_chr_write(md->cs, (const uint8_t*)message, len);
     47 }
     48 
     49 static int
     50 modem_driver_can_read( void*  _md )
     51 {
     52     ModemDriver*  md  = _md;
     53     int           ret = sizeof(md->in_buff) - md->in_pos;
     54 
     55     return ret;
     56 }
     57 
     58 /* despite its name, this function is called when the device writes to the modem */
     59 static void
     60 modem_driver_read( void*  _md, const uint8_t*  src, int  len )
     61 {
     62     ModemDriver*      md  = _md;
     63     const uint8_t*    end = src + len;
     64     int               nn;
     65 
     66     D( "%s: reading %d from %p bytes:", __FUNCTION__, len, src );
     67     for (nn = 0; nn < len; nn++) {
     68         int  c = src[nn];
     69         if (c >= 32 && c < 127)
     70             D( "%c", c );
     71         else if (c == '\n')
     72             D( "<LF>" );
     73         else if (c == '\r')
     74             D( "<CR>" );
     75         else
     76             D( "\\x%02x", c );
     77     }
     78     D( "\n" );
     79 
     80     for ( ; src < end; src++ ) {
     81         char  c = src[0];
     82 
     83         if (md->in_sms) {
     84             if (c != 26)
     85                 goto AppendChar;
     86 
     87             md->in_buff[ md->in_pos ] = c;
     88             md->in_pos++;
     89             md->in_sms = 0;
     90             c = '\n';
     91         }
     92 
     93         if (c == '\n' || c == '\r') {
     94             const char*  answer;
     95 
     96             if (md->in_pos == 0)  /* skip empty lines */
     97                 continue;
     98 
     99             md->in_buff[ md->in_pos ] = 0;
    100             md->in_pos                = 0;
    101 
    102             D( "%s: << %s\n", __FUNCTION__, md->in_buff );
    103             answer = amodem_send(android_modem, md->in_buff);
    104             if (answer != NULL) {
    105                 D( "%s: >> %s\n", __FUNCTION__, answer );
    106                 len = strlen(answer);
    107                 if (len == 2 && answer[0] == '>' && answer[1] == ' ')
    108                     md->in_sms = 1;
    109 
    110                 qemu_chr_write(md->cs, (const uint8_t*)answer, len);
    111                 qemu_chr_write(md->cs, (const uint8_t*)"\r", 1);
    112             } else
    113                 D( "%s: -- NO ANSWER\n", __FUNCTION__ );
    114 
    115             continue;
    116         }
    117     AppendChar:
    118         md->in_buff[ md->in_pos++ ] = c;
    119         if (md->in_pos == sizeof(md->in_buff)) {
    120             /* input is too long !! */
    121             md->in_pos = 0;
    122         }
    123     }
    124     D( "%s: done\n", __FUNCTION__ );
    125 }
    126 
    127 
    128 static void
    129 modem_driver_init( int  base_port, ModemDriver*  dm, CharDriverState*  cs )
    130 {
    131     dm->cs     = cs;
    132     dm->in_pos = 0;
    133     dm->in_sms = 0;
    134     dm->modem  = amodem_create( base_port, modem_driver_unsol, dm );
    135 
    136     qemu_chr_add_handlers( cs, modem_driver_can_read, modem_driver_read, NULL, dm );
    137 }
    138 
    139 
    140 void android_modem_init( int  base_port )
    141 {
    142     static ModemDriver  modem_driver[1];
    143 
    144     if (android_modem_cs != NULL) {
    145         modem_driver_init( base_port, modem_driver, android_modem_cs );
    146         android_modem = modem_driver->modem;
    147     }
    148 }
    149