Table of Contents

FIXME This page is not fully translated, yet. Please help completing the translation.
(remove this paragraph once the translation is finished)

添加一个新的设备支持

本文假定你的设备是基于OpenWrt已经支持的平台的。若需要增加新平台(platform)的支持,参考→add.new.platform

常用流程

  1. 列出设备上芯片的详细列表,并找到有关支持的信息。主要关注设备上的处理器,闪存,以太网和无线等硬件。一些有用的技巧可以在hw.hacking.first.steps上进行查询。
  2. 确保您具有一个可用的串口控制台(serial console)并且可以通过他访问设备的bootloader引导程序。
  3. 准备好固件,然后进行安装,观察固件安装后引导日志中出现的问题和错误。
  4. 验证Flash的分区,和LED及按钮的功能。

GPIOs

大多数路由设备使用 GPIOs 去控制led或者作为按钮。所有的路由设备没有一个通用的GPIO编号,因此OpenWrt针对每个设备必须使用特定的GPIO功能的映射。这意味着我们需要为每个受支持设备上的每个可控LED和按钮找出他们所使用的GPIO端口。

GPIO LEDs

如果设备的LED使用GPIO端口控制,那么GPIO方向将被设置为out,而且我们必须知道这些GPIO的极性:

单个的GPIO测试我们可以通过以下途径:

cd /sys/class/gpio
GPIO=3
echo $GPIO > export
echo "out" > gpio$GPIO/direction
echo 0 > gpio$GPIO/value
sleep 1s
echo 1 > gpio$GPIO/value
sleep 1s
echo $GPIO > unexport

当然每个GPIO端口都应该被测试(从0开始),而不仅仅是上述例子中的GPIO 3。

因此,基本上,您需要创建一个表,如下所示:

Color Name GPIO Polarity
Green Power 0 Active high
Blue WLAN 7 Active high
Blue USB 12 Active low

为了加快所有GPIO的测试速度,可以使用以下bash脚本。请注意,您必须记录和关注每个LED状态和控制台输出。 如果USB LED点亮并且最后一个控制台消息为[GPIO12]尝试值为0,则表示USB LED使用GPIO 12且为低电平有效。

#!/bin/sh
GPIOCHIP=0
BASE=$(cat /sys/class/gpio/gpiochip${GPIOCHIP}/base)
NGPIO=$(cat /sys/class/gpio/gpiochip${GPIOCHIP}/ngpio)
max=$(($BASE+$NGPIO))
gpio=$BASE
while [ $gpio -lt $max ] ; do
	echo $gpio > /sys/class/gpio/export
	[ -d /sys/class/gpio/gpio${gpio} ] && {
		echo out > /sys/class/gpio/gpio$gpio/direction
 
		echo "[GPIO$gpio] Trying value 0"
		echo 0 > /sys/class/gpio/gpio$gpio/value
		sleep 3s
 
		echo "[GPIO$gpio] Trying value 1"
		echo 1 > /sys/class/gpio/gpio$gpio/value
		sleep 3s
 
		echo $gpio > /sys/class/gpio/unexport
	}
	gpio=$((gpio+1))
done

GPIO 按钮

如果使用GPIO控制的按钮,则在按下按钮期间会更改值。因此,找出哪个GPIO连接到某个硬件按钮的最佳方法是:

  1. 记录所有GPIO的值
  2. 按下按钮并保持按下状态
  3. 再次记录所有GPIO的值
  4. 找出哪个GPIO改变了它的值

对于GPIO值的查看,可以使用以下脚本:

#!/bin/sh
GPIOCHIP=0
BASE=$(cat /sys/class/gpio/gpiochip${GPIOCHIP}/base)
NGPIO=$(cat /sys/class/gpio/gpiochip${GPIOCHIP}/ngpio)
max=$(($BASE+$NGPIO))
gpio=$BASE
while [ $gpio -lt $max ] ; do
	echo $gpio > /sys/class/gpio/export
	[ -d /sys/class/gpio/gpio${gpio} ] && {
		echo in > /sys/class/gpio/gpio${gpio}/direction
		echo "[GPIO${gpio}] value $(cat /sys/class/gpio/gpio${gpio}/value)"
		echo ${gpio} > /sys/class/gpio/unexport
	}
	gpio=$((gpio+1))
done

如果在按下按钮时GPIO值从1变为0,则它​​为低电平有效。否则,它为高电平有效。

例子如下:

Name GPIO Polarity
WPS 4 Active low
Reset 6 Active low

KSEG1ADDR()和访问NOR flash

为了获得板卡的MAC地址,EEPROM和其他校准数据,您可能需要从内核中的flash中读取数据。 对于许多使用NOR flash的Atheros芯片,可使用KSEG1ADDR()宏完成,该宏将flash的硬件地址转换为执行初始化功能的进程上下文的虚拟地址。

如果您正在查看用于初始化与自己相似的电路板的代码,并且看到以下信息:KSEG1ADDR(0x1fff0000),最初的数字似乎是不可思议的,但是如果您了解两件事,这是合乎逻辑的。 首先,使用NOR flash的Atheros SoC将其连接到物理地址0x1f000000(无法保证将flash连接到板上的位置,但这是一个常见的位置)。 您不能依赖引导加载程序中提供的地址,您可能会看到0xbf000000,但这也可能是虚拟地址。 如果您的电路板导线flash到这些存储位置,则显然可以使用KSEG1ADDR(0x1f000000 + OFFSET_FROM_BEGIN)访问flash,但是如果您必须访问flash末尾知道的数据,则可以使用技巧使您的代码与多种大小的flash兼容。

不管是4MB,8MB还是16MB,flash通常都会映射到完整的16MB地址空间,因此在这种情况下,KSEG1ADDR(0x20000000-OFFSET_FROM_END)将用于访问您知道与地址末尾有一定距离的flash内容。 当您在具有4MB或8MBflash的设备上看到KSEG1ADDR(0x1fff0000)时,可以猜测是使用此技巧引用了位于flash末尾下方64k(存储Atheros无线电测试数据)的flash。

添加新的设备举例

Brcm63xx 平台

如果您具有bcm63xx 特定设备的OEM源代码,则在以后添加OpenWrt支持时可能会有些用处:

(详细查看 https://forum.openwrt.org/viewtopic.php?pid=123105#p123105)

要在bcm63xx设备上创建OpenWrt固件,可以执行以下步骤:

  1. 获取源代码,并使用make menuconfig作为最后一步,按照编译过程进行操作。
  2. menuconfig期间,选择正确的目标系统。
  3. 接下来,使用所有板卡参数为所选平台生成board_bcm963xx.c文件,执行以下命令:
    make kernel_menuconfig
  4. 将board-id添加到./target/linux/brcm63xx/image/Makefile。
    举例
    # Davolink DV2020	
    	$(call Image/Build/CFE,$(1),DV2020,6348)
  5. 将带有参数的board-id添加到./build_dir/linux-brcm63xx/linux-2.6.37.4/arch/mips/bcm63xx/boards/board_bcm963xx.c
    举例
    static struct board_info __initdata board_DV2020 = {
            .name                           = "DV2020",
            .expected_cpu_id                = 0x6348,
     
            .has_uart0                      = 1,
            .has_pci                        = 1,
            .has_ohci0                      = 1,
     
            .has_enet0                      = 1,
            .has_enet1                      = 1,
            .enet0 = {
                    .has_phy                = 1,
                    .use_internal_phy       = 1,
            },	
            .enet1 = {	
                    .force_speed_100        = 1,	
                    .force_duplex_full      = 1,	
            },	
    };
     
    static const struct board_info __initdat
    :
    :
    :
    	&board_DV2020,
  6. 根据make步骤中的过程完成编译指令

Ramips 平台

只要添加对具有现有芯片组的ramips板的支持,这就非常简单。您需要创建一个新的电路板(board)定义,该定义将为您的设备生成一个镜像文件并运行特定于设备的代码。然后编写各种特定于主板的技巧来初始化设备并设置正确的默认配置。

您的设备主板信息将按以下顺序传递:

 (Image Generator puts it in the kernel command line)
(镜像将关于设备主板信息推送到内核命令行)
          ↓
 (Kernel command line is executed with BOARD=MY_BOARD)
(内核命令行通过BOARD=MY_BOARD执行)
          ↓
 (Kernel code for ramips finds your board and loads machine-specific code)
(针对ramips架构的内核代码找到你的板级信息导入到机器的特殊代码里)
          ↓
 (/lib/ramips.sh:ramips_board_name() reads the board name from /proc/cpuinfo)/lib/ramips.sh脚本的ramips_borad_name()函数读取板子的名称从根文件系统的/proc/cpuinfo
          ↓
 (Several userspace scripts use ramips_board_name() for board-specific setup)
(用户空间的脚本通过ramips_borad_name()函数来完成板子的特殊设置)

至少,您需要进行以下更改以进行基本构建,所有这些都在target/linux/ramips/目录下:

然后,您将需要根据主板的功能来修改其中一些文件:

已经合并(commits)的设备文件举例:

提示

添加新板后,您可能应该先清理““tmp”“文件夹。

cd trunk
rm -rf tmp
make menuconfig 

如果您已添加设备配置文件,但未在“make menuconfig”中显示,请尝试touch主目标makefile

touch target/linux/*/Makefile