Merge branch 'devel-1.6' into prepare-1.6

This commit is contained in:
Florian Pose 2024-02-01 13:09:45 +01:00
commit be41b79f3f
65 changed files with 58662 additions and 90 deletions

View File

@ -12,7 +12,7 @@ build:
script:
- ./bootstrap
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --disable-8139too --enable-tty --with-devices=2 --enable-ccat
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --enable-tty --with-devices=2 --enable-ccat
- make -j8 all modules
- make DISTCHECK_CONFIGURE_FLAGS="--with-linux-dir=/usr/src/linux-obj/$(uname -i)/default" distcheck
@ -54,7 +54,7 @@ doxygen:
GIT_SUBMODULE_STRATEGY: recursive
script:
- ./bootstrap
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --disable-8139too --enable-tty --with-devices=2 --enable-ccat
- ./configure --with-linux-dir=/usr/src/linux-obj/$(uname -i)/default --enable-tty --with-devices=2 --enable-ccat
- make doc
- mv doxygen-output/html/ html/
artifacts:

View File

@ -24,7 +24,6 @@ include $(top_srcdir)/Makefile.kbuild
ACLOCAL_AMFLAGS = -I m4
AM_DISTCHECK_CONFIGURE_FLAGS = \
--disable-8139too \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
SUBDIRS = \

View File

@ -203,7 +203,7 @@ AC_ARG_ENABLE([8139too],
;;
esac
],
[enable8139too=$enablekernel]
[enable8139too=0] # disabled by default
)
AM_CONDITIONAL(ENABLE_8139TOO, test "x$enable8139too" = "x1")
@ -608,16 +608,25 @@ if test "x${enable_r8169}" = "x1"; then
AC_MSG_CHECKING([for kernel for r8169 driver])
kernels=`ls -1 ${srcdir}/devices/ | grep -oE "^r8169-.*-" | cut -d "-" -f 2 | uniq`
kernels_subdir=`ls -1 ${srcdir}/devices/r8169/ | grep -oE "^r8169_main-.*-" | cut -d "-" -f 2 | uniq`
found=0
found_subdir=0
for k in $kernels; do
if test "$kernel_r8169" = "$k"; then
found=1
fi
done
for k in $kernels_subdir; do
if test "$kernel_r8169" = "$k"; then
found=1
found_subdir=1
fi
done
if test $found -ne 1; then
AC_MSG_ERROR([kernel $kernel_r8169 not available for r8169 driver!])
fi
AC_SUBST(R8169_IN_SUBDIR, [$found_subdir])
AC_MSG_RESULT([$kernel_r8169])
fi
@ -1216,6 +1225,8 @@ AC_CONFIG_FILES([
devices/igb/Makefile
devices/igc/Kbuild
devices/igc/Makefile
devices/r8169/Kbuild
devices/r8169/Makefile
ethercat.spec
examples/Kbuild
examples/Makefile

View File

@ -77,11 +77,15 @@ ifeq (@ENABLE_IGC@,1)
endif
ifeq (@ENABLE_R8169@,1)
ifeq (@R8169_IN_SUBDIR@,1)
obj-m += r8169/
else
EC_R8169_OBJ := r8169-@KERNEL_R8169@-ethercat.o
obj-m += ec_r8169.o
ec_r8169-objs := $(EC_R8169_OBJ)
CFLAGS_$(EC_R8169_OBJ) = -DREV=$(REV)
endif
endif
KBUILD_EXTRA_SYMBOLS := \
@abs_top_builddir@/$(LINUX_SYMVERS) \

View File

@ -27,7 +27,8 @@ SUBDIRS = \
e1000e \
genet \
igb \
igc
igc \
r8169
# using HEADERS to enable tags target
noinst_HEADERS = \

View File

@ -35,9 +35,12 @@ DRIVER_MAP=(
("igb", "igb", "igb_main"),
("igc", "igc", "igc_main"),
(".", "r8169", "r8169"),
("r8169", "r8169", "r8169_main"),
)
DRIVERS = tuple([x[1] for x in DRIVER_MAP])
DRIVERS = sorted(set([x[1] for x in DRIVER_MAP]))
def compile_regex(prefix, file_extension):
"""

59
devices/r8169/Kbuild.in Normal file
View File

@ -0,0 +1,59 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
# ---
#
# vim: syntax=make
#
#------------------------------------------------------------------------------
TOPDIR := $(src)/../..
REV := $(shell if test -s $(TOPDIR)/revision; then \
cat $(TOPDIR)/revision; \
else \
git -C $(TOPDIR) describe 2>/dev/null || echo "unknown"; \
fi)
ifeq (@ENABLE_R8169@,1)
ifeq (@R8169_IN_SUBDIR@,1)
obj-m += ec_r8169.o
ec_r8169-objs := \
r8169_firmware-@KERNEL_R8169@-ethercat.o \
r8169_main-@KERNEL_R8169@-ethercat.o \
r8169_phy_config-@KERNEL_R8169@-ethercat.o
CFLAGS_r8169_main-@KERNEL_R8169@-ethercat.o = -DREV=$(REV)
endif
endif
KBUILD_EXTRA_SYMBOLS := \
@abs_top_builddir@/$(LINUX_SYMVERS) \
@abs_top_builddir@/master/$(LINUX_SYMVERS)

70
devices/r8169/Makefile.am Normal file
View File

@ -0,0 +1,70 @@
#------------------------------------------------------------------------------
#
# Copyright (C) 2006-2021 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT Master.
#
# The IgH EtherCAT Master is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 2, as
# published by the Free Software Foundation.
#
# The IgH EtherCAT Master 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 the IgH EtherCAT Master; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# ---
#
# The license mentioned above concerns the source code only. Using the
# EtherCAT technology and brand is only permitted in compliance with the
# industrial property and similar rights of Beckhoff Automation GmbH.
#
#------------------------------------------------------------------------------
include $(top_srcdir)/Makefile.kbuild
EXTRA_DIST = \
r8169-5.10-ethercat.h \
r8169-5.10-orig.h \
r8169-5.14-ethercat.h \
r8169-5.14-orig.h \
r8169-5.15-ethercat.h \
r8169-5.15-orig.h \
r8169-6.1-ethercat.h \
r8169-6.1-orig.h \
r8169_firmware-5.10-ethercat.c \
r8169_firmware-5.10-ethercat.h \
r8169_firmware-5.10-orig.c \
r8169_firmware-5.10-orig.h \
r8169_firmware-5.14-ethercat.c \
r8169_firmware-5.14-ethercat.h \
r8169_firmware-5.14-orig.c \
r8169_firmware-5.14-orig.h \
r8169_firmware-5.15-ethercat.c \
r8169_firmware-5.15-ethercat.h \
r8169_firmware-5.15-orig.c \
r8169_firmware-5.15-orig.h \
r8169_firmware-6.1-ethercat.c \
r8169_firmware-6.1-ethercat.h \
r8169_firmware-6.1-orig.c \
r8169_firmware-6.1-orig.h \
r8169_main-5.10-ethercat.c \
r8169_main-5.10-orig.c \
r8169_main-5.14-ethercat.c \
r8169_main-5.14-orig.c \
r8169_main-5.15-ethercat.c \
r8169_main-5.15-orig.c \
r8169_main-6.1-ethercat.c \
r8169_main-6.1-orig.c \
r8169_phy_config-5.10-ethercat.c \
r8169_phy_config-5.10-orig.c \
r8169_phy_config-5.14-ethercat.c \
r8169_phy_config-5.14-orig.c \
r8169_phy_config-5.15-ethercat.c \
r8169_phy_config-5.15-orig.c \
r8169_phy_config-6.1-ethercat.c \
r8169_phy_config-6.1-orig.c

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,78 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
RTL_GIGA_MAC_VER_12,
RTL_GIGA_MAC_VER_13,
RTL_GIGA_MAC_VER_14,
RTL_GIGA_MAC_VER_16,
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
RTL_GIGA_MAC_VER_27,
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
RTL_GIGA_MAC_VER_41,
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
RTL_GIGA_MAC_VER_45,
RTL_GIGA_MAC_VER_46,
RTL_GIGA_MAC_VER_47,
RTL_GIGA_MAC_VER_48,
RTL_GIGA_MAC_VER_49,
RTL_GIGA_MAC_VER_50,
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
RTL_GIGA_MAC_VER_60,
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
/* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */
/* RTL_GIGA_MAC_VER_13 was merged with VER_10 */
RTL_GIGA_MAC_VER_14,
/* RTL_GIGA_MAC_VER_16 was merged with VER_10 */
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
/* support for RTL_GIGA_MAC_VER_27 has been removed */
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
/* support for RTL_GIGA_MAC_VER_41 has been removed */
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
/* support for RTL_GIGA_MAC_VER_45 has been removed */
RTL_GIGA_MAC_VER_46,
/* support for RTL_GIGA_MAC_VER_47 has been removed */
RTL_GIGA_MAC_VER_48,
/* support for RTL_GIGA_MAC_VER_49 has been removed */
/* support for RTL_GIGA_MAC_VER_50 has been removed */
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
/* support for RTL_GIGA_MAC_VER_60 has been removed */
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,79 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/types.h>
#include <linux/phy.h>
enum mac_version {
/* support for ancient RTL_GIGA_MAC_VER_01 has been removed */
RTL_GIGA_MAC_VER_02,
RTL_GIGA_MAC_VER_03,
RTL_GIGA_MAC_VER_04,
RTL_GIGA_MAC_VER_05,
RTL_GIGA_MAC_VER_06,
RTL_GIGA_MAC_VER_07,
RTL_GIGA_MAC_VER_08,
RTL_GIGA_MAC_VER_09,
RTL_GIGA_MAC_VER_10,
RTL_GIGA_MAC_VER_11,
/* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */
/* RTL_GIGA_MAC_VER_13 was merged with VER_10 */
RTL_GIGA_MAC_VER_14,
/* RTL_GIGA_MAC_VER_16 was merged with VER_10 */
RTL_GIGA_MAC_VER_17,
RTL_GIGA_MAC_VER_18,
RTL_GIGA_MAC_VER_19,
RTL_GIGA_MAC_VER_20,
RTL_GIGA_MAC_VER_21,
RTL_GIGA_MAC_VER_22,
RTL_GIGA_MAC_VER_23,
RTL_GIGA_MAC_VER_24,
RTL_GIGA_MAC_VER_25,
RTL_GIGA_MAC_VER_26,
/* support for RTL_GIGA_MAC_VER_27 has been removed */
RTL_GIGA_MAC_VER_28,
RTL_GIGA_MAC_VER_29,
RTL_GIGA_MAC_VER_30,
RTL_GIGA_MAC_VER_31,
RTL_GIGA_MAC_VER_32,
RTL_GIGA_MAC_VER_33,
RTL_GIGA_MAC_VER_34,
RTL_GIGA_MAC_VER_35,
RTL_GIGA_MAC_VER_36,
RTL_GIGA_MAC_VER_37,
RTL_GIGA_MAC_VER_38,
RTL_GIGA_MAC_VER_39,
RTL_GIGA_MAC_VER_40,
/* support for RTL_GIGA_MAC_VER_41 has been removed */
RTL_GIGA_MAC_VER_42,
RTL_GIGA_MAC_VER_43,
RTL_GIGA_MAC_VER_44,
/* support for RTL_GIGA_MAC_VER_45 has been removed */
RTL_GIGA_MAC_VER_46,
/* support for RTL_GIGA_MAC_VER_47 has been removed */
RTL_GIGA_MAC_VER_48,
/* support for RTL_GIGA_MAC_VER_49 has been removed */
/* support for RTL_GIGA_MAC_VER_50 has been removed */
RTL_GIGA_MAC_VER_51,
RTL_GIGA_MAC_VER_52,
RTL_GIGA_MAC_VER_53,
/* support for RTL_GIGA_MAC_VER_60 has been removed */
RTL_GIGA_MAC_VER_61,
RTL_GIGA_MAC_VER_63,
RTL_GIGA_MAC_NONE
};
struct rtl8169_private;
void r8169_apply_firmware(struct rtl8169_private *tp);
u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware-5.10-ethercat.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware-5.14-ethercat.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware-5.15-ethercat.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware-6.1-ethercat.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

View File

@ -0,0 +1,236 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_firmware.c: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/delay.h>
#include <linux/firmware.h>
#include "r8169_firmware.h"
enum rtl_fw_opcode {
PHY_READ = 0x0,
PHY_DATA_OR = 0x1,
PHY_DATA_AND = 0x2,
PHY_BJMPN = 0x3,
PHY_MDIO_CHG = 0x4,
PHY_CLEAR_READCOUNT = 0x7,
PHY_WRITE = 0x8,
PHY_READCOUNT_EQ_SKIP = 0x9,
PHY_COMP_EQ_SKIPN = 0xa,
PHY_COMP_NEQ_SKIPN = 0xb,
PHY_WRITE_PREVIOUS = 0xc,
PHY_SKIPN = 0xd,
PHY_DELAY_MS = 0xe,
};
struct fw_info {
u32 magic;
char version[RTL_VER_SIZE];
__le32 fw_start;
__le32 fw_len;
u8 chksum;
} __packed;
#define FW_OPCODE_SIZE sizeof_field(struct rtl_fw_phy_action, code[0])
static bool rtl_fw_format_ok(struct rtl_fw *rtl_fw)
{
const struct firmware *fw = rtl_fw->fw;
struct fw_info *fw_info = (struct fw_info *)fw->data;
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
if (fw->size < FW_OPCODE_SIZE)
return false;
if (!fw_info->magic) {
size_t i, size, start;
u8 checksum = 0;
if (fw->size < sizeof(*fw_info))
return false;
for (i = 0; i < fw->size; i++)
checksum += fw->data[i];
if (checksum != 0)
return false;
start = le32_to_cpu(fw_info->fw_start);
if (start > fw->size)
return false;
size = le32_to_cpu(fw_info->fw_len);
if (size > (fw->size - start) / FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, fw_info->version, RTL_VER_SIZE);
pa->code = (__le32 *)(fw->data + start);
pa->size = size;
} else {
if (fw->size % FW_OPCODE_SIZE)
return false;
strscpy(rtl_fw->version, rtl_fw->fw_name, RTL_VER_SIZE);
pa->code = (__le32 *)fw->data;
pa->size = fw->size / FW_OPCODE_SIZE;
}
return true;
}
static bool rtl_fw_data_ok(struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 val = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
switch (action >> 28) {
case PHY_READ:
case PHY_DATA_OR:
case PHY_DATA_AND:
case PHY_CLEAR_READCOUNT:
case PHY_WRITE:
case PHY_WRITE_PREVIOUS:
case PHY_DELAY_MS:
break;
case PHY_MDIO_CHG:
if (val > 1)
goto out;
break;
case PHY_BJMPN:
if (regno > index)
goto out;
break;
case PHY_READCOUNT_EQ_SKIP:
if (index + 2 >= pa->size)
goto out;
break;
case PHY_COMP_EQ_SKIPN:
case PHY_COMP_NEQ_SKIPN:
case PHY_SKIPN:
if (index + 1 + regno >= pa->size)
goto out;
break;
default:
dev_err(rtl_fw->dev, "Invalid action 0x%08x\n", action);
return false;
}
}
return true;
out:
dev_err(rtl_fw->dev, "Out of range of firmware\n");
return false;
}
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
{
struct rtl_fw_phy_action *pa = &rtl_fw->phy_action;
rtl_fw_write_t fw_write = rtl_fw->phy_write;
rtl_fw_read_t fw_read = rtl_fw->phy_read;
int predata = 0, count = 0;
size_t index;
for (index = 0; index < pa->size; index++) {
u32 action = le32_to_cpu(pa->code[index]);
u32 data = action & 0x0000ffff;
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);
count++;
break;
case PHY_DATA_OR:
predata |= data;
break;
case PHY_DATA_AND:
predata &= data;
break;
case PHY_BJMPN:
index -= (regno + 1);
break;
case PHY_MDIO_CHG:
if (data) {
fw_write = rtl_fw->mac_mcu_write;
fw_read = rtl_fw->mac_mcu_read;
} else {
fw_write = rtl_fw->phy_write;
fw_read = rtl_fw->phy_read;
}
break;
case PHY_CLEAR_READCOUNT:
count = 0;
break;
case PHY_WRITE:
fw_write(tp, regno, data);
break;
case PHY_READCOUNT_EQ_SKIP:
if (count == data)
index++;
break;
case PHY_COMP_EQ_SKIPN:
if (predata == data)
index += regno;
break;
case PHY_COMP_NEQ_SKIPN:
if (predata != data)
index += regno;
break;
case PHY_WRITE_PREVIOUS:
fw_write(tp, regno, predata);
break;
case PHY_SKIPN:
index += regno;
break;
case PHY_DELAY_MS:
msleep(data);
break;
}
}
}
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw)
{
release_firmware(rtl_fw->fw);
}
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw)
{
int rc;
rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev);
if (rc < 0)
goto out;
if (!rtl_fw_format_ok(rtl_fw) || !rtl_fw_data_ok(rtl_fw)) {
release_firmware(rtl_fw->fw);
rc = -EINVAL;
goto out;
}
return 0;
out:
dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n",
rtl_fw->fw_name, rc);
return rc;
}

View File

@ -0,0 +1,39 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* r8169_firmware.h: RealTek 8169/8168/8101 ethernet driver.
*
* Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
* Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
* Copyright (c) a lot of people too. Please respect their work.
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/device.h>
#include <linux/firmware.h>
struct rtl8169_private;
typedef void (*rtl_fw_write_t)(struct rtl8169_private *tp, int reg, int val);
typedef int (*rtl_fw_read_t)(struct rtl8169_private *tp, int reg);
#define RTL_VER_SIZE 32
struct rtl_fw {
rtl_fw_write_t phy_write;
rtl_fw_read_t phy_read;
rtl_fw_write_t mac_mcu_write;
rtl_fw_read_t mac_mcu_read;
const struct firmware *fw;
const char *fw_name;
struct device *dev;
char version[RTL_VER_SIZE];
struct rtl_fw_phy_action {
__le32 *code;
size_t size;
} phy_action;
};
int rtl_fw_request_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_release_firmware(struct rtl_fw *rtl_fw);
void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
@ -48,6 +46,13 @@
*
* - Added the ecrt_slave_config_flag() method and the EC_HAVE_FLAGS
* definition to check for its existence.
* - Added SoE IDN requests, including the datatype ec_soe_request_t and the
* methods ecrt_slave_config_create_soe_request(),
* ecrt_soe_request_object(), ecrt_soe_request_timeout(),
* ecrt_soe_request_data(), ecrt_soe_request_data_size(),
* ecrt_soe_request_state(), ecrt_soe_request_write() and
* ecrt_soe_request_read(). Use the EC_HAVE_SOE_REQUESTS to check, if the
* functionality is available.
*
* Changes in version 1.5.2:
*
@ -57,7 +62,7 @@
* - Added the EC_HAVE_REDUNDANCY define, to check, if the interface contains
* redundancy features.
* - Added ecrt_sdo_request_index() to change SDO index and subindex after
* handler creation.
* request creation.
* - Added interface for retrieving CoE emergency messages, i. e.
* ecrt_slave_config_emerg_size(), ecrt_slave_config_emerg_pop(),
* ecrt_slave_config_emerg_clear(), ecrt_slave_config_emerg_overruns() and
@ -219,6 +224,14 @@
*/
#define EC_HAVE_FLAGS
/** Defined if the methods ecrt_slave_config_create_soe_request(),
* ecrt_soe_request_object(), ecrt_soe_request_timeout(),
* ecrt_soe_request_data(), ecrt_soe_request_data_size(),
* ecrt_soe_request_state(), ecrt_soe_request_write() and
* ecrt_soe_request_read() and the datatype ec_soe_request_t are available.
*/
#define EC_HAVE_SOE_REQUESTS
/*****************************************************************************/
/** Symbol visibility control macro.
@ -285,11 +298,14 @@ typedef struct ec_domain ec_domain_t; /**< \see ec_domain */
struct ec_sdo_request;
typedef struct ec_sdo_request ec_sdo_request_t; /**< \see ec_sdo_request. */
struct ec_soe_request;
typedef struct ec_soe_request ec_soe_request_t; /**< \see ec_soe_request. */
struct ec_voe_handler;
typedef struct ec_voe_handler ec_voe_handler_t; /**< \see ec_voe_handler. */
struct ec_reg_request;
typedef struct ec_reg_request ec_reg_request_t; /**< \see ec_sdo_request. */
typedef struct ec_reg_request ec_reg_request_t; /**< \see ec_reg_request. */
/*****************************************************************************/
@ -1606,6 +1622,23 @@ EC_PUBLIC_API ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
size_t size /**< Data size to reserve. */
);
/** Create an SoE request to exchange SoE IDNs during realtime operation.
*
* The created SoE request object is freed automatically when the master is
* released.
*
* This method has to be called in non-realtime context before
* ecrt_master_activate().
*
* \return New SoE request, or NULL on error.
*/
ec_soe_request_t *ecrt_slave_config_create_soe_request(
ec_slave_config_t *sc, /**< Slave configuration. */
uint8_t drive_no, /**< Drive number. */
uint16_t idn, /**< Sercos ID-Number. */
size_t size /**< Data size to reserve. */
);
/** Create an VoE handler to exchange vendor-specific data during realtime
* operation.
*
@ -1930,6 +1963,105 @@ EC_PUBLIC_API void ecrt_sdo_request_read(
ec_sdo_request_t *req /**< SDO request. */
);
/*****************************************************************************
* SoE request methods.
****************************************************************************/
/** Set the request's drive and Sercos ID numbers.
*
* \attention If the drive number and/or IDN is changed while
* ecrt_soe_request_state() returns EC_REQUEST_BUSY, this may lead to
* unexpected results.
*/
void ecrt_soe_request_idn(
ec_soe_request_t *req, /**< IDN request. */
uint8_t drive_no, /**< SDO index. */
uint16_t idn /**< SoE IDN. */
);
/** Set the timeout for an SoE request.
*
* If the request cannot be processed in the specified time, if will be marked
* as failed.
*
* The timeout is permanently stored in the request object and is valid until
* the next call of this method.
*/
void ecrt_soe_request_timeout(
ec_soe_request_t *req, /**< SoE request. */
uint32_t timeout /**< Timeout in milliseconds. Zero means no
timeout. */
);
/** Access to the SoE request's data.
*
* This function returns a pointer to the request's internal IDN data memory.
*
* - After a read operation was successful, integer data can be evaluated
* using the EC_READ_*() macros as usual. Example:
* \code
* uint16_t value = EC_READ_U16(ecrt_soe_request_data(idn_req)));
* \endcode
* - If a write operation shall be triggered, the data have to be written to
* the internal memory. Use the EC_WRITE_*() macros, if you are writing
* integer data. Be sure, that the data fit into the memory. The memory size
* is a parameter of ecrt_slave_config_create_soe_request().
* \code
* EC_WRITE_U16(ecrt_soe_request_data(idn_req), 0xFFFF);
* \endcode
*
* \attention The return value can be invalidated during a read operation,
* because the internal IDN data memory could be re-allocated if the read IDN
* data do not fit inside.
*
* \return Pointer to the internal IDN data memory.
*/
uint8_t *ecrt_soe_request_data(
ec_soe_request_t *req /**< SoE request. */
);
/** Returns the current IDN data size.
*
* When the SoE request is created, the data size is set to the size of the
* reserved memory. After a read operation the size is set to the size of the
* read data. The size is not modified in any other situation.
*
* \return IDN data size in bytes.
*/
size_t ecrt_soe_request_data_size(
const ec_soe_request_t *req /**< SoE request. */
);
/** Get the current state of the SoE request.
*
* \return Request state.
*/
ec_request_state_t ecrt_soe_request_state(
ec_soe_request_t *req /**< SoE request. */
);
/** Schedule an SoE IDN write operation.
*
* \attention This method may not be called while ecrt_soe_request_state()
* returns EC_REQUEST_BUSY.
*/
void ecrt_soe_request_write(
ec_soe_request_t *req /**< SoE request. */
);
/** Schedule an SoE IDN read operation.
*
* \attention This method may not be called while ecrt_soe_request_state()
* returns EC_REQUEST_BUSY.
*
* \attention After calling this function, the return value of
* ecrt_soe_request_data() must be considered as invalid while
* ecrt_soe_request_state() returns EC_REQUEST_BUSY.
*/
void ecrt_soe_request_read(
ec_soe_request_t *req /**< SoE request. */
);
/*****************************************************************************
* VoE handler methods.
****************************************************************************/

View File

@ -1,8 +1,6 @@
#------------------------------------------------------------------------------
#
# $Id$
#
# Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
# Copyright (C) 2006-2024 Florian Pose, Ingenieurgemeinschaft IgH
#
# This file is part of the IgH EtherCAT master userspace library.
#
@ -33,6 +31,7 @@ libethercat_la_SOURCES = \
reg_request.c \
sdo_request.c \
slave_config.c \
soe_request.c \
voe_handler.c
noinst_HEADERS = \
@ -42,6 +41,7 @@ noinst_HEADERS = \
reg_request.h \
sdo_request.h \
slave_config.h \
soe_request.h \
voe_handler.h
libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir) \
@ -66,8 +66,10 @@ libethercat_la_CFLAGS = -fno-strict-aliasing -Wall -I$(top_srcdir) \
# 1:0.0
# ecrt_master_sync_reference_clock_to() added.
# 2:0:1
# SoE requests added
# 3:0:2
#
libethercat_la_LDFLAGS = -version-info 2:0:1 \
libethercat_la_LDFLAGS = -version-info 3:0:2 \
-fvisibility=hidden
pkgconfig_DATA = libethercat.pc

View File

@ -29,6 +29,7 @@
#include "slave_config.h"
#include "domain.h"
#include "sdo_request.h"
#include "soe_request.h"
#include "reg_request.h"
#include "voe_handler.h"
#include "master.h"
@ -38,6 +39,7 @@
void ec_slave_config_clear(ec_slave_config_t *sc)
{
ec_sdo_request_t *r, *next_r;
ec_soe_request_t *s, *next_s;
ec_reg_request_t *e, *next_e;
ec_voe_handler_t *v, *next_v;
@ -50,6 +52,15 @@ void ec_slave_config_clear(ec_slave_config_t *sc)
}
sc->first_sdo_request = NULL;
s = sc->first_soe_request;
while (r) {
next_s = s->next;
ec_soe_request_clear(s);
free(s);
s = next_s;
}
sc->first_soe_request = NULL;
e = sc->first_reg_request;
while (e) {
next_e = e->next;
@ -601,6 +612,76 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(ec_slave_config_t *sc,
/*****************************************************************************/
void ec_slave_config_add_soe_request(ec_slave_config_t *sc,
ec_soe_request_t *req)
{
if (sc->first_soe_request) {
ec_soe_request_t *r = sc->first_soe_request;
while (r->next) {
r = r->next;
}
r->next = req;
} else {
sc->first_soe_request = req;
}
}
/*****************************************************************************/
ec_soe_request_t *ecrt_slave_config_create_soe_request(ec_slave_config_t *sc,
uint8_t drive_no, uint16_t idn, size_t size)
{
ec_ioctl_soe_request_t data;
ec_soe_request_t *req;
int ret;
req = malloc(sizeof(ec_soe_request_t));
if (!req) {
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
if (size) {
req->data = malloc(size);
if (!req->data) {
fprintf(stderr, "Failed to allocate %zu bytes of SoE data"
" memory.\n", size);
free(req);
return 0;
}
} else {
req->data = NULL;
}
data.config_index = sc->index;
data.drive_no = drive_no;
data.idn = idn;
data.size = size;
ret = ioctl(sc->master->fd, EC_IOCTL_SC_SOE_REQUEST, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to create SoE request: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
ec_soe_request_clear(req);
free(req);
return NULL;
}
req->next = NULL;
req->config = sc;
req->index = data.request_index;
req->drive_no = data.drive_no;
req->idn = data.idn;
req->data_size = size;
req->mem_size = size;
ec_slave_config_add_soe_request(sc, req);
return req;
}
/*****************************************************************************/
void ec_slave_config_add_reg_request(ec_slave_config_t *sc,
ec_reg_request_t *reg)
{

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
@ -33,6 +31,7 @@ struct ec_slave_config {
uint16_t alias;
uint16_t position;
ec_sdo_request_t *first_sdo_request;
ec_soe_request_t *first_soe_request;
ec_reg_request_t *first_reg_request;
ec_voe_handler_t *first_voe_handler;
};

182
lib/soe_request.c Normal file
View File

@ -0,0 +1,182 @@
/******************************************************************************
*
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
* The IgH EtherCAT master userspace library is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* ---
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
/** \file
* Canopen over EtherCAT SoE request functions.
*/
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include "ioctl.h"
#include "soe_request.h"
#include "slave_config.h"
#include "master.h"
/*****************************************************************************/
void ec_soe_request_clear(ec_soe_request_t *req)
{
if (req->data) {
free(req->data);
req->data = NULL;
}
}
/*****************************************************************************
* Application interface.
****************************************************************************/
void ecrt_soe_request_idn(ec_soe_request_t *req, uint8_t drive_no,
uint16_t idn)
{
ec_ioctl_soe_request_t data;
int ret;
data.config_index = req->config->index;
data.request_index = req->index;
data.drive_no = drive_no;
data.idn = idn;
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_IDN, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to set SoE request IDN: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
}
/*****************************************************************************/
void ecrt_soe_request_timeout(ec_soe_request_t *req, uint32_t timeout)
{
ec_ioctl_soe_request_t data;
int ret;
data.config_index = req->config->index;
data.request_index = req->index;
data.timeout = timeout;
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_TIMEOUT, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to set SoE request timeout: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
}
/*****************************************************************************/
uint8_t *ecrt_soe_request_data(ec_soe_request_t *req)
{
return req->data;
}
/*****************************************************************************/
size_t ecrt_soe_request_data_size(const ec_soe_request_t *req)
{
return req->data_size;
}
/*****************************************************************************/
ec_request_state_t ecrt_soe_request_state(ec_soe_request_t *req)
{
ec_ioctl_soe_request_t data;
int ret;
data.config_index = req->config->index;
data.request_index = req->index;
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_STATE, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to get SoE request state: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
return EC_REQUEST_ERROR;
}
if (data.size) { // new data waiting to be copied
if (req->mem_size < data.size) {
fprintf(stderr, "Received %zu bytes do not fit info SoE data"
" memory (%zu bytes)!\n", data.size, req->mem_size);
return EC_REQUEST_ERROR;
}
data.data = req->data;
ret = ioctl(req->config->master->fd,
EC_IOCTL_SOE_REQUEST_DATA, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to get SoE data: %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
return EC_REQUEST_ERROR;
}
req->data_size = data.size;
}
return data.state;
}
/*****************************************************************************/
void ecrt_soe_request_read(ec_soe_request_t *req)
{
ec_ioctl_soe_request_t data;
int ret;
data.config_index = req->config->index;
data.request_index = req->index;
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_READ, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to command an SoE read operation : %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
}
/*****************************************************************************/
void ecrt_soe_request_write(ec_soe_request_t *req)
{
ec_ioctl_soe_request_t data;
int ret;
data.config_index = req->config->index;
data.request_index = req->index;
data.data = req->data;
data.size = req->data_size;
ret = ioctl(req->config->master->fd, EC_IOCTL_SOE_REQUEST_WRITE, &data);
if (EC_IOCTL_IS_ERROR(ret)) {
fprintf(stderr, "Failed to command an SDO write operation : %s\n",
strerror(EC_IOCTL_ERRNO(ret)));
}
}
/*****************************************************************************/

48
lib/soe_request.h Normal file
View File

@ -0,0 +1,48 @@
/******************************************************************************
*
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT master userspace library.
*
* The IgH EtherCAT master userspace library is free software; you can
* redistribute it and/or modify it under the terms of the GNU Lesser General
* Public License as published by the Free Software Foundation; version 2.1
* of the License.
*
* The IgH EtherCAT master userspace library 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the IgH EtherCAT master userspace library. If not, see
* <http://www.gnu.org/licenses/>.
*
* ---
*
* The license mentioned above concerns the source code only. Using the
* EtherCAT technology and brand is only permitted in compliance with the
* industrial property and similar rights of Beckhoff Automation GmbH.
*
*****************************************************************************/
#include "include/ecrt.h"
/*****************************************************************************/
struct ec_soe_request {
ec_soe_request_t *next; /**< List header. */
ec_slave_config_t *config; /**< Parent slave configuration. */
unsigned int index; /**< Request index (identifier). */
uint8_t drive_no; /**< SoE drive number. */
uint16_t idn; /**< SoE ID number. */
uint8_t *data; /**< Pointer to SoE data. */
size_t mem_size; /**< Size of SoE data memory. */
size_t data_size; /**< Size of SoE data. */
};
/*****************************************************************************/
void ec_soe_request_clear(ec_soe_request_t *);
/*****************************************************************************/

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -60,6 +58,7 @@ void ec_fsm_master_state_assign_sii(ec_fsm_master_t *);
void ec_fsm_master_state_write_sii(ec_fsm_master_t *);
void ec_fsm_master_state_sdo_dictionary(ec_fsm_master_t *);
void ec_fsm_master_state_sdo_request(ec_fsm_master_t *);
void ec_fsm_master_state_soe_request(ec_fsm_master_t *);
void ec_fsm_master_enter_clear_addresses(ec_fsm_master_t *);
void ec_fsm_master_enter_write_system_times(ec_fsm_master_t *);
@ -77,8 +76,18 @@ void ec_fsm_master_init(
fsm->master = master;
fsm->datagram = datagram;
// inits the member variables state, idle, dev_idx, link_state,
// slaves_responding, slave_states and rescan_required
ec_fsm_master_reset(fsm);
fsm->retries = 0;
fsm->scan_jiffies = 0;
fsm->slave = NULL;
fsm->sii_request = NULL;
fsm->sii_index = 0;
fsm->sdo_request = NULL;
fsm->soe_request = NULL;
// init sub-state-machines
ec_fsm_coe_init(&fsm->fsm_coe);
ec_fsm_soe_init(&fsm->fsm_soe);
@ -486,17 +495,18 @@ int ec_fsm_master_action_process_sii(
/*****************************************************************************/
/** Check for pending SDO requests and process one.
/** Check for pending internal SDO/SoE requests and process one.
*
* \return non-zero, if an SDO request is processed.
*/
int ec_fsm_master_action_process_sdo(
int ec_fsm_master_action_process_int_request(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_master_t *master = fsm->master;
ec_slave_t *slave;
ec_sdo_request_t *req;
ec_sdo_request_t *sdo_req;
ec_soe_request_t *soe_req;
// search for internal requests to be processed
for (slave = master->slaves;
@ -507,33 +517,61 @@ int ec_fsm_master_action_process_sdo(
continue;
}
list_for_each_entry(req, &slave->config->sdo_requests, list) {
if (req->state == EC_INT_REQUEST_QUEUED) {
list_for_each_entry(sdo_req, &slave->config->sdo_requests, list) {
if (sdo_req->state == EC_INT_REQUEST_QUEUED) {
if (ec_sdo_request_timed_out(req)) {
req->state = EC_INT_REQUEST_FAILURE;
if (ec_sdo_request_timed_out(sdo_req)) {
sdo_req->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_DBG(slave, 1, "Internal SDO request"
" timed out.\n");
continue;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
req->state = EC_INT_REQUEST_FAILURE;
sdo_req->state = EC_INT_REQUEST_FAILURE;
continue;
}
req->state = EC_INT_REQUEST_BUSY;
sdo_req->state = EC_INT_REQUEST_BUSY;
EC_SLAVE_DBG(slave, 1, "Processing internal"
" SDO request...\n");
fsm->idle = 0;
fsm->sdo_request = req;
fsm->sdo_request = sdo_req;
fsm->slave = slave;
fsm->state = ec_fsm_master_state_sdo_request;
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, req);
ec_fsm_coe_transfer(&fsm->fsm_coe, slave, sdo_req);
ec_fsm_coe_exec(&fsm->fsm_coe, fsm->datagram);
return 1;
}
}
list_for_each_entry(soe_req, &slave->config->soe_requests, list) {
if (soe_req->state == EC_INT_REQUEST_QUEUED) {
if (ec_soe_request_timed_out(soe_req)) {
soe_req->state = EC_INT_REQUEST_FAILURE;
EC_SLAVE_DBG(slave, 1, "Internal SoE request"
" timed out.\n");
continue;
}
if (slave->current_state == EC_SLAVE_STATE_INIT) {
soe_req->state = EC_INT_REQUEST_FAILURE;
continue;
}
soe_req->state = EC_INT_REQUEST_BUSY;
EC_SLAVE_DBG(slave, 1, "Processing internal"
" SoE request...\n");
fsm->idle = 0;
fsm->soe_request = soe_req;
fsm->slave = slave;
fsm->state = ec_fsm_master_state_soe_request;
ec_fsm_soe_transfer(&fsm->fsm_soe, slave, soe_req);
ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram);
return 1;
}
}
}
return 0;
}
@ -551,8 +589,8 @@ void ec_fsm_master_action_idle(
ec_master_t *master = fsm->master;
ec_slave_t *slave;
// Check for pending internal SDO requests
if (ec_fsm_master_action_process_sdo(fsm)) {
// Check for pending internal SDO or SoE requests
if (ec_fsm_master_action_process_int_request(fsm)) {
return;
}
@ -1351,8 +1389,51 @@ void ec_fsm_master_state_sdo_request(
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SDO request.\n");
// check for another SDO request
if (ec_fsm_master_action_process_sdo(fsm)) {
// check for another SDO/SoE request
if (ec_fsm_master_action_process_int_request(fsm)) {
return; // processing another request
}
ec_fsm_master_restart(fsm);
}
/*****************************************************************************/
/** Master state: SoE REQUEST.
*/
void ec_fsm_master_state_soe_request(
ec_fsm_master_t *fsm /**< Master state machine. */
)
{
ec_soe_request_t *request = fsm->soe_request;
if (!request) {
// configuration was cleared in the meantime
ec_fsm_master_restart(fsm);
return;
}
if (ec_fsm_soe_exec(&fsm->fsm_soe, fsm->datagram)) {
return;
}
if (!ec_fsm_soe_success(&fsm->fsm_soe)) {
EC_SLAVE_DBG(fsm->slave, 1,
"Failed to process internal SoE request.\n");
request->state = EC_INT_REQUEST_FAILURE;
wake_up_all(&fsm->master->request_queue);
ec_fsm_master_restart(fsm);
return;
}
// SoE request finished
request->state = EC_INT_REQUEST_SUCCESS;
wake_up_all(&fsm->master->request_queue);
EC_SLAVE_DBG(fsm->slave, 1, "Finished internal SoE request.\n");
// check for another CoE/SoE request
if (ec_fsm_master_action_process_int_request(fsm)) {
return; // processing another request
}

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -82,6 +80,7 @@ struct ec_fsm_master {
ec_sii_write_request_t *sii_request; /**< SII write request */
off_t sii_index; /**< index to SII write request data */
ec_sdo_request_t *sdo_request; /**< SDO request to process. */
ec_soe_request_t *soe_request; /**< SoE request to process. */
ec_fsm_coe_t fsm_coe; /**< CoE state machine */
ec_fsm_soe_t fsm_soe; /**< SoE state machine */

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*

View File

@ -2834,6 +2834,59 @@ static ATTRIBUTES int ec_ioctl_sc_create_sdo_request(
/*****************************************************************************/
/** Create an SoE request.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_sc_create_soe_request(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data))) {
return -EFAULT;
}
data.request_index = 0;
if (down_interruptible(&master->master_sem))
return -EINTR;
sc = ec_master_get_config(master, data.config_index);
if (!sc) {
up(&master->master_sem);
return -ENOENT;
}
list_for_each_entry(req, &sc->soe_requests, list) {
data.request_index++;
}
up(&master->master_sem); /** \todo sc could be invalidated */
req = ecrt_slave_config_create_soe_request_err(sc, data.drive_no,
data.idn, data.size);
if (IS_ERR(req)) {
return PTR_ERR(req);
}
if (copy_to_user((void __user *) arg, &data, sizeof(data))) {
return -EFAULT;
}
return 0;
}
/*****************************************************************************/
/** Create a register request.
*
* \return Zero on success, otherwise a negative error code.
@ -3499,6 +3552,255 @@ static ATTRIBUTES int ec_ioctl_sdo_request_data(
/*****************************************************************************/
/** Sets an SoE request's drive number and IDN.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_index(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_idn(req, data.drive_no, data.idn);
return 0;
}
/*****************************************************************************/
/** Sets an CoE request's timeout.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_timeout(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_timeout(req, data.timeout);
return 0;
}
/*****************************************************************************/
/** Gets an SoE request's state.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_state(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
data.state = ecrt_soe_request_state(req);
if (data.state == EC_REQUEST_SUCCESS && req->dir == EC_DIR_INPUT) {
data.size = ecrt_soe_request_data_size(req);
}
else {
data.size = 0;
}
if (copy_to_user((void __user *) arg, &data, sizeof(data)))
return -EFAULT;
return 0;
}
/*****************************************************************************/
/** Starts an SoE IDN read operation.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_read(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ecrt_soe_request_read(req);
return 0;
}
/*****************************************************************************/
/** Starts an SoE IDN write operation.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_write(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
int ret;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
if (!data.size) {
EC_MASTER_ERR(master, "IDN write: Data size may not be zero!\n");
return -EINVAL;
}
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
ret = ec_soe_request_alloc(req, data.size);
if (ret)
return ret;
if (copy_from_user(req->data, (void __user *) data.data, data.size))
return -EFAULT;
req->data_size = data.size;
ecrt_soe_request_write(req);
return 0;
}
/*****************************************************************************/
/** Read SoE IDN data.
*
* \return Zero on success, otherwise a negative error code.
*/
static ATTRIBUTES int ec_ioctl_soe_request_data(
ec_master_t *master, /**< EtherCAT master. */
void *arg, /**< ioctl() argument. */
ec_ioctl_context_t *ctx /**< Private data structure of file handle. */
)
{
ec_ioctl_soe_request_t data;
ec_slave_config_t *sc;
ec_soe_request_t *req;
if (unlikely(!ctx->requested))
return -EPERM;
if (copy_from_user(&data, (void __user *) arg, sizeof(data)))
return -EFAULT;
/* no locking of master_sem needed, because neither sc nor req will not be
* deleted in the meantime. */
if (!(sc = ec_master_get_config(master, data.config_index))) {
return -ENOENT;
}
if (!(req = ec_slave_config_find_soe_request(sc, data.request_index))) {
return -ENOENT;
}
if (copy_to_user((void __user *) data.data, ecrt_soe_request_data(req),
ecrt_soe_request_data_size(req)))
return -EFAULT;
return 0;
}
/*****************************************************************************/
/** Read register data.
*
* \return Zero on success, otherwise a negative error code.
@ -4634,6 +4936,13 @@ long EC_IOCTL(
}
ret = ec_ioctl_sc_create_sdo_request(master, arg, ctx);
break;
case EC_IOCTL_SC_SOE_REQUEST:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_sc_create_soe_request(master, arg, ctx);
break;
case EC_IOCTL_SC_REG_REQUEST:
if (!ctx->writable) {
ret = -EPERM;
@ -4722,6 +5031,40 @@ long EC_IOCTL(
case EC_IOCTL_SDO_REQUEST_DATA:
ret = ec_ioctl_sdo_request_data(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_IDN:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_index(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_TIMEOUT:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_timeout(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_STATE:
ret = ec_ioctl_soe_request_state(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_READ:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_read(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_WRITE:
if (!ctx->writable) {
ret = -EPERM;
break;
}
ret = ec_ioctl_soe_request_write(master, arg, ctx);
break;
case EC_IOCTL_SOE_REQUEST_DATA:
ret = ec_ioctl_soe_request_data(master, arg, ctx);
break;
case EC_IOCTL_REG_REQUEST_DATA:
ret = ec_ioctl_reg_request_data(master, arg, ctx);
break;

View File

@ -47,7 +47,7 @@
*
* Increment this when changing the ioctl interface!
*/
#define EC_IOCTL_VERSION_MAGIC 32
#define EC_IOCTL_VERSION_MAGIC 33
// Command-line tool
#define EC_IOCTL_MODULE EC_IOR(0x00, ec_ioctl_module_t)
@ -118,34 +118,41 @@
#define EC_IOCTL_SC_EMERG_CLEAR EC_IOW(0x3d, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_EMERG_OVERRUNS EC_IOWR(0x3e, ec_ioctl_sc_emerg_t)
#define EC_IOCTL_SC_SDO_REQUEST EC_IOWR(0x3f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x40, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x41, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x42, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x43, ec_ioctl_sc_idn_t)
#define EC_IOCTL_SC_FLAG EC_IOW(0x44, ec_ioctl_sc_flag_t)
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x45)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x46)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x47)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x48)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x49, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4a, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x51, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x52, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x53, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x54, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x55, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x56, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x57, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x58, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x59, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x5a, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x5b, size_t)
#define EC_IOCTL_SC_SOE_REQUEST EC_IOWR(0x40, ec_ioctl_soe_request_t)
#define EC_IOCTL_SC_REG_REQUEST EC_IOWR(0x41, ec_ioctl_reg_request_t)
#define EC_IOCTL_SC_VOE EC_IOWR(0x42, ec_ioctl_voe_t)
#define EC_IOCTL_SC_STATE EC_IOWR(0x43, ec_ioctl_sc_state_t)
#define EC_IOCTL_SC_IDN EC_IOW(0x44, ec_ioctl_sc_idn_t)
#define EC_IOCTL_SC_FLAG EC_IOW(0x45, ec_ioctl_sc_flag_t)
#define EC_IOCTL_DOMAIN_SIZE EC_IO(0x46)
#define EC_IOCTL_DOMAIN_OFFSET EC_IO(0x47)
#define EC_IOCTL_DOMAIN_PROCESS EC_IO(0x48)
#define EC_IOCTL_DOMAIN_QUEUE EC_IO(0x49)
#define EC_IOCTL_DOMAIN_STATE EC_IOWR(0x4a, ec_ioctl_domain_state_t)
#define EC_IOCTL_SDO_REQUEST_INDEX EC_IOWR(0x4b, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_TIMEOUT EC_IOWR(0x4c, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_STATE EC_IOWR(0x4d, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_READ EC_IOWR(0x4e, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_WRITE EC_IOWR(0x4f, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SDO_REQUEST_DATA EC_IOWR(0x50, ec_ioctl_sdo_request_t)
#define EC_IOCTL_SOE_REQUEST_IDN EC_IOWR(0x51, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_TIMEOUT EC_IOWR(0x52, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_STATE EC_IOWR(0x53, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_READ EC_IOWR(0x54, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_WRITE EC_IOWR(0x55, ec_ioctl_soe_request_t)
#define EC_IOCTL_SOE_REQUEST_DATA EC_IOWR(0x56, ec_ioctl_soe_request_t)
#define EC_IOCTL_REG_REQUEST_DATA EC_IOWR(0x57, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_STATE EC_IOWR(0x58, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_WRITE EC_IOWR(0x59, ec_ioctl_reg_request_t)
#define EC_IOCTL_REG_REQUEST_READ EC_IOWR(0x5a, ec_ioctl_reg_request_t)
#define EC_IOCTL_VOE_SEND_HEADER EC_IOW(0x5b, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_REC_HEADER EC_IOWR(0x5c, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ EC_IOW(0x5d, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_READ_NOSYNC EC_IOW(0x5e, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_WRITE EC_IOWR(0x5f, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_EXEC EC_IOWR(0x60, ec_ioctl_voe_t)
#define EC_IOCTL_VOE_DATA EC_IOWR(0x61, ec_ioctl_voe_t)
#define EC_IOCTL_SET_SEND_INTERVAL EC_IOW(0x62, size_t)
/*****************************************************************************/
@ -728,6 +735,22 @@ typedef struct {
/*****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;
// inputs/outputs
uint32_t request_index;
uint8_t drive_no;
uint16_t idn;
size_t size;
uint8_t *data;
uint32_t timeout;
ec_request_state_t state;
} ec_ioctl_soe_request_t;
/*****************************************************************************/
typedef struct {
// inputs
uint32_t config_index;

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -55,10 +53,12 @@ void ec_sdo_request_init(
req->data = NULL;
req->mem_size = 0;
req->data_size = 0;
req->dir = EC_DIR_INVALID;
req->issue_timeout = 0; // no timeout
req->response_timeout = EC_SDO_REQUEST_RESPONSE_TIMEOUT;
req->dir = EC_DIR_INVALID;
req->state = EC_INT_REQUEST_INIT;
req->jiffies_start = 0U;
req->jiffies_sent = 0U;
req->errno = 0;
req->abort_code = 0x00000000;
}

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -81,6 +79,7 @@ void ec_slave_config_init(
INIT_LIST_HEAD(&sc->sdo_configs);
INIT_LIST_HEAD(&sc->sdo_requests);
INIT_LIST_HEAD(&sc->soe_requests);
INIT_LIST_HEAD(&sc->reg_requests);
INIT_LIST_HEAD(&sc->voe_handlers);
INIT_LIST_HEAD(&sc->soe_configs);
@ -126,6 +125,13 @@ void ec_slave_config_clear(
kfree(req);
}
// free all SoE requests
list_for_each_entry_safe(soe, next_soe, &sc->soe_requests, list) {
list_del(&soe->list);
ec_soe_request_clear(soe);
kfree(soe);
}
// free all register requests
list_for_each_entry_safe(reg, next_reg, &sc->reg_requests, list) {
list_del(&reg->list);
@ -501,7 +507,7 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
/*****************************************************************************/
/** Finds a CoE handler via its position in the list.
/** Finds a CoE SDO request via its position in the list.
*
* \return Search result, or NULL.
*/
@ -523,6 +529,28 @@ ec_sdo_request_t *ec_slave_config_find_sdo_request(
/*****************************************************************************/
/** Finds a SoE request via its position in the list.
*
* \return Search result, or NULL.
*/
ec_soe_request_t *ec_slave_config_find_soe_request(
ec_slave_config_t *sc, /**< Slave configuration. */
unsigned int pos /**< Position in the list. */
)
{
ec_soe_request_t *req;
list_for_each_entry(req, &sc->soe_requests, list) {
if (pos--)
continue;
return req;
}
return NULL;
}
/*****************************************************************************/
/** Finds a register handler via its position in the list.
*
* \return Search result, or NULL.
@ -1152,6 +1180,58 @@ ec_sdo_request_t *ecrt_slave_config_create_sdo_request(
/*****************************************************************************/
/** Same as ecrt_slave_config_create_soe_request(), but with ERR_PTR() return
* value.
*/
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
{
ec_soe_request_t *req;
int ret;
EC_CONFIG_DBG(sc, 1, "%s(sc = 0x%p, "
"drive_no = 0x%02X, idn = 0x%04X, size = %zu)\n",
__func__, sc, drive_no, idn, size);
if (!(req = (ec_soe_request_t *)
kmalloc(sizeof(ec_soe_request_t), GFP_KERNEL))) {
EC_CONFIG_ERR(sc, "Failed to allocate IDN request memory!\n");
return ERR_PTR(-ENOMEM);
}
ec_soe_request_init(req);
ecrt_soe_request_idn(req, drive_no, idn);
ret = ec_soe_request_alloc(req, size);
if (ret < 0) {
ec_soe_request_clear(req);
kfree(req);
return ERR_PTR(ret);
}
// prepare data for optional writing
memset(req->data, 0x00, size);
req->data_size = size;
down(&sc->master->master_sem);
list_add_tail(&req->list, &sc->soe_requests);
up(&sc->master->master_sem);
return req;
}
/*****************************************************************************/
ec_soe_request_t *ecrt_slave_config_create_soe_request(
ec_slave_config_t *sc, uint8_t drive_no, uint16_t idn, size_t size)
{
ec_soe_request_t *req = ecrt_slave_config_create_soe_request_err(sc,
drive_no, idn, size);
return IS_ERR(req) ? NULL : req;
}
/*****************************************************************************/
/** Same as ecrt_slave_config_create_reg_request(), but with ERR_PTR() return
* value.
*/
@ -1367,6 +1447,7 @@ EXPORT_SYMBOL(ecrt_slave_config_emerg_pop);
EXPORT_SYMBOL(ecrt_slave_config_emerg_clear);
EXPORT_SYMBOL(ecrt_slave_config_emerg_overruns);
EXPORT_SYMBOL(ecrt_slave_config_create_sdo_request);
EXPORT_SYMBOL(ecrt_slave_config_create_soe_request);
EXPORT_SYMBOL(ecrt_slave_config_create_voe_handler);
EXPORT_SYMBOL(ecrt_slave_config_create_reg_request);
EXPORT_SYMBOL(ecrt_slave_config_state);

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2012 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -137,6 +135,7 @@ struct ec_slave_config {
struct list_head sdo_configs; /**< List of SDO configurations. */
struct list_head sdo_requests; /**< List of SDO requests. */
struct list_head soe_requests; /**< List of SoE requests. */
struct list_head voe_handlers; /**< List of VoE handlers. */
struct list_head reg_requests; /**< List of register requests. */
struct list_head soe_configs; /**< List of SoE configurations. */
@ -167,6 +166,8 @@ const ec_flag_t *ec_slave_config_get_flag_by_pos_const(
const ec_slave_config_t *, unsigned int);
ec_sdo_request_t *ec_slave_config_find_sdo_request(ec_slave_config_t *,
unsigned int);
ec_soe_request_t *ec_slave_config_find_soe_request(ec_slave_config_t *,
unsigned int);
ec_reg_request_t *ec_slave_config_find_reg_request(ec_slave_config_t *,
unsigned int);
ec_voe_handler_t *ec_slave_config_find_voe_handler(ec_slave_config_t *,
@ -175,6 +176,8 @@ ec_flag_t *ec_slave_config_find_flag(ec_slave_config_t *, const char *);
ec_sdo_request_t *ecrt_slave_config_create_sdo_request_err(
ec_slave_config_t *, uint16_t, uint8_t, size_t);
ec_soe_request_t *ecrt_slave_config_create_soe_request_err(
ec_slave_config_t *, uint8_t, uint16_t, size_t);
ec_voe_handler_t *ecrt_slave_config_create_voe_handler_err(
ec_slave_config_t *, size_t);
ec_reg_request_t *ecrt_slave_config_create_reg_request_err(

View File

@ -1,8 +1,6 @@
/******************************************************************************
*
* $Id$
*
* Copyright (C) 2006-2008 Florian Pose, Ingenieurgemeinschaft IgH
* Copyright (C) 2006-2023 Florian Pose, Ingenieurgemeinschaft IgH
*
* This file is part of the IgH EtherCAT Master.
*
@ -58,8 +56,10 @@ void ec_soe_request_init(
req->data = NULL;
req->mem_size = 0;
req->data_size = 0;
req->issue_timeout = 0; // no timeout
req->dir = EC_DIR_INVALID;
req->state = EC_INT_REQUEST_INIT;
req->jiffies_start = 0U;
req->jiffies_sent = 0U;
req->error_code = 0x0000;
}
@ -230,6 +230,7 @@ void ec_soe_request_read(
req->dir = EC_DIR_INPUT;
req->state = EC_INT_REQUEST_QUEUED;
req->error_code = 0x0000;
req->jiffies_start = jiffies;
}
/*****************************************************************************/
@ -243,6 +244,86 @@ void ec_soe_request_write(
req->dir = EC_DIR_OUTPUT;
req->state = EC_INT_REQUEST_QUEUED;
req->error_code = 0x0000;
req->jiffies_start = jiffies;
}
/*****************************************************************************/
/** Checks, if the timeout was exceeded.
*
* \return non-zero if the timeout was exceeded, else zero.
*/
int ec_soe_request_timed_out(const ec_soe_request_t *req /**< SDO request. */)
{
return req->issue_timeout
&& jiffies - req->jiffies_start > HZ * req->issue_timeout / 1000;
}
/*****************************************************************************
* Application interface.
****************************************************************************/
void ecrt_soe_request_idn(ec_soe_request_t *req, uint8_t drive_no,
uint16_t idn)
{
req->drive_no = drive_no;
req->idn = idn;
}
/*****************************************************************************/
void ecrt_soe_request_timeout(ec_soe_request_t *req, uint32_t timeout)
{
req->issue_timeout = timeout;
}
/*****************************************************************************/
uint8_t *ecrt_soe_request_data(ec_soe_request_t *req)
{
return req->data;
}
/*****************************************************************************/
size_t ecrt_soe_request_data_size(const ec_soe_request_t *req)
{
return req->data_size;
}
/*****************************************************************************/
ec_request_state_t ecrt_soe_request_state(ec_soe_request_t *req)
{
return ec_request_state_translation_table[req->state];
}
/*****************************************************************************/
void ecrt_soe_request_read(ec_soe_request_t *req)
{
ec_soe_request_read(req);
}
/*****************************************************************************/
void ecrt_soe_request_write(ec_soe_request_t *req)
{
ec_soe_request_write(req);
}
/*****************************************************************************/
/** \cond */
EXPORT_SYMBOL(ecrt_soe_request_idn);
EXPORT_SYMBOL(ecrt_soe_request_timeout);
EXPORT_SYMBOL(ecrt_soe_request_data);
EXPORT_SYMBOL(ecrt_soe_request_data_size);
EXPORT_SYMBOL(ecrt_soe_request_state);
EXPORT_SYMBOL(ecrt_soe_request_read);
EXPORT_SYMBOL(ecrt_soe_request_write);
/** \endcond */
/*****************************************************************************/

View File

@ -39,7 +39,7 @@
/** Sercos-over-EtherCAT request.
*/
typedef struct {
struct ec_soe_request {
struct list_head list; /**< List item. */
uint8_t drive_no; /**< Drive number. */
uint16_t idn; /**< Sercos ID-Number. */
@ -47,13 +47,16 @@ typedef struct {
uint8_t *data; /**< Pointer to SDO data. */
size_t mem_size; /**< Size of SDO data memory. */
size_t data_size; /**< Size of SDO data. */
uint32_t issue_timeout; /**< Maximum time in ms, the processing of the
request may take. */
ec_direction_t dir; /**< Direction. EC_DIR_OUTPUT means writing to the
slave, EC_DIR_INPUT means reading from the slave. */
ec_internal_request_state_t state; /**< Request state. */
unsigned long jiffies_start; /**< Jiffies, when the request was issued. */
unsigned long jiffies_sent; /**< Jiffies, when the upload/download
request was sent. */
uint16_t error_code; /**< SoE error code. */
} ec_soe_request_t;
};
/*****************************************************************************/
@ -68,6 +71,7 @@ int ec_soe_request_copy_data(ec_soe_request_t *, const uint8_t *, size_t);
int ec_soe_request_append_data(ec_soe_request_t *, const uint8_t *, size_t);
void ec_soe_request_read(ec_soe_request_t *);
void ec_soe_request_write(ec_soe_request_t *);
int ec_soe_request_timed_out(const ec_soe_request_t *);
/*****************************************************************************/