• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "qemu-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
modem_driver_unsol(void * _md,const char * message)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
modem_driver_can_read(void * _md)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
modem_driver_read(void * _md,const uint8_t * src,int len)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
modem_driver_init(int base_port,ModemDriver * dm,CharDriverState * cs)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 
android_modem_init(int base_port)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