G1: Add initial HTC G1 modem support
PATCH 1/3 G1: Add initial HTC G1 modem support
This series adds support for the HTC G1 phone (that is, the Google phone).
G1 plugin is based on generic_at, with a bunch of stuff dropped and simplified. We use AT+CFUN=1 for powering on rather than having a configurable init string. We also manually set the default state during init (the G1 appears to start in mode V0 by default). The device (/dev/smd0) is hardcoded.
--- Makefile.am | 5 + configure.ac | 8 ++- plugins/g1.c | 309 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 321 insertions(+), 1 deletions(-) create mode 100644 plugins/g1.c
Makefile.am +5 -0
@@ -78,6 +78,11 @@ builtin_modules += generic_at builtin_sources += plugins/generic_at.c endif +if G1MODEM +builtin_modules += g1 +builtin_sources += plugins/g1.c +endif + if MAINTAINER_MODE builtin_modules += example_history builtin_sources += plugins/example_history.c
configure.ac +7 -1
@@ -65,10 +65,16 @@ AC_ARG_ENABLE(isimodem, AC_HELP_STRING([--disable-isimodem], [enable_isimodem=${enableval}]) AM_CONDITIONAL(ISIMODEM, test "${enable_isimodem}" != "no") +AC_ARG_ENABLE(g1, AC_HELP_STRING([--disable-g1], + [disable HTC G1 modem support]), + [enable_g1=${enableval}]) +AM_CONDITIONAL(G1MODEM, test "${enable_g1}" != "no") + AC_ARG_ENABLE(atmodem, AC_HELP_STRING([--disable-atmodem], [disable ETSI AT modem support]), [enable_atmodem=${enableval}]) -AM_CONDITIONAL(ATMODEM, test "${enable_atmodem}" != "no") +AM_CONDITIONAL(ATMODEM, [test "${enable_atmodem}" != "no" || + test "${enable_g1}" != "no"]) AC_CHECK_LIB(dl, dlopen, dummy=yes, AC_MSG_ERROR(dynamic linking loader is required))
plugins/g1.c new file +309 -0
309 lines not on this page · raw message
Signature · 1 line
1.6.3.3
Hi Andres,
Quoted 34 lines
This series adds support for the HTC G1 phone (that is, the Google phone).
G1 plugin is based on
generic_at, with a bunch of stuff dropped and simplified. We use AT+CFUN=1 for powering on rather than having a configurable init string. We also manually set the default state during init (the G1 appears to start in mode V0 by default). The device (/dev/smd0) is hardcoded.
+static gbooleanconnect_cb(GIOChannel *io, GIOCondition cond, gpointer user)+{plugins/g1.c new file +24
-0+struct ofono_modem *modem = user; +struct g1_data *d =ofono_modem_get_data (modem); +int err =0 ; +gboolean success; +GAtSyntax *syntax; + +if (cond &G_IO_NVAL ) +return FALSE; + +if (cond &G_IO_OUT ) { +int sock =g_io_channel_unix_get_fd (io); +socklen_t len =sizeof (err); + +if (getsockopt (sock,SOL_SOCKET ,SO_ERROR , &err, &len) <0 ) + err = errno ==ENOTSOCK ?0 : errno; + }else if (cond & (G_IO_HUP |G_IO_ERR )) + err =ECONNRESET ; + + success = !err; + +DBG ("io ref: %d" , io->ref_count); + +if (success == FALSE) + goto error;
plugins/g1.c line 113
Quoted 10 lines
plugins/g1.c new file +10
-0+ + syntax =g_at_syntax_new_gsmv1 (); + d->chat =g_at_chat_new (io, syntax); +g_at_syntax_unref (syntax); + +DBG ("io ref: %d" , io->ref_count); + +if (!d->chat) + goto error; +
Since this is a tty, you probably don't need this function at all.
Quoted 31 lines
plugins/g1.c new file +31
-0+static GIOChannel *tty_connect (const char *tty) +{ +GIOChannel *io; +int sk; +struct termios newtio; + + sk =open (tty,O_RDWR |O_NOCTTY ); + +if (sk <0 ) { +ofono_error ("Can't open TTY %s: %s(%d)" , + tty,strerror (errno), errno); +return NULL ; + } + + newtio.c_cflag =B115200 |CRTSCTS |CLOCAL |CREAD ; + newtio.c_iflag =IGNPAR ; + newtio.c_oflag =0 ; + newtio.c_lflag =0 ; + + newtio.c_cc[VTIME ] =1 ; + newtio.c_cc[VMIN ] =5 ; + +tcflush (sk,TCIFLUSH ); +if (tcsetattr (sk,TCSANOW , &newtio) <0 ) { +ofono_error ("Can't change serial settings: %s(%d)" , +strerror (errno), errno); +close (sk); +return NULL ; + } + + io =g_io_channel_unix_new (sk);
plugins/g1.c line 172
Quoted 10 lines
plugins/g1.c new file +10
-0+g_io_channel_set_close_on_unref (io, TRUE); + +if (g_io_channel_set_flags (io,G_IO_FLAG_NONBLOCK , +NULL ) !=G_IO_STATUS_NORMAL ) { +g_io_channel_unref (io); +return NULL ; + } + +return io; +}
You might want to see if using g_at_chat_new_from_tty works here. If not, then the opening the tty should be broken out into a separate utility function that can be used from multiple drivers.
Quoted 17 lines
plugins/g1.c new file +17
-0+static int g1_enable (struct ofono_modem *modem) +{ +struct g1_data *d =ofono_modem_get_data (modem); +GIOChannel *io; +GIOCondition cond; + +DBG ("" ); + + io =tty_connect (MODEM_DEVICE ); +if (io ==NULL ) +return -EINVAL ; + +DBG ("io ref: %d" , io->ref_count); + + cond =G_IO_OUT |G_IO_ERR |G_IO_HUP |G_IO_NVAL ; +g_io_add_watch_full (io,G_PRIORITY_DEFAULT , cond, connect_cb, + modem, connect_destroy);
plugins/g1.c line 219
Quoted 10 lines
plugins/g1.c new file +10
-0+ +DBG ("io ref: %d" , io->ref_count); + +g_io_channel_unref (io); + +DBG ("io ref: %d" , io->ref_count); + d->io = io; + +return -EINPROGRESS ; +}
So I know the generic_at driver does this, but in a real device driver this is wrong. You should probably be using AT+CFUN=1 here. If the g1 supports even more drastic power up/down options, then these should be used.
Quoted 7 lines
plugins/g1.c new file +7
-0+ +static int g1_disable (struct ofono_modem *modem) +{ +struct g1_data *d =ofono_modem_get_data (modem); + +if (d->io) { +g_io_channel_close (d->io);
plugins/g1.c line 236
Quoted 10 lines
plugins/g1.c new file +10
-0+ d->io =NULL ; + } + +if (d->chat) { +g_at_chat_unref (d->chat); + d->chat =NULL ; + } + +return 0 ; +}
Same thing here. AT+CFUN=0 or AT+CFUN=4.
Quoted 18 lines
plugins/g1.c new file +18
-0+static int g1_init (void ) +{ +int err; + + err =ofono_modem_driver_register (&g1_driver); +if (err) + goto done; + + g1_modem =ofono_modem_create ("G1" ,"HTC G1" ); +if (!g1_modem) { + err = -EIO ; + goto unreg; + } + + err =ofono_modem_register (g1_modem); +if (err) + goto remove; +
plugins/g1.c line 300
Quoted 10 lines
plugins/g1.c new file +10
-0+return 0 ; + +remove: +ofono_modem_remove (g1_modem); +unreg: +ofono_modem_driver_unregister (&g1_driver); +done: +return err; +} +
I'd really like to see some sort of detection mechanism here. Even if it is a basic 'if exists /dev/smd0' or reading something from /proc. As I don't necessarily want to see the g1 showing up everywhere.
Regads,
-Denis