Merge branch 'devel-1.6' into prepare-1.6
This commit is contained in:
commit
be41b79f3f
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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 = \
|
||||
|
|
|
|||
13
configure.ac
13
configure.ac
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) \
|
||||
|
|
|
|||
|
|
@ -27,7 +27,8 @@ SUBDIRS = \
|
|||
e1000e \
|
||||
genet \
|
||||
igb \
|
||||
igc
|
||||
igc \
|
||||
r8169
|
||||
|
||||
# using HEADERS to enable tags target
|
||||
noinst_HEADERS = \
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
142
include/ecrt.h
142
include/ecrt.h
|
|
@ -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.
|
||||
****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -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 *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
343
master/ioctl.c
343
master/ioctl.c
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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(®->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);
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
/*****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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 *);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue