initial
This commit is contained in:
commit
984d8f39dc
38
Makefile
Normal file
38
Makefile
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
##
|
||||||
|
## Makefile for smctool
|
||||||
|
##
|
||||||
|
## Copyright (C) 2019 Evgeny Zinoviev <me@ch1p.io>
|
||||||
|
##
|
||||||
|
## 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.
|
||||||
|
##
|
||||||
|
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -O2 -Wall -W
|
||||||
|
PROGRAM = smctool
|
||||||
|
INSTALL = /usr/bin/env install
|
||||||
|
PREFIX = /usr/local
|
||||||
|
|
||||||
|
all: $(PROGRAM)
|
||||||
|
|
||||||
|
$(PROGRAM): smc.o smctool.o
|
||||||
|
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
install: $(PROGRAM)
|
||||||
|
$(INSTALL) $(PROGRAM) $(PREFIX)/sbin
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f *.o $(PROGRAM)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
$(CC) $(CFLAGS) -c $^ -I. -o $@
|
||||||
|
|
||||||
|
.PHONY: all install clean distclean
|
45
README.md
Normal file
45
README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# smctool
|
||||||
|
|
||||||
|
A Linux userspace tool to read Apple SMC keys. Supports various data types and output formats.
|
||||||
|
This tool is a part of the coreboot project.
|
||||||
|
|
||||||
|
### Usage
|
||||||
|
|
||||||
|
##### Main options
|
||||||
|
|
||||||
|
```
|
||||||
|
-h, --help: print help
|
||||||
|
-k, --key <name>: key name
|
||||||
|
-t, --type <type>: data type, see below
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Output format options:
|
||||||
|
```
|
||||||
|
--output-hex: print value as a hexadecimal number
|
||||||
|
--output-bin: print binary representation
|
||||||
|
```
|
||||||
|
|
||||||
|
##### Supported data types
|
||||||
|
`ui8`, `ui16`, `ui32`, `si8`, `si16`, `flag`, `fpXY`, `spXY`
|
||||||
|
|
||||||
|
**fp** and **sp** are unsigned and signed fixed point data types respectively.
|
||||||
|
The `X` in **fp** and **sp** data types is integer bits count and `Y` is fraction bits count.
|
||||||
|
|
||||||
|
For example: `fpe2` means 14 integer bits, 2 fraction bits, `sp78` means 7 integer bits, 8 fraction bits (and one sign bit).
|
||||||
|
|
||||||
|
### Examples
|
||||||
|
|
||||||
|
Reading battery level:
|
||||||
|
```
|
||||||
|
smctool -k B0FC -t ui16 # returns Full Capacity of Battery 0
|
||||||
|
smctool -k B0RM -t ui16 # returns Remaining Capacity of Batery 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Reading fan speed:
|
||||||
|
```
|
||||||
|
smctool -k F0Ac -t fpe2
|
||||||
|
```
|
||||||
|
|
||||||
|
### License
|
||||||
|
|
||||||
|
GPLv2
|
156
smc.c
Normal file
156
smc.c
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Evgeny Zinoviev <me@ch1p.io>
|
||||||
|
*
|
||||||
|
* SMC interacting code is based on applesmc linux driver by:
|
||||||
|
* Copyright (C) 2007 Nicolas Boichat <nicolas@boichat.ch>
|
||||||
|
* Copyright (C) 2010 Henrik Rydberg <rydberg@euromail.se>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/io.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "smc.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* wait_read - Wait for a byte to appear on SMC port. Callers must
|
||||||
|
* hold applesmc_lock.
|
||||||
|
*/
|
||||||
|
int wait_read(void)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int us;
|
||||||
|
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
|
||||||
|
usleep(us);
|
||||||
|
status = inb(APPLESMC_CMD_PORT);
|
||||||
|
|
||||||
|
/* read: wait for smc to settle */
|
||||||
|
if (status & 0x01)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s() fail: 0x%02x\n", __func__, status);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send_byte - Write to SMC port, retrying when necessary. Callers
|
||||||
|
* must hold applesmc_lock.
|
||||||
|
*/
|
||||||
|
int send_byte(uint8_t cmd, uint16_t port)
|
||||||
|
{
|
||||||
|
uint8_t status;
|
||||||
|
int us;
|
||||||
|
|
||||||
|
outb(cmd, port);
|
||||||
|
for (us = APPLESMC_MIN_WAIT; us < APPLESMC_MAX_WAIT; us <<= 1) {
|
||||||
|
usleep(us);
|
||||||
|
status = inb(APPLESMC_CMD_PORT);
|
||||||
|
/* write: wait for smc to settle */
|
||||||
|
if (status & 0x02)
|
||||||
|
continue;
|
||||||
|
/* ready: cmd accepted, return */
|
||||||
|
if (status & 0x04)
|
||||||
|
return 0;
|
||||||
|
/* timeout: give up */
|
||||||
|
if (us << 1 == APPLESMC_MAX_WAIT)
|
||||||
|
break;
|
||||||
|
/* busy: long wait and resend */
|
||||||
|
usleep(APPLESMC_RETRY_WAIT);
|
||||||
|
outb(cmd, port);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "%s(0x%02x, 0x%04x) fail: 0x%02x\n",
|
||||||
|
__func__, cmd, port, status);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_command(uint8_t cmd)
|
||||||
|
{
|
||||||
|
return send_byte(cmd, APPLESMC_CMD_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int send_argument(const char *key)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++)
|
||||||
|
if (send_byte(key[i], APPLESMC_DATA_PORT))
|
||||||
|
return -EIO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_smc(uint8_t cmd, const char *key, uint8_t *buffer, uint8_t len)
|
||||||
|
{
|
||||||
|
uint8_t status, data = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (send_command(cmd) || send_argument(key)) {
|
||||||
|
fprintf(stderr, "%.4s: read arg fail\n", key);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This has no effect on newer (2012) SMCs */
|
||||||
|
if (send_byte(len, APPLESMC_DATA_PORT)) {
|
||||||
|
fprintf(stderr, "%.4s: read len fail\n", key);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (wait_read()) {
|
||||||
|
fprintf(stderr, "%.4s: read data[%d] fail\n", key, i);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
buffer[i] = inb(APPLESMC_DATA_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the data port until bit0 is cleared */
|
||||||
|
for (i = 0; i < 16; i++) {
|
||||||
|
usleep(APPLESMC_MIN_WAIT);
|
||||||
|
status = inb(APPLESMC_CMD_PORT);
|
||||||
|
if (!(status & 0x01))
|
||||||
|
break;
|
||||||
|
data = inb(APPLESMC_DATA_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i)
|
||||||
|
fprintf(stderr, "flushed %d bytes, last value is: %d\n",
|
||||||
|
i, data);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_smc(uint8_t cmd, const char *key, const uint8_t *buffer, uint8_t len)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (send_command(cmd) || send_argument(key)) {
|
||||||
|
fprintf(stderr, "%s: write arg fail\n", key);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (send_byte(len, APPLESMC_DATA_PORT)) {
|
||||||
|
fprintf(stderr, "%.4s: write len fail\n", key);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
if (send_byte(buffer[i], APPLESMC_DATA_PORT)) {
|
||||||
|
fprintf(stderr, "%s: write data fail\n", key);
|
||||||
|
return -EIO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
45
smc.h
Normal file
45
smc.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Evgeny Zinoviev <me@ch1p.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SMC_H
|
||||||
|
#define SMC_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/* data port used by Apple SMC */
|
||||||
|
#define APPLESMC_DATA_PORT 0x300
|
||||||
|
/* command/status port used by Apple SMC */
|
||||||
|
#define APPLESMC_CMD_PORT 0x304
|
||||||
|
|
||||||
|
#define APPLESMC_MAX_DATA_LENGTH 32
|
||||||
|
|
||||||
|
/* wait up to 128 ms for a status change. */
|
||||||
|
#define APPLESMC_MIN_WAIT 0x0010
|
||||||
|
#define APPLESMC_RETRY_WAIT 0x0100
|
||||||
|
#define APPLESMC_MAX_WAIT 0x20000
|
||||||
|
|
||||||
|
#define APPLESMC_READ_CMD 0x10
|
||||||
|
#define APPLESMC_WRITE_CMD 0x11
|
||||||
|
|
||||||
|
int wait_read(void);
|
||||||
|
int send_byte(uint8_t cmd, uint16_t port);
|
||||||
|
int send_command(uint8_t cmd);
|
||||||
|
int send_argument(const char *key);
|
||||||
|
int read_smc(uint8_t cmd, const char *key, uint8_t *buffer, uint8_t len);
|
||||||
|
int write_smc(uint8_t cmd, const char *key, const uint8_t *buffer, uint8_t len);
|
||||||
|
|
||||||
|
#endif /* SMC_H */
|
298
smctool.c
Normal file
298
smctool.c
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of the coreboot project.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 Evgeny Zinoviev <me@ch1p.io>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <sys/io.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "smc.h"
|
||||||
|
#include "smctool.h"
|
||||||
|
|
||||||
|
static bool fp_bits(char c, uint8_t *dest)
|
||||||
|
{
|
||||||
|
if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
|
||||||
|
*dest = strtol(&c, NULL, 16);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_bits(uint8_t len, uint8_t *ptr)
|
||||||
|
{
|
||||||
|
for (int i = len - 1; i >= 0; i--) {
|
||||||
|
for (int j = 7; j >= 0; j--)
|
||||||
|
printf("%u", (ptr[i] >> j) & 1);
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_usage(const char *name)
|
||||||
|
{
|
||||||
|
printf("usage: %s <options>\n", name);
|
||||||
|
printf("\n"
|
||||||
|
"Options:\n"
|
||||||
|
" -h, --help: print this help\n"
|
||||||
|
" -k, --key <name>: key name\n"
|
||||||
|
" -t, --type <type>: data type, see below\n"
|
||||||
|
" --output-hex\n"
|
||||||
|
" --output-bin\n"
|
||||||
|
"\n"
|
||||||
|
"Supported data types:\n"
|
||||||
|
" ui8, ui16, ui32, si8, si16, flag, fpXY, spXY\n"
|
||||||
|
"\n"
|
||||||
|
" fp and sp are unsigned and signed fixed point\n"
|
||||||
|
" data types respectively.\n"
|
||||||
|
"\n"
|
||||||
|
" The X in fp and sp data types is integer bits count\n"
|
||||||
|
" and Y is fraction bits count.\n"
|
||||||
|
"\n"
|
||||||
|
" For example,\n"
|
||||||
|
" fpe2 means 14 integer bits, 2 fraction bits,\n"
|
||||||
|
" sp78 means 7 integer bits, 8 fraction bits\n"
|
||||||
|
" (and one sign bit).\n"
|
||||||
|
"\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
enum output_format {dec, hex, bin};
|
||||||
|
|
||||||
|
enum smctype {none, ui8, ui16, ui32, si8, si16, flag, fp, sp};
|
||||||
|
struct {
|
||||||
|
enum smctype type;
|
||||||
|
uint8_t len;
|
||||||
|
char *str;
|
||||||
|
char *decfmt;
|
||||||
|
char *hexfmt;
|
||||||
|
} types[] = {
|
||||||
|
{ui8, 1, "ui8", "%u", "0x%02x"},
|
||||||
|
{ui16, 2, "ui16", "%u", "0x%04x"},
|
||||||
|
{ui32, 4, "ui32", "%u", "0x%08x"},
|
||||||
|
{si8, 1, "si8", "%d", "0x%02x"},
|
||||||
|
{si16, 2, "si16", "%d", "0x%04x"},
|
||||||
|
{flag, 1, "flag", "%u", "0x%01x"},
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
bool show_help = false;
|
||||||
|
int opt, option_index = 0;
|
||||||
|
char name[KEYBUFSIZE+1] = {0};
|
||||||
|
char typebuf[KEYBUFSIZE+1] = {0};
|
||||||
|
uint8_t fp_int_bits = 0, fp_fraction_bits = 0;
|
||||||
|
|
||||||
|
enum output_format of = dec;
|
||||||
|
char *ofmt = NULL;
|
||||||
|
char fmtbuf[32];
|
||||||
|
|
||||||
|
enum smctype type = none;
|
||||||
|
uint8_t len;
|
||||||
|
|
||||||
|
struct option long_options[] = {
|
||||||
|
{"help", 0, 0, 'h'},
|
||||||
|
{"key", 1, 0, 'k'},
|
||||||
|
{"type", 1, 0, 't'},
|
||||||
|
{"output-hex", 0, 0, 1000},
|
||||||
|
{"output-bin", 0, 0, 1001},
|
||||||
|
{0, 0, 0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (argv[1] == NULL) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((opt = getopt_long(argc, argv, "hk:t:",
|
||||||
|
long_options, &option_index)) != EOF) {
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
show_help = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'k':
|
||||||
|
snprintf(name, KEYBUFSIZE, "%s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 't':
|
||||||
|
snprintf(typebuf, KEYBUFSIZE, "%s", optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1000: // output-hex
|
||||||
|
of = hex;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1001: // output-bin
|
||||||
|
of = bin;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (optind < argc) {
|
||||||
|
fprintf(stderr, "Error: Extra parameter found.\n");
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (show_help) {
|
||||||
|
print_usage(argv[0]);
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate key name */
|
||||||
|
if (strlen(name) != 4) {
|
||||||
|
fprintf(stderr, "Key name must be 4 characters long.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate key type */
|
||||||
|
if ((typebuf[0] == 'f' || typebuf[0] == 's') && typebuf[1] == 'p') {
|
||||||
|
if (!fp_bits(typebuf[2], &fp_int_bits)
|
||||||
|
|| !fp_bits(typebuf[3], &fp_fraction_bits)) {
|
||||||
|
fprintf(stderr, "Invalid fixed point data type.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (typebuf[0] == 'f' && fp_int_bits + fp_fraction_bits != 16) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Invalid unsigned fixed point data type.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if (typebuf[0] == 's' && fp_int_bits + fp_fraction_bits != 15) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Invalid signed fixed point data type.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
type = typebuf[0] == 'f' ? fp : sp;
|
||||||
|
len = 2;
|
||||||
|
ofmt = "%d.%u";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == none) {
|
||||||
|
for (unsigned int i = 0; i < ARRAY_SIZE(types); i++) {
|
||||||
|
if (strcmp(typebuf, types[i].str))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
type = types[i].type;
|
||||||
|
len = types[i].len;
|
||||||
|
if (of == dec)
|
||||||
|
ofmt = types[i].decfmt;
|
||||||
|
else if (of == hex)
|
||||||
|
ofmt = types[i].hexfmt;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == none) {
|
||||||
|
fprintf(stderr, "Key type \"%s\" is not known.\n", typebuf);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check permissions */
|
||||||
|
if (geteuid() != 0) {
|
||||||
|
fprintf(stderr, "You must be root.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Open SMC port */
|
||||||
|
if (ioperm(APPLESMC_DATA_PORT, 0x10, 1)) {
|
||||||
|
fprintf(stderr, "ioperm: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read key from SMC */
|
||||||
|
int retval;
|
||||||
|
uint32_t buf = 0;
|
||||||
|
|
||||||
|
retval = read_smc(APPLESMC_READ_CMD, name, (uint8_t *)&buf, len);
|
||||||
|
assert(retval == 0);
|
||||||
|
|
||||||
|
/* Handle returned value according to the requested type */
|
||||||
|
buf = be32toh(buf);
|
||||||
|
|
||||||
|
int32_t fp_int = 0;
|
||||||
|
uint16_t fp_fraction = 0;
|
||||||
|
bool fp_sign = false;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case flag:
|
||||||
|
buf = (buf >> 24) & 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ui8:
|
||||||
|
buf = (buf >> 24) & 0xff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case si8:
|
||||||
|
buf = (buf >> 24) & 0xff;
|
||||||
|
if (of == dec)
|
||||||
|
buf = (int8_t)buf;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ui16:
|
||||||
|
buf = (buf >> 16) & 0xffff;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case si16:
|
||||||
|
buf = (buf >> 16) & 0xffff;
|
||||||
|
if (of == dec)
|
||||||
|
buf = (int16_t)buf;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case fp:
|
||||||
|
buf = (buf >> 16) & 0xffff;
|
||||||
|
fp_int = buf >> fp_fraction_bits;
|
||||||
|
fp_fraction = buf & (0xffff >> fp_int_bits);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case sp:
|
||||||
|
buf = (buf >> 16) & 0xffff;
|
||||||
|
fp_sign = ((buf >> 15) & 1) == 1;
|
||||||
|
|
||||||
|
buf &= ~(1 << 15);
|
||||||
|
|
||||||
|
fp_int = buf >> fp_fraction_bits;
|
||||||
|
fp_fraction = buf & (0xffff >> fp_int_bits);
|
||||||
|
|
||||||
|
if (fp_sign)
|
||||||
|
fp_int *= -1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ui32:
|
||||||
|
case none: // to avoid gcc warning
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output the result */
|
||||||
|
if (of != bin) {
|
||||||
|
strcpy(fmtbuf, "%s = ");
|
||||||
|
strcat(fmtbuf, ofmt);
|
||||||
|
strcat(fmtbuf, "\n");
|
||||||
|
|
||||||
|
if (type == fp || type == sp)
|
||||||
|
printf(fmtbuf, name, fp_int, fp_fraction);
|
||||||
|
else
|
||||||
|
printf(fmtbuf, name, buf);
|
||||||
|
} else {
|
||||||
|
printf("%s = ", name);
|
||||||
|
print_bits(len, (uint8_t *)&buf);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user