ramips/mt7621: Add HATLab GateBoard-One Support

Signed-off-by: Aodzip <aodzip@gmail.com>
Signed-off-by: AnYun <amadeus@openjmu.xyz>
This commit is contained in:
aodzip 2022-08-26 13:55:23 +08:00 committed by AmadeusGhost
parent ea9e965d33
commit 3302e26e94
27 changed files with 2072 additions and 2 deletions

View File

@ -0,0 +1,54 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=rdloader
PKG_VERSION:=1.0.1
PKG_RELEASE:=1
PKG_LICENSE:=GPLv3
PKG_BUILD_DEPENDS:=util-linux e2fsprogs
include $(INCLUDE_DIR)/package.mk
include $(INCLUDE_DIR)/cmake.mk
define Package/rdloader
SECTION:=base
CATEGORY:=Base system
TITLE:=kmod loader for ramdisk enviroment
DEPENDS:=@TARGET_ramips +e2fsprogs +libblkid
endef
define Package/rdloader/description
Lightweight kmod loader for ramdisk enviroment,
support uuid-based rootfs mount
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
$(CP) ./src/* $(PKG_BUILD_DIR)/
endef
CMAKE_OPTIONS += -DCMAKE_BUILD_TYPE=Release
define Build/InstallDev
rm -fR $(STAGING_DIR)/rdloader
mkdir -p $(STAGING_DIR)/rdloader/{bin,lib,etc}
$(CP) $(PKG_BUILD_DIR)/rdloader $(STAGING_DIR)/rdloader/bin/
$(CP) $(STAGING_DIR_ROOT)/usr/sbin/e2fsck $(STAGING_DIR)/rdloader/bin/
$(CP) $(STAGING_DIR_ROOT)/etc/e2fsck.conf $(STAGING_DIR)/rdloader/etc/
( \
export \
READELF=$(TARGET_CROSS)readelf \
OBJCOPY=$(TARGET_CROSS)objcopy \
XARGS="$(XARGS)"; \
find $(STAGING_DIR)/rdloader/bin/ -type f -a -exec \
$(SCRIPT_DIR)/gen-rddependencies.sh {} \; ; \
) | while read FILE; do \
cp $(STAGING_DIR_ROOT)/lib/$$$$FILE $(STAGING_DIR)/rdloader/lib/ || \
cp $(STAGING_DIR_ROOT)/usr/lib/$$$$FILE $(STAGING_DIR)/rdloader/lib/ \
; \
done;
endef
$(eval $(call BuildPackage,rdloader))

View File

@ -0,0 +1,9 @@
cmake_minimum_required(VERSION 3.15)
set(CMAKE_C_STANDARD 99)
project(rdloader C)
add_executable(rdloader main.c insmod.c insmod.h mknod.c mknod.h mkdev_node.c mkdev_node.h blkid2.c blkid2.h cmdline.c cmdline.h switch_root.c switch_root.h)
target_link_libraries(${PROJECT_NAME} blkid)
install(TARGETS rdloader RUNTIME DESTINATION /usr/sbin)

View File

@ -0,0 +1,40 @@
//
// Created by juno on 2022/1/11.
//
#include <stdio.h>
#include <blkid/blkid.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "blkid2.h"
int get_blkid(const char *blkdev, char **uuid)
{
blkid_probe pr;
int ret;
size_t len;
const char *data;
void *out;
pr = blkid_new_probe_from_filename(blkdev);
if (!pr)
{
fprintf(stderr, "Failed open %s:%s\n", blkdev, strerror(errno));
return -1;
}
blkid_do_probe(pr);
ret = blkid_probe_lookup_value(pr, "UUID", &data, &len);
if (ret == 0)
{
out = calloc(1, len + 1);
memcpy(out, data, len);
*uuid = out;
}
blkid_free_probe(pr);
return ret;
}

View File

@ -0,0 +1,10 @@
//
// Created by juno on 2022/1/11.
//
#ifndef INIT_BLKID2_H
#define INIT_BLKID2_H
int get_blkid(const char *blkdev, char **uuid);
#endif //INIT_BLKID2_H

View File

@ -0,0 +1,209 @@
//
// Created by juno on 2022/1/11.
//
#define _GNU_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include "cmdline.h"
static void insert_fstype_tail(struct fstype **head, struct fstype *fs)
{
struct fstype *curr = *head;
struct fstype *next = NULL;
if (!curr)
{
*head = fs;
return;
}
do
{
next = curr->next;
if (!next)
{
curr->next = fs;
break;
}
curr = next;
} while (curr);
}
static int parse_root(char *args, char **ret)
{
char *root = NULL;
if (!args)
return -1;
if (strstr(args, "PARTUUID=") != NULL)
{
root = strtok(args, "=");
root = strtok(NULL, "=");
root = strtok(NULL, "=");
if (!root)
return -1;
asprintf(ret, "/dev/disk/by-partuuid/%s", root);
}
else if (strstr(args, "UUID=") != NULL)
{
root = strtok(args, "=");
root = strtok(NULL, "=");
root = strtok(NULL, "=");
if (!root)
return -1;
asprintf(ret, "/dev/disk/by-uuid/%s", root);
}
else if (strstr(args, "/dev/"))
{
*ret = strdup(args);
}
else
{
asprintf(ret, "/dev/%s", args);
}
return 0;
}
struct fstype *parse_rootfs(char **fstype_list)
{
struct fstype *ret = NULL;
char *list = *fstype_list;
struct fstype *default_fs = NULL;
struct fstype *fs = NULL;
if (list)
{
list = strtok(list, "=");
while ((list = strtok(NULL, ",")))
{
fs = calloc(1, sizeof(struct fstype));
if (!fs)
return NULL;
fs->name = strdup(list);
insert_fstype_tail(&ret, fs);
}
}
default_fs = calloc(1, sizeof(struct fstype));
default_fs->name = strdup("ext4");
insert_fstype_tail(&ret, default_fs);
return ret;
}
int parse_cmdline(struct bootargs_t **ret)
{
FILE *fp;
char *cmdline = NULL;
struct fstype *fs = NULL;
char str[1024] = {0};
char *root = NULL;
char *rootfs = NULL;
struct bootargs_t *bootargs = NULL;
fp = fopen("/proc/cmdline", "r");
if (!fp)
{
fprintf(stderr, "get cmdline failed:%s\n", strerror(errno));
return -1;
}
if (fgets(str, sizeof(str) - 1, fp) == NULL)
{
fprintf(stderr, "cmdline empty\n");
fclose(fp);
return -1;
}
fclose(fp);
cmdline = strtok(str, " ");
do
{
if (!cmdline)
continue;
if (strstr(cmdline, "root="))
root = cmdline;
if (strstr(cmdline, "rootfstype="))
rootfs = cmdline;
} while ((cmdline = strtok(NULL, " ")) != NULL);
if (parse_root(root, &root) < 0)
{
fprintf(stderr, "root args error\n");
return -1;
}
if ((fs = parse_rootfs(&rootfs)) == NULL)
{
fprintf(stderr, "fstype error\n");
return -1;
}
bootargs = calloc(1, sizeof(struct bootargs_t));
if (!bootargs)
{
fprintf(stderr, "alloc bootargs failed\n");
free(fs);
free(root);
return -1;
}
bootargs->root = root;
bootargs->fstype = fs;
*ret = bootargs;
return 0;
}
void free_bootargs(struct bootargs_t **args)
{
struct bootargs_t *bootargs = *args;
struct fstype *curr = NULL;
struct fstype *next = NULL;
if (!bootargs)
return;
if (bootargs->root)
free(bootargs->root);
curr = bootargs->fstype;
do
{
if (curr)
{
if (curr->name)
free(curr->name);
next = curr->next;
free(curr);
}
curr = next;
} while (curr);
free(bootargs);
}

View File

@ -0,0 +1,24 @@
//
// Created by juno on 2022/1/11.
//
#ifndef INIT_CMDLINE_H
#define INIT_CMDLINE_H
struct fstype
{
char *name;
struct fstype *next;
};
struct bootargs_t
{
char *root;
struct fstype *fstype;
};
int parse_cmdline(struct bootargs_t **ret);
void free_bootargs(struct bootargs_t **args);
#endif //INIT_CMDLINE_H

View File

@ -0,0 +1,161 @@
//
// Created by juno on 2022/1/7.
//
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/syscall.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <byteswap.h>
#include <limits.h>
#include "insmod.h"
#define init_module(module, len, opts) syscall(__NR_init_module, module, len, opts)
#if __BYTE_ORDER == __BIG_ENDIAN
#define SWAP_BE32(x) (x)
#define SWAP_BE64(x) (x)
#else
#define SWAP_BE32(x) bswap_32(x)
#define SWAP_BE64(x) bswap_64(x)
#endif
static char *parse_cmdline_module_options(const char **argv, int quote_space)
{
char *options;
int optlen;
options = calloc(1, sizeof(char));
optlen = 0;
while (*++argv)
{
const char *fmt;
const char *var;
const char *val;
var = *argv;
options = realloc(options, optlen + 2 + strlen(var) + 2);
fmt = "%.*s%s ";
var = strchrnul(var, '=');
if (quote_space)
{
if (*val)
{
val++;
if (strchr(val, ' '))
fmt = "%.*s\"%s\" ";
}
}
optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val);
}
return options;
}
static void *mmap_read(int fd, size_t size)
{
return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
}
static void *try_to_map_module(const char *filename, size_t *image_size_p)
{
void *image = NULL;
struct stat st;
int fd;
fd = open(filename, O_RDONLY);
if (fd < 0)
{
fprintf(stderr, "open %s failed:%s\n", filename, strerror(errno));
return NULL;
}
fstat(fd, &st);
if (st.st_size <= *image_size_p)
{
size_t image_size = st.st_size;
image = mmap_read(fd, image_size);
if (image == MAP_FAILED)
{
image = NULL;
}
else if (*(u_int32_t *)image != SWAP_BE32(0x7f454C46))
{
munmap(image, image_size);
}
else
{
*image_size_p = image_size;
}
}
close(fd);
return image;
}
static void *malloc_open_zipped_read_close(const char *filename, size_t *image_size_p)
{
return NULL;
}
int do_insmod(const char *modname, const char **argv)
{
int mmaped = 0;
size_t image_size = INT_MAX - 4095;
void *image = NULL;
int ret;
if (!modname)
{
return -1;
}
char *options = *argv == NULL ? "" : parse_cmdline_module_options(argv, 0);
image = try_to_map_module(modname, &image_size);
if (image)
{
mmaped = 1;
}
else
{
errno = ENOMEM;
image = malloc_open_zipped_read_close(modname, &image_size);
if (!image)
return -ENOMEM;
}
errno = 0;
init_module(image, image_size, options);
ret = errno;
if (mmaped)
munmap(image, image_size);
else
free(image);
if (ret)
{
fprintf(stderr, "insmod failed:%s\n", strerror(ret));
}
return ret;
}

View File

@ -0,0 +1,10 @@
//
// Created by juno on 2022/1/7.
//
#ifndef INIT_INSMOD_H
#define INIT_INSMOD_H
int do_insmod(const char *modname, const char **argv);
#endif //INIT_INSMOD_H

View File

@ -0,0 +1,257 @@
#include <sys/mount.h>
#include <stdio.h>
#include <stddef.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <limits.h>
#include <inttypes.h>
#include "insmod.h"
#include "mknod.h"
#include "mkdev_node.h"
#include "cmdline.h"
#include "switch_root.h"
static void hang(void);
static int mount_fs(void)
{
int ret;
unsigned long flags = MS_NOEXEC | MS_NOSUID | MS_RELATIME | MS_NODEV;
ret = mount(NULL, "/proc", "proc", flags, NULL);
if (ret < 0)
goto err;
ret = mount(NULL, "/sys", "sysfs", flags, NULL);
if (ret < 0)
goto err;
ret = mount(NULL, "/dev", "tmpfs", MS_RELATIME, NULL);
if (ret < 0)
goto err;
return 0;
err:
ret = errno;
return ret;
}
struct dev_node_t
{
const char *mode;
const char *name;
char type;
uint8_t major;
uint8_t minor;
} dev_nodes[] = {
{
.mode = "0666",
.name = "/dev/tty",
.type = 'c',
.major = 5,
.minor = 0,
},
{
.mode = "0622",
.name = "/dev/console",
.type = 'c',
.major = 5,
.minor = 1,
},
{
.mode = "0666",
.name = "/dev/null",
.type = 'c',
.major = 1,
.minor = 3,
},
{
.mode = "0666",
.name = "/dev/zero",
.type = 'c',
.major = 1,
.minor = 5,
},
};
static int make_node(void)
{
for (int i = 0; i < sizeof(dev_nodes) / sizeof((dev_nodes)[0]); i++)
{
if (do_mknod(dev_nodes[i].mode, dev_nodes[i].name, dev_nodes[i].type, dev_nodes[i].major, dev_nodes[i].minor) < 0)
{
if (errno == EEXIST)
continue;
fprintf(stderr, "make %s failed:%s\n", dev_nodes[i].name, strerror(errno));
return -1;
}
}
return 0;
}
static int insert_kernel_module(const char *path, const char **argv)
{
int ret;
FILE *fp = NULL;
char module_name[1024] = {0};
if (access(path, F_OK) != 0)
{
fprintf(stderr, "%s not found\n", path);
return -1;
}
fp = fopen(path, "r");
if (!fp)
{
fprintf(stderr, "open %s failed:%s\n", path, strerror(errno));
return -1;
}
while ((fgets(module_name, sizeof(module_name) - 1, fp)) != NULL)
{
for (int i = 0; i < sizeof(module_name); i++)
{
if (module_name[i] == '\n')
{
module_name[i] = '\0';
break;
}
}
ret = do_insmod(module_name, argv);
if (ret)
{
break;
}
}
fclose(fp);
return ret;
}
static void e2fsck(const char *dev_path)
{
int pid;
pid = fork();
if (pid < 0)
{
printf("fork failed");
hang();
}
if (pid == 0)
{
execl("/bin/e2fsck", "-f", "-y", dev_path);
printf("execl failed");
hang();
}
else
{
waitpid(pid);
}
}
static int mount_rootfs(struct bootargs_t *bootargs)
{
int ret = 0;
char realroot[PATH_MAX];
struct fstype *fstype = NULL;
// OpenWrt dont have /dev/disk/by-* yet, use realpath as workaround.
if (realpath(bootargs->root, realroot) == NULL)
return -1;
fstype = bootargs->fstype;
for (struct fstype *next = fstype->next; fstype; next = fstype->next, fstype = next)
{
if (strcmp(fstype->name, "ext4") == 0)
{
e2fsck(realroot);
}
ret = mount(realroot, "/root", fstype->name, MS_RELATIME, NULL);
if (ret == 0)
break;
}
return ret;
}
static void hang()
{
exit(-1);
while (1)
{
}
}
int main(int argc, const char *argv[])
{
int ret;
struct bootargs_t *bootargs = NULL;
if (getpid() != 1)
{
fprintf(stderr, "must run PID 1\n");
hang();
}
if ((ret = mount_fs()) < 0)
{
fprintf(stderr, "mount ramdisk fs failed:%s\n", strerror(ret));
hang();
}
if (make_node() < 0)
{
fprintf(stderr, "make ramdisk dev node failed\n");
hang();
}
if ((ret = parse_cmdline(&bootargs)) < 0)
{
fprintf(stderr, "cmdline format error\n");
hang();
}
if (insert_kernel_module("/etc/rdloader_list", argv + 1) != 0)
{
fprintf(stderr, "failed to load kmods\n");
hang();
}
printf("Waiting for root: %s\n", bootargs->root);
do
{
ret = mkdev_node();
if (ret)
continue;
ret = mount_rootfs(bootargs);
} while (ret != 0);
free_bootargs(&bootargs);
umount("/dev");
umount("/proc");
umount("/sys");
switch_root("/root", "/etc/preinit", argv++);
return 0;
}

View File

@ -0,0 +1,272 @@
//
// Created by juno on 2022/1/10.
//
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <blkid/blkid.h>
#include "mkdev_node.h"
#include "mknod.h"
#include "blkid2.h"
static int parse_devno(const char *devname, int *maj, int *min)
{
FILE *fp;
char *major_s, *minor_s;
int major, minor;
char dev_path[1024] = {0};
char dev_no[32] = {0};
snprintf(dev_path, sizeof(dev_path) - 1, "/sys/class/block/%s/dev", devname);
fp = fopen(dev_path, "r");
if (fp == NULL)
return -1;
if (!fgets(dev_no, 31, fp))
return -1;
fclose(fp);
major_s = strtok(dev_no, ":");
minor_s = strtok(NULL, ":");
major = (int)strtoul(major_s, NULL, 0);
minor = (int)strtoul(minor_s, NULL, 0);
*maj = major;
*min = minor;
return 0;
}
static int mkpartion_node(const char *devname)
{
int ret = 0;
dev_t part_devno;
dev_t disk_devno;
char *disk_name;
blkid_probe disk_pr;
blkid_partlist ls;
blkid_partition par;
const char *uuid;
char *dev_path = NULL;
asprintf(&dev_path, "/dev/%s", devname);
if (dev_path == NULL)
return -1;
blkid_probe part_pr = blkid_new_probe_from_filename(dev_path);
if (!part_pr)
{
ret = -1;
goto out1;
}
part_devno = blkid_probe_get_devno(part_pr);
if (!part_devno)
{
ret = -1;
goto out2;
}
disk_devno = blkid_probe_get_wholedisk_devno(part_pr);
if (!disk_devno)
{
ret = -1;
goto out2;
}
disk_name = blkid_devno_to_devname(disk_devno);
if (!disk_name)
{
ret = -1;
goto out2;
}
disk_pr = blkid_new_probe_from_filename(disk_name);
if (!disk_pr)
{
ret = -1;
goto out3;
}
ls = blkid_probe_get_partitions(disk_pr);
if (!ls)
{
ret = -1;
goto out4;
}
par = blkid_partlist_devno_to_partition(ls, part_devno);
uuid = blkid_partition_get_uuid(par);
if (uuid)
{
char long_path[1024] = {0};
snprintf(long_path, sizeof(long_path) - 1, "/dev/disk/by-partuuid/%s", uuid);
if (access(long_path, F_OK) == 0)
goto out4;
if (access(dev_path, F_OK) != 0)
goto out4;
symlink(dev_path, long_path);
}
else
{
ret = -1;
}
out4:
blkid_free_probe(disk_pr);
out3:
free(disk_name);
out2:
blkid_free_probe(part_pr);
out1:
free(dev_path);
return ret;
}
static int dev_by_partuuit(void)
{
DIR *dir;
DIR *disk_dir;
struct dirent *filename;
struct dirent *partname;
char *disk = NULL;
mkdir("/dev/disk/by-partuuid", 0755);
dir = opendir("/sys/block");
if (!dir)
{
return -1;
}
while ((filename = readdir(dir)))
{
if (filename->d_type != DT_LNK)
continue;
asprintf(&disk, "/sys/block/%s", filename->d_name);
disk_dir = opendir(disk);
if (disk)
free(disk);
if (disk_dir)
{
while ((partname = readdir(disk_dir)))
{
char *dev = NULL;
asprintf(&dev, "/sys/block/%s/%s/dev", filename->d_name, partname->d_name);
if (access(dev, F_OK) == 0)
{
mkpartion_node(partname->d_name);
}
if (dev)
free(dev);
}
}
closedir(disk_dir);
}
closedir(dir);
return 0;
}
int mkdev_node(void)
{
int ret;
struct dirent *filename;
DIR *dir = NULL;
char dev_path[1024];
char uuid_node[1024];
dir = opendir("/sys/class/block");
ret = mkdir("/dev/disk", 0755);
if (ret < 0 && errno != EEXIST)
{
fprintf(stderr, "create /dev/disk directory failed:%s\n", strerror(errno));
return -1;
}
ret = mkdir("/dev/disk/by-uuid", 0755);
if (ret < 0 && errno != EEXIST)
{
fprintf(stderr, "create /dev/disk/by-uuid directory failed:%s\n", strerror(errno));
return -1;
}
while ((filename = readdir(dir)))
{
if (filename->d_type == DT_LNK)
{
int major, minor;
char *uuid = NULL;
memset(dev_path, 0, sizeof(dev_path));
snprintf(dev_path, sizeof(dev_path) - 1, "/dev/%s", filename->d_name);
if (access(dev_path, F_OK) == 0)
continue;
if (parse_devno(filename->d_name, &major, &minor) < 0)
continue;
ret = do_mknod("0755", dev_path, 'b', major, minor);
if (ret < 0)
return ret;
ret = get_blkid(dev_path, &uuid);
if (ret < 0)
continue;
memset(uuid_node, 0, sizeof(uuid_node));
snprintf(uuid_node, sizeof(uuid_node) - 1, "/dev/disk/by-uuid/%s", uuid);
symlink(dev_path, uuid_node);
if (uuid)
{
free(uuid);
uuid = NULL;
}
}
}
closedir(dir);
dev_by_partuuit();
return 0;
}

View File

@ -0,0 +1,10 @@
//
// Created by juno on 2022/1/10.
//
#ifndef INIT_MKDEV_NODE_H
#define INIT_MKDEV_NODE_H
int mkdev_node(void);
#endif //INIT_MKDEV_NODE_H

View File

@ -0,0 +1,217 @@
//
// Created by juno on 2022/1/7.
//
#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include "mknod.h"
static const mode_t modes_cubp[] = {
S_IFIFO,
S_IFCHR,
S_IFBLK,
S_IFLNK,
};
#define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
static mode_t parse_mode(const char *s)
{
static const mode_t who_mask[] = {
S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */
S_ISUID | S_IRWXU, /* u */
S_ISGID | S_IRWXG, /* g */
S_IRWXO /* o */
};
static const mode_t perm_mask[] = {
S_IRUSR | S_IRGRP | S_IROTH, /* r */
S_IWUSR | S_IWGRP | S_IWOTH, /* w */
S_IXUSR | S_IXGRP | S_IXOTH, /* x */
S_IXUSR | S_IXGRP | S_IXOTH, /* X -- special -- see below */
S_ISUID | S_ISGID, /* s */
S_ISVTX /* t */
};
static const char who_chars[] ALIGN1 = "augo";
static const char perm_chars[] ALIGN1 = "rwxXst";
const char *p;
mode_t wholist;
mode_t permlist;
mode_t new_mode;
char op;
if ((unsigned char)(*s - '0') < 8)
{
unsigned long tmp;
char *e;
tmp = strtoul(s, &e, 8);
if (*e || (tmp > 07777U))
{ /* Check range and trailing chars. */
return -1;
}
return tmp;
}
new_mode = 0666;
/* Note: we allow empty clauses, and hence empty modes.
* We treat an empty mode as no change to perms. */
while (*s)
{ /* Process clauses. */
if (*s == ',')
{ /* We allow empty clauses. */
++s;
continue;
}
/* Get a wholist. */
wholist = 0;
WHO_LIST:
p = who_chars;
do
{
if (*p == *s)
{
wholist |= who_mask[(int)(p - who_chars)];
if (!*++s)
{
return -1;
}
goto WHO_LIST;
}
} while (*++p);
do
{ /* Process action list. */
if ((*s != '+') && (*s != '-'))
{
if (*s != '=')
{
return -1;
}
/* Since op is '=', clear all bits corresponding to the
* wholist, or all file bits if wholist is empty. */
permlist = ~FILEMODEBITS;
if (wholist)
{
permlist = ~wholist;
}
new_mode &= permlist;
}
op = *s++;
/* Check for permcopy. */
p = who_chars + 1; /* Skip 'a' entry. */
do
{
if (*p == *s)
{
int i = 0;
permlist = who_mask[(int)(p - who_chars)] & (S_IRWXU | S_IRWXG | S_IRWXO) & new_mode;
do
{
if (permlist & perm_mask[i])
{
permlist |= perm_mask[i];
}
} while (++i < 3);
++s;
goto GOT_ACTION;
}
} while (*++p);
/* It was not a permcopy, so get a permlist. */
permlist = 0;
PERM_LIST:
p = perm_chars;
do
{
if (*p == *s)
{
if ((*p != 'X') || (new_mode & (S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH)))
{
permlist |= perm_mask[(int)(p - perm_chars)];
}
if (!*++s)
{
break;
}
goto PERM_LIST;
}
} while (*++p);
GOT_ACTION:
if (permlist)
{ /* The permlist was nonempty. */
mode_t tmp = wholist;
if (!wholist)
{
mode_t u_mask = umask(0);
umask(u_mask);
tmp = ~u_mask;
}
permlist &= tmp;
if (op == '-')
{
new_mode &= ~permlist;
}
else
{
new_mode |= permlist;
}
}
} while (*s && (*s != ','));
}
return new_mode;
}
static mode_t char_to_mode(char type)
{
switch (type)
{
case 'f':
return modes_cubp[0];
case 'c':
return modes_cubp[1];
case 'b':
return modes_cubp[2];
case 'l':
return modes_cubp[3];
}
return -1;
}
int do_mknod(const char *mod, const char *name, char type, int maj, int min)
{
int ret;
mode_t mode;
dev_t dev;
mode = parse_mode(mod);
if (mode != (mode_t)-1)
umask(0);
else
{
fprintf(stderr, "mode failed\n");
return -1;
}
dev = makedev(maj, min);
mode |= char_to_mode(type);
ret = mknod(name, mode, dev);
if (ret < 0)
ret = errno;
return ret;
}

View File

@ -0,0 +1,11 @@
//
// Created by juno on 2022/1/7.
//
#ifndef INIT_MKNOD_H
#define INIT_MKNOD_H
#define ALIGN1 __attribute__((aligned(1)))
int do_mknod(const char *mod, const char *name, char type, int maj, int min);
#endif //INIT_MKNOD_H

View File

@ -0,0 +1,108 @@
//
// Created by juno on 2022/1/12.
//
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/mount.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include "switch_root.h"
static char *last_char_is(const char *s, int c)
{
if (!s[0])
return NULL;
while (s[1])
s++;
return (*s == (char)c) ? (char *)s : NULL;
}
static char *concat_path_file(const char *path, const char *filename)
{
char *lc;
char *ret;
if (!path)
path = "";
lc = last_char_is(path, '/');
while (*filename == '/')
filename++;
asprintf(&ret, "%s/%s/%s", path, (lc == NULL ? "/" : ""), filename);
return ret;
}
static void delete_contents(const char *directory, dev_t rootdev)
{
DIR *dir;
struct dirent *d;
struct stat st;
if (lstat(directory, &st) || st.st_dev != rootdev)
return;
if (S_ISDIR(st.st_mode))
{
dir = opendir(directory);
if (dir)
{
while ((d = readdir(dir)))
{
char *newdir = d->d_name;
if (DOT_OR_DOTDOT(newdir))
continue;
newdir = concat_path_file(directory, newdir);
delete_contents(newdir, rootdev);
free(newdir);
}
closedir(dir);
rmdir(directory);
}
else
{
unlink(directory);
}
}
}
void switch_root(const char *new_root, const char *prog, char *const argv[])
{
struct stat st;
dev_t root_dev;
chdir(new_root);
stat("/", &st);
root_dev = st.st_dev;
stat(".", &st);
if (st.st_dev == root_dev)
{
fprintf(stderr, "%s must be a mountpoint\n", new_root);
return;
}
delete_contents("/", root_dev);
if (mount(".", "/", NULL, MS_MOVE, NULL))
{
fprintf(stderr, "failed to moving root\n");
return;
}
chroot(".");
execv(prog, argv);
}

View File

@ -0,0 +1,12 @@
//
// Created by juno on 2022/1/12.
//
#ifndef INIT_SWITCH_ROOT_H
#define INIT_SWITCH_ROOT_H
#define DOT_OR_DOTDOT(s) ((s)[0] == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
void switch_root(const char *newroot, const char *prog, char *const argv[]);
#endif //INIT_SWITCH_ROOT_H

13
scripts/gen-rddependencies.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
TARGETS=$*
READELF="${READELF:-readelf}"
XARGS="${XARGS:-xargs -r}"
find $TARGETS -type f -a -exec file {} \; | \
sed -n -e 's/^\(.*\):.*ELF.*\(executable\|shared object\).*,.*/\1/p' | \
$XARGS -n1 $READELF -l | grep 'Requesting' | cut -d':' -f2 | tr -d ' ]' | \
$XARGS basename
cd `dirname ${0}`
./gen-dependencies.sh ${TARGETS}

View File

@ -0,0 +1,278 @@
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
#include "mt7621.dtsi"
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/input/input.h>
#include <dt-bindings/thermal/thermal.h>
/ {
compatible = "hatlab,gateboard-one", "mediatek,mt7621-soc";
model = "HATLab GateBoard-One";
aliases {
led-boot = &led_sys;
led-failsafe = &led_sys;
led-running = &led_sys;
led-upgrade = &led_sys;
};
chosen {
bootargs = "console=ttyS0,115200";
};
leds {
compatible = "gpio-leds";
led_sys: sys {
label = "green:sys";
gpios = <&gpio 0 GPIO_ACTIVE_HIGH>;
};
usb {
label = "blue:usb";
gpios = <&gpio 16 GPIO_ACTIVE_HIGH>;
trigger-sources = <&xhci_ehci_port1>;
linux,default-trigger = "usbport";
};
};
keys {
compatible = "gpio-keys";
reset {
label = "reset";
gpios = <&gpio 17 GPIO_ACTIVE_HIGH>;
linux,code = <KEY_RESTART>;
};
};
gpio_export {
compatible = "gpio-export";
#size-cells = <0>;
power_peripheral {
gpio-export,name = "power_peripheral";
gpio-export,output = <0>;
gpios = <&gpio 18 GPIO_ACTIVE_LOW>;
};
};
cpu_fan: cpu_fan {
compatible = "gpio-fan";
gpios = <&gpio 13 GPIO_ACTIVE_HIGH
&gpio 14 GPIO_ACTIVE_HIGH>;
gpio-fan,speed-map = < 0 0
2000 1
4000 2
6000 3>;
#cooling-cells = <2>;
};
thermal-zones {
cpu-thermal {
polling-delay = <1000>;
polling-delay-passive = <250>;
thermal-sensors = <&cpu_sensor>;
trips {
cpu_warm: cpu-warm {
temperature = <26000>;
hysteresis = <2000>;
type = "passive";
};
cpu_hot: cpu-hot {
temperature = <37000>;
hysteresis = <2000>;
type = "active";
};
cpu_alert: cpu-alert {
temperature = <75000>;
hysteresis = <2000>;
type = "hot";
};
cpu_crit: cpu-crit {
temperature = <80000>;
hysteresis = <2000>;
type = "critical";
};
};
cooling-maps {
map0 {
trip = <&cpu_warm>;
cooling-device = <&cpu_fan THERMAL_NO_LIMIT 2>;
};
map1 {
trip = <&cpu_hot>;
cooling-device = <&cpu_fan 3 THERMAL_NO_LIMIT>;
};
};
};
};
i2c_sfp: i2c-sfp {
compatible = "i2c-gpio";
#address-cells = <1>;
#size-cells = <0>;
sda-gpios = <&expender0 1 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
scl-gpios = <&expender0 2 (GPIO_ACTIVE_HIGH | GPIO_OPEN_DRAIN)>;
};
sfp: sfp {
compatible = "sff,sfp";
i2c-bus = <&i2c_sfp>;
maximum-power-milliwatt = <5000>;
mod-def0-gpios = <&expender0 5 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>;
};
};
&spi0 {
status = "okay";
spi-nor@0 {
compatible = "jedec,spi-nor";
reg = <0>;
spi-max-frequency = <50000000>;
partitions@0 {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
partition@0 {
label = "u-boot";
reg = <0x0 0x40000>;
read-only;
};
partition@40000 {
label = "u-boot-env";
reg = <0x40000 0x10000>;
};
factory: partition@50000 {
label = "factory";
reg = <0x50000 0x10000>;
};
};
};
};
&i2c {
status = "okay";
expender0: pcf8574a@38 {
compatible = "nxp,pcf8574a";
reg = <0x38>;
gpio-controller;
#gpio-cells = <2>;
interrupt-parent = <&gpio>;
interrupts = <15 IRQ_TYPE_EDGE_FALLING>;
interrupt-controller;
#interrupt-cells = <2>;
};
cpu_sensor: lm75@4f {
compatible = "national,lm75";
reg = <0x4f>;
#thermal-sensor-cells = <0>;
};
rtc@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
};
};
&mdio {
ephy7: ethernet-phy@7 {
reg = <7>;
eee-broken-1000t;
};
};
&gmac0 {
label = "dsa";
mtd-mac-address = <&factory 0x0>;
};
&gmac1 {
status = "okay";
label = "eth5";
phy-handle = <&ephy7>;
phy-mode = "rgmii-rxid";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <6>;
};
&switch0 {
ports {
port@0 {
status = "okay";
label = "eth0";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <1>;
};
port@1 {
status = "okay";
label = "eth1";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <2>;
};
port@2 {
status = "okay";
label = "eth2";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <3>;
};
port@3 {
status = "okay";
label = "eth3";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <4>;
};
port@4 {
status = "okay";
label = "eth4";
mtd-mac-address = <&factory 0x0>;
mtd-mac-address-increment = <5>;
};
};
};
&pcie {
status = "okay";
};
&sdhci {
status = "okay";
max-frequency = <20000000>;
};
&state_default {
gpio {
groups = "wdt", "jtag";
function = "gpio";
};
};
&uartlite2 {
status = "okay";
};
&uartlite3 {
status = "okay";
};

View File

@ -99,6 +99,7 @@
#define MAX_SGMT_SZ (MAX_DMA_CNT)
#define MAX_REQ_SZ (MAX_SGMT_SZ * 8)
static int host_max_mclk = HOST_MAX_MCLK;
static int cd_active_low = 1;
//=================================
@ -455,7 +456,7 @@ static void msdc_tasklet_card(struct work_struct *work)
host->card_inserted = inserted;
if (!host->suspend) {
host->mmc->f_max = HOST_MAX_MCLK;
host->mmc->f_max = host_max_mclk;
mmc_detect_change(host->mmc, msecs_to_jiffies(20));
}
@ -2233,10 +2234,13 @@ static int msdc_drv_probe(struct platform_device *pdev)
goto host_free;
}
if (of_property_read_u32(pdev->dev.of_node, "max-frequency", &ret) == 0)
host_max_mclk = ret;
/* Set host parameters to mmc */
mmc->ops = &mt_msdc_ops;
mmc->f_min = HOST_MIN_MCLK;
mmc->f_max = HOST_MAX_MCLK;
mmc->f_max = host_max_mclk;
mmc->ocr_avail = MSDC_OCR_AVAIL;
mmc->caps = MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;

View File

@ -26,6 +26,71 @@ define Build/gemtek-trailer
printf "%s%08X" ".GEMTEK." "$$(cksum $@ | cut -d ' ' -f1)" >> $@
endef
define Build/hatlab-gateboard-combined
rm -fR $@.bootfs.img
mkfs.fat $@.bootfs.img -C 16384
mcopy -i $@.bootfs.img $(IMAGE_KERNEL) ::vmlinux.itb
( \
set $$(ptgen -o $@ -h 4 -s 63 -l 1024 -g -p 16M -p "${CONFIG_TARGET_ROOTFS_PARTSIZE}M" -G ${IMG_PART_DISKGUID}); \
BOOTFSOFFSET="$$(($$1 / 512))"; \
ROOTFSOFFSET="$$(($$3 / 512))"; \
dd if="$@.bootfs.img" of="$@" bs=512 seek="$${BOOTFSOFFSET}" conv=notrunc; \
dd if="${IMAGE_ROOTFS}" of="$@" bs=512 seek="$${ROOTFSOFFSET}" conv=notrunc; \
)
endef
define Build/hatlab-gateboard-kernel
rm -fR $@.initrd
rm -fR $@.initrd.cpio
mkdir -p $@.initrd/{bin,dev,proc,sys,lib,etc}
mkdir -p $@.initrd/lib/modules/$(LINUX_VERSION)
$(CP) $(STAGING_DIR)/rdloader/bin/* $@.initrd/bin/
$(CP) $(STAGING_DIR)/rdloader/lib/* $@.initrd/lib/
$(CP) $(STAGING_DIR)/rdloader/etc/* $@.initrd/etc/
$(RSTRIP) $@.initrd/bin/
$(RSTRIP) $@.initrd/lib/
chmod +x $@.initrd/bin/*
ln -s ./bin/rdloader $@.initrd/init
( \
KMODS=(usb-common nls_base usbcore xhci-hcd xhci-mtk jbd2 mbcache ext4 scsi_mod usb-storage sd_mod mmc_core mmc_block mtk_sd crc32c_generic); \
for kmod in "$${KMODS[@]}"; do \
$(CP) \
$(TARGET_DIR)/lib/modules/$(LINUX_VERSION)/$$kmod.ko \
$@.initrd/lib/modules/$(LINUX_VERSION)/; \
echo /lib/modules/$(LINUX_VERSION)/$$kmod.ko \
>> $@.initrd/etc/rdloader_list; \
done; \
)
( \
if [ -f $(STAGING_DIR_HOST)/bin/cpio ]; then \
CPIO=$(STAGING_DIR_HOST)/bin/cpio; \
else \
CPIO="cpio"; \
fi; \
cd $@.initrd; \
find . | cpio -o -H newc -R 0:0 > $@.initrd.cpio; \
)
$(TOPDIR)/scripts/mkits.sh \
-D $(DEVICE_NAME) -o $@.its -k $@ \
-C gzip -d $(KDIR)/image-$(DEVICE_DTS).dtb \
-i $@.initrd.cpio \
-a $(KERNEL_LOADADDR) -e $(KERNEL_LOADADDR) \
-c config-1 -A $(LINUX_KARCH) -v $(LINUX_VERSION)
PATH=$(LINUX_DIR)/scripts/dtc:$(PATH) mkimage -f $@.its $@.new
@mv $@.new $@
endef
define Build/iodata-factory
$(eval fw_size=$(word 1,$(1)))
$(eval fw_type=$(word 2,$(1)))
@ -672,6 +737,28 @@ define Device/gnubee_gb-pc2
endef
TARGET_DEVICES += gnubee_gb-pc2
define Device/hatlab_gateboard-one
$(Device/dsa-migration)
DEVICE_VENDOR := HATLab
DEVICE_MODEL := GateBoard-One
DEVICE_PACKAGES := kmod-fs-ext4 kmod-gpio-pcf857x kmod-hwmon-gpiofan \
kmod-hwmon-lm75 kmod-i2c-gpio kmod-rtc-pcf8563 kmod-sdhci-mt7620 \
kmod-sfp kmod-thermal kmod-usb3 kmod-usb-ledtrig-usbport rdloader
KERNEL := kernel-bin | gzip | hatlab-gateboard-kernel
IMAGE/kernel.itb := append-kernel
IMAGE/rootfs.img := append-rootfs | pad-to $(ROOTFS_PARTSIZE)
IMAGE/rootfs.img.gz := append-rootfs | pad-to $(ROOTFS_PARTSIZE) | gzip
IMAGE/combined.img := hatlab-gateboard-combined | append-metadata
IMAGE/combined.img.gz := hatlab-gateboard-combined | gzip | append-metadata
IMAGES := kernel.itb
ifeq ($(CONFIG_TARGET_IMAGES_GZIP),y)
IMAGES += rootfs.img.gz combined.img.gz
else
IMAGES += rootfs.img combined.img
endif
endef
TARGET_DEVICES += hatlab_gateboard-one
define Device/hilink_hlk-7621a
IMAGE_SIZE := 32448k
DEVICE_VENDOR := HiLink

View File

@ -57,6 +57,9 @@ ramips_setup_interfaces()
gnubee,gb-pc2)
ucidef_set_interface_lan "lan1 lan2"
;;
hatlab,gateboard-one)
ucidef_set_interfaces_lan_wan "eth0 eth1 eth2 eth3 eth4" "eth5"
;;
linksys,re6500|\
netgear,wac104)
ucidef_set_interface_lan "lan1 lan2 lan3 lan4"

View File

@ -0,0 +1,88 @@
. /lib/functions.sh
hatlab_check_image() {
local diskdev partdev diff
export_bootdevice && export_partdevice diskdev 0 || {
echo "Unable to determine upgrade device"
return 1
}
get_partitions "/dev/$diskdev" bootdisk
#extract the boot sector from the image
get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b 2>/dev/null
get_partitions /tmp/image.bs image
#compare tables
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
rm -f /tmp/image.bs /tmp/partmap.bootdisk /tmp/partmap.image
if [ -n "$diff" ]; then
echo "Partition layout has changed. Full image will be written."
ask_bool 0 "Abort" && exit 1
return 0
fi
}
hatlab_copy_config() {
local partdev parttype=ext4
if export_partdevice partdev 2; then
mount -t $parttype -o rw,noatime "/dev/$partdev" /mnt
cp -af "$UPGRADE_BACKUP" "/mnt/$BACKUP_FILE"
umount /mnt
fi
}
hatlab_do_upgrade() {
local diskdev partdev diff
export_bootdevice && export_partdevice diskdev 0 || {
echo "Unable to determine upgrade device"
return 1
}
sync
if [ "$UPGRADE_OPT_SAVE_PARTITIONS" = "1" ]; then
get_partitions "/dev/$diskdev" bootdisk
#extract the boot sector from the image
get_image "$@" | dd of=/tmp/image.bs count=1 bs=512b
get_partitions /tmp/image.bs image
#compare tables
diff="$(grep -F -x -v -f /tmp/partmap.bootdisk /tmp/partmap.image)"
else
diff=1
fi
if [ -n "$diff" ]; then
get_image "$@" | dd of="/dev/$diskdev" bs=4096 conv=fsync
# Separate removal and addtion is necessary; otherwise, partition 1
# will be missing if it overlaps with the old partition 2
partx -d - "/dev/$diskdev"
partx -a - "/dev/$diskdev"
return 0
fi
#iterate over each partition from the image and write it to the boot disk
while read part start size; do
if export_partdevice partdev $part; then
echo "Writing image to /dev/$partdev..."
get_image "$@" | dd of="/dev/$partdev" ibs="512" obs=1M skip="$start" count="$size" conv=fsync
else
echo "Unable to find partition $part device, skipped."
fi
done < /tmp/partmap.image
#copy partition uuid
echo "Writing new UUID to /dev/$diskdev..."
get_image "$@" | dd of="/dev/$diskdev" bs=1 skip=440 count=4 seek=440 conv=fsync
}

View File

@ -9,6 +9,28 @@ RAMFS_COPY_BIN='fw_printenv fw_setenv'
RAMFS_COPY_DATA='/etc/fw_env.config /var/lock/fw_printenv.lock'
platform_check_image() {
local board=$(board_name)
case "$board" in
hatlab,gateboard-one)
hatlab_check_image "$1"
return $?;
;;
esac
return 0
}
platform_copy_config() {
local board=$(board_name)
case "$board" in
hatlab,gateboard-one)
hatlab_copy_config
return $?;
;;
esac
return 0
}
@ -86,6 +108,9 @@ platform_do_upgrade() {
xiaomi,redmi-router-ac2100)
nand_do_upgrade "$1"
;;
hatlab,gateboard-one)
hatlab_do_upgrade "$1"
;;
iodata,wn-ax1167gr2|\
iodata,wn-ax2033gr|\
iodata,wn-dx1167r)

View File

@ -9,6 +9,10 @@ YES=
board=$(board_name)
case $board in
hatlab,gateboard-one)
partname=factory
offset=$((0x0))
;;
mqmaker,witi)
partname=factory
offset=$((0xe000))

View File

@ -233,6 +233,7 @@ CONFIG_RALINK=y
CONFIG_RATIONAL=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_REALTEK_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_MMIO=y
CONFIG_REGULATOR=y

View File

@ -229,6 +229,7 @@ CONFIG_RALINK=y
CONFIG_RATIONAL=y
CONFIG_RCU_NEED_SEGCBLIST=y
CONFIG_RCU_STALL_COMMON=y
CONFIG_REALTEK_PHY=y
CONFIG_REGMAP=y
CONFIG_REGMAP_I2C=y
CONFIG_REGMAP_MMIO=y

View File

@ -0,0 +1,12 @@
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -2410,6 +2410,9 @@ static const struct flash_info spi_nor_ids[] = {
{ "pm25lv010", INFO(0, 0, 32 * 1024, 4, SECT_4K_PMC) },
{ "pm25lq032", INFO(0x7f9d46, 0, 64 * 1024, 64, SECT_4K) },
+ /* PUYA */
+ { "p25d40h", INFO(0x856013, 0, 64 * 1024, 8, SECT_4K) },
+
/* Spansion/Cypress -- single (large) sector size only, at least
* for the chips listed here (without boot sectors).
*/

View File

@ -0,0 +1,150 @@
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -7,6 +7,7 @@
* Author: Johnson Leung <r58129@freescale.com>
*
* Copyright (c) 2004 Freescale Semiconductor, Inc.
+ * Copyright (c) 2022 Aodzip <aodzip@gmail.com>
*/
#include <linux/bitops.h>
#include <linux/phy.h>
@@ -28,6 +29,12 @@
#define RTL8211F_INSR 0x1d
+#define RTL8211x_FIBER_ESR 0x0F
+#define RTL8211x_MODE_MASK 0xC000
+
+#define RTL8211x_MODE_COPPER 0
+#define RTL8211x_MODE_FIBER 1
+
#define RTL8211F_TX_DELAY BIT(8)
#define RTL8211E_TX_DELAY BIT(1)
#define RTL8211E_RX_DELAY BIT(2)
@@ -49,6 +56,10 @@
#define RTL_GENERIC_PHYID 0x001cc800
+struct rtl8211x_priv {
+ int lastmode;
+};
+
MODULE_DESCRIPTION("Realtek PHY driver");
MODULE_AUTHOR("Johnson Leung");
MODULE_LICENSE("GPL");
@@ -443,6 +454,88 @@ static int rtl8125_match_phy_device(struct phy_device *phydev)
rtlgen_supports_2_5gbps(phydev);
}
+static int rtl8211x_probe(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl8211x_priv *priv;
+
+ priv = devm_kzalloc(dev, sizeof(struct rtl8211x_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ phydev->priv = priv;
+
+ return 0;
+}
+
+static void rtl8211x_remove(struct phy_device *phydev)
+{
+ struct device *dev = &phydev->mdio.dev;
+ struct rtl8211x_priv *priv = phydev->priv;
+
+ if (priv)
+ devm_kfree(dev, priv);
+}
+
+static int rtl8211x_mode(struct phy_device *phydev)
+{
+ u16 val;
+
+ val = phy_read(phydev, RTL8211x_FIBER_ESR);
+ val &= RTL8211x_MODE_MASK;
+
+ if(val)
+ return RTL8211x_MODE_FIBER;
+ else
+ return RTL8211x_MODE_COPPER;
+}
+
+static int rtl8211x_config_aneg(struct phy_device *phydev)
+{
+ int ret;
+
+ struct rtl8211x_priv *priv = phydev->priv;
+
+ ret = genphy_read_abilities(phydev);
+ if(ret < 0)
+ return ret;
+
+ linkmode_copy(phydev->advertising, phydev->supported);
+
+ if (rtl8211x_mode(phydev) == RTL8211x_MODE_FIBER) {
+ dev_info(&phydev->mdio.dev, "Fiber Mode");
+ priv->lastmode = RTL8211x_MODE_FIBER;
+ return genphy_c37_config_aneg(phydev);
+ }
+
+ dev_info(&phydev->mdio.dev, "Copper Mode");
+
+ priv->lastmode = RTL8211x_MODE_COPPER;
+
+ return genphy_config_aneg(phydev);
+}
+
+static int rtl8211x_read_status(struct phy_device *phydev)
+{
+ int ret;
+ struct rtl8211x_priv *priv = phydev->priv;
+
+ if(rtl8211x_mode(phydev) != priv->lastmode) {
+ ret = rtl8211x_config_aneg(phydev);
+ if(ret < 0)
+ return ret;
+
+ ret = genphy_restart_aneg(phydev);
+ if(ret < 0)
+ return ret;
+ }
+
+ if (rtl8211x_mode(phydev) == RTL8211x_MODE_FIBER)
+ return genphy_c37_read_status(phydev);
+
+ return genphy_read_status(phydev);
+}
+
static struct phy_driver realtek_drvs[] = {
{
PHY_ID_MATCH_EXACT(0x00008201),
@@ -495,8 +588,12 @@ static struct phy_driver realtek_drvs[] = {
}, {
PHY_ID_MATCH_EXACT(0x001cc914),
.name = "RTL8211DN Gigabit Ethernet",
+ .probe = rtl8211x_probe,
+ .remove = rtl8211x_remove,
.ack_interrupt = rtl821x_ack_interrupt,
.config_intr = rtl8211e_config_intr,
+ .config_aneg = rtl8211x_config_aneg,
+ .read_status = rtl8211x_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = rtl821x_read_page,
@@ -514,9 +611,13 @@ static struct phy_driver realtek_drvs[] = {
}, {
PHY_ID_MATCH_EXACT(0x001cc916),
.name = "RTL8211F Gigabit Ethernet",
+ .probe = rtl8211x_probe,
+ .remove = rtl8211x_remove,
.config_init = &rtl8211f_config_init,
.ack_interrupt = &rtl8211f_ack_interrupt,
.config_intr = &rtl8211f_config_intr,
+ .config_aneg = rtl8211x_config_aneg,
+ .read_status = rtl8211x_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = rtl821x_read_page,