Skip to content
Snippets Groups Projects
Commit 87496550 authored by Norman Stetter's avatar Norman Stetter
Browse files

bootselect: pull in bootselect from yocto rocko

* Pull in bootselect recipe and source from rocko
  272d10683433807afc0fcb485a534e6801398cb0
* Add bootselect to guf-image
parent 76ffcd9e
No related branches found
No related tags found
1 merge request!3Add bootselect
...@@ -18,6 +18,10 @@ IMAGE_FEATURES += " \ ...@@ -18,6 +18,10 @@ IMAGE_FEATURES += " \
tools-debug \ tools-debug \
" "
IMAGE_INSTALL_BASE += " \
bootselect \
"
IMAGE_INSTALL_GRAPHICS += " \ IMAGE_INSTALL_GRAPHICS += " \
freetype \ freetype \
fontconfig \ fontconfig \
...@@ -100,6 +104,7 @@ IMAGE_INSTALL_TEST +=" \ ...@@ -100,6 +104,7 @@ IMAGE_INSTALL_TEST +=" \
" "
CORE_IMAGE_EXTRA_INSTALL += " \ CORE_IMAGE_EXTRA_INSTALL += " \
${IMAGE_INSTALL_BASE} \
${IMAGE_INSTALL_GRAPHICS} \ ${IMAGE_INSTALL_GRAPHICS} \
${IMAGE_INSTALL_GUF} \ ${IMAGE_INSTALL_GUF} \
${IMAGE_INSTALL_MULTIMEDIA} \ ${IMAGE_INSTALL_MULTIMEDIA} \
......
SUMMARY = "Garz & Fricke bootselect tool to switch boot mode between FNGSystem and normal OS"
require conf/guf-recipe.inc
FILESEXTRAPATHS_prepend := "${THISDIR}:"
SRC_URI = "file://bootselect"
S = "${WORKDIR}/bootselect"
PR = "r0"
CFLAGS += " -Wall -Werror -std=c99 -O2"
do_install () {
install -d ${D}${bindir}
install -m 0755 bootselect ${D}${bindir}
}
CFLAGS += -Wall -Werror -std=c99 -O2
all: bootselect
bootselect: bootselect.o
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
clean:
rm -f bootselect *.o *~ *.bak
#include <stdio.h>
#include<stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <strings.h>
#include <stdarg.h>
#include <stdbool.h>
#include <sys/ioctl.h>
#ifdef ANDROID
#include <linux/i2c.h>
#else
#include <linux/i2c-dev.h>
#endif
//=======================================================================================
// Debug
//=======================================================================================
enum{ QUIET, ERROR, DEBUG, VERBOSE };
static int verbosity = ERROR;
#define pr(level, ...) do{ \
if(level <= verbosity){ \
if(verbosity == VERBOSE){ \
fprintf(stderr, "%20s %4d %8s: ", __func__, __LINE__, \
level==ERROR?"Error":level==DEBUG?"Debug":"" ); \
} \
fprintf( stderr, __VA_ARGS__);\
}}while(false)
enum { OPTIONS_READ = -1, OPTIONS_USAGE = -2 };
//=======================================================================================
//== RTC Struct Bootselect specific
//=======================================================================================
struct rtc_device{
const struct rtc_type * d;
int fd;
int bus;
char * path;
};
/* Searchpath in sysfs */
static const char * sysfs_path[] = {
"/sys/class/i2c-adapter/i2c-%d/%d-%04X",
"/sys/class/i2c-dev/i2c-%d/device/%d-%04X",
0
};
/* The highest i2c bus number to scan */
#define I2C_RTC_MAX_BUS_ID 3
/* The naming pattern for the device node to access to i2c bus */
#define I2C_DEVICE_PATH "/dev/i2c-%d"
//=======================================================================================
// Glue macros to handle different i2c apis
//=======================================================================================
static int i2c_read(int fd, char reg, unsigned char * const value);
static int i2c_write(int fd, char reg, const unsigned char * const value);
#define I2C_READ( rtc, reg, value) i2c_read(rtc->fd, reg, value)
#define I2C_WRITE( rtc, reg, value) i2c_write(rtc->fd, reg, value)
//=======================================================================================
//==== Generic stuff, shared between FNG Boot and bootselect ============================
//=======================================================================================
//== Bootmode definitions ================================================================
//=======================================================================================
#define BOOTCFG_A 0
#define BOOTCFG_B 1
#define BOOTCFG_ALT 2
//=======================================================================================
// PCF RV
// init 0x03 0x00
// alt 0x01 0x10
// reg 0x02 0x20
// one 0x00 0x30
//
//=======================================================================================
#define BOOTMODES /* Boottarget: */ \
/* Macro, No/ID, Default Fallback 1 Fallback 2 Next Mode (for one shots), PCF Mapping, name shortname help for bootselect, */ \
X( BOOTMODE_INITIALIZED, 0, BOOTCFG_A, BOOTCFG_B, BOOTCFG_ALT , 0, 0x03, "initialized", 0, "Initialized" ) \
X( BOOTMODE_ALTERNATIVE, 1, BOOTCFG_ALT, BOOTCFG_A, BOOTCFG_B , 0, 0x01, "alternative", 0, "Alternative (Flash-N-Go System) " ) \
X( BOOTMODE_REGULAR_A, 2, BOOTCFG_A, BOOTCFG_ALT, BOOTCFG_B , 0, 0x02, "regular", "regA", "Regular (A) " ) \
X( BOOTMODE_ONESHOT_ALT, 3, BOOTCFG_A, BOOTCFG_ALT, BOOTCFG_B , BOOTMODE_ALTERNATIVE, 0x00, "oneshot", 0, "Oneshot, Boot A, next Boot Alternative " ) \
X( BOOTMODE_REGULAR_B, 4, BOOTCFG_B, BOOTCFG_ALT, BOOTCFG_A , 0, 0x04, "regularB", "regB", "Regular (B) " ) \
X( BOOTMODE_ONESHOT_A, 5, BOOTCFG_A, BOOTCFG_B, BOOTCFG_ALT , BOOTMODE_REGULAR_B, 0x05, "oneshotA", "oneA", "OneShotA, Boot A, next Boot B " ) \
X( BOOTMODE_ONESHOT_B, 6, BOOTCFG_B, BOOTCFG_A, BOOTCFG_ALT , BOOTMODE_REGULAR_A, 0x06, "oneshotB", "oneB", "OneShotB, Boot B, next Boot A " ) \
#define X( mname, id, def, fallback1, fallback2, nextmode, map, name, shortname, help ) mname=id,
enum bootmode { RTC_READ_ERROR=-1, BOOTMODES BOOTMODE_CNT };
#undef X
//=======================================================================================
//== Known and supported rtc variants ===================================================
//=======================================================================================
struct rtc_type;
struct rtc_device;
struct rtc_type{
char * name;
unsigned char address;
enum bootmode (*bootmode_read)( const struct rtc_device * );
unsigned int (*bootmode_write)( const struct rtc_device *, enum bootmode mode);
};
static enum bootmode bootmode_read_pcf8563( const struct rtc_device * rtc );
static unsigned int bootmode_write_pcf8563( const struct rtc_device * rtc, enum bootmode mode);
static enum bootmode bootmode_read_rv8803( const struct rtc_device * rtc );
static unsigned int bootmode_write_rv8803( const struct rtc_device * rtc, enum bootmode mode);
/* Known RTCs with name, address and access functions */
const static struct rtc_type rtc_types[] = {
{ "pcf8563", 0x51, bootmode_read_pcf8563, bootmode_write_pcf8563 },
{ "rv8803", 0x32, bootmode_read_rv8803, bootmode_write_rv8803 },
{ 0 }
};
//=======================================================================================
// PCF8563 access functions, default RTC on mode G&F devices
//=======================================================================================
#define RTC_REG1_PFC8563 0x0E /* Boot CFG Bit 0 and 1 are in Timer_control TD[1:0] */
#define RTC_REG2_PFC8563 0x01 /* Boot CFG Bit 2 is in Control_status_2 TIE */
#define X( mname, id, def, fallback1, fallback2, nextmode, map, name, shortname, help ) [id] = map,
static const enum bootmode pcf8563_mapping[BOOTMODE_CNT]= { BOOTMODES };
#undef X
#define X( mname, id, def, fallback1, fallback2, nextmode, map, name, shortname, help ) [map] = id,
static const unsigned char pcf8563_mappingreverse[BOOTMODE_CNT]= { BOOTMODES };
#undef X
static enum bootmode bootmode_read_pcf8563( const struct rtc_device * rtc )
{
unsigned char value, index;
enum bootmode mode = BOOTMODE_INITIALIZED;
if(I2C_READ(rtc, RTC_REG1_PFC8563, &value)) return RTC_READ_ERROR;
index = value & 0x03;
if(I2C_READ(rtc, RTC_REG2_PFC8563, &value)) return RTC_READ_ERROR;
index |= (value & 0x1 ) << 2;
if ( index > BOOTMODE_CNT ) return BOOTMODE_INITIALIZED;
mode = pcf8563_mapping[index];
return mode;
}
static unsigned int bootmode_write_pcf8563( const struct rtc_device * rtc, enum bootmode mode)
{
int ret = 0;
unsigned char value, v;
// write mode
if ( mode > BOOTMODE_CNT ) mode = BOOTMODE_INITIALIZED;
value = pcf8563_mappingreverse[mode];
v = value & 0x3;
I2C_WRITE(rtc, RTC_REG1_PFC8563, &v );
// Read-Modify-Write access to TIE bit
v = (value >> 2) & 0x1;
I2C_READ(rtc, RTC_REG2_PFC8563, &value);
value = ( value & 0x1e ) | v;
I2C_WRITE(rtc, RTC_REG2_PFC8563, &value );
return ret;
}
//=======================================================================================
// RV8803 access functions, default RTC on some devices, option for most G&F devices
//=======================================================================================
#define RTC_REG1_RV8803 0x0c // Timer Counter 1 Register has 4 General Purpose bits, that reset to 0.
// We Use GP2, GP3 and GP4 for the bootmode
static enum bootmode bootmode_read_rv8803( const struct rtc_device * rtc )
{
unsigned char value;
enum bootmode mode = BOOTMODE_INITIALIZED;
if( I2C_READ(rtc, RTC_REG1_RV8803, &value) ) return RTC_READ_ERROR;
mode = (value >> 4 ) & 0x07;
return mode;
}
static unsigned int bootmode_write_rv8803( const struct rtc_device * rtc, enum bootmode mode)
{
int ret = 0;
unsigned char value;
// write mode
value = (mode & 0x07) << 4;
I2C_WRITE(rtc, RTC_REG1_RV8803, &value );
return ret;
}
//=======================================================================================
//== Bootmode variabels, bootselect specific
//=======================================================================================
#define X( mname, id, def, fallback1, fallback2, nextmode, map, name, shortname, help ) [id] = { name, shortname },
const char * bootmode_names[][2] = { BOOTMODES };
#undef X
#define X( mname, id, def, fallback1, fallback2, nextmode, map, name, shortname, help ) [id] = help,
const char * bootmode_help[] = { BOOTMODES };
#undef X
//=======================================================================================
// I2C access functions
//=======================================================================================
static int i2c_read(int fd, char reg, unsigned char * const value)
{
if( write(fd, &reg, 1) !=1 ) {
pr(ERROR, "Failed to write i2c address: %d\n", errno );
return -1;
}
if(read(fd, value, 1) !=1 ) {
pr(ERROR, "Failed read i2c register 0x%02X: %d\n", reg, errno );
return -1;
}
pr(DEBUG, "Read 0x%02X from register 0x%02X\n", *value, reg);
return 0;
}
static int i2c_write(int fd, char reg, const unsigned char * const value)
{
char buf[2];
buf[0] = reg;
buf[1] = * value;
if(write(fd, buf, 2) != 2) {
pr(ERROR, "Failed to write to i2c register 0x%02X: %d\n", reg, errno );
return -1;
}
pr(DEBUG, "Wrote 0x%02X to register 0x%02X\n", *value, reg);
return 0;
}
//=======================================================================================
// Parameter parsing and usage and debug
//=======================================================================================
void print_usage() {
if(verbosity <= ERROR)
return;
printf("Usage: bootselect [-qv] [<bootmode>]\n");
printf("\n");
printf("When called without parameters, bootselect reads the\n");
printf("current boot-mode setting from the RTC-register\n");
printf("\n");
printf("Options:\n");
printf(" <bootmode> Writes the given boot-mode into the RTC-register\n");
printf(" May be one of:\n");
for( int i = 0; i < BOOTMODE_CNT; i++ ){
if( bootmode_names[i][1]){
printf(" %s, %s: %s\n", bootmode_names[i][0], bootmode_names[i][1], bootmode_help[i] );
}else{
printf(" %s: %s\n", bootmode_names[i][0], bootmode_help[i] );
}
}
printf(" -v More verbose output, repeat for even more verbose output\n");
printf(" -q Quiet\n");
}
int parse_options(int argc, char** argv)
{
unsigned int i, j, k, len, argl;
const char * mode, * arg;
int bootmode = OPTIONS_READ;
for( i = 1; i < argc; i++)
{
arg = argv[i];
if ( arg[0] == '-' ){
while(*(++arg)) {
switch( *arg ){
case 'q': verbosity--; break;
case 'v': verbosity++; break;
default: print_usage(); return OPTIONS_USAGE;
}
}
}else{
// Parse mode
argl = strlen(arg);
j=0;
while( bootmode == -1 && j < BOOTMODE_CNT ){
for( k = 0; k < 2; k++ ){
mode = bootmode_names[j][k];
if ( 0 == mode ) continue;
len = strlen(mode);
// if the argument is regularB, we don't want to match regular
if( len < argl ) continue;
if( strncasecmp(arg, mode, argl) == 0) {
bootmode = j;
break;
}
}
j++;
}
}
}
return bootmode;
}
//========================================================
//=== Helper functions
//========================================================
static inline bool dir_exist(const char * const d)
{
struct stat sb;
return stat(d, &sb) == 0 && S_ISDIR(sb.st_mode);
}
static inline bool file_is_chardev(char * f)
{
struct stat sb;
return stat(f, &sb) == 0 && S_ISCHR(sb.st_mode);
}
//========================================================
// RTC Dectect, open and close
//========================================================
void rtc_device_free(struct rtc_device * d)
{
if(!d) return;
if( d->path){
free(d->path);
}
free(d);
return;
}
struct rtc_device * rtc_device_create(const struct rtc_type * r, const char * const path )
{
struct rtc_device * d = 0;
d = calloc( 1, sizeof(struct rtc_device));
if(!d) goto error;
d->d = r;
d->path = calloc(strlen(path) + 1, sizeof(char));
if(!d->path) goto error;
strcpy(d->path, path);
return d;
error:
rtc_device_free(d);
pr(ERROR,"Failed to allocate memory for the rtc struct\n");
return NULL;
}
struct rtc_device * rtc_find_sysfs_path(void)
{
#define PATH_LEN 256
char path[PATH_LEN];
char name[PATH_LEN] = {0};
int ret;
const char ** p = sysfs_path;
do{
const struct rtc_type *r = rtc_types;
do{
for( int bus = 0; bus < I2C_RTC_MAX_BUS_ID; bus ++ ){
snprintf(path, PATH_LEN, *p, bus, bus, r->address);
if( dir_exist( path )){
pr(DEBUG, "Found sysfs path: '%s'.\n",path);
// Read the 'name' file from sysfs and compare with the expected one
strncat(path, "/name", PATH_LEN);
int fd_sysfs = open( path, O_RDONLY);
if(fd_sysfs < 0) {
pr(ERROR, "Failed to open: '%s'\n", path);
continue;
}
ret = read(fd_sysfs, name, PATH_LEN);
close(fd_sysfs);
if( ret <= 0){
pr(ERROR, "Failed to read name from '%s': %d\n", path, errno );
continue;
}
// strip newline from 'name' file
if( name[strlen(name) - 1] == '\n' )name[strlen(name) - 1] = 0;
// compare with the know makes
if( 0 != strcmp(r->name, name)){
pr(ERROR, "RTC on '%s', is unknown ( expected: '%s', but found: '%s' )\n", path, r->name, name );
continue;
}
// Check if the device node exists
snprintf(path, PATH_LEN, I2C_DEVICE_PATH, bus );
if( ! file_is_chardev(path) ){
pr(ERROR, "Found RTC in sysfs but, device node '%s' is not a character device\n", path);
continue;
}
return rtc_device_create(r, path);
}else{
pr(DEBUG, "'%s' does not exist.\n",path);
}
}
}while( NULL != (++r)->name );
}while( NULL != *(++p) );
pr(ERROR, "Failed to find rtc sysfs path\n");
errno = ENOENT; // No such file or directory
return NULL;
}
void rtc_close(struct rtc_device * rtc)
{
pr(DEBUG, "Closing rtc at path: '%s' address 0x%02X.\n",rtc->path, rtc->d->address);
close(rtc->fd);
rtc_device_free(rtc);
}
struct rtc_device * rtc_open(void)
{
int fd;
int ret = 0;
struct rtc_device * rtc;
// Search for the path in the sysfs
rtc = rtc_find_sysfs_path();
if(!rtc) goto error1;
pr(DEBUG, "Opening i2c-bus on '%s' address: 0x%02x\n", rtc->path, rtc->d->address);
fd = open(rtc->path, O_RDWR);
if( fd < 0){
pr(ERROR, "Failed to open i2c-bus on '%s': %d\n", rtc->path, errno );
goto error2;
}
//NOTE: We need to use I2C_SLAVE_FORCE since the kernel's
// RTC-Driver has claimed the i2c-device. This is save
// because the driver does not use the register we are
// interested in.
pr(DEBUG, "Force slave access to address 0x%02x\n", rtc->d->address);
ret = ioctl(fd, I2C_SLAVE_FORCE, rtc->d->address);
if( ret < 0 )
{
pr(ERROR, "Force slave address in i2c-bus '%s' to 0x%02X failed: %d\n", rtc->path, rtc->d->address, errno );
goto error3;
}
rtc->fd = fd;
return rtc;
error3:
close(rtc->fd);
error2:
rtc_device_free(rtc);
error1:
return NULL;
}
//========================================================
// Main
//========================================================
void print_mode(int mode)
{
printf("%s\n", bootmode_names[mode][0] );
}
int main(int argc, char** argv)
{
int bootmode = -1;
struct rtc_device * rtc;
bootmode = parse_options(argc, argv);
if ( bootmode == OPTIONS_USAGE ) return -1;
rtc = rtc_open();
if( !rtc ) return errno;
pr(DEBUG, "Opened device '%s'\n", rtc->path );
if ( bootmode == -1 ){
pr(DEBUG, "Reading bootmode from device '%s'\n", rtc->path );
// Read and print current mode
bootmode = rtc->d->bootmode_read( rtc);
if( bootmode >= 0 && bootmode < BOOTMODE_CNT )
print_mode(bootmode);
else
pr(ERROR, "Invalid boot mode %d\n",bootmode);
}else{
pr(DEBUG, "Writing bootmode %d (%s) to device '%s'\n",bootmode, bootmode_names[bootmode][0], rtc->path );
// Write new mode to rtc
rtc->d->bootmode_write( rtc, bootmode);
// Verify
enum bootmode mode = rtc->d->bootmode_read( rtc );
if( bootmode == mode )
print_mode(bootmode);
else
pr(ERROR,"Failed to write bootmode %d to RTC: %d\n", bootmode, mode );
}
rtc_close(rtc);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment