|
|
|
@ -0,0 +1,773 @@
|
|
|
|
|
/*
|
|
|
|
|
* iMX utp decode program
|
|
|
|
|
*
|
|
|
|
|
* Copyright (C) 2010-2014 Freescale Semiconductor, Inc.
|
|
|
|
|
*
|
|
|
|
|
* 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; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* 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, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "fsl_updater.h"
|
|
|
|
|
|
|
|
|
|
char *utp_firmware_version = "2.6.32";
|
|
|
|
|
char *utp_sn = "000000000000";
|
|
|
|
|
char *utp_chipid = "370000A5";
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <syscall.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <malloc.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <signal.h>
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <stropts.h>
|
|
|
|
|
#include <linux/reboot.h>
|
|
|
|
|
#include <sys/reboot.h>
|
|
|
|
|
/* mxc SoC will enable watchdog at USB recovery mode
|
|
|
|
|
* so, the user must service watchdog
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define UTP_DEVNODE "/dev/utp"
|
|
|
|
|
#define UTP_TARGET_FILE "/tmp/file.utp"
|
|
|
|
|
|
|
|
|
|
#define UTP_FLAG_COMMAND 0x00000001
|
|
|
|
|
#define UTP_FLAG_DATA 0x00000002
|
|
|
|
|
#define UTP_FLAG_STATUS 0x00000004 //indicate an error happens
|
|
|
|
|
#define UTP_FLAG_REPORT_BUSY 0x10000000
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma pack(1)
|
|
|
|
|
|
|
|
|
|
#define PACKAGE "uuc"
|
|
|
|
|
#define VERSION "0.5"
|
|
|
|
|
|
|
|
|
|
/* for utp ioctl */
|
|
|
|
|
#define UTP_IOCTL_BASE 'U'
|
|
|
|
|
#define UTP_GET_CPU_ID _IOR(UTP_IOCTL_BASE, 0, int)
|
|
|
|
|
|
|
|
|
|
#define NEED_TO_GET_CHILD_PID 1
|
|
|
|
|
/*
|
|
|
|
|
* this structure should be in sync with the same in
|
|
|
|
|
* $KERNEL/drivers/usb/gadget/fsl_updater.c
|
|
|
|
|
*/
|
|
|
|
|
struct utp_message {
|
|
|
|
|
uint32_t flags;
|
|
|
|
|
size_t size;
|
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
uint64_t payload;
|
|
|
|
|
char command[1];
|
|
|
|
|
};
|
|
|
|
|
struct {
|
|
|
|
|
size_t bufsize;
|
|
|
|
|
uint8_t data[1];
|
|
|
|
|
};
|
|
|
|
|
uint32_t status;
|
|
|
|
|
};
|
|
|
|
|
};
|
|
|
|
|
#pragma pack()
|
|
|
|
|
|
|
|
|
|
static int utp_file = -1;
|
|
|
|
|
static FILE *utp_file_f = NULL;
|
|
|
|
|
|
|
|
|
|
static inline char *utp_answer_type(struct utp_message *u)
|
|
|
|
|
{
|
|
|
|
|
if (!u)
|
|
|
|
|
return "UNKNOWN";
|
|
|
|
|
if (u->flags & UTP_FLAG_STATUS)
|
|
|
|
|
return "Non-success";
|
|
|
|
|
if (u->flags & UTP_FLAG_DATA)
|
|
|
|
|
return "Data";
|
|
|
|
|
if (u->flags & UTP_FLAG_REPORT_BUSY)
|
|
|
|
|
return "Busy";
|
|
|
|
|
if (u->flags & UTP_FLAG_COMMAND)
|
|
|
|
|
return "Command ?!";
|
|
|
|
|
return "Success";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_mk_devnode
|
|
|
|
|
*
|
|
|
|
|
* Parse the /sys entry to find major and minor for device
|
|
|
|
|
* If/when found, create device node with type 'type'
|
|
|
|
|
*
|
|
|
|
|
* Example: utp_mk_devnode("block", "sda", "/dev/scsi-disk-0", S_IFBLK)
|
|
|
|
|
*/
|
|
|
|
|
static int utp_mk_devnode(char *class, char *name, char *node, int type)
|
|
|
|
|
{
|
|
|
|
|
char sys[256];
|
|
|
|
|
char devnode[20]; /* major:minor */
|
|
|
|
|
int major, minor;
|
|
|
|
|
char *colon;
|
|
|
|
|
int len, f, rc = -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (access(node, F_OK) == 0) {
|
|
|
|
|
printf("UTP: file/device node %s already exists\n", node);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
snprintf(sys, sizeof(sys), "/sys/%s/%s/dev", class, name);
|
|
|
|
|
f = open(sys, O_RDONLY);
|
|
|
|
|
if (f >= 0) {
|
|
|
|
|
memset(devnode, 0, sizeof(devnode));
|
|
|
|
|
len = read(f, devnode, sizeof(devnode));
|
|
|
|
|
if (len >= 0) {
|
|
|
|
|
sscanf(devnode, "%d:%d", &major, &minor);
|
|
|
|
|
printf("%s: creating node '%s' with %d+%d\n", __func__, node, major, minor);
|
|
|
|
|
unlink(node);
|
|
|
|
|
rc = mknod(node, type | 0666, makedev(major, minor));
|
|
|
|
|
}
|
|
|
|
|
close(f);
|
|
|
|
|
}
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_run
|
|
|
|
|
*
|
|
|
|
|
* Start the subshell and execute the command passed
|
|
|
|
|
*/
|
|
|
|
|
static int utp_run(char *command, ... )
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
char cmd[1024];
|
|
|
|
|
va_list vptr;
|
|
|
|
|
|
|
|
|
|
va_start(vptr, command);
|
|
|
|
|
vsnprintf(cmd, sizeof(cmd), command, vptr);
|
|
|
|
|
va_end(vptr);
|
|
|
|
|
|
|
|
|
|
printf("UTP: executing \"%s\"\n", cmd);
|
|
|
|
|
return system(cmd);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_send_busy
|
|
|
|
|
*
|
|
|
|
|
* report the busy state to the kernel state machine
|
|
|
|
|
*/
|
|
|
|
|
static void utp_send_busy(int u)
|
|
|
|
|
{
|
|
|
|
|
struct utp_message w;
|
|
|
|
|
|
|
|
|
|
w.flags = UTP_FLAG_REPORT_BUSY;
|
|
|
|
|
w.size = sizeof(w);
|
|
|
|
|
write(u, &w, w.size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_partition_mmc
|
|
|
|
|
*
|
|
|
|
|
* chat with fdisk to create bootable partition of type 0x53 and extended one
|
|
|
|
|
*/
|
|
|
|
|
static int utp_partition_mmc(char *disk)
|
|
|
|
|
{
|
|
|
|
|
char fc[50];
|
|
|
|
|
int i;
|
|
|
|
|
char shell_cmd[256];
|
|
|
|
|
int fdisk;
|
|
|
|
|
FILE *fdisk_f;
|
|
|
|
|
|
|
|
|
|
sprintf(shell_cmd, "fdisk %s", disk);
|
|
|
|
|
fdisk_f = popen(shell_cmd, "w");
|
|
|
|
|
if (fdisk_f < 0)
|
|
|
|
|
return errno;
|
|
|
|
|
|
|
|
|
|
fdisk = fileno(fdisk_f);
|
|
|
|
|
for (i = 4; i >= 1 ; i--) {
|
|
|
|
|
sprintf(fc, "d\n%d\n", i);
|
|
|
|
|
write(fdisk, fc, strlen(fc));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sprintf(fc, "n\np\n1\n1\n+16M\n");
|
|
|
|
|
write(fdisk, fc, strlen(fc));
|
|
|
|
|
|
|
|
|
|
sprintf(fc, "n\np\n2\n\n\n");
|
|
|
|
|
write(fdisk, fc, strlen(fc));
|
|
|
|
|
|
|
|
|
|
sprintf(fc, "t\n1\n0x%X\n\n", 0x53);
|
|
|
|
|
write(fdisk, fc, strlen(fc));
|
|
|
|
|
|
|
|
|
|
write(fdisk, "w\nq\n", 2);
|
|
|
|
|
|
|
|
|
|
pclose(fdisk_f);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_do_selftest
|
|
|
|
|
*
|
|
|
|
|
* perform some diagnostics
|
|
|
|
|
*
|
|
|
|
|
* TBW
|
|
|
|
|
*/
|
|
|
|
|
static int utp_do_selftest(void)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Put the command which needs to send busy first
|
|
|
|
|
* And the host will send poll for getting its return value
|
|
|
|
|
* later, we call these kinds of commands as Asynchronous Commands.
|
|
|
|
|
*/
|
|
|
|
|
static int utp_can_busy(char *command)
|
|
|
|
|
{
|
|
|
|
|
char *async[] ={
|
|
|
|
|
"$ ", "frf", "pollpipe", NULL,
|
|
|
|
|
};
|
|
|
|
|
char **ptr;
|
|
|
|
|
|
|
|
|
|
ptr = async;
|
|
|
|
|
while (*ptr) {
|
|
|
|
|
if (strncmp(command, *ptr, strlen(*ptr)) == 0)
|
|
|
|
|
return 1;
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#ifdef NEED_TO_GET_CHILD_PID
|
|
|
|
|
/* for pipe */
|
|
|
|
|
#define READ 0
|
|
|
|
|
#define WRITE 1
|
|
|
|
|
static pid_t child_pid = -1;
|
|
|
|
|
/*
|
|
|
|
|
* Check the process is dead
|
|
|
|
|
*/
|
|
|
|
|
#define NAME_MAX 30
|
|
|
|
|
int is_child_dead(void)
|
|
|
|
|
{
|
|
|
|
|
FILE *fh;
|
|
|
|
|
char path[NAME_MAX + 1];
|
|
|
|
|
sprintf(path, "/proc/%u/status", (unsigned int)child_pid);
|
|
|
|
|
if ((fh = fopen(path, "r"))){
|
|
|
|
|
char buf[1024];
|
|
|
|
|
while (fgets(buf, sizeof(buf) -1, fh)){
|
|
|
|
|
if (!strncmp(buf, "State:", 6))
|
|
|
|
|
{
|
|
|
|
|
char *p = buf + 6;
|
|
|
|
|
while (*p == '\t'){
|
|
|
|
|
p++;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (*p == 'Z'){
|
|
|
|
|
printf("Process status polling: %s is in zombie.\n",path);
|
|
|
|
|
fclose(fh);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
printf("Process polling: can't open %s, maybe the process %u has been killed already\n",path,child_pid);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fclose(fh);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int utp_flush(void)
|
|
|
|
|
{
|
|
|
|
|
int pstat;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
pid_t pid;
|
|
|
|
|
if (utp_file >= 0) {
|
|
|
|
|
fflush(NULL);
|
|
|
|
|
ret = close(utp_file);
|
|
|
|
|
do{
|
|
|
|
|
pid = waitpid(child_pid, &pstat, 0); /* wait for child finished */
|
|
|
|
|
}while (pid == -1 && errno == EINTR);
|
|
|
|
|
printf("UTP: closing the file\n");
|
|
|
|
|
}
|
|
|
|
|
utp_file = -1;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
pid_t popen2(const char *command, int *infp, int *outfp)
|
|
|
|
|
{
|
|
|
|
|
int p_stdin[2], p_stdout[2];
|
|
|
|
|
pid_t pid;
|
|
|
|
|
|
|
|
|
|
if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0)
|
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
|
|
|
|
|
|
if (pid < 0)
|
|
|
|
|
return pid;
|
|
|
|
|
else if (pid == 0){
|
|
|
|
|
close(p_stdin[WRITE]);
|
|
|
|
|
if (infp == NULL)
|
|
|
|
|
close(p_stdin[READ]);
|
|
|
|
|
else
|
|
|
|
|
dup2(p_stdin[READ], READ);
|
|
|
|
|
close(p_stdout[READ]);
|
|
|
|
|
if (outfp == NULL)
|
|
|
|
|
close(p_stdout[WRITE]);
|
|
|
|
|
else
|
|
|
|
|
dup2(p_stdout[WRITE], WRITE);
|
|
|
|
|
|
|
|
|
|
execl("/bin/sh", "sh", "-c", command, NULL);
|
|
|
|
|
perror("execl");
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (infp == NULL)
|
|
|
|
|
close(p_stdin[WRITE]);
|
|
|
|
|
else
|
|
|
|
|
*infp = p_stdin[WRITE];
|
|
|
|
|
|
|
|
|
|
if (outfp == NULL)
|
|
|
|
|
close(p_stdout[READ]);
|
|
|
|
|
else
|
|
|
|
|
*outfp = p_stdout[READ];
|
|
|
|
|
|
|
|
|
|
close(p_stdin[READ]);
|
|
|
|
|
close(p_stdout[WRITE]);
|
|
|
|
|
return pid;
|
|
|
|
|
}
|
|
|
|
|
int utp_pipe(char *command, ... )
|
|
|
|
|
{
|
|
|
|
|
int r, infp;
|
|
|
|
|
char shell_cmd[1024];
|
|
|
|
|
va_list vptr;
|
|
|
|
|
va_start(vptr, command);
|
|
|
|
|
vsnprintf(shell_cmd, sizeof(shell_cmd), command, vptr);
|
|
|
|
|
va_end(vptr);
|
|
|
|
|
|
|
|
|
|
child_pid = popen2(shell_cmd, &infp, NULL);
|
|
|
|
|
if (child_pid < 0){
|
|
|
|
|
printf("the fork is failed \n");
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
utp_file = infp;
|
|
|
|
|
printf("pid is %d, UTP: executing \"%s\"\n",child_pid, shell_cmd);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
int utp_poll_pipe()
|
|
|
|
|
{
|
|
|
|
|
int ret = 0, cnt = 0xFFFF;
|
|
|
|
|
while(ret == 0 && cnt > 0){
|
|
|
|
|
ret = is_child_dead();
|
|
|
|
|
usleep(10000);
|
|
|
|
|
cnt--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(ret == 0)
|
|
|
|
|
return 1;//failure
|
|
|
|
|
else
|
|
|
|
|
return 0;//Success
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
static int utp_flush(void)
|
|
|
|
|
{
|
|
|
|
|
int ret;
|
|
|
|
|
if (utp_file_f) {
|
|
|
|
|
printf("UTP: waiting for pipe to close\n");
|
|
|
|
|
ret = pclose(utp_file_f);
|
|
|
|
|
}
|
|
|
|
|
else if (utp_file >= 0) {
|
|
|
|
|
printf("UTP: closing the file\n");
|
|
|
|
|
ret = close(utp_file);
|
|
|
|
|
}
|
|
|
|
|
utp_file_f = NULL;
|
|
|
|
|
utp_file = -1;
|
|
|
|
|
printf("UTP: files were flushed.\n");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
static int utp_pipe(char *command, ... )
|
|
|
|
|
{
|
|
|
|
|
int r;
|
|
|
|
|
char shell_cmd[1024];
|
|
|
|
|
va_list vptr;
|
|
|
|
|
|
|
|
|
|
va_start(vptr, command);
|
|
|
|
|
vsnprintf(shell_cmd, sizeof(shell_cmd), command, vptr);
|
|
|
|
|
va_end(vptr);
|
|
|
|
|
|
|
|
|
|
utp_file_f = popen(shell_cmd, "w");
|
|
|
|
|
utp_file = fileno(utp_file_f);
|
|
|
|
|
|
|
|
|
|
return utp_file_f ? 0 : errno;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#endif /*0*/
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* utp_handle_command
|
|
|
|
|
*
|
|
|
|
|
* handle the command from MSC driver
|
|
|
|
|
* command can be:
|
|
|
|
|
* ?
|
|
|
|
|
* !<type>
|
|
|
|
|
* $ <shell_command>
|
|
|
|
|
* wfs/wff <X> write firmware to SD/flash
|
|
|
|
|
* wrs/wrf <X> write rootfs to SD/flash
|
|
|
|
|
* frs/frf <X> format partition for root on SD/flash
|
|
|
|
|
* erase <X> erase partition on flash
|
|
|
|
|
* read not implemented yet
|
|
|
|
|
* write not implemented yet
|
|
|
|
|
*/
|
|
|
|
|
struct utp_message *utp_handle_command(char *cmd, unsigned long long payload)
|
|
|
|
|
{
|
|
|
|
|
struct utp_message *w = NULL;
|
|
|
|
|
char devnode[50]; /* enough to fit /dev/mmcblk0p99 */
|
|
|
|
|
char sysnode[50]; /* -"- -"- mmcblk0/mmcblk0p99 */
|
|
|
|
|
uint32_t flags, status;
|
|
|
|
|
char *data = NULL;
|
|
|
|
|
int f;
|
|
|
|
|
size_t size;
|
|
|
|
|
|
|
|
|
|
printf("UTP: received command '%s'\n", cmd);
|
|
|
|
|
|
|
|
|
|
/* defaults */
|
|
|
|
|
status = 0;
|
|
|
|
|
flags = 0;
|
|
|
|
|
size = 0;
|
|
|
|
|
|
|
|
|
|
/* these are asynchronous commands and need to send busy */
|
|
|
|
|
/*if (utp_can_busy(cmd)){
|
|
|
|
|
utp_send_busy(u);
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
if (strcmp(cmd, "?") == 0) {
|
|
|
|
|
/* query */
|
|
|
|
|
flags = UTP_FLAG_DATA;
|
|
|
|
|
data = malloc(256);
|
|
|
|
|
sprintf(data,
|
|
|
|
|
"<DEVICE>\n"
|
|
|
|
|
" <FW>%s</FW>\n"
|
|
|
|
|
" <DCE>%s</DCE>\n"
|
|
|
|
|
" <SN>%s</SN>"
|
|
|
|
|
" <CID>%s</CID>"
|
|
|
|
|
" <VID>%04X</VID>"
|
|
|
|
|
" <PID>%04X</PID>"
|
|
|
|
|
"</DEVICE>\n", utp_firmware_version, VERSION, utp_sn, utp_chipid, 0x66F, 0x37FF);
|
|
|
|
|
size = (strlen(data) + 1 ) * sizeof(data[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (cmd[0] == '!') {
|
|
|
|
|
/* reboot the system, and the ACK has already sent out */
|
|
|
|
|
if (cmd[1] == '3') {
|
|
|
|
|
sync();
|
|
|
|
|
kill(-1, SIGTERM);
|
|
|
|
|
sleep(1);
|
|
|
|
|
kill(-1, SIGKILL);
|
|
|
|
|
|
|
|
|
|
reboot(LINUX_REBOOT_CMD_RESTART);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "$ ", 2) == 0) {
|
|
|
|
|
status = utp_run(cmd + 2);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
else if ((strcmp(cmd,"wff") == 0) || (strcmp(cmd, "wfs") == 0)) {
|
|
|
|
|
/* Write firmware - to flash or to SD, no matter */
|
|
|
|
|
utp_file = open(UTP_TARGET_FILE, O_CREAT | O_TRUNC | O_WRONLY, 0666);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strcmp(cmd, "fff") == 0) {
|
|
|
|
|
/* perform actual flashing of the firmware to the NAND */
|
|
|
|
|
utp_flush();
|
|
|
|
|
if (utp_mk_devnode("class/mtd", "mtd1", "/dev/mtd1", S_IFCHR) >= 0 &&
|
|
|
|
|
utp_mk_devnode("class/mtd", "mtd0", "/dev/mtd0", S_IFCHR) >= 0) {
|
|
|
|
|
utp_run("kobs-ng -v -d %s", UTP_TARGET_FILE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(cmd, "ffs") == 0) {
|
|
|
|
|
/* perform actual flashing of the firmware to the SD */
|
|
|
|
|
utp_flush();
|
|
|
|
|
|
|
|
|
|
/* partition the card */
|
|
|
|
|
if (!status && utp_mk_devnode("block", "mmcblk0", "/dev/mmc", S_IFBLK) >= 0) {
|
|
|
|
|
status = utp_partition_mmc("/dev/mmc");
|
|
|
|
|
/* waiting for partition table to settle */
|
|
|
|
|
sleep(5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* write data to the first partition */
|
|
|
|
|
if (!status && utp_mk_devnode("block", "mmcblk0/mmcblk0p1", "/dev/mmc0p1", S_IFBLK) >= 0) {
|
|
|
|
|
utp_run("dd if=/dev/zero of=/dev/mmc0p1 bs=512 count=4");
|
|
|
|
|
utp_run("dd if=%s of=/dev/mmc0p1 ibs=512 seek=4 conv=sync,notrunc", UTP_TARGET_FILE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "mknod", 5) == 0) {
|
|
|
|
|
int devtype = S_IFCHR;
|
|
|
|
|
char *class, *item, *type, *node;
|
|
|
|
|
|
|
|
|
|
class = strtok(cmd + 6, " \t,;");
|
|
|
|
|
printf("class = '%s'\n", class);
|
|
|
|
|
item = strtok(NULL, " \t,;");
|
|
|
|
|
printf("item = '%s'\n", item);
|
|
|
|
|
node = strtok(NULL, " \t,;");
|
|
|
|
|
printf("node = %s\n", node);
|
|
|
|
|
type = strtok(NULL, " \t,;");
|
|
|
|
|
printf("type = %s\n", type);
|
|
|
|
|
if (!node && item)
|
|
|
|
|
sprintf(devnode, "/dev/%s", item);
|
|
|
|
|
else
|
|
|
|
|
strcpy(devnode, node);
|
|
|
|
|
if (type && (strcmp(type, "block") == 0 || strcmp(type, "blk") == 0))
|
|
|
|
|
devtype = S_IFBLK;
|
|
|
|
|
printf("UTP: running utp_mk_devnode(%s,%s,%s,0x%x)\n",
|
|
|
|
|
class, item, devnode, devtype);
|
|
|
|
|
status = utp_mk_devnode(class, item, devnode, devtype);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "wrf", 3) == 0) {
|
|
|
|
|
/* Write rootfs to flash */
|
|
|
|
|
printf("UTP: writing rootfs to flash, mtd #%c, size %lld\n",
|
|
|
|
|
cmd[3], payload);
|
|
|
|
|
|
|
|
|
|
/* ensure that device node is here */
|
|
|
|
|
snprintf(devnode, sizeof(devnode), "/dev/mtd%c", cmd[3]);
|
|
|
|
|
utp_mk_devnode("class/mtd", devnode + 5, devnode, S_IFCHR);
|
|
|
|
|
|
|
|
|
|
/* then start ubiformat and redirect its input */
|
|
|
|
|
status = utp_pipe("ubiformat %s -f - -S %lld", devnode, payload);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "pipe", 4) == 0) {
|
|
|
|
|
status = utp_pipe(cmd + 5);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "pollpipe", 8) == 0) {
|
|
|
|
|
printf("UTP: poll pipe.\n");
|
|
|
|
|
status = utp_poll_pipe();
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "wrs", 3) == 0) {
|
|
|
|
|
/* Write rootfs to the SD */
|
|
|
|
|
printf("UTP: writing rootfs to SD card, mmc partition #%c, size %lld\n",
|
|
|
|
|
cmd[3], payload);
|
|
|
|
|
|
|
|
|
|
/* ensure that device node is here */
|
|
|
|
|
snprintf(devnode, sizeof(devnode), "/dev/mmcblk0p%c", cmd[3]);
|
|
|
|
|
snprintf(sysnode, sizeof(sysnode), "mmcblk0/mmcblk0p%d", cmd[3]);
|
|
|
|
|
utp_mk_devnode("block", sysnode, devnode, S_IFBLK);
|
|
|
|
|
|
|
|
|
|
if (payload % 1024)
|
|
|
|
|
printf("UTP: WARNING! payload %% 1024 != 0, the rest will be skipped");
|
|
|
|
|
|
|
|
|
|
status = utp_pipe("dd of=%s bs=1K", devnode);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if (strcmp(cmd, "frf") == 0 || strcmp(cmd, "frs") == 0) {
|
|
|
|
|
/* perform actual flashing of the rootfs to the NAND/SD */
|
|
|
|
|
status = utp_flush();
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "untar.", 6) == 0) {
|
|
|
|
|
status = utp_pipe("tar %cxv -C %s", cmd[6], cmd + 8);
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "read", 4) == 0) {
|
|
|
|
|
f = open(cmd + 5, O_RDONLY);
|
|
|
|
|
if (f < 0) {
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
status = errno;
|
|
|
|
|
} else {
|
|
|
|
|
size = lseek(f, 0, SEEK_END); /* get the file size */
|
|
|
|
|
lseek(f, 0, SEEK_SET);
|
|
|
|
|
|
|
|
|
|
data = malloc(size);
|
|
|
|
|
if (!data) {
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
status = -ENOMEM;
|
|
|
|
|
} else {
|
|
|
|
|
read(f, data, size);
|
|
|
|
|
flags = UTP_FLAG_DATA;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strcmp(cmd, "send") == 0) {
|
|
|
|
|
utp_file = open(UTP_TARGET_FILE, O_TRUNC | O_CREAT | O_WRONLY, 0666);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else if (strncmp(cmd, "save", 4) == 0) {
|
|
|
|
|
close(utp_file);
|
|
|
|
|
rename(UTP_TARGET_FILE, cmd + 5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
else if (strcmp(cmd, "selftest") == 0) {
|
|
|
|
|
status = utp_do_selftest();
|
|
|
|
|
if (status)
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
else {
|
|
|
|
|
printf("UTP: Unknown command received, ignored\n");
|
|
|
|
|
flags = UTP_FLAG_STATUS;
|
|
|
|
|
status = -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
w = malloc(size + sizeof(*w));
|
|
|
|
|
if (!w) {
|
|
|
|
|
printf("UTP: Could not allocate %d+%d bytes!\n", size, sizeof(*w));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(w, 0, sizeof(*w) + size);
|
|
|
|
|
w->flags = flags;
|
|
|
|
|
w->size = size + sizeof(*w);
|
|
|
|
|
if (flags & UTP_FLAG_DATA) {
|
|
|
|
|
w->bufsize = size;
|
|
|
|
|
memcpy(w->data, data, size);
|
|
|
|
|
}
|
|
|
|
|
if (flags & UTP_FLAG_STATUS)
|
|
|
|
|
w->status = status;
|
|
|
|
|
if (data)
|
|
|
|
|
free(data);
|
|
|
|
|
return w;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
void feed_watchdog(void *arg)
|
|
|
|
|
{
|
|
|
|
|
int res;
|
|
|
|
|
int *fd = arg;
|
|
|
|
|
while(1) {
|
|
|
|
|
res = ioctl(*fd, WDIOC_KEEPALIVE);
|
|
|
|
|
if (res)
|
|
|
|
|
printf("ioctl WDIOC_KEEPALIVE error L%d, %s\n", __LINE__, strerror(errno));
|
|
|
|
|
printf("%s\n", __func__);
|
|
|
|
|
sleep(60);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
int u = -1, wdt_fd = -1, r, need_watchdog = 0;
|
|
|
|
|
int watchdog_timeout = 127; /* sec */
|
|
|
|
|
int cpu_id = 50;
|
|
|
|
|
struct utp_message *uc, *answer;
|
|
|
|
|
char env[256];
|
|
|
|
|
pthread_t a_thread;
|
|
|
|
|
void *thread_result;
|
|
|
|
|
|
|
|
|
|
printf("%s %s [built %s %s]\n", PACKAGE, VERSION, __DATE__, __TIME__);
|
|
|
|
|
/* set stdout unbuffered, what is the usage??? */
|
|
|
|
|
// setvbuf(stdout, NULL, _IONBF, 0);
|
|
|
|
|
uc = malloc(sizeof(*uc) + 0x10000);
|
|
|
|
|
|
|
|
|
|
mkdir("/tmp", 0777);
|
|
|
|
|
|
|
|
|
|
setenv("FILE", UTP_TARGET_FILE, !0);
|
|
|
|
|
|
|
|
|
|
printf("UTP: Waiting for device to appear\n");
|
|
|
|
|
while (utp_mk_devnode("class/misc", "utp", UTP_DEVNODE, S_IFCHR) < 0) {
|
|
|
|
|
putchar('.');
|
|
|
|
|
sleep(1);
|
|
|
|
|
}
|
|
|
|
|
u = open(UTP_DEVNODE, O_RDWR);
|
|
|
|
|
r = ioctl(u, UTP_GET_CPU_ID, &cpu_id);
|
|
|
|
|
if (r)
|
|
|
|
|
printf("cpu id get error:L%d, %s\n", __LINE__, strerror(errno));
|
|
|
|
|
else{
|
|
|
|
|
switch (cpu_id) {
|
|
|
|
|
case 23:
|
|
|
|
|
case 25:
|
|
|
|
|
case 28:
|
|
|
|
|
case 50:
|
|
|
|
|
need_watchdog = 0;
|
|
|
|
|
break;
|
|
|
|
|
case 35:
|
|
|
|
|
case 51:
|
|
|
|
|
case 53:
|
|
|
|
|
need_watchdog = 1;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
need_watchdog = 0;
|
|
|
|
|
}
|
|
|
|
|
printf("cpu_id is %d\n", cpu_id);
|
|
|
|
|
if (need_watchdog){
|
|
|
|
|
if (utp_mk_devnode("class/misc", "watchdog", "/dev/watchdog", S_IFCHR)){
|
|
|
|
|
printf("The watchdog is not configured, needed by mx35/mx51/mx53 \n");
|
|
|
|
|
printf("%d, %s\n", __LINE__, strerror(errno));
|
|
|
|
|
} else{
|
|
|
|
|
wdt_fd = open("/dev/watchdog", O_RDWR);
|
|
|
|
|
/* set the MAX timeout */
|
|
|
|
|
r = ioctl(wdt_fd, WDIOC_SETTIMEOUT, &watchdog_timeout);
|
|
|
|
|
if (r)
|
|
|
|
|
printf("%d, %s\n", __LINE__, strerror(errno));
|
|
|
|
|
r = pthread_create(&a_thread, NULL, (void *)feed_watchdog, (void *)(&wdt_fd));
|
|
|
|
|
if (r != 0) {
|
|
|
|
|
perror("Thread creation failed");
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for(;;) {
|
|
|
|
|
r = read(u, uc, sizeof(*uc) + 0x10000);
|
|
|
|
|
if (uc->flags & UTP_FLAG_COMMAND) {
|
|
|
|
|
answer = utp_handle_command(uc->command, uc->payload);
|
|
|
|
|
if (answer) {
|
|
|
|
|
printf("UTP: sending %s to kernel for command %s.\n", utp_answer_type(answer), uc->command);
|
|
|
|
|
write(u, answer, answer->size);
|
|
|
|
|
free(answer);
|
|
|
|
|
}
|
|
|
|
|
}else if (uc->flags & UTP_FLAG_DATA) {
|
|
|
|
|
write(utp_file, uc->data, uc->bufsize);
|
|
|
|
|
}else {
|
|
|
|
|
printf("UTP: Unknown flag %x\n", uc->flags);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* should never be here */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|