From 991c7abf7acf0a95e713198ee0e6b058ccfba2ed Mon Sep 17 00:00:00 2001 From: Pierre Pronchery Date: Thu, 5 Jul 2012 22:17:20 +0000 Subject: [PATCH] Introducing the osmocom modem plug-in (not functional, not built yet) --- src/modems/osmocom.c | 560 ++++++++++++++++++++++++++++++++++++++++ src/modems/project.conf | 6 + 2 files changed, 566 insertions(+) create mode 100644 src/modems/osmocom.c diff --git a/src/modems/osmocom.c b/src/modems/osmocom.c new file mode 100644 index 0000000..0823880 --- /dev/null +++ b/src/modems/osmocom.c @@ -0,0 +1,560 @@ +/* $Id$ */ +/* Copyright (c) 2012 Pierre Pronchery */ +/* This file is part of DeforaOS Desktop Phone */ +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ + + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "../../config.h" + + +/* Osmocom */ +/* private */ +/* types */ +struct tool_server +{ + struct osmo_fd bfd; + uint8_t dlci; + struct llist_head connections; +}; + +enum dnload_state +{ + WAITING_PROMPT1, + WAITING_PROMPT2, + DOWNLOADING +}; + +enum romload_state +{ + WAITING_IDENTIFICATION, + WAITING_PARAM_ACK, + SENDING_BLOCKS, + SENDING_LAST_BLOCK, + LAST_BLOCK_SENT, + WAITING_BLOCK_ACK, + WAITING_CHECKSUM_ACK, + WAITING_BRANCH_ACK, + FINISHED +}; + +enum mtk_state +{ + MTK_INIT_1, + MTK_INIT_2, + MTK_INIT_3, + MTK_INIT_4, + MTK_WAIT_WRITE_ACK, + MTK_WAIT_ADDR_ACK, + MTK_WAIT_SIZE_ACK, + MTK_SENDING_BLOCKS, + MTK_WAIT_BRANCH_CMD_ACK, + MTK_WAIT_BRANCH_ADDR_ACK, + MTK_FINISHED +}; + +enum dnload_mode +{ + MODE_C123, + MODE_C123xor, + MODE_C140, + MODE_C140xor, + MODE_C155, + MODE_ROMLOAD, + MODE_MTK, + MODE_INVALID +}; + +typedef struct _OsmocomDnload +{ + enum dnload_state state; + enum romload_state romload_state; + enum mtk_state mtk_state; + enum dnload_mode mode, previous_mode; + struct osmo_fd serial_fd; + char *filename, *previous_filename; + char *chainload_filename; + + int expect_hdlc; + + int dump_rx; + int dump_tx; + int beacon_interval; + + /* data to be downloaded */ + uint8_t *data; + int data_len; + + uint8_t *write_ptr; + + /* romload: block to be downloaded */ + uint8_t *block; + int block_len; + uint8_t block_number; + uint16_t block_payload_size; + int romload_dl_checksum; + uint8_t *block_ptr; + uint8_t load_address[4]; + + uint8_t mtk_send_size[4]; + int block_count; + int echo_bytecount; + + struct tool_server layer2_server; + struct tool_server loader_server; +} OsmocomDnload; + +typedef struct _ModemPlugin +{ + ModemPluginHelper * helper; + + guint reset; + + /* modem */ + struct osmo_fd fd; + guint source; + OsmocomDnload dnload; + struct osmo_timer_list tick_timer; +} Osmocom; + + +/* constants */ +#define ROMLOAD_INIT_BAUDRATE B19200 +#define ROMLOAD_DL_BAUDRATE B115200 +#define ROMLOAD_BLOCK_HDR_LEN 10 +#define ROMLOAD_ADDRESS 0x820000 + +#define MTK_INIT_BAUDRATE B19200 +#define MTK_ADDRESS 0x40001400 +#define MTK_BLOCK_SIZE 1024 + +static const uint8_t romload_ident_cmd[] = { 0x3c, 0x69 }; /* helper = helper; + return osmocom; +} + + +/* osmocom_destroy */ +static void _osmocom_destroy(ModemPlugin * modem) +{ + _osmocom_stop(modem); + object_delete(osmocom); + osmocom = NULL; +} + + +/* osmocom_reset */ +static int _reset_open(ModemPlugin * modem); +static unsigned int _reset_baudrate(ModemPlugin * modem, unsigned int baudrate); + +static int _osmocom_reset(ModemPlugin * modem, unsigned int retry) +{ + Osmocom * osmocom = modem; + + _osmocom_stop(modem); + if(_reset_open(modem) != 0) + { + if(retry > 0) + osmocom->reset = g_timeout_add(retry, + _osmocom_on_reset, modem); + return -1; + } +#if 0 + osmocom->channel = g_io_channel_unix_new(fd); + if(g_io_channel_set_encoding(osmocom->channel, NULL, &error) + != G_IO_STATUS_NORMAL) + { + modem->helper->error(modem->helper->modem, error->message, 1); + g_error_free(error); + } + g_io_channel_set_buffered(osmocom->channel, FALSE); + osmocom-> +#else + osmocom->source = g_idle_add(_osmocom_on_idle, modem); +#endif + return 0; +} + +static int _reset_open(ModemPlugin * modem) +{ + Osmocom * osmocom = modem; + ModemPluginHelper * helper = osmocom->helper; + char const * device; + unsigned int baudrate; + int flags; + uint32_t tmpaddr = ROMLOAD_ADDRESS; + char const * p; + + if((device = helper->config_get(helper->modem, "device")) == NULL) + device = "/dev/modem"; + if((p = helper->config_get(helper->modem, "baudrate")) == NULL + || (baudrate = strtoul(p, NULL, 10)) == 0) + baudrate = 115200; + baudrate = _reset_baudrate(modem, baudrate); + if((osmocom->fd.fd = osmo_serial_init(device, baudrate)) < 0) + { + /* XXX report error */ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s: %s\n", device, strerror(errno)); +#endif + return -1; + } + if(osmo_fd_register(&osmocom->fd) != 0) + { +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s: %s\n", device, strerror(errno)); +#endif + /* XXX report error */ + return -1; + } + /* Set serial socket to non-blocking mode of operation */ + if((flags = fcntl(osmocom->fd.fd, F_GETFL)) != -1) + { + flags |= O_NONBLOCK; + fcntl(osmocom->fd.fd, F_SETFL, flags); + } + osmocom->dnload.serial_fd.when = BSC_FD_READ; + osmocom->dnload.serial_fd.cb = _osmocom_on_serial_read; + if(osmocom->dnload.mode == MODE_ROMLOAD) + { + tmpaddr = ROMLOAD_ADDRESS; + osmo_serial_set_baudrate(osmocom->fd.fd, ROMLOAD_INIT_BAUDRATE); + osmocom->tick_timer.cb = &_osmocom_on_beacon_timer; + osmocom->tick_timer.data = modem; + osmo_timer_schedule(&osmocom->tick_timer, 0, + osmocom->dnload.beacon_interval); + } + else + { + tmpaddr = MTK_ADDRESS; + osmo_serial_set_baudrate(osmocom->fd.fd, MTK_INIT_BAUDRATE); + osmocom->tick_timer.cb = &_osmocom_on_mtk_timer; + osmocom->tick_timer.data = modem; + osmo_timer_schedule(&osmocom->tick_timer, 0, + osmocom->dnload.beacon_interval); + } + /* FIXME not endian proof */ + osmocom->dnload.load_address[0] = (tmpaddr >> 24) & 0xff; + osmocom->dnload.load_address[1] = (tmpaddr >> 16) & 0xff; + osmocom->dnload.load_address[2] = (tmpaddr >> 8) & 0xff; + osmocom->dnload.load_address[3] = tmpaddr & 0xff; + return 0; +} + +static unsigned int _reset_baudrate(ModemPlugin * modem, unsigned int baudrate) +{ + switch(baudrate) + { + case 1200: + return B1200; + case 2400: + return B2400; + case 4800: + return B4800; + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; +#ifdef B76800 + case 76800: + return B76800; +#endif +#ifdef B14400 + case 14400: + return B14400; +#endif +#ifdef B28800 + case 28800: + return B28800; +#endif + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 921600: + return B921600; + default: + error_set("%u%s", baudrate, + "Unsupported baudrate (using 115200)"); + modem->helper->error(NULL, error_get(), 1); + return B115200; + } +} + + +/* osmocom_start */ +static int _osmocom_start(ModemPlugin * modem, unsigned int retry) +{ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + _osmocom_reset(modem, retry); + return 0; +} + + +/* osmocom_stop */ +static int _osmocom_stop(ModemPlugin * modem) +{ + Osmocom * osmocom = modem; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + if(osmocom->source != 0) + { + g_source_remove(osmocom->source); + osmocom->source = 0; + } + return 0; +} + + +/* osmocom_request */ +static int _request_call(ModemPlugin * modem, ModemRequest * request); +static int _request_message_send(ModemPlugin * modem, ModemRequest * request); + +static int _osmocom_request(ModemPlugin * modem, ModemRequest * request) +{ + switch(request->type) + { + case MODEM_REQUEST_CALL: + return _request_call(modem, request); + case MODEM_REQUEST_MESSAGE_SEND: + return _request_message_send(modem, request); +#ifdef DEBUG + default: + break; +#endif + } + return 0; +} + +static int _request_call(ModemPlugin * modem, ModemRequest * request) +{ + Osmocom * osmocom = modem; + + /* FIXME implement */ + return -1; +} + +static int _request_message_send(ModemPlugin * modem, ModemRequest * request) +{ + Osmocom * osmocom = modem; + + /* FIXME implement */ + return -1; +} + + +/* callbacks */ +/* osmocom_on_idle */ +static gboolean _osmocom_on_idle(gpointer data) +{ + ModemPlugin * modem = data; + Osmocom * osmocom = modem; + + if(osmo_select_main(0) < 0) + { + osmocom->source = 0; + return FALSE; + } + return TRUE; +} + + +/* osmocom_on_reset */ +static gboolean _osmocom_on_reset(gpointer data) +{ + ModemPlugin * modem = data; + Osmocom * osmocom = modem; + + if(_osmocom_reset(modem, 0) == 0) + { + osmocom->reset = 0; + return FALSE; + } + return TRUE; +} + + +/* osmocom_on_beacon_timer */ +static void _osmocom_on_beacon_timer(void * data) +{ + ModemPlugin * modem = data; + Osmocom * osmocom = modem; + int rc; + + if(osmocom->dnload.romload_state == WAITING_IDENTIFICATION) + { + printf("Sending Calypso romloader beacon...\n"); + rc = write(osmocom->dnload.serial_fd.fd, romload_ident_cmd, + sizeof(romload_ident_cmd)); + if(rc != sizeof(romload_ident_cmd)) + printf("Error sending identification beacon\n"); + osmo_timer_schedule(&osmocom->tick_timer, 0, + osmocom->dnload.beacon_interval); + } +} + + +/* osmocom_on_mtk_timer */ +static void _osmocom_on_mtk_timer(void * data) +{ + ModemPlugin * modem = data; + Osmocom * osmocom = modem; + int rc; + + if(osmocom->dnload.mtk_state == MTK_INIT_1) + { + printf("Sending MTK romloader beacon...\n"); + rc = write(osmocom->dnload.serial_fd.fd, &mtk_init_cmd[0], 1); + if(rc != 1) + printf("Error sending identification beacon\n"); + osmo_timer_schedule(&osmocom->tick_timer, 0, + osmocom->dnload.beacon_interval); + } +} + + +/* osmocom_on_serial_read */ +static int _read_handle_romload(); +static int _read_handle(); +static int _read_handle_write(); + +static int _osmocom_on_serial_read(struct osmo_fd * fd, unsigned int flags) +{ + int rc; + + /* FIXME really implement */ + if(flags & BSC_FD_READ) + { +#if 0 + switch(osmocom->mode) + { + case MODE_ROMLOAD: + rc = _read_handle_romload(); + break; + default: + rc = _read_handle(); + break; + } + if(rc == 0) + /* XXX wtf? */ + exit(2); +#endif + } + if(flags & BSC_FD_WRITE) + { + rc = _read_handle_write(); + if(rc != 0) + osmocom->dnload.state = WAITING_PROMPT1; + } + return 0; +} + +static int _read_handle_romload() +{ + return -1; +} + +static int _read_handle() +{ + return -1; +} + +static int _read_handle_write() +{ + return -1; +} diff --git a/src/modems/project.conf b/src/modems/project.conf index bb36cfd..9a60f90 100644 --- a/src/modems/project.conf +++ b/src/modems/project.conf @@ -25,6 +25,12 @@ depends=hayes.h [hayes.h] install=$(INCLUDEDIR)/Desktop/Phone/modems +#[osmocom] +#type=plugin +#sources=osmocom.c +#ldflags=-L $(PREFIX)/lib -Wl,-rpath,$(PREFIX)/lib -losmocore +#install=$(LIBDIR)/Phone/modem + [purple] type=plugin sources=purple.c