Browse Source

replace linux application

pull/1/head
Olaf Rempel 7 years ago
parent
commit
ca2a0a99ae
15 changed files with 2063 additions and 1059 deletions
  1. +4
    -2
      linux/Makefile
  2. +52
    -0
      linux/chipinfo_avr.c
  3. +8
    -0
      linux/chipinfo_avr.h
  4. +328
    -328
      linux/filedata.c
  5. +4
    -4
      linux/filedata.h
  6. +635
    -0
      linux/mpm.c
  7. +320
    -0
      linux/multiboot.c
  8. +33
    -0
      linux/multiboot.h
  9. +193
    -0
      linux/optarg.c
  10. +15
    -0
      linux/optarg.h
  11. +2
    -0
      linux/rules/99-i2c-tiny-usb.rules
  12. +0
    -329
      linux/twb.c
  13. +0
    -31
      linux/twb.h
  14. +469
    -0
      linux/twi.c
  15. +0
    -365
      linux/twiboot.c

+ 4
- 2
linux/Makefile View File

@@ -1,4 +1,5 @@
TARGET = twiboot
TARGET = twiboot
TARGET2 = mpmboot

CFLAGS = -Wall -Wno-unused-result -O2 -MMD -MP -MF $(*F).d

@@ -11,12 +12,13 @@ all: $(TARGET)
$(TARGET): $(SRC:.c=.o)
@echo " Linking file: $@"
@$(CC) $(CFLAGS) $^ -o $@ $(LDFLAGS) > /dev/null
@ln -sf $@ $(TARGET2)

%.o: %.c
@echo " Building file: $<"
@$(CC) -c $(CFLAGS) $< -o $@

clean:
rm -rf $(TARGET) *.o *.d
rm -rf $(TARGET) $(TARGET2) *.o *.d

-include $(shell find . -name \*.d 2> /dev/null)

+ 52
- 0
linux/chipinfo_avr.c View File

@@ -0,0 +1,52 @@
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <stdint.h>

#include "chipinfo_avr.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))

struct chipinfo {
uint8_t sig[3];
const char name[16];
};

static struct chipinfo chips[] = {
{ { 0x1E, 0x93, 0x07 }, "AVR Mega 8" },
{ { 0x1E, 0x93, 0x0A }, "AVR Mega 88" },
{ { 0x1E, 0x94, 0x06 }, "AVR Mega 168" },
{ { 0x1E, 0x95, 0x02 }, "AVR Mega 32" },
};

const char * chipinfo_get_avr_name(const uint8_t *sig)
{
int i;
for (i = 0; i < ARRAY_SIZE(chips); i++) {
struct chipinfo *chip = &chips[i];
if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2])
return chip->name;
}

return "unknown";
}

+ 8
- 0
linux/chipinfo_avr.h View File

@@ -0,0 +1,8 @@
#ifndef _CHIPINFO_H_
#define _CHIPINFO_H_

#include <stdint.h>

const char * chipinfo_get_avr_name(const uint8_t *sig);

#endif /* _CHIPINFO_H_ */

+ 328
- 328
linux/filedata.c View File

@@ -1,21 +1,21 @@
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -31,393 +31,393 @@
#define FILETYPE_BINARY 1
#define FILETYPE_INTELHEX 2

int dbuf_alloc(struct databuf **dbuf, uint32_t size)
struct databuf * dbuf_alloc(uint32_t size)
{
*dbuf = malloc(sizeof(struct databuf) + size);
if (*dbuf == NULL) {
perror("dbuf_alloc");
return -1;
}
memset((*dbuf)->data, 0xFF, size);
(*dbuf)->size = size;
(*dbuf)->length = 0;
return 0;
struct databuf *dbuf = malloc(sizeof(struct databuf) + size);
if (dbuf == NULL) {
perror("dbuf_alloc");
return NULL;
}
memset(dbuf->data, 0xFF, size);
dbuf->size = size;
dbuf->length = 0;
return dbuf;
}

void dbuf_free(struct databuf *dbuf)
{
free(dbuf);
free(dbuf);
}

static void dbuf_dump(struct databuf *dbuf)
{
int pos = 0, oldskip = 0;
while (pos < dbuf->length) {
char buf[128];
int j, i = 0;
int skip = 1;
for (j = 0; j < 16; j++) {
if (pos + j < dbuf->length)
i += sprintf(buf + i, "%02X", dbuf->data[pos + j]);
else
i += sprintf(buf + i, " ");
if (j % 2)
buf[i++] = ' ';
}
for (j = 0; j < 16; j++) {
if (pos + j < dbuf->length) {
unsigned char val = dbuf->data[pos + j];
if (val >= 0x20 && val < 0x7F)
buf[i++] = val;
else
buf[i++] = '.';
if (val != 0xFF)
skip = 0;
} else {
buf[i++] = ' ';
}
}
if (pos == 0 || (pos + 16) >= dbuf->length || skip == 0) {
buf[i++] = '\0';
printf("%04X: %s\r\n", pos, buf);
oldskip = 0;
} else if (skip == 1 && oldskip == 0) {
printf("****\n");
oldskip = 1;
}
pos += 16;
}
int pos = 0, oldskip = 0;
while (pos < dbuf->length) {
char buf[128];
int j, i = 0;
int skip = 1;
for (j = 0; j < 16; j++) {
if (pos + j < dbuf->length)
i += sprintf(buf + i, "%02X", dbuf->data[pos + j]);
else
i += sprintf(buf + i, " ");
if (j % 2)
buf[i++] = ' ';
}
for (j = 0; j < 16; j++) {
if (pos + j < dbuf->length) {
unsigned char val = dbuf->data[pos + j];
if (val >= 0x20 && val < 0x7F)
buf[i++] = val;
else
buf[i++] = '.';
if (val != 0xFF)
skip = 0;
} else {
buf[i++] = ' ';
}
}
if (pos == 0 || (pos + 16) >= dbuf->length || skip == 0) {
buf[i++] = '\0';
printf("%04X: %s\r\n", pos, buf);
oldskip = 0;
} else if (skip == 1 && oldskip == 0) {
printf("****\n");
oldskip = 1;
}
pos += 16;
}
}

static int binfile_getsize(const char *filename, uint32_t *size)
{
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("binfile_getsize(): open()");
return -1;
}
struct stat filestat;
if (fstat(fd, &filestat) < 0) {
perror("binfile_getsize(): fstat()");
close(fd);
return -1;
}
*size = filestat.st_size;
close(fd);
return 0;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("binfile_getsize(): open()");
return -1;
}
struct stat filestat;
if (fstat(fd, &filestat) < 0) {
perror("binfile_getsize(): fstat()");
close(fd);
return -1;
}
*size = filestat.st_size;
close(fd);
return 0;
}

static int binfile_read(const char *filename, struct databuf *dbuf)
{
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("binfile_read(): open()");
return -1;
}
ssize_t readsize = read(fd, dbuf->data, dbuf->size);
if (readsize <= 0) {
perror("binfile_read(): read()");
close(fd);
return -1;
}
dbuf->length = readsize;
close(fd);
return 0;
int fd = open(filename, O_RDONLY);
if (fd < 0) {
perror("binfile_read(): open()");
return -1;
}
ssize_t readsize = read(fd, dbuf->data, dbuf->size);
if (readsize <= 0) {
perror("binfile_read(): read()");
close(fd);
return -1;
}
dbuf->length = readsize;
close(fd);
return 0;
}

static int binfile_write(const char *filename, struct databuf *dbuf)
{
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("binfile_write(): open()");
return -1;
}
ssize_t writesize = write(fd, dbuf->data, dbuf->length);
if (writesize != dbuf->length) {
perror("binfile_write(): write()");
close(fd);
return -1;
}
close(fd);
return 0;
int fd = open(filename, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd < 0) {
perror("binfile_write(): open()");
return -1;
}
ssize_t writesize = write(fd, dbuf->data, dbuf->length);
if (writesize != dbuf->length) {
perror("binfile_write(): write()");
close(fd);
return -1;
}
close(fd);
return 0;
}

struct ihex_record {
uint8_t byte_count;
uint16_t address;
uint8_t type;
uint8_t byte_count;
uint16_t address;
uint8_t type;

uint8_t *data;
uint8_t chksum;
uint8_t *data;
uint8_t chksum;
};

static uint8_t hex2byte(const char *ptr)
{
int i;
uint8_t result = 0;
int i;
uint8_t result = 0;

for (i = 0; i < 2; i++) {
result <<= 4;
result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0') :
(((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A) :
0x00);
}
for (i = 0; i < 2; i++) {
result <<= 4;
result |= (ptr[i] >= '0' && ptr[i] <= '9') ? (ptr[i] - '0') :
(((ptr[i] & 0xDF) >= 'A' && (ptr[i] & 0xDF) <= 'F') ? (ptr[i] - 'A' + 0x0A) :
0x00);
}

return result;
return result;
}

static int hexfile_getrecord(FILE *stream, struct ihex_record *record)
{
char *hexline = NULL;
size_t size;
ssize_t length = getline(&hexline, &size, stream);
if (length == -1) {
if (!feof(stream)) {
perror("hexfile_getrecord(): getline()");
}
return -1;
}
if (length < 12) {
fprintf(stderr, "record too short (%d)\n", length);
free(hexline);
return -1;
}
int pos = 0;
if (hexline[pos] != ':') {
fprintf(stderr, "invalid startcode\n");
free(hexline);
return -1;
}
pos++;
uint8_t chksum = 0x00;
record->byte_count = hex2byte(&hexline[pos]);
chksum += record->byte_count;
pos += 2;
if (record->byte_count > 0) {
record->data = malloc(record->byte_count);
if (record->data == NULL) {
perror("hexfile_getrecord(): malloc()");
free(hexline);
return -1;
}
}
uint8_t hiaddr = hex2byte(&hexline[pos]);
uint8_t loaddr = hex2byte(&hexline[pos +2]);
record->address = (hiaddr << 8) + loaddr;
chksum += hiaddr + loaddr;
pos += 4;
record->type = hex2byte(&hexline[pos]);
chksum += record->type;
pos += 2;
int i;
for (i = 0; i < record->byte_count; i++) {
record->data[i] = hex2byte(&hexline[pos]);
chksum += record->data[i];
pos += 2;
}
record->chksum = hex2byte(&hexline[pos]);
chksum += record->chksum;
pos += 2;
if (chksum != 0x00) {
fprintf(stderr, "invalid checksum (0x%02X)\n", chksum);
if (record->byte_count > 0)
free(record->data);
free(hexline);
return -1;
}
free(hexline);
return 0;
char *hexline = NULL;
size_t size;
ssize_t length = getline(&hexline, &size, stream);
if (length == -1) {
if (!feof(stream)) {
perror("hexfile_getrecord(): getline()");
}
return -1;
}
if (length < 12) {
fprintf(stderr, "record too short (%d)\n", length);
free(hexline);
return -1;
}
int pos = 0;
if (hexline[pos] != ':') {
fprintf(stderr, "invalid startcode\n");
free(hexline);
return -1;
}
pos++;
uint8_t chksum = 0x00;
record->byte_count = hex2byte(&hexline[pos]);
chksum += record->byte_count;
pos += 2;
if (record->byte_count > 0) {
record->data = malloc(record->byte_count);
if (record->data == NULL) {
perror("hexfile_getrecord(): malloc()");
free(hexline);
return -1;
}
}
uint8_t hiaddr = hex2byte(&hexline[pos]);
uint8_t loaddr = hex2byte(&hexline[pos +2]);
record->address = (hiaddr << 8) + loaddr;
chksum += hiaddr + loaddr;
pos += 4;
record->type = hex2byte(&hexline[pos]);
chksum += record->type;
pos += 2;
int i;
for (i = 0; i < record->byte_count; i++) {
record->data[i] = hex2byte(&hexline[pos]);
chksum += record->data[i];
pos += 2;
}
record->chksum = hex2byte(&hexline[pos]);
chksum += record->chksum;
pos += 2;
if (chksum != 0x00) {
fprintf(stderr, "invalid checksum (0x%02X)\n", chksum);
if (record->byte_count > 0)
free(record->data);
free(hexline);
return -1;
}
free(hexline);
return 0;
}

static int hexfile_putrecord(FILE *stream, struct ihex_record *record)
{
uint8_t chksum = record->byte_count;
chksum += (record->address >> 8) & 0xFF;
chksum += (record->address & 0xFF);
chksum += record->type;
int i, len = 0;
char buf[64];
buf[0] = '\0';
for (i = 0; i < record->byte_count; i++) {
len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]);
chksum += record->data[i];
}
fprintf(stream, ":%02X%04X%02X%s%02X\n", record->byte_count, record->address, record->type, buf, (uint8_t)(0x100 - chksum));
return -1;
uint8_t chksum = record->byte_count;
chksum += (record->address >> 8) & 0xFF;
chksum += (record->address & 0xFF);
chksum += record->type;
int i, len = 0;
char buf[64];
buf[0] = '\0';
for (i = 0; i < record->byte_count; i++) {
len += snprintf(buf + len, sizeof(buf) - len, "%02X", record->data[i]);
chksum += record->data[i];
}
fprintf(stream, ":%02X%04X%02X%s%02X\n", record->byte_count, record->address, record->type, buf, (uint8_t)(0x100 - chksum));
return -1;
}

static int hexfile_getsize(const char *filename, uint32_t *size)
{
*size = 0x10000;
return 0;
*size = 0x10000;
return 0;
}

static int hexfile_read(const char *filename, struct databuf *dbuf)
{
FILE *stream = fopen(filename, "r");
if (stream == NULL) {
perror("hexfile_read(): fopen()");
return -1;
}
while (1) {
struct ihex_record record;
memset(&record, 0x00, sizeof(struct ihex_record));
int result = hexfile_getrecord(stream, &record);
if (result == -1)
break;
if (record.type == 0x00) {
if (record.address > dbuf->size || record.address + record.byte_count > dbuf->size) {
fprintf(stderr, "hexfile_read(): data out of bounds\n");
break;
}
memcpy(&dbuf->data[record.address], record.data, record.byte_count);
dbuf->length = record.address + record.byte_count;
}
}
fclose(stream);
return 0;
FILE *stream = fopen(filename, "r");
if (stream == NULL) {
perror("hexfile_read(): fopen()");
return -1;
}
while (1) {
struct ihex_record record;
memset(&record, 0x00, sizeof(struct ihex_record));
int result = hexfile_getrecord(stream, &record);
if (result == -1)
break;
if (record.type == 0x00) {
if (record.address > dbuf->size || record.address + record.byte_count > dbuf->size) {
fprintf(stderr, "hexfile_read(): data out of bounds\n");
break;
}
memcpy(&dbuf->data[record.address], record.data, record.byte_count);
dbuf->length = record.address + record.byte_count;
}
}
fclose(stream);
return 0;
}

static int hexfile_write(const char *filename, struct databuf *dbuf)
{
FILE *stream = fopen(filename, "w");
if (stream == NULL) {
perror("hexfile_write(): fopen()");
return -1;
}
int i;
int addr_min = dbuf->length;
int addr_max = 0;
for (i = 0; i < dbuf->length; i++) {
if (dbuf->data[i] == 0xFF)
continue;
if (addr_min > i)
addr_min = i;
if (addr_max < i)
addr_max = i;
}
addr_min = addr_min & ~0x0F;
addr_max = (addr_max + 0x0F) & ~0x0F;
struct ihex_record record;
for (i = addr_min; i < addr_max; i += 0x10) {
record.byte_count = 0x10;
record.address = i;
record.type = 0x00;
record.data = &dbuf->data[i];
hexfile_putrecord(stream, &record);
}
record.byte_count = 0x00;
record.address = addr_min;
record.type = 0x01;
record.data = NULL;
hexfile_putrecord(stream, &record);
fclose(stream);
return 0;
FILE *stream = fopen(filename, "w");
if (stream == NULL) {
perror("hexfile_write(): fopen()");
return -1;
}
int i;
int addr_min = dbuf->length;
int addr_max = 0;
for (i = 0; i < dbuf->length; i++) {
if (dbuf->data[i] == 0xFF)
continue;
if (addr_min > i)
addr_min = i;
if (addr_max < i)
addr_max = i;
}
addr_min = addr_min & ~0x0F;
addr_max = (addr_max + 0x0F) & ~0x0F;
struct ihex_record record;
for (i = addr_min; i < addr_max; i += 0x10) {
record.byte_count = 0x10;
record.address = i;
record.type = 0x00;
record.data = &dbuf->data[i];
hexfile_putrecord(stream, &record);
}
record.byte_count = 0x00;
record.address = addr_min;
record.type = 0x01;
record.data = NULL;
hexfile_putrecord(stream, &record);
fclose(stream);
return 0;
}

static int get_filetype(const char *filename)
{
const char *ext = filename + (strlen(filename) -4);
const char *ext = filename + (strlen(filename) -4);

if (ext < filename)
return FILETYPE_UNKNOWN;
if (ext < filename)
return FILETYPE_UNKNOWN;

if (strncmp(ext, ".bin", 4) == 0)
return FILETYPE_BINARY;
if (strncmp(ext, ".bin", 4) == 0)
return FILETYPE_BINARY;

if (strncmp(ext, ".hex", 4) == 0)
return FILETYPE_INTELHEX;
if (strncmp(ext, ".hex", 4) == 0)
return FILETYPE_INTELHEX;

return FILETYPE_UNKNOWN;
return FILETYPE_UNKNOWN;
}

int file_getsize(const char *filename, uint32_t *size)
{
switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_getsize(filename, size);
switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_getsize(filename, size);

case FILETYPE_INTELHEX:
return hexfile_getsize(filename, size);
case FILETYPE_INTELHEX:
return hexfile_getsize(filename, size);

default:
return -1;
}
default:
return -1;
}
}

int file_read(const char *filename, struct databuf *dbuf)
{
switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_read(filename, dbuf);
switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_read(filename, dbuf);

case FILETYPE_INTELHEX:
return hexfile_read(filename, dbuf);
case FILETYPE_INTELHEX:
return hexfile_read(filename, dbuf);

default:
return -1;
}
default:
return -1;
}
}

int file_write(const char *filename, struct databuf *dbuf)
{
if (strncmp(filename, "-", 1) == 0) {
dbuf_dump(dbuf);
return 0;
}
if (strncmp(filename, "-", 1) == 0) {
dbuf_dump(dbuf);
return 0;
}

switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_write(filename, dbuf);
switch (get_filetype(filename)) {
case FILETYPE_BINARY:
return binfile_write(filename, dbuf);

case FILETYPE_INTELHEX:
return hexfile_write(filename, dbuf);
case FILETYPE_INTELHEX:
return hexfile_write(filename, dbuf);

default:
return -1;
}
default:
return -1;
}
}

+ 4
- 4
linux/filedata.h View File

@@ -4,12 +4,12 @@
#include <stdint.h>

struct databuf {
uint32_t size; // allocation size
uint32_t length; // used size
uint8_t data[0];
uint32_t size; // allocation size
uint32_t length; // used size
uint8_t data[0];
};

int dbuf_alloc(struct databuf **dbuf, uint32_t size);
struct databuf * dbuf_alloc(uint32_t size);
void dbuf_free(struct databuf *dbuf);

int file_getsize(const char *filename, uint32_t *size);

+ 635
- 0
linux/mpm.c View File

@@ -0,0 +1,635 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/time.h>

#include "chipinfo_avr.h"
#include "multiboot.h"
#include "optarg.h"

#define READ_BLOCK_SIZE 256 /* bytes in one flash/eeprom read request */
#define WRITE_BLOCK_SIZE 16 /* bytes in one eeprom write request */

#define CMD_SWITCH_APPLICATION 0x01
#define CMD_GET_BOOTLOADER_VERSION 0x02
#define CMD_GET_CHIP_INFO 0x03
#define CMD_READ_MEMORY 0x11
#define CMD_WRITE_MEMORY 0x12

#define CAUSE_SUCCESS 0x00
#define CAUSE_COMMAND_NOT_SUPPORTED 0xF0
#define CAUSE_INVALID_PARAMETER 0xF1
#define CAUSE_UNSPECIFIED_ERROR 0xFF

/* CMD_SWITCH_APPLICATION parameter */
#define BOOTTYPE_BOOTLOADER 0x00
#define BOOTTYPE_APPLICATION 0x80

#define MEMTYPE_FLASH 0x01
#define MEMTYPE_EEPROM 0x02

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

struct multiboot_ops mpm_ops;

struct mpm_privdata {
char *device;
int fd;
int connected;

int address;

int flashsize;
int flashpage;
int eepromsize;

struct termios oldtio;
};

static struct option mpm_optargs[] = {
{"address", 1, 0, 'a'}, /* -a <addr> */
{"device", 1, 0, 'd'}, /* [ -d <device> ] */
};

static int mpm_optarg_cb(int val, const char *arg, void *privdata)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)privdata;

switch (val) {
case 'a': /* address */
{
char *endptr;
mpm->address = strtol(arg, &endptr, 16);
if (*endptr != '\0' || mpm->address < 0x01 || mpm->address > 0x7F) {
fprintf(stderr, "invalid address: '%s'\n", arg);
return -1;
}
}
break;

case 'd': /* device */
{
if (mpm->device != NULL) {
fprintf(stderr, "invalid device: '%s'\n", optarg);
return -1;
}

mpm->device = strdup(optarg);
if (mpm->device == NULL) {
perror("strdup()");
return -1;
}
}
break;

case 'h':
case '?': /* error */
fprintf(stderr, "Usage: mpmboot [options]\n"
" -a <address> - selects mpm address (0x01 - 0xFF)\n"
" -d <device> - selects mpm device\n"
" -r <flash|eeprom>:<file> - reads flash/eeprom to file (.bin | .hex | -)\n"
" -w <flash|eeprom>:<file> - write flash/eeprom from file (.bin | .hex)\n"
" -n - disable verify after write\n"
" -p <0|1|2> - progress bar mode\n"
"\n"
"Example: mpmboot -d /dev/ttyUSB0 -a 0x22 -w flash:blmc.hex -w flash:blmc_eeprom.hex\n"
"\n");
return -1;

default:
return 1;
}

return 0;
}

static struct multiboot * mpm_alloc(void)
{
struct multiboot * mboot = malloc(sizeof(struct multiboot));
if (mboot == NULL)
return NULL;

memset(mboot, 0x00, sizeof(struct multiboot));
mboot->ops = &mpm_ops;

struct mpm_privdata *mpm = malloc(sizeof(struct mpm_privdata));
if (mpm == NULL) {
free(mboot);
return NULL;
}

memset(mpm, 0x00, sizeof(struct mpm_privdata));
mpm->device = NULL;
mpm->address = 0;

optarg_register(mpm_optargs, ARRAY_SIZE(mpm_optargs), mpm_optarg_cb, (void *)mpm);

mboot->privdata = mpm;
return mboot;
}

static void mpm_free(struct multiboot *mboot)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;

if (mpm->device != NULL)
free(mpm->device);

free(mpm);
free(mboot);
}

static int mpm_get_memtype(struct multiboot *mboot, const char *memname)
{
if (strcmp(memname, "flash") == 0)
return MEMTYPE_FLASH;

else if (strcmp(memname, "eeprom") == 0)
return MEMTYPE_EEPROM;

return -1;
}

static int mpm_get_memsize(struct multiboot *mboot, int memtype)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;

if (!mpm->connected)
return 0;

switch (memtype) {
case MEMTYPE_FLASH:
return mpm->flashsize;

case MEMTYPE_EEPROM:
return mpm->eepromsize;

default:
return 0;
}
}

static int mpm_send(struct mpm_privdata *mpm, uint8_t command, uint8_t *data, int length)
{
struct termios tio;

if (tcgetattr(mpm->fd, &tio) < 0) {
perror("tcgetattr(tio)");
return -1;
}

tio.c_cflag |= PARODD;

if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0) {
perror("tcsetattr(tio)");
return -1;
}

// usleep(5000);

uint8_t address = mpm->address;
if (write(mpm->fd, &address, sizeof(address)) != sizeof(address)) {
perror("write(address)");
return -1;
}

usleep(500);

tio.c_cflag &= ~(PARODD);

if (tcsetattr(mpm->fd, TCSAFLUSH, &tio) < 0) {
perror("tcsetattr(tio)");
return -1;
}

uint8_t header[3];
header[0] = command;
header[1] = (length >> 8) & 0xFF;
header[2] = length & 0xFF;

if (write(mpm->fd, header, sizeof(header)) != sizeof(header)) {
perror("write(header)");
return -1;
}

if (data != NULL && length != 0) {
if (write(mpm->fd, data, length) != length) {
perror("write(data)");
return -1;
}
}

return 0;
}

static int myread(int fd, void *data, int size)
{
int pos = 0;

while (1) {
fd_set fdset;
struct timeval timeout = { .tv_sec = 1, .tv_usec = 0 };

FD_ZERO(&fdset);
FD_SET(fd, &fdset);

int ret = select(fd +1, &fdset, NULL, NULL, &timeout);
if (ret == -1) {
perror("select");
return -1;

} else if (ret == 0) {
break;

} else if (FD_ISSET(fd, &fdset)) {
int len = read(fd, data + pos, size - pos);
if (len < 0) {
return -1;

} else {
pos += len;
if (pos == size) {
break;
}
}
}
}

return pos;
}

static int mpm_recv(struct mpm_privdata *mpm, uint8_t command, uint8_t *cause, uint8_t *buffer, uint16_t buffersize)
{
int len;
uint8_t header[4];

len = myread(mpm->fd, header, sizeof(header));
if (len != sizeof(header)) {
fprintf(stderr, "short read() from device (not addressed?)\n");
return -1;
}

if (header[0] != command) {
fprintf(stderr, "invalid command response (0x%02x != 0x%02x)\n", header[0], command);
return -1;
}

*cause = header[1];

uint16_t length = (header[2] << 8) | header[3];
// printf("mpm_recv() cmd=0x%02x cause=0x%02x length=0x%04x\n", command, *cause, length);

uint16_t bufferpos = 0;
while (length > 0) {

/* free space in output buffer? */
if ((bufferpos < buffersize) && (buffer != NULL)) {

uint16_t size = MIN(buffersize - bufferpos, length);
len = myread(mpm->fd, buffer + bufferpos, size);
if (len <= 0) {
fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
return -1;
}
bufferpos += len;
length -= len;

} else {
uint8_t dummy[256];

/* no space in output buffer, but device still sends data -> do dummy read */
uint16_t size = MIN(sizeof(dummy), length);
len = myread(mpm->fd, dummy, size);
if (len <= 0) {
fprintf(stderr, "short read() from device (%d != %d)\n", len, size);
return -1;
}
length -= len;
}
}

return bufferpos;
}

static void mpm_close_device(struct mpm_privdata *mpm)
{
/* delay close() / tcsetattr() */
usleep(100000);

tcsetattr(mpm->fd, TCSANOW, &mpm->oldtio);
close(mpm->fd);
}

static int mpm_open_device(struct mpm_privdata *mpm)
{
mpm->fd = open(mpm->device, O_RDWR | O_NOCTTY | O_CLOEXEC);
if (mpm->fd < 0) {
perror("open()");
return -1;
}

if (tcgetattr(mpm->fd, &mpm->oldtio) < 0) {
perror("tcgetattr(oldtio)");
close(mpm->fd);
return -1;
}

struct termios newtio;
memset(&newtio, 0, sizeof(newtio));

newtio.c_iflag |= IGNBRK;
newtio.c_cflag |= B115200 | CS8 | CLOCAL | CREAD | PARENB | CMSPAR;

newtio.c_cc[VMIN] = 1;
newtio.c_cc[VTIME] = 0;

int err = tcsetattr(mpm->fd, TCSANOW, &newtio);
if (err < 0) {
perror("tcsetattr(newtio)");
close(mpm->fd);
return -1;
}

mpm->connected = 1;
return 0;
}

static int mpm_switch_application(struct mpm_privdata *mpm, uint8_t application)
{
uint8_t data[] = { application };
int ret = mpm_send(mpm, CMD_SWITCH_APPLICATION, data, sizeof(data));
if (ret < 0)
return ret;

uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_SWITCH_APPLICATION, &cause, NULL, 0);
if (ret < 0)
return ret;

return (cause != CAUSE_SUCCESS);
}

static int mpm_read_version(struct mpm_privdata *mpm, uint8_t *version, uint16_t length)
{
memset(version, 0, length);

int ret = mpm_send(mpm, CMD_GET_BOOTLOADER_VERSION, NULL, 0);
if (ret < 0)
return ret;

uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_GET_BOOTLOADER_VERSION, &cause, version, length);
if (ret < 0)
return ret;

int i;
for (i = 0; i < length; i++)
version[i] &= ~0x80;

return (cause != CAUSE_SUCCESS);
}

static int mpm_read_chipinfo(struct mpm_privdata *mpm, uint8_t *chipinfo, uint16_t length)
{
int ret = mpm_send(mpm, CMD_GET_CHIP_INFO, NULL, 0);
if (ret < 0)
return ret;

uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_GET_CHIP_INFO, &cause, chipinfo, length);
if (ret < 0)
return ret;

return (cause != CAUSE_SUCCESS);
}

static int mpm_read_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address)
{
uint8_t param[5] = {
memtype,
(address >> 8) & 0xFF,
(address & 0xFF),
(size >> 8) & 0xFF,
(size & 0xFF)
};

int ret = mpm_send(mpm, CMD_READ_MEMORY, param, sizeof(param));
if (ret < 0)
return ret;

uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_READ_MEMORY, &cause, buffer, size);
if (ret < 0)
return ret;

return (cause != CAUSE_SUCCESS);
}

static int mpm_write_memory(struct mpm_privdata *mpm, uint8_t *buffer, uint16_t size, uint8_t memtype, uint16_t address)
{
int bufsize;
if (memtype == MEMTYPE_FLASH) {
if ((address & (mpm->flashpage -1)) != 0x00) {
fprintf(stderr, "mpm_write_memory(): address 0x%04x not aligned to pagesize 0x%02x\n", address, mpm->flashpage);
return -1;
}
bufsize = 5 + mpm->flashpage;

} else {
bufsize = 5 + size;
}

uint8_t *cmd = malloc(bufsize);
if (cmd == NULL)
return -1;

cmd[0] = memtype;
cmd[1] = (address >> 8) & 0xFF;
cmd[2] = (address & 0xFF);
cmd[3] = ((bufsize -5) >> 8) & 0xFF;
cmd[4] = ((bufsize -5) & 0xFF);
memcpy(cmd +5, buffer, size);

if (memtype == MEMTYPE_FLASH) {
memset(cmd +5 +size, 0xFF, mpm->flashpage - size);
}

int ret = mpm_send(mpm, CMD_WRITE_MEMORY, cmd, bufsize);
if (ret < 0)
return ret;

free(cmd);

uint8_t cause = CAUSE_SUCCESS;
ret = mpm_recv(mpm, CMD_WRITE_MEMORY, &cause, NULL, 0);
if (ret < 0)
return ret;

return (cause != CAUSE_SUCCESS);
}

static int mpm_close(struct multiboot *mboot)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;

if (mpm->connected)
mpm_switch_application(mpm, BOOTTYPE_APPLICATION);

mpm_close_device(mpm);
return 0;
}

static int mpm_open(struct multiboot *mboot)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;

if (mpm->address == 0) {
fprintf(stderr, "abort: no address given\n");
return -1;
}

if (mpm->device == NULL) {
fprintf(stderr, "abort: no device given\n");
return -1;
}

if (mpm_open_device(mpm) < 0)
return -1;

if (mpm_switch_application(mpm, BOOTTYPE_BOOTLOADER)) {
fprintf(stderr, "failed to switch to bootloader (invalid address?)\n");
mpm_close(mboot);
return -1;
}

/* wait for watchdog and startup time */
usleep(100000);

char version[16];
if (mpm_read_version(mpm, (uint8_t *)version, sizeof(version))) {
fprintf(stderr, "failed to get bootloader version");
mpm_close(mboot);
return -1;
}

uint8_t chipinfo[8];
if (mpm_read_chipinfo(mpm, chipinfo, sizeof(chipinfo))) {
fprintf(stderr, "failed to get bootloader version");
mpm_close(mboot);
return -1;
}

const char *chipname = chipinfo_get_avr_name(chipinfo);

mpm->flashpage = chipinfo[3];
mpm->flashsize = (chipinfo[4] << 8) + chipinfo[5];
mpm->eepromsize = (chipinfo[6] << 8) + chipinfo[7];

printf("device : %-16s (address: 0x%02X)\n", mpm->device, mpm->address);
printf("version : %-16s (sig: 0x%02x 0x%02x 0x%02x => %s)\n", version, chipinfo[0], chipinfo[1], chipinfo[2], chipname);
printf("flash size : 0x%04x / %5d (0x%02x bytes/page)\n", mpm->flashsize, mpm->flashsize, mpm->flashpage);
printf("eeprom size : 0x%04x / %5d\n", mpm->eepromsize, mpm->eepromsize);

return 0;
}

static int mpm_read(struct multiboot *mboot, struct databuf *dbuf, int memtype)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "reading flash" : "reading eeprom";

int pos = 0;
int size = (memtype == MEMTYPE_FLASH) ? mpm->flashsize : mpm->eepromsize;
while (pos < size) {
mboot->progress_cb(progress_msg, pos, size);

int len = MIN(READ_BLOCK_SIZE, size - pos);
if (mpm_read_memory(mpm, dbuf->data + pos, len, memtype, pos)) {
mboot->progress_cb(progress_msg, -1, -1);
return -1;
}

pos += len;
}

dbuf->length = pos;

mboot->progress_cb(progress_msg, pos, size);
return 0;
}

static int mpm_write(struct multiboot *mboot, struct databuf *dbuf, int memtype)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "writing flash" : "writing eeprom";

int pos = 0;
while (pos < dbuf->length) {
mboot->progress_cb(progress_msg, pos, dbuf->length);

int len = (memtype == MEMTYPE_FLASH) ? mpm->flashpage : WRITE_BLOCK_SIZE;

len = MIN(len, dbuf->length - pos);
if (mpm_write_memory(mpm, dbuf->data + pos, len, memtype, pos)) {
mboot->progress_cb(progress_msg, -1, -1);
return -1;
}

pos += len;
}

mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0;
}

static int mpm_verify(struct multiboot *mboot, struct databuf *dbuf, int memtype)
{
struct mpm_privdata *mpm = (struct mpm_privdata *)mboot->privdata;
char *progress_msg = (memtype == MEMTYPE_FLASH) ? "verifing flash" : "verifing eeprom";

int pos = 0;
uint8_t comp[READ_BLOCK_SIZE];
while (pos < dbuf->length) {
mboot->progress_cb(progress_msg, pos, dbuf->length);

int len = MIN(READ_BLOCK_SIZE, dbuf->length - pos);
if (mpm_read_memory(mpm, comp, len, memtype, pos)) {
mboot->progress_cb(progress_msg, -1, -1);
return -1;
}

if (memcmp(comp, dbuf->data + pos, len) != 0x00) {
mboot->progress_cb(progress_msg, -1, -1);
fprintf(stderr, "verify failed at page 0x%04x!!\n", pos);
return -1;
}

pos += len;
}

dbuf->length = pos;

mboot->progress_cb(progress_msg, pos, dbuf->length);
return 0;
}

struct multiboot_ops mpm_ops = {
.alloc = mpm_alloc,
.free = mpm_free,
.get_memtype = mpm_get_memtype,
.get_memsize = mpm_get_memsize,

.open = mpm_open,
.close = mpm_close,
.read = mpm_read,
.write = mpm_write,
.verify = mpm_verify,
};

+ 320
- 0
linux/multiboot.c View File

@@ -0,0 +1,320 @@
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <getopt.h>

#include "filedata.h"
#include "list.h"
#include "multiboot.h"
#include "optarg.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))

#define ACTION_READ 0x01
#define ACTION_WRITE 0x02

struct mboot_action {
struct list_head list;

char *filename;
int memtype;
int mode;
};

static LIST_HEAD(action_list);

static struct option main_optargs[] = {
{"help", 0, 0, 'h'}, /* [ -h ] */
{"progress", 1, 0, 'p'}, /* [ -p <0|1|2> ] */
{"read", 1, 0, 'r'}, /* [ -r <flash|eeprom>:<file.hex> ] */
{"write", 1, 0, 'w'}, /* [ -w <flash|eeprom>:<file.hex> ] */
{"no-verify", 0, 0, 'n'}, /* [ -n ] */
{0, 0, 0, 0}
};

static void progress_mode0_cb(const char *msg, int pos, int size)
{
/* no progress output */
}

static void progress_mode1_cb(const char *msg, int pos, int size)
{
if (pos != -1 && size != -1) {
char stars[50];

int i;
int count = (pos * sizeof(stars) / size);
for (i = 0; i < sizeof(stars); i++)
stars[i] = (i < count) ? '*' : ' ';

printf("%-15s: [%s] (%d)\r", msg, stars, pos);
}

if (pos == size)
printf("\n");
}

static void progress_mode2_cb(const char *msg, int pos, int size)
{
static int old_count;

if (pos != -1 && size != -1) {
if (pos == 0) {
old_count = 0;
printf("%-15s: [", msg);

} else if (pos <=size) {
int i;
int count = (pos * 50 / size);
for (i = old_count; i < count; i++)
printf("*");

old_count = count;

if (pos == size) {
printf("] (%d)\n", pos);
}
}
}
}

static int add_action(struct multiboot *mboot, int mode, const char *arg)
{
struct mboot_action *action = malloc(sizeof(struct mboot_action));
if (action == NULL) {
perror("malloc()");
return -1;
}

char *argcopy = strdup(arg);
if (argcopy == NULL) {
perror("strdup()");
free(action);
return -1;
}

char *tok = strtok(argcopy, ":");
if (tok == NULL) {
fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy);
free(action);
return -1;
}

action->memtype = mboot->ops->get_memtype(mboot, tok);
if (action->memtype == -1) {
fprintf(stderr, "invalid memtype: '%s'\n", tok);
free(argcopy);
free(action);
return -1;
}

tok = strtok(NULL, ":");
if (tok == NULL) {
fprintf(stderr, "invalid argument: '%s'\n", arg);
free(argcopy);
free(action);
return -1;
}

action->filename = strdup(tok);
if (action->filename == NULL) {
perror("strdup()");
free(argcopy);
free(action);
return -1;
}

action->mode = mode;

list_add_tail(&action->list, &action_list);
free(argcopy);
return 0;
}

static int main_optarg_cb(int val, const char *arg, void *privdata)
{
struct multiboot *mboot = (struct multiboot *)privdata;

switch (val) {
case 'r': /* read */
{
if (add_action(mboot, ACTION_READ, arg) < 0)
return -1;
}
break;

case 'w': /* write */
{
if (add_action(mboot, ACTION_WRITE, arg) < 0)
return -1;
}
break;

case 'n': /* no verify after write */
mboot->verify = 0;
break;

case 'p':
{
switch (*arg) {
case '0':
mboot->progress_cb = progress_mode0_cb;
break;

case '1':
mboot->progress_cb = progress_mode1_cb;
break;

case '2':
mboot->progress_cb = progress_mode2_cb;
break;

default:
fprintf(stderr, "invalid progress bar mode: '%s'\n", arg);
return -1;
}
}
break;
}

return 0;
}

int main(int argc, char *argv[])
{
struct multiboot *mboot;

char *progname = strrchr(argv[0], '/');
progname = (progname != NULL) ? (progname +1) : argv[0];

if (strcmp(progname, "twiboot") == 0) {
mboot = twi_ops.alloc();
} else if (strcmp(progname, "mpmboot") == 0) {
mboot = mpm_ops.alloc();
} else {
fprintf(stderr, "invalid progname, use 'twiboot' or 'mpmboot'\n");
return -1;
}

if (mboot == NULL)
return -1;

mboot->verify = 1;
mboot->progress_cb = progress_mode1_cb;

optarg_register(main_optargs, ARRAY_SIZE(main_optargs), main_optarg_cb, (void *)mboot);
int abort = optarg_parse(argc, argv);

if (abort == -1 || mboot->ops->open(mboot) != 0)
return -1;

setbuf(stdout, NULL);

struct mboot_action *action, *tmp;
list_for_each_entry(action, &action_list, list) {
abort = 1;
if (action->mode == ACTION_READ) {
int memsize = mboot->ops->get_memsize(mboot, action->memtype);
if (memsize == 0)
break;

struct databuf *dbuf = dbuf_alloc(memsize);
if (dbuf == NULL)
break;

int result = mboot->ops->read(mboot, dbuf, action->memtype);
if (result != 0) {
fprintf(stderr, "failed to read from device\n");
dbuf_free(dbuf);
break;
}

result = file_write(action->filename, dbuf);
if (result != 0) {
fprintf(stderr, "failed to write file '%s'\n", action->filename);
dbuf_free(dbuf);
break;
}

dbuf_free(dbuf);
abort = 0;

} else if (action->mode == ACTION_WRITE) {
unsigned int size;
int result;

result = file_getsize(action->filename, &size);
if (result != 0)
break;

struct databuf *dbuf = dbuf_alloc(size);
if (dbuf == NULL)
break;

result = file_read(action->filename, dbuf);
if (result != 0) {
fprintf(stderr, "failed to read file '%s'\n", action->filename);
dbuf_free(dbuf);
break;
}

int memsize = mboot->ops->get_memsize(mboot, action->memtype);
if (memsize == 0) {
fprintf(stderr, "invalid memsize: 0x%04x > 0x%04x\n", dbuf->length, memsize);
dbuf_free(dbuf);
break;
}

result = mboot->ops->write(mboot, dbuf, action->memtype);
if (result != 0) {
fprintf(stderr, "failed to write to device\n");
dbuf_free(dbuf);
break;
}

if (mboot->verify) {
result = mboot->ops->verify(mboot, dbuf, action->memtype);
if (result != 0) {
fprintf(stderr, "failed to verify\n");
dbuf_free(dbuf);
break;
}
}

dbuf_free(dbuf);
abort = 0;
}
}

list_for_each_entry_safe(action, tmp, &action_list, list) {
free(action->filename);
free(action);
}

mboot->ops->close(mboot);
mboot->ops->free(mboot);

optarg_free();
return abort;
}

+ 33
- 0
linux/multiboot.h View File

@@ -0,0 +1,33 @@
#ifndef _MULTIBOOT_H_
#define _MULTIBOOT_H_

#include <stdint.h>
#include "filedata.h"

struct multiboot {
struct multiboot_ops *ops;
void *privdata;

int verify;
void (* progress_cb)(const char *msg, int pos, int max);
};

struct multiboot_ops {
struct multiboot * (* alloc)(void);
void (* free)(struct multiboot *mboot);

int (* get_memtype)(struct multiboot *mboot, const char *memname);
int (* get_memsize)(struct multiboot *mboot, int memtype);

int (* open)(struct multiboot *mboot);
int (* close)(struct multiboot *mboot);

int (* read)(struct multiboot *mboot, struct databuf *dbuf, int memtype);
int (* verify)(struct multiboot *mboot, struct databuf *dbuf, int memtype);
int (* write)(struct multiboot *mboot, struct databuf *dbuf, int memtype);
};

extern struct multiboot_ops twi_ops;
extern struct multiboot_ops mpm_ops;

#endif /* _MULTIBOOT_H_ */

+ 193
- 0
linux/optarg.c View File

@@ -0,0 +1,193 @@
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <getopt.h>

#include "list.h"
#include "optarg.h"

#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))

struct optarg_entry {
struct list_head list;
const struct option *opts;
int count;

int (* parser_cb)(int val, const char *arg, void *privdata);
void *privdata;
};

static LIST_HEAD(option_list);

int optarg_register(const struct option *opts, int count,
int (* parser_cb)(int val, const char *arg, void *privdata),
void *privdata)
{
struct optarg_entry *entry;

entry = malloc(sizeof(struct optarg_entry));
if (entry == NULL)
return -1;

entry->opts = opts; /* TODO: copy? */
entry->count = count;
entry->parser_cb = parser_cb;
entry->privdata = privdata;

list_add_tail(&entry->list, &option_list);
return 0;
}

void optarg_free(void)
{
struct optarg_entry *entry, *entry_tmp;

list_for_each_entry_safe(entry, entry_tmp, &option_list, list) {
list_del(&entry->list);
free(entry);
}
}

static void optarg_getsize(int *opt_count, int *optstring_len)
{
int count = 0;
int length = 0;

struct optarg_entry *entry;

list_for_each_entry(entry, &option_list, list) {
count += entry->count;

int i;
for (i = 0; i < entry->count; i++) {
switch (entry->opts[i].has_arg) {
case 0: /* no arguments */
case 1: /* has argument */
case 2: /* optional argument */
length += entry->opts[i].has_arg +1;
break;
default:
break;
}
}
}

*opt_count = count +1;
*optstring_len = length +1;
}

static void optarg_copy(struct option *opts, char *optstring)
{
struct optarg_entry *entry;

list_for_each_entry(entry, &option_list, list) {
memcpy(opts, entry->opts, sizeof(struct option) * entry->count);
opts += entry->count;

int i;
for (i = 0; i < entry->count; i++) {
switch (entry->opts[i].has_arg) {
case 0: /* no arguments */
*optstring++ = (char)entry->opts[i].val;
break;

case 1: /* has argument */
*optstring++ = (char)entry->opts[i].val;
*optstring++ = ':';
break;

case 2: /* optional argument */
*optstring++ = (char)entry->opts[i].val;
*optstring++ = ':';
*optstring++ = ':';
break;

default:
break;
}
}
}

memset(opts++, 0x00, sizeof(struct option));
*optstring++ = '\0';
}

int optarg_parse(int argc, char * const argv[])
{
struct option *longopts;
char *optstring;

int opt_count;
int optstring_len;
optarg_getsize(&opt_count, &optstring_len);

longopts = malloc(sizeof(struct option) * opt_count);
if (longopts == NULL)
return -1;

optstring = malloc(optstring_len);
if (optstring == NULL) {
free(longopts);
return -1;
}

optarg_copy(longopts, optstring);

int retval = 0;
int val = 0;
while (val != -1 && retval == 0) {
opterr = 1; /* print error message to stderr */
val = getopt_long(argc, argv, optstring, longopts, NULL);

if (val == 0x00) /* variable assigned (not supported) */
continue;

struct optarg_entry *entry;
list_for_each_entry(entry, &option_list, list) {
int ret = entry->parser_cb(val, optarg, entry->privdata);

/* option recognized, with error */
if (ret < 0) {
retval = ret;
break;

/* option recognized, no error */
} else if (ret == 0) {
break;
}
}

if (val == -1) /* parsing completed */
break;

if (val == '?') { /* parsing error */
retval = 1;
break;
}
}

free(optstring);
free(longopts);

return retval;
}

+ 15
- 0
linux/optarg.h View File

@@ -0,0 +1,15 @@
#ifndef _OPTARG_H_
#define _OPTARG_H_

#include <getopt.h>

int optarg_register(const struct option *opts, int count,
int (* parser_cb)(int val, const char *arg, void *privdata),
void *privdata);


void optarg_free(void);

int optarg_parse(int argc, char * const argv[]);

#endif /* _OPTARG_H_ */

+ 2
- 0
linux/rules/99-i2c-tiny-usb.rules View File

@@ -0,0 +1,2 @@
SUBSYSTEM=="usb", ATTR{product}=="i2c-tiny-usb", RUN+="/sbin/modprobe -b i2c-dev"
SUBSYSTEM=="i2c-dev", DRIVERS=="i2c-tiny-usb", MODE="0660", GROUP="dialout"

+ 0
- 329
linux/twb.c View File

@@ -1,329 +0,0 @@
/***************************************************************************
* Copyright (C) 10/2010 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* 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 2 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, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>

#include <linux/i2c.h>
#include <linux/i2c-dev.h>

#include "filedata.h"
#include "list.h"
#include "twb.h"

#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*x))

#define READ_BLOCK_SIZE 128 /* bytes in one flash/eeprom read request */
#define WRITE_BLOCK_SIZE 16 /* bytes in one eeprom write request */

/* SLA+R */
#define CMD_WAIT 0x00
#define CMD_READ_VERSION 0x01
#define CMD_READ_MEMORY 0x02

/* SLA+W */
#define CMD_SWITCH_APPLICATION CMD_READ_VERSION
#define CMD_WRITE_MEMORY CMD_READ_MEMORY

/* CMD_SWITCH_APPLICATION parameter */
#define BOOTTYPE_BOOTLOADER 0x00 /* only in APP */
#define BOOTTYPE_APPLICATION 0x80

/* CMD_{READ|WRITE}_* parameter */
#define MEMTYPE_CHIPINFO 0x00
#define MEMTYPE_FLASH 0x01
#define MEMTYPE_EEPROM 0x02
#define MEMTYPE_PARAMETERS 0x03 /* only in APP */

struct chipinfo {
uint8_t sig[3];
const char name[16];
};

static struct chipinfo chips[] = {
{ { 0x1E, 0x93, 0x07 }, "AVR Mega 8" },
{ { 0x1E, 0x93, 0x0A }, "AVR Mega 88" },
{ { 0x1E, 0x94, 0x06 }, "AVR Mega 168" },
};

static const char * twb_get_chipname(uint8_t *sig)
{
int i;
for (i = 0; i < ARRAY_SIZE(chips); i++) {
struct chipinfo *chip = &chips[i];
if (chip->sig[0] == sig[0] && chip->sig[1] == sig[1] && chip->sig[2] == sig[2])
return chip->name;