*
*/
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
-#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
-#include <sys/time.h>
#include <sercomm.h>
#include <osmocore/linuxlist.h>
#include <osmocore/select.h>
#include <osmocore/talloc.h>
+#include <osmocore/timer.h>
#include <arpa/inet.h>
#define MAX_HDR_SIZE 128
#define MAGIC_OFFSET 0x3be2
+#define DEFAULT_BEACON_INTERVAL 50000
#define ROMLOAD_INIT_BAUDRATE B19200
#define ROMLOAD_DL_BAUDRATE B115200
-#define ROMLOAD_BEACON_INTERVAL 50000
#define ROMLOAD_BLOCK_HDR_LEN 10
#define ROMLOAD_ADDRESS 0x820000
+#define MTK_INIT_BAUDRATE B19200
+#define MTK_ADDRESS 0x40001400
+#define MTK_BLOCK_SIZE 1024
+
struct tool_server *tool_server_for_dlci[256];
/**
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_C140xor,
MODE_C155,
MODE_ROMLOAD,
+ MODE_MTK,
};
struct dnload {
enum dnload_state state;
enum romload_state romload_state;
+ enum mtk_state mtk_state;
enum dnload_mode mode;
struct bsc_fd serial_fd;
char *filename;
+ char *chainload_filename;
- int print_hdlc;
+ int expect_hdlc;
+
+ int dump_rx;
+ int dump_tx;
+ int beacon_interval;
/* data to be downloaded */
uint8_t *data;
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;
static struct dnload dnload;
+static struct timer_list tick_timer;
/* Compal ramloader specific */
static const uint8_t phone_prompt1[] = { 0x1b, 0xf6, 0x02, 0x00, 0x41, 0x01, 0x40 };
static const uint8_t ftmtool[] = { 0x66, 0x74, 0x6d, 0x74, 0x6f, 0x6f, 0x6c };
static const uint8_t phone_magic[] = { 0x31, 0x30, 0x30, 0x33 }; /* "1003" */
-/* romloader specific */
+/* The C123 has a hard-coded check inside the ramloader that requires the
+ * following bytes to be always the first four bytes of the image */
+static const uint8_t data_hdr_c123[] = { 0xee, 0x4c, 0x9f, 0x63 };
+
+/* The C155 doesn't have some strange restriction on what the first four bytes
+ * have to be, but it starts the ramloader in THUMB mode. We use the following
+ * four bytes to switch back to ARM mode:
+ 800100: 4778 bx pc
+ 800102: 46c0 nop ; (mov r8, r8)
+ */
+static const uint8_t data_hdr_c155[] = { 0x78, 0x47, 0xc0, 0x46 };
+
+/* Calypso romloader specific */
static const uint8_t romload_ident_cmd[] = { 0x3c, 0x69 }; /* <i */
static const uint8_t romload_abort_cmd[] = { 0x3c, 0x61 }; /* <a */
static const uint8_t romload_write_cmd[] = { 0x3c, 0x77 }; /* <w */
static const uint8_t romload_param[] = { 0x3c, 0x70, 0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00 };
-/* The C123 has a hard-coded check inside the ramloader that requires the following
- * bytes to be always the first four bytes of the image */
-static const uint8_t data_hdr_c123[] = { 0xee, 0x4c, 0x9f, 0x63 };
-
-/* The C155 doesn't have some strange restriction on what the first four bytes have
- * to be, but it starts the ramloader in THUMB mode. We use the following four bytes
- * to switch back to ARM mode:
- 800100: 4778 bx pc
- 800102: 46c0 nop ; (mov r8, r8)
- */
-static const uint8_t data_hdr_c155[] = { 0x78, 0x47, 0xc0, 0x46 };
+/* MTK romloader specific */
+static const uint8_t mtk_init_cmd[] = { 0xa0, 0x0a, 0x50, 0x05 };
+static const uint8_t mtk_init_resp[] = { 0x5f, 0xf5, 0xaf, 0xfa };
+static const uint8_t mtk_command[] = { 0xa1, 0xa2, 0xa4, 0xa8 };
/* FIXME: this routine is more or less what openbsc/src/rs232:rs232_setup()
* does, we should move it to libosmocore at some point */
int rc;
struct termios tio;
+ rc = tcgetattr(dnload.serial_fd.fd, &tio);
+ if (rc < 0) {
+ perror("tcgetattr()");
+ return rc;
+ }
cfsetispeed(&tio, baudrate);
cfsetospeed(&tio, baudrate);
return rc;
}
-static void reload_beacon_timer(void)
-{
- struct itimerval t_val;
- int rc;
-
- /* load timer to our <i beacon interval */
- bzero(&t_val, sizeof(t_val));
- t_val.it_value.tv_usec = ROMLOAD_BEACON_INTERVAL;
-
- if ((rc = setitimer(ITIMER_REAL, &t_val, NULL)) < 0) {
- fprintf(stderr, "Error in setitimer()\n");
- exit(1);
- }
-}
-
-static void beacon_timer_cb(int signr)
+static void beacon_timer_cb(void *p)
{
int rc;
if (dnload.romload_state == WAITING_IDENTIFICATION) {
- printf("Sending beacon...\n");
+ printf("Sending Calypso romloader beacon...\n");
rc = write(dnload.serial_fd.fd, romload_ident_cmd,
sizeof(romload_ident_cmd));
if (!(rc == sizeof(romload_ident_cmd)))
printf("Error sending identification beacon\n");
- reload_beacon_timer();
+ bsc_schedule_timer(p, 0, dnload.beacon_interval);
}
}
-static void start_beacon_timer(void)
+static void mtk_timer_cb(void *p)
{
- if (signal(SIGALRM, beacon_timer_cb) == SIG_ERR) {
- fprintf(stderr, "Cannot register signal handler\n");
- exit(1);
- }
+ int rc;
+
+ if (dnload.mtk_state == MTK_INIT_1) {
+ printf("Sending MTK romloader beacon...\n");
+ rc = write(dnload.serial_fd.fd, &mtk_init_cmd[0], 1);
+
+ if (!(rc == 1))
+ printf("Error sending identification beacon\n");
- reload_beacon_timer();
+ bsc_schedule_timer(p, 0, dnload.beacon_interval);
+ }
}
/* Read the to-be-downloaded file, prepend header and length, append XOR sum */
static void hexdump(const uint8_t *data, unsigned int len)
{
- const uint8_t *bufptr = data;
int n;
- for (n=0; n < len; n++, bufptr++)
- printf("%02x ", *bufptr);
+ for (n=0; n < len; n++)
+ printf("%02x ", data[n]);
+ printf(" ");
+ for (n=0; n < len; n++)
+ if (isprint(data[n]))
+ putchar(data[n]);
+ else
+ putchar('.');
printf("\n");
}
static int romload_prepare_block(void)
{
- int rc, i;
+ int i;
int block_checksum = 5;
int remaining_bytes;
dnload.block_len = ROMLOAD_BLOCK_HDR_LEN + dnload.block_payload_size;
/* if first block, allocate memory */
- if (!dnload.block_number){
+ if (!dnload.block_number) {
dnload.block = malloc(dnload.block_len);
if (!dnload.block) {
fprintf(stderr, "No memory\n");
dnload.write_ptr = dnload.data + 2 +
(dnload.block_payload_size * dnload.block_number);
- remaining_bytes = dnload.data_len-3 -
+ remaining_bytes = dnload.data_len - 3 -
(dnload.block_payload_size * dnload.block_number);
memcpy(block_data, dnload.write_ptr, dnload.block_payload_size);
printf("Preparing block %i,", dnload.block_number+1);
}
- /* block checksum is lsb of !(5 + block_size_lsb + block_address + data) */
+ /* block checksum is lsb of ~(5 + block_size_lsb + all bytes of
+ * block_address + all data bytes) */
for (i = 5; i < ROMLOAD_BLOCK_HDR_LEN + dnload.block_payload_size; i++)
block_checksum += dnload.block[i];
- /* checksum is lsb of !(sum of LSBs of all block checksums) */
+ /* checksum is lsb of ~(sum of LSBs of all block checksums) */
printf(" block checksum is 0x%02x \n", ~(block_checksum) & 0xff);
dnload.romload_dl_checksum += ~(block_checksum) & 0xff;
dnload.block_number++;
dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
+ return 0;
+}
+
+static int mtk_prepare_block(void)
+{
+ int rc, i;
+
+ int remaining_bytes;
+ int fill_bytes;
+ uint8_t *block_data;
+ uint8_t tmp_byteswap;
+ uint32_t tmp_size;
+
+ dnload.block_len = MTK_BLOCK_SIZE;
+ dnload.echo_bytecount = 0;
+
+ /* if first block, allocate memory */
+ if (!dnload.block_number) {
+ dnload.block = malloc(dnload.block_len);
+ if (!dnload.block) {
+ fprintf(stderr, "No memory\n");
+ return -ENOMEM;
+ }
+
+ /* calculate the number of blocks we need to send */
+ dnload.block_count = (dnload.data_len-3) / MTK_BLOCK_SIZE;
+ /* add one more block if no multiple of blocksize */
+ if((dnload.data_len-3) % MTK_BLOCK_SIZE)
+ dnload.block_count++;
+
+ /* divide by 2, since we have to tell the mtk loader the size
+ * as count of uint16 (odd transfer sizes are not possible) */
+ tmp_size = (dnload.block_count * MTK_BLOCK_SIZE)/2;
+ dnload.mtk_send_size[0] = (tmp_size >> 24) & 0xff;
+ dnload.mtk_send_size[1] = (tmp_size >> 16) & 0xff;
+ dnload.mtk_send_size[2] = (tmp_size >> 8) & 0xff;
+ dnload.mtk_send_size[3] = tmp_size & 0xff;
+
+ /* initialize write pointer to start of data */
+ dnload.write_ptr = dnload.data;
+ }
+
+ block_data = dnload.block;
+ dnload.write_ptr = dnload.data + 2 +
+ (dnload.block_len * dnload.block_number);
+
+ remaining_bytes = dnload.data_len - 3 -
+ (dnload.block_len * dnload.block_number);
+
+ memcpy(block_data, dnload.write_ptr, MTK_BLOCK_SIZE);
+
+ if (remaining_bytes <= MTK_BLOCK_SIZE) {
+ fill_bytes = (MTK_BLOCK_SIZE - remaining_bytes);
+ printf("Preparing the last block, filling %i bytes\n",
+ fill_bytes);
+ memset(block_data + remaining_bytes, 0x00, fill_bytes);
+ dnload.romload_state = SENDING_LAST_BLOCK;
+ } else {
+ dnload.romload_state = SENDING_BLOCKS;
+ printf("Preparing block %i\n", dnload.block_number+1);
+ }
+
+ /* for the mtk romloader we need to swap MSB <-> LSB */
+ for (i = 0; i < dnload.block_len; i += 2) {
+ tmp_byteswap = dnload.block[i];
+ dnload.block[i] = dnload.block[i+1];
+ dnload.block[i+1] = tmp_byteswap;
+ }
+
+ /* initialize block pointer to start of block */
+ dnload.block_ptr = dnload.block;
+
+ dnload.block_number++;
return rc;
}
static int handle_write(void)
{
- if (dnload.mode == MODE_ROMLOAD) {
+ /* TODO: simplify this again (global state: downloading, sercomm) */
+ switch (dnload.mode) {
+ case MODE_ROMLOAD:
switch (dnload.romload_state) {
case SENDING_BLOCKS:
case SENDING_LAST_BLOCK:
default:
return handle_sercomm_write();
}
- } else {
+ break;
+ case MODE_MTK:
+ switch (dnload.mtk_state) {
+ case MTK_SENDING_BLOCKS:
+ return handle_write_block();
+ default:
+ return handle_sercomm_write();
+ }
+ break;
+ default:
switch (dnload.state) {
case DOWNLOADING:
return handle_write_dnload();
struct msgb *msg;
uint8_t *dest;
- printf("hdlc_send_to_phone(dlci=%u): ", dlci);
- hexdump(data, len);
+ if(dnload.dump_tx) {
+ printf("hdlc_send(dlci=%u): ", dlci);
+ hexdump(data, len);
+ }
if (len > 512) {
fprintf(stderr, "Too much data to send. %u\n", len);
{
struct tool_server *srv = tool_server_for_dlci[dlci];
+ if(dnload.dump_rx) {
+ printf("hdlc_recv(dlci=%u): ", dlci);
+ hexdump(msg->data, msg->len);
+ }
+
if(srv) {
struct tool_connection *con;
- u_int16_t *len;
+ uint16_t *len;
- len = (u_int16_t *) msgb_push(msg, 2);
+ len = (uint16_t *) msgb_push(msg, 2);
*len = htons(msg->len - sizeof(*len));
llist_for_each_entry(con, &srv->connections, entry) {
msgb_free(msg);
}
-static void print_hdlc(uint8_t *buffer, int length)
-{
- int i;
-
- for (i = 0; i < length; ++i)
- if (sercomm_drv_rx_char(buffer[i]) == 0)
- printf("Dropping sample '%c'\n", buffer[i]);
-}
-
static int handle_buffer(int buf_used_len)
{
- int nbytes, buf_left;
+ int nbytes, buf_left, i;
buf_left = buf_used_len - (bufptr - buffer);
if (buf_left <= 0) {
if (nbytes <= 0)
return nbytes;
- if (!dnload.print_hdlc) {
+ if (!dnload.expect_hdlc) {
printf("got %i bytes from modem, ", nbytes);
printf("data looks like: ");
hexdump(bufptr, nbytes);
} else {
- print_hdlc(bufptr, nbytes);
+ for (i = 0; i < nbytes; ++i)
+ if (sercomm_drv_rx_char(bufptr[i]) == 0)
+ printf("Dropping sample '%c'\n", bufptr[i]);
}
return nbytes;
if (!memcmp(buffer, phone_prompt1, sizeof(phone_prompt1))) {
printf("Received PROMPT1 from phone, responding with CMD\n");
- dnload.print_hdlc = 0;
+ dnload.expect_hdlc = 0;
dnload.state = WAITING_PROMPT2;
- rc = write(dnload.serial_fd.fd, dnload_cmd, sizeof(dnload_cmd));
-
- /* re-read file */
- rc = read_file(dnload.filename);
- if (rc < 0) {
- fprintf(stderr, "read_file(%s) failed with %d\n",
- dnload.filename, rc);
- exit(1);
+ if(dnload.filename) {
+ rc = write(dnload.serial_fd.fd, dnload_cmd, sizeof(dnload_cmd));
+
+ /* re-read file */
+ rc = read_file(dnload.filename);
+ if (rc < 0) {
+ fprintf(stderr, "read_file(%s) failed with %d\n",
+ dnload.filename, rc);
+ exit(1);
+ }
}
} else if (!memcmp(buffer, phone_prompt2, sizeof(phone_prompt2))) {
printf("Received PROMPT2 from phone, starting download\n");
dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
dnload.state = DOWNLOADING;
} else if (!memcmp(buffer, phone_ack, sizeof(phone_ack))) {
- printf("Received DOWNLOAD ACK from phone, your code is running now!\n");
+ printf("Received DOWNLOAD ACK from phone, your code is"
+ " running now!\n");
dnload.serial_fd.when = BSC_FD_READ;
dnload.state = WAITING_PROMPT1;
dnload.write_ptr = dnload.data;
- dnload.print_hdlc = 1;
+ dnload.expect_hdlc = 1;
+
+ /* check for romloader chainloading mode used as a workaround
+ * for the magic on the C139/C140 and J100i */
+ if (dnload.chainload_filename != NULL) {
+ printf("Enabled Compal ramloader -> Calypso romloader"
+ " chainloading mode\n");
+ bufptr = buffer;
+ dnload.filename = dnload.chainload_filename;
+ dnload.mode = MODE_ROMLOAD;
+ serial_set_baudrate(ROMLOAD_INIT_BAUDRATE);
+ tick_timer.cb = &beacon_timer_cb;
+ tick_timer.data = &tick_timer;
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
+ }
} else if (!memcmp(buffer, phone_nack, sizeof(phone_nack))) {
- printf("Received DOWNLOAD NACK from phone, something went wrong :(\n");
+ printf("Received DOWNLOAD NACK from phone, something went"
+ " wrong :(\n");
dnload.serial_fd.when = BSC_FD_READ;
dnload.state = WAITING_PROMPT1;
dnload.write_ptr = dnload.data;
} else if (!memcmp(buffer, phone_nack_magic, sizeof(phone_nack_magic))) {
- printf("Received MAGIC NACK from phone, you need to have \"1003\" at 0x803ce0\n");
+ printf("Received MAGIC NACK from phone, you need to"
+ " have \"1003\" at 0x803ce0\n");
dnload.serial_fd.when = BSC_FD_READ;
dnload.state = WAITING_PROMPT1;
dnload.write_ptr = dnload.data;
printf("Received ident ack from phone, sending "
"parameter sequence\n");
- dnload.print_hdlc = 1;
+ dnload.expect_hdlc = 1;
dnload.romload_state = WAITING_PARAM_ACK;
rc = write(dnload.serial_fd.fd, romload_param,
sizeof(romload_param));
printf("Received parameter ack from phone, "
"starting download\n");
serial_set_baudrate(ROMLOAD_DL_BAUDRATE);
- /* let the target's UART settle after changing baud*/
- usleep(ROMLOAD_BEACON_INTERVAL*2);
/* using the max blocksize the phone tells us */
dnload.block_payload_size = ((buffer[3] << 8) + buffer[2]);
"something went wrong, aborting\n");
serial_set_baudrate(ROMLOAD_INIT_BAUDRATE);
dnload.romload_state = WAITING_IDENTIFICATION;
- usleep(ROMLOAD_BEACON_INTERVAL*2);
- reload_beacon_timer();
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
}
break;
case WAITING_CHECKSUM_ACK:
sizeof(romload_checksum_ack))) {
printf("Checksum on phone side matches, "
"let's branch to your code\n");
-
- uint32_t branch_address_32 = ROMLOAD_ADDRESS;
- uint8_t branch_address[4];
- branch_address[0] = (branch_address_32 >> 24) & 0xff;
- branch_address[1] = (branch_address_32 >> 16) & 0xff;
- branch_address[2] = (branch_address_32 >> 8) & 0xff;
- branch_address[3] = branch_address_32 & 0xff;
- printf("Branching to 0x%08x\n", branch_address_32);
+ printf("Branching to 0x%08x\n", ROMLOAD_ADDRESS);
rc = write(dnload.serial_fd.fd, romload_branch_cmd,
sizeof(romload_branch_cmd));
- rc = write(dnload.serial_fd.fd, &branch_address, 4);
+ rc = write(dnload.serial_fd.fd, &dnload.load_address,
+ sizeof(dnload.load_address));
dnload.romload_state = WAITING_BRANCH_ACK;
bufptr -= 1;
} else if (!memcmp(buffer, romload_checksum_nack,
sizeof(romload_checksum_nack))) {
printf("Checksum on phone side (0x%02x) doesn't "
- "match ours, aborting\n", buffer[2]);
+ "match ours, aborting\n", ~buffer[2]);
serial_set_baudrate(ROMLOAD_INIT_BAUDRATE);
dnload.romload_state = WAITING_IDENTIFICATION;
- usleep(ROMLOAD_BEACON_INTERVAL*2);
- reload_beacon_timer();
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
bufptr -= 1;
}
break;
dnload.serial_fd.when = BSC_FD_READ;
dnload.romload_state = FINISHED;
dnload.write_ptr = dnload.data;
- dnload.print_hdlc = 1;
+ dnload.expect_hdlc = 1;
} else if (!memcmp(buffer, romload_branch_nack,
sizeof(romload_branch_nack))) {
printf("Received branch nack, aborting\n");
serial_set_baudrate(ROMLOAD_INIT_BAUDRATE);
dnload.romload_state = WAITING_IDENTIFICATION;
- usleep(ROMLOAD_BEACON_INTERVAL*2);
- reload_beacon_timer();
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
+ }
+ break;
+ default:
+ break;
+ }
+
+ bufptr += nbytes;
+ return nbytes;
+}
+
+/* MTK romloader */
+static int handle_read_mtk(void)
+{
+ int rc, nbytes, buf_used_len;
+
+ switch (dnload.mtk_state) {
+ case MTK_WAIT_ADDR_ACK:
+ case MTK_WAIT_SIZE_ACK:
+ case MTK_WAIT_BRANCH_ADDR_ACK:
+ buf_used_len = 4;
+ break;
+ case MTK_FINISHED:
+ buf_used_len = sizeof(buffer);
+ break;
+ default:
+ buf_used_len = 1;
+ }
+
+ nbytes = handle_buffer(buf_used_len);
+ if (nbytes <= 0)
+ return nbytes;
+
+ switch (dnload.mtk_state) {
+ case MTK_INIT_1:
+ if (!(buffer[0] == mtk_init_resp[0]))
+ break;
+ dnload.mtk_state = MTK_INIT_2;
+ printf("Received init magic byte 1\n");
+ rc = write(dnload.serial_fd.fd, &mtk_init_cmd[1], 1);
+ break;
+ case MTK_INIT_2:
+ if (!(buffer[0] == mtk_init_resp[1]))
+ break;
+ dnload.mtk_state = MTK_INIT_3;
+ printf("Received init magic byte 2\n");
+ rc = write(dnload.serial_fd.fd, &mtk_init_cmd[2], 1);
+ break;
+ case MTK_INIT_3:
+ if (!(buffer[0] == mtk_init_resp[2]))
+ break;
+ dnload.mtk_state = MTK_INIT_4;
+ printf("Received init magic byte 3\n");
+ rc = write(dnload.serial_fd.fd, &mtk_init_cmd[3], 1);
+ break;
+ case MTK_INIT_4:
+ if (!(buffer[0] == mtk_init_resp[3]))
+ break;
+ dnload.mtk_state = MTK_WAIT_WRITE_ACK;
+ printf("Received init magic byte 4, requesting write\n");
+ rc = write(dnload.serial_fd.fd, &mtk_command[0], 1);
+ break;
+ case MTK_WAIT_WRITE_ACK:
+ if (!(buffer[0] == mtk_command[0]))
+ break;
+ dnload.mtk_state = MTK_WAIT_ADDR_ACK;
+ printf("Received write ack, sending load address\n");
+
+ rc = write(dnload.serial_fd.fd, &dnload.load_address,
+ sizeof(dnload.load_address));
+ break;
+ case MTK_WAIT_ADDR_ACK:
+ if (memcmp(buffer, dnload.load_address,
+ sizeof(dnload.load_address)))
+ break;
+ printf("Received address ack from phone, sending loadsize\n");
+ /* re-read file */
+ rc = read_file(dnload.filename);
+ if (rc < 0) {
+ fprintf(stderr, "read_file(%s) failed with %d\n",
+ dnload.filename, rc);
+ exit(1);
+ }
+ dnload.block_number = 0;
+ mtk_prepare_block();
+ dnload.mtk_state = MTK_WAIT_SIZE_ACK;
+ rc = write(dnload.serial_fd.fd, &dnload.mtk_send_size,
+ sizeof(dnload.mtk_send_size));
+ break;
+ case MTK_WAIT_SIZE_ACK:
+ if (memcmp(buffer, dnload.mtk_send_size,
+ sizeof(dnload.mtk_send_size)))
+ break;
+ printf("Received size ack\n");
+ dnload.expect_hdlc = 1;
+ dnload.mtk_state = MTK_SENDING_BLOCKS;
+ dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
+ bufptr -= 3;
+ break;
+ case MTK_SENDING_BLOCKS:
+ if (!(buffer[0] == dnload.block[dnload.echo_bytecount]))
+ printf("Warning: Byte %i of Block %i doesn't match,"
+ " check your serial connection!\n",
+ dnload.echo_bytecount, dnload.block_number);
+ dnload.echo_bytecount++;
+
+ if ((dnload.echo_bytecount+1) > MTK_BLOCK_SIZE) {
+ if ( dnload.block_number == dnload.block_count) {
+ rc = write(dnload.serial_fd.fd,
+ &mtk_command[3], 1);
+ printf("Sending branch command\n");
+ dnload.expect_hdlc = 0;
+ dnload.mtk_state = MTK_WAIT_BRANCH_CMD_ACK;
+ break;
+ }
+ printf("Received Block %i preparing next block\n",
+ dnload.block_number);
+ mtk_prepare_block();
+ dnload.serial_fd.when = BSC_FD_READ | BSC_FD_WRITE;
}
break;
+ case MTK_WAIT_BRANCH_CMD_ACK:
+ if (!(buffer[0] == mtk_command[3]))
+ break;
+ dnload.mtk_state = MTK_WAIT_BRANCH_ADDR_ACK;
+ printf("Received branch command ack, sending address\n");
+
+ rc = write(dnload.serial_fd.fd, &dnload.load_address,
+ sizeof(dnload.load_address));
+ break;
+ case MTK_WAIT_BRANCH_ADDR_ACK:
+ if (memcmp(buffer, dnload.load_address,
+ sizeof(dnload.load_address)))
+ break;
+ printf("Received branch address ack, code should run now\n");
+ serial_set_baudrate(MODEM_BAUDRATE);
+ dnload.serial_fd.when = BSC_FD_READ;
+ dnload.mtk_state = MTK_FINISHED;
+ dnload.write_ptr = dnload.data;
+ dnload.expect_hdlc = 1;
+ break;
default:
break;
}
{
int rc;
if (flags & BSC_FD_READ) {
- if (dnload.mode == MODE_ROMLOAD)
- rc = handle_read_romload();
- else
- rc = handle_read();
-
+ switch (dnload.mode) {
+ case MODE_ROMLOAD:
+ rc = handle_read_romload();
+ break;
+ case MODE_MTK:
+ rc = handle_read_mtk();
+ break;
+ default:
+ rc = handle_read();
+ break;
+ }
if (rc == 0)
exit(2);
}
return MODE_C155;
else if (!strcasecmp(arg, "romload"))
return MODE_ROMLOAD;
+ else if (!strcasecmp(arg, "mtk"))
+ return MODE_MTK;
return -1;
}
#define HELP_TEXT \
- "[ -v | -h ] [ -p /dev/ttyXXXX ] [ -s /tmp/osmocom_l2 ]\n" \
- "\t\t[ -l /tmp/osmocom_loader ]\n" \
- "\t\t[ -m {c123,c123xor,c140,c140xor,c155,romload} ]\n" \
- "\t\t file.bin\n\n" \
+ "[ -v | -h ] [ -d [t][r] ] [ -p /dev/ttyXXXX ]\n" \
+ "\t\t [ -s /tmp/osmocom_l2 ]\n" \
+ "\t\t [ -l /tmp/osmocom_loader ]\n" \
+ "\t\t [ -m {c123,c123xor,c140,c140xor,c155,romload,mtk} ]\n" \
+ "\t\t [ -c /to-be-chainloaded-file.bin ]\n" \
+ "\t\t [ -i beacon-interval (mS) ]\n" \
+ "\t\t file.bin\n\n" \
"* Open serial port /dev/ttyXXXX (connected to your phone)\n" \
"* Perform handshaking with the ramloader in the phone\n" \
"* Download file.bin to the attached phone (base address 0x00800100)\n"
static int un_tool_read(struct bsc_fd *fd, unsigned int flags)
{
int rc, c;
- u_int16_t length = 0xffff;
- u_int8_t buf[4096];
+ uint16_t length = 0xffff;
+ uint8_t buf[4096];
struct tool_connection *con = (struct tool_connection *)fd->data;
c = 0;
c += rc;
}
- length = ntohs(*(u_int16_t*)buf);
+ length = ntohs(*(uint16_t*)buf);
c = 0;
while(c < length) {
* Register and start a tool server
*/
static int register_tool_server(struct tool_server *ts,
- const char *path,
- uint8_t dlci)
+ const char *path,
+ uint8_t dlci)
{
struct bsc_fd *bfd = &ts->bfd;
struct sockaddr_un local;
extern void hdlc_tpudbg_cb(uint8_t dlci, struct msgb *msg);
+void parse_debug(const char *str)
+{
+ while(*str) {
+ switch(*str) {
+ case 't':
+ dnload.dump_tx = 1;
+ break;
+ case 'r':
+ dnload.dump_rx = 1;
+ break;
+ default:
+ printf("Unknown debug flag %c\n", *str);
+ abort();
+ break;
+ }
+ str++;
+ }
+}
+
int main(int argc, char **argv)
{
int opt, flags;
+ uint32_t tmp_load_address = ROMLOAD_ADDRESS;
const char *serial_dev = "/dev/ttyUSB1";
const char *layer2_un_path = "/tmp/osmocom_l2";
const char *loader_un_path = "/tmp/osmocom_loader";
dnload.mode = MODE_C123;
+ dnload.chainload_filename = NULL;
+ dnload.beacon_interval = DEFAULT_BEACON_INTERVAL;
- while ((opt = getopt(argc, argv, "hl:p:m:s:v")) != -1) {
+ while ((opt = getopt(argc, argv, "d:hl:p:m:c:s:i:v")) != -1) {
switch (opt) {
case 'p':
serial_dev = optarg;
case 'v':
version(argv[0]);
break;
+ case 'd':
+ parse_debug(optarg);
+ break;
+ case 'c':
+ dnload.chainload_filename = optarg;
+ break;
+ case 'i':
+ dnload.beacon_interval = atoi(optarg) * 1000;
+ break;
case 'h':
default:
usage(argv[0]);
}
if (argc <= optind) {
- fprintf(stderr, "You have to specify the filename\n");
- usage(argv[0]);
+ dnload.filename = NULL;
+ } else {
+ dnload.filename = argv[optind];
}
- dnload.filename = argv[optind];
-
dnload.serial_fd.fd = serial_init(serial_dev);
if (dnload.serial_fd.fd < 0) {
fprintf(stderr, "Cannot open serial device %s\n", serial_dev);
/* if in romload mode, start our beacon timer */
if (dnload.mode == MODE_ROMLOAD) {
+ tmp_load_address = ROMLOAD_ADDRESS;
serial_set_baudrate(ROMLOAD_INIT_BAUDRATE);
- start_beacon_timer();
+ tick_timer.cb = &beacon_timer_cb;
+ tick_timer.data = &tick_timer;
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
}
+ else if (dnload.mode == MODE_MTK) {
+ tmp_load_address = MTK_ADDRESS;
+ serial_set_baudrate(MTK_INIT_BAUDRATE);
+ tick_timer.cb = &mtk_timer_cb;
+ tick_timer.data = &tick_timer;
+ bsc_schedule_timer(&tick_timer, 0, dnload.beacon_interval);
+ }
+
+ dnload.load_address[0] = (tmp_load_address >> 24) & 0xff;
+ dnload.load_address[1] = (tmp_load_address >> 16) & 0xff;
+ dnload.load_address[2] = (tmp_load_address >> 8) & 0xff;
+ dnload.load_address[3] = tmp_load_address & 0xff;
while (1)
bsc_select_main(0);