From c7e618f5aeaedd49a28309feeadc79bc0d7ca57b Mon Sep 17 00:00:00 2001 From: Sven Peter Date: Fri, 15 May 2009 16:06:07 +0200 Subject: [PATCH] added dhewg's bootmii client --- client/.gitignore | 3 + client/Makefile | 11 +++ client/gecko.c | 199 ++++++++++++++++++++++++++++++++++++++++++ client/gecko.h | 32 +++++++ client/main.c | 218 ++++++++++++++++++++++++++++++++++++++++++++++ common.mk | 60 +++++++++++++ starlet.mk | 12 +++ 7 files changed, 535 insertions(+) create mode 100644 client/.gitignore create mode 100644 client/Makefile create mode 100644 client/gecko.c create mode 100644 client/gecko.h create mode 100644 client/main.c create mode 100644 common.mk create mode 100644 starlet.mk diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..186d0fe --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,3 @@ +bootmii +*~ + diff --git a/client/Makefile b/client/Makefile new file mode 100644 index 0000000..d3f9f16 --- /dev/null +++ b/client/Makefile @@ -0,0 +1,11 @@ +CFLAGS = -Wall -W -Os -g +TARGET = bootmii +OBJS = gecko.o main.o + +NOMAPFILE = 1 + +include ../common.mk + +install: all + install -m 755 $(TARGET) $(WIIDEV)/bin + diff --git a/client/gecko.c b/client/gecko.c new file mode 100644 index 0000000..9c3ab18 --- /dev/null +++ b/client/gecko.c @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2008 dhewg, #wiidev efnet + * + * this file is part of wiifuse + * http://wiibrew.org/index.php?title=Wiifuse + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include + +#ifndef __WIN32__ +#include +#else +#define WIN32_LEAN_AND_MEAN +#include +#endif + +#include "gecko.h" + +#define FTDI_PACKET_SIZE 3968 + +#ifndef __WIN32__ +static int fd_gecko = -1; +#else +static HANDLE handle_gecko = NULL; +#endif + +int gecko_open(const char *dev) { +#ifndef __WIN32__ + struct termios newtio; + + fd_gecko = open(dev, O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK); + + if (fd_gecko == -1) { + perror("gecko_open"); + return 1; + } + + if (fcntl(fd_gecko, F_SETFL, 0)) { + perror("F_SETFL on serial port"); + return 1; + } + + if (tcgetattr(fd_gecko, &newtio)) { + perror("tcgetattr"); + return 1; + } + + cfmakeraw(&newtio); + + newtio.c_cflag |= CRTSCTS | CS8 | CLOCAL | CREAD; + + if (tcsetattr(fd_gecko, TCSANOW, &newtio)) { + perror("tcsetattr"); + return 1; + } +#else + COMMTIMEOUTS timeouts; + + handle_gecko = CreateFile(dev, GENERIC_READ | GENERIC_WRITE, 0, 0, + OPEN_EXISTING, 0, 0); + + GetCommTimeouts(handle_gecko, &timeouts); + + timeouts.ReadIntervalTimeout = MAXDWORD; + timeouts.ReadTotalTimeoutMultiplier = 0; + timeouts.ReadTotalTimeoutConstant = 0; + timeouts.WriteTotalTimeoutMultiplier = 0; + timeouts.WriteTotalTimeoutConstant = 0; + + if (!SetCommTimeouts(handle_gecko, &timeouts)) { + fprintf(stderr, "error setting timeouts on port\n"); + return 1; + } + + if (!SetCommMask(handle_gecko, 0)) { + fprintf(stderr, "error setting communications event mask\n"); + return 1; + } +#endif + + gecko_flush(); + + return 0; +} + +void gecko_close() { +#ifndef __WIN32__ + if (fd_gecko > 0) + close(fd_gecko); +#else + CloseHandle(handle_gecko); +#endif +} + +void gecko_flush() { +#ifndef __WIN32__ + tcflush(fd_gecko, TCIOFLUSH); +#else + PurgeComm(handle_gecko, PURGE_RXCLEAR | PURGE_TXCLEAR | + PURGE_TXABORT | PURGE_RXABORT); + +#endif +} + +int gecko_read(void *buf, size_t count) { + size_t left, chunk; +#ifndef __WIN32__ + size_t res; +#else + DWORD res; +#endif + + left = count; + while (left) { + chunk = left; + if (chunk > FTDI_PACKET_SIZE) + chunk = FTDI_PACKET_SIZE; + +#ifndef __WIN32__ + res = read(fd_gecko, buf, chunk); + if (res < 1) { + perror("gecko_read"); + return 1; + } +#else + if (!ReadFile(handle_gecko, buf, chunk, &res, NULL)) { + fprintf(stderr, "gecko_read\n"); + return 1; + } +#endif + + left -= res; + buf += res; + } + + return 0; +} + +int gecko_write(const void *buf, size_t count) { + size_t left, chunk; +#ifndef __WIN32__ + size_t res; +#else + DWORD res; +#endif + + left = count; + + while (left) { + chunk = left; + if (chunk > FTDI_PACKET_SIZE) + chunk = FTDI_PACKET_SIZE; + +#ifndef __WIN32__ + res = write(fd_gecko, buf, count); + if (res < 1) { + perror("gecko_write"); + return 1; + } +#else + if (!WriteFile(handle_gecko, buf, chunk, &res, NULL)) { + fprintf (stderr, "gecko_write\n"); + return 1; + } +#endif + + left -= res; + buf += res; + +#ifndef __WIN32__ + // does this work with ftdi-sio? + if (tcdrain(fd_gecko)) { + perror ("gecko_drain"); + return 1; + } +#endif + } + + return 0; +} + diff --git a/client/gecko.h b/client/gecko.h new file mode 100644 index 0000000..97ac881 --- /dev/null +++ b/client/gecko.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2008 dhewg, #wiidev efnet + * + * this file is part of wiifuse + * http://wiibrew.org/index.php?title=Wiifuse + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _GECKO_H_ +#define _GECKO_H_ + +int gecko_open(const char *dev); +void gecko_close(); +void gecko_flush(); +int gecko_read(void *buf, size_t count); +int gecko_write(const void *buf, size_t count); + +#endif + diff --git a/client/main.c b/client/main.c new file mode 100644 index 0000000..6932539 --- /dev/null +++ b/client/main.c @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2008 dhewg, #wiidev efnet + * + * this file is part of geckoloader + * http://wiibrew.org/index.php?title=Geckoloader + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gecko.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define BOOTMII_CLIENT_VERSION "v0.1" +#define MAX_BINARY_SIZE (20 * 1024 *1024) + +#define CMD_NONE 0 +#define CMD_UPLOAD_ARM 1 +#define CMD_UPLOAD_PPC 2 + +const char *envvar = "USBGECKODEVICE"; + +#ifndef __WIN32__ +#ifdef __APPLE__ +char *default_tty = "/dev/tty.usbserial-GECKUSB0"; +#else +char *default_tty = "/dev/ttyUSB0"; +#endif +#else +char *default_tty = NULL; +#endif + +void usage(const char *appname) { + fprintf(stderr, "usage: %s \n", appname); + fprintf(stderr, "commands: -a: upload ARM binary\n"); + fprintf(stderr, " -p: upload PPC binary\n"); + exit(EXIT_FAILURE); +} + +int main(int argc, char **argv) { + int cmd, fd; + struct stat st; + char *tty; + unsigned char buf4[4]; + unsigned char *buf, *p; + off_t fsize, block; + + printf("bootmii client " BOOTMII_CLIENT_VERSION "\n" + "coded by dhewg, #wiidev efnet\n\n"); + + if (argc < 2) + usage(argv[0]); + + cmd = CMD_NONE; + if (!strcmp(argv[1], "-a")) + cmd = CMD_UPLOAD_ARM; + else if (!strcmp(argv[1], "-p")) + cmd = CMD_UPLOAD_PPC; + + if (cmd == CMD_NONE) + usage(argv[0]); + + tty = getenv(envvar); + if (!tty) + tty = default_tty; + + if (tty && stat(tty, &st)) + tty = NULL; + + if (!tty) { + fprintf(stderr, "please set the environment variable %s to " + "your usbgecko " +#ifndef __WIN32__ + "tty device (eg \"/dev/ttyUSB0\")" +#else + "COM port (eg \"COM3\")" +#endif + "\n", envvar); + exit(EXIT_FAILURE); + } + + printf("using %s\n", tty); + + fd = open(argv[2], O_RDONLY | O_BINARY); + if (fd < 0) { + perror("error opening the device"); + exit(EXIT_FAILURE); + } + + if (fstat(fd, &st)) { + close(fd); + perror("error stat'ing the file"); + exit(EXIT_FAILURE); + } + fsize = st.st_size; + + if (fsize < 1 || fsize > MAX_BINARY_SIZE) { + close(fd); + fprintf(stderr, "error: invalid file size\n"); + exit(EXIT_FAILURE); + } + + buf = malloc(fsize); + if (!buf) { + close(fd); + fprintf(stderr, "out of memory\n"); + exit(EXIT_FAILURE); + } + + if (read(fd, buf, fsize) != fsize) { + close(fd); + free(buf); + perror("error reading the file"); + exit(EXIT_FAILURE); + } + close (fd); + + if (gecko_open(tty)) { + free(buf); + fprintf(stderr, "unable to open the device\n"); + exit(EXIT_FAILURE); + } + + switch (cmd) { + case CMD_UPLOAD_ARM: + printf("sending ARM upload request\n"); + buf4[0] = 'B'; + buf4[1] = 'A'; + buf4[2] = 'R'; + buf4[3] = 'M'; + break; + case CMD_UPLOAD_PPC: + printf("sending PPC upload request\n"); + buf4[0] = 'B'; + buf4[1] = 'P'; + buf4[2] = 'P'; + buf4[3] = 'C'; + break; + default: + free(buf); + fprintf(stderr, "internal error\n"); + exit(EXIT_FAILURE); + } + + if (gecko_write(buf4, 4)) { + free(buf); + gecko_close(); + exit(EXIT_FAILURE); + } + + buf4[0] = (fsize >> 24) & 0xff; + buf4[1] = (fsize >> 16) & 0xff; + buf4[2] = (fsize >> 8) & 0xff; + buf4[3] = fsize & 0xff; + + printf("sending file size (%u bytes)\n", (unsigned int) fsize); + + if (gecko_write(buf4, 4)) { + free(buf); + gecko_close(); + fprintf(stderr, "error sending data\n"); + exit(EXIT_FAILURE); + } + + printf("sending data"); + fflush(stdout); + + p = buf; + while (fsize > 0) { + block = fsize; + if (block > 63488) + block = 63488; + fsize -= block; + + if (gecko_write(p, block)) { + fprintf(stderr, "error sending block\n"); + break; + } + p += block; + + printf("."); + fflush(stdout); + + if (fsize == 0) + printf("\n"); + } + + printf("done.\n"); + + free(buf); + gecko_close(); + + return 0; +} + diff --git a/common.mk b/common.mk new file mode 100644 index 0000000..cd9fdcb --- /dev/null +++ b/common.mk @@ -0,0 +1,60 @@ +AR = $(PREFIX)ar +AS = $(PREFIX)as +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +LD = $(PREFIX)ld +OBJCOPY = $(PREFIX)objcopy +RANLIB = $(PREFIX)ranlib +STRIP = $(PREFIX)strip + +BIN2S = $(DEVKITPPC)/bin/bin2s + +ifeq ($(NOMAPFILE),) +LDFLAGS += -Wl,-Map,$(TARGET).map +endif + +ifneq ($(LDSCRIPT),) +LDFLAGS += -Wl,-T$(LDSCRIPT) +endif + +DEPDIR = .deps + +all: $(TARGET) + +$(TARGET): $(OBJS) + @echo " LINK $@" + @$(CC) $(LDFLAGS) $(OBJS) $(LIBS) -o $@ + +ifneq ($(LDSCRIPT),) +$(TARGET): $(LDSCRIPT) +endif + +%.o: %.c + @echo " COMPILE $<" + @mkdir -p $(DEPDIR) + @$(CC) $(CFLAGS) $(DEFINES) -Wp,-MMD,$(DEPDIR)/$(*F).d,-MQ,"$@",-MP -c $< -o $@ + +%.o: %.s + @echo " ASSEMBLE $<" + @$(CC) $(CFLAGS) $(DEFINES) $(ASFLAGS) -c $< -o $@ + +%.o: %.S + @echo " ASSEMBLE $<" + @$(CC) $(CFLAGS) $(DEFINES) $(ASFLAGS) -c $< -o $@ + +clean: + rm -rf $(DEPDIR) + rm -f $(TARGET) $(TARGET).map $(OBJS) + +define bin2o + @echo " BIN2S $(notdir $<)" + @$(BIN2S) -a 32 $< | $(AS) -o $(@) + @echo "extern const u8" `(echo $( `(echo $(> `(echo $(> `(echo $(