blob: 914bbbe6f7c9e36b2f94d85c5537e7873746cf99 [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "serial.h"
/* RTS is erase, asserted high */
static void set_erase(int en)
{
serial_set_rts(en);
}
static int get_erase(void)
{
return serial_get_rts();
}
/* DTR is reset, asserted low */
static void set_reset(int en)
{
serial_set_dtr(!en);
}
static int get_reset(void)
{
return !serial_get_dtr();
}
static void secret_knock(void)
{
int i;
const int magic = 0xac5a;
set_reset(1);
set_erase(0);
for (i = 0; i < 16; i++) {
set_erase(!(~(magic >> i) & 1));
set_reset(0);
usleep(1000);
set_reset(1);
}
set_erase(0);
set_reset(0);
}
#ifndef __WIN32
#include <termios.h>
#include <poll.h>
/* raw terminal stuff */
static struct termios oldstdin;
static struct termios oldstdout;
static void resetconsole(void)
{
tcsetattr(0, TCSANOW, &oldstdin);
tcsetattr(1, TCSANOW, &oldstdout);
}
static void setconsole(void)
{
struct termios t;
tcgetattr(0, &oldstdin);
tcgetattr(1, &oldstdout);
atexit(&resetconsole);
t = oldstdin;
t.c_lflag = ISIG; // no input processing
// Don't interpret various control characters, pass them through instead
t.c_cc[VINTR] = t.c_cc[VQUIT] = t.c_cc[VSUSP] = '\0';
t.c_cc[VMIN] = 0; // nonblocking read
t.c_cc[VTIME] = 0; // nonblocking read
tcsetattr(0, TCSANOW, &t);
fcntl(0, F_SETFL, O_NONBLOCK);
t = oldstdout;
t.c_lflag = ISIG; // no output processing
tcsetattr(1, TCSANOW, &t);
}
static void console(int serial_fd)
{
struct pollfd pfd[2];
char c;
int err;
printf("starting console mode, ctrl-c to exit\n");
fflush(stdout);
setconsole();
pfd[0].fd = STDIN_FILENO;
pfd[0].events = POLLIN | POLLERR;
pfd[1].fd = serial_fd;
pfd[1].events = POLLIN | POLLERR;
for (;;) {
err = poll(pfd, 2, -1);
if (err <= 0)
break;
if (pfd[0].revents & POLLIN) {
err = read(STDIN_FILENO, &c, 1);
if (err < 0)
break;
write(serial_fd, &c, 1);
}
if (pfd[1].revents & POLLIN) {
err = read(serial_fd, &c, 1);
if (err < 0)
break;
write(STDOUT_FILENO, &c, 1);
}
if ((pfd[0].revents | pfd[1].revents) & POLLERR)
break;
}
}
#endif
static void usage(int argc, char **argv)
{
fprintf(stderr, "usage: %s <serial port> [commands ...]\n", argv[0]);
fprintf(stderr, "valid commands are:\n");
fprintf(stderr, "\terase: perform a handshake with a microcontroller to erase the flash\n");
fprintf(stderr, "\treset: toggle the reset line\n");
fprintf(stderr, "\tolderase: toggle the erase line\n");
#ifndef __WIN32
fprintf(stderr, "\tconsole: go into console mode on the serial line\n");
fprintf(stderr, "\tmonitor: display the current status of the lines\n");
fprintf(stderr, "\thold: keep the uart open and wait for ctrl-c\n");
#endif
exit(1);
}
int main(int argc, char **argv)
{
int i, serial, status;
if (argc < 3) {
fprintf(stderr, "not enough arguments\n");
usage(argc, argv);
}
const char *port;
port = argv[1];
if (serial_open(port) < 0) {
fprintf(stderr, "error opening serial\n");
return 1;
}
int arg;
for (arg = 2; arg < argc; arg++) {
if (!strcasecmp(argv[arg], "erase")) {
printf("erasing...");
set_reset(1);
usleep(500000);
set_reset(0);
secret_knock();
usleep(1000000);
printf("done.\n");
} else if (!strcasecmp(argv[arg], "olderase")) {
set_reset(0);
set_erase(1);
usleep(300000);
set_erase(0);
set_reset(1);
usleep(100000);
set_reset(0);
} else if (!strcasecmp(argv[arg], "reset")) {
printf("resetting...");
set_erase(0);
set_reset(0);
usleep(100000);
set_reset(1);
usleep(500000);
set_reset(0);
printf("done.\n");
#ifndef __WIN32
} else if (!strcasecmp(argv[arg], "monitor")) {
printf("monitoring state of erase and reset lines\n");
int r, e;
e = get_erase();
r = get_reset();
for (;;) {
int e1 = get_erase();
if (e1 != e)
printf("erase %d\n", e1);
int r1 = get_reset();
if (r1 != r)
printf("reset %d\n", r1);
e = e1;
r = r1;
}
} else if (!strcasecmp(argv[arg], "hold")) {
printf("holding port open, ctrl-c to exit.\n");
set_erase(0);
set_reset(0);
for (;;)
usleep(1000000);
} else if (!strcasecmp(argv[arg], "console")) {
console(serial_get_fd());
#endif
} else {
printf("bad command '%s'\n", argv[arg]);
exit(1);
}
}
serial_close();
}