mirror of
https://github.com/outbackdingo/mt76.git
synced 2026-10-24 21:36:52 +00:00
This fixes the following compile error when compiling against recent
glibc:
------------
/tools/eeprom.c:223:9: error: ignoring return value of 'fread' declared with attribute 'warn_unused_result' [-Werror=unused-result]
223 | fread(buf, 1, EEPROM_PART_SIZE, f);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
------------
Signed-off-by: Hauke Mehrtens <[email protected]>
267 lines
4.7 KiB
C
267 lines
4.7 KiB
C
// SPDX-License-Identifier: ISC
|
|
/* Copyright (C) 2020 Felix Fietkau <[email protected]> */
|
|
#define _GNU_SOURCE
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
|
|
#include "mt76-test.h"
|
|
|
|
static const char *mtd_part;
|
|
static uint32_t mtd_offset;
|
|
|
|
static char *eeprom_file;
|
|
static int eeprom_fd = -1;
|
|
unsigned char *eeprom_data;
|
|
|
|
static int mt76_eeprom_dump_cb(struct nl_msg *msg, void *arg)
|
|
{
|
|
struct nlattr *tb[NUM_MT76_TM_ATTRS];
|
|
struct nlattr *attr;
|
|
|
|
attr = unl_find_attr(&unl, msg, NL80211_ATTR_TESTDATA);
|
|
if (!attr)
|
|
return NL_SKIP;
|
|
|
|
nla_parse_nested(tb, MT76_TM_ATTR_MAX, attr, msg_field.policy);
|
|
if (!tb[MT76_TM_ATTR_MTD_PART] || !tb[MT76_TM_ATTR_MTD_OFFSET])
|
|
return NL_SKIP;
|
|
|
|
mtd_part = strdup(nla_get_string(tb[MT76_TM_ATTR_MTD_PART]));
|
|
mtd_offset = nla_get_u32(tb[MT76_TM_ATTR_MTD_OFFSET]);
|
|
|
|
return NL_SKIP;
|
|
}
|
|
|
|
static FILE *mtd_open(const char *mtd)
|
|
{
|
|
char line[128], name[64];
|
|
FILE *fp;
|
|
int i;
|
|
|
|
fp = fopen("/proc/mtd", "r");
|
|
if (!fp)
|
|
return NULL;
|
|
|
|
snprintf(name, sizeof(name), "\"%s\"", mtd);
|
|
while (fgets(line, sizeof(line), fp)) {
|
|
if (!sscanf(line, "mtd%d:", &i) || !strstr(line, name))
|
|
continue;
|
|
|
|
snprintf(line, sizeof(line), "/dev/mtd%d", i);
|
|
fclose(fp);
|
|
return fopen(line, "r");
|
|
}
|
|
fclose(fp);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
static int
|
|
mt76_eeprom_create_file(void)
|
|
{
|
|
char buf[1024];
|
|
ssize_t len;
|
|
FILE *f;
|
|
int fd;
|
|
|
|
f = mtd_open(mtd_part);
|
|
if (!f) {
|
|
fprintf(stderr, "Failed to open MTD device\n");
|
|
return -1;
|
|
}
|
|
|
|
fd = open(eeprom_file, O_RDWR | O_CREAT | O_EXCL, 00644);
|
|
if (fd < 0)
|
|
goto out;
|
|
|
|
while ((len = fread(buf, 1, sizeof(buf), f)) > 0) {
|
|
ssize_t w;
|
|
|
|
retry:
|
|
w = write(fd, buf, len);
|
|
if (w > 0)
|
|
continue;
|
|
|
|
if (errno == EINTR)
|
|
goto retry;
|
|
|
|
perror("write");
|
|
unlink(eeprom_file);
|
|
close(fd);
|
|
fd = -1;
|
|
goto out;
|
|
}
|
|
|
|
lseek(fd, 0, SEEK_SET);
|
|
|
|
out:
|
|
fclose(f);
|
|
return fd;
|
|
}
|
|
|
|
static bool
|
|
mt76_eeprom_file_exists(void)
|
|
{
|
|
struct stat st;
|
|
|
|
return stat(eeprom_file, &st) == 0;
|
|
}
|
|
|
|
static int
|
|
mt76_eeprom_init_file(void)
|
|
{
|
|
int fd;
|
|
|
|
if (!mt76_eeprom_file_exists())
|
|
return mt76_eeprom_create_file();
|
|
|
|
fd = open(eeprom_file, O_RDWR);
|
|
if (fd < 0)
|
|
perror("open");
|
|
|
|
return fd;
|
|
}
|
|
|
|
int mt76_eeprom_init(int phy)
|
|
{
|
|
struct nl_msg *msg;
|
|
|
|
msg = unl_genl_msg(&unl, NL80211_CMD_TESTMODE, true);
|
|
nla_put_u32(msg, NL80211_ATTR_WIPHY, phy);
|
|
unl_genl_request(&unl, msg, mt76_eeprom_dump_cb, NULL);
|
|
|
|
if (!mtd_part) {
|
|
fprintf(stderr, "Could not find MTD partition information\n");
|
|
return -1;
|
|
}
|
|
|
|
eeprom_file = malloc(sizeof(EEPROM_FILE_PATH_FMT) + strlen(mtd_part));
|
|
sprintf(eeprom_file, EEPROM_FILE_PATH_FMT, mtd_part);
|
|
|
|
eeprom_fd = mt76_eeprom_init_file();
|
|
if (eeprom_fd < 0)
|
|
return -1;
|
|
|
|
eeprom_data = mmap(NULL, EEPROM_PART_SIZE, PROT_READ | PROT_WRITE,
|
|
MAP_SHARED, eeprom_fd, mtd_offset);
|
|
if (!eeprom_data) {
|
|
perror("mmap");
|
|
close(eeprom_fd);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void mt76_eeprom_close(void)
|
|
{
|
|
if (eeprom_fd < 0)
|
|
return;
|
|
|
|
msync(eeprom_data, EEPROM_PART_SIZE, MS_SYNC);
|
|
munmap(eeprom_data, EEPROM_PART_SIZE);
|
|
close(eeprom_fd);
|
|
eeprom_fd = -1;
|
|
}
|
|
|
|
static int
|
|
mt76_eeprom_set(int argc, char **argv)
|
|
{
|
|
for (; argc > 0; argc--, argv++) {
|
|
char *addr_str = argv[0];
|
|
char *val_str = strchr(addr_str, '=');
|
|
unsigned long addr, val;
|
|
char *err;
|
|
|
|
if (!val_str) {
|
|
fprintf(stderr, "Invalid argument: %s\n", addr_str);
|
|
return 1;
|
|
}
|
|
|
|
*(val_str++) = 0;
|
|
|
|
addr = strtoul(addr_str, &err, 0);
|
|
if ((err && *err) || addr >= EEPROM_PART_SIZE) {
|
|
fprintf(stderr, "Invalid address: %s\n", addr_str);
|
|
return 1;
|
|
}
|
|
|
|
val = strtoul(val_str, &err, 0);
|
|
if ((err && *err) || val >= 0xff) {
|
|
fprintf(stderr, "Invalid value: %s\n", val_str);
|
|
return 1;
|
|
}
|
|
|
|
eeprom_data[addr] = val;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
mt76_eeprom_changes(void)
|
|
{
|
|
unsigned char *buf;
|
|
size_t ret;
|
|
FILE *f;
|
|
int i;
|
|
|
|
f = mtd_open(mtd_part);
|
|
if (!f) {
|
|
fprintf(stderr, "Cannot open MTD device\n");
|
|
return 1;
|
|
}
|
|
|
|
buf = malloc(EEPROM_PART_SIZE);
|
|
fseek(f, mtd_offset, SEEK_SET);
|
|
ret = fread(buf, 1, EEPROM_PART_SIZE, f);
|
|
if (ret != EEPROM_PART_SIZE)
|
|
return EXIT_FAILURE;
|
|
for (i = 0; i < EEPROM_PART_SIZE; i++) {
|
|
if (buf[i] == eeprom_data[i])
|
|
continue;
|
|
|
|
printf("[%04x] %02x => %02x\n", i, buf[i], eeprom_data[i]);
|
|
}
|
|
free(buf);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int mt76_eeprom(int phy, int argc, char **argv)
|
|
{
|
|
const char *cmd;
|
|
int ret = 0;
|
|
|
|
if (argc < 1)
|
|
usage();
|
|
|
|
if (mt76_eeprom_init(phy))
|
|
return 1;
|
|
|
|
cmd = argv[0];
|
|
argv++;
|
|
argc--;
|
|
|
|
if (!strcmp(cmd, "file"))
|
|
printf("%s\n", eeprom_file);
|
|
else if (!strcmp(cmd, "set"))
|
|
ret = mt76_eeprom_set(argc, argv);
|
|
else if (!strcmp(cmd, "reset"))
|
|
unlink(eeprom_file);
|
|
else if (!strcmp(cmd, "changes"))
|
|
ret = mt76_eeprom_changes();
|
|
|
|
mt76_eeprom_close();
|
|
|
|
return ret;
|
|
}
|