usb_modeswitch使用详解

本文介绍了USB_ModeSwitch工具,用于控制具备多种模式的USB设备。它能够帮助设备在存储模式和调制解调器模式间切换,支持众多高速WAN上网卡。文章详细讲述了安装、使用方法及故障排查技巧。
部署运行你感兴趣的模型镜像

注:这篇博客内容目前无法转换hilink的网卡设备,本人亲试

摘要:

一、介绍 USB_ModeSwitch是一种模式切换工具,用于控制具有“多种模式”的USB设备。 越来越多的USB设备(特别是高速WAN上网卡,它基于一些手机芯片,能够改变它们的USB连接模式)都会板载它们自己的MS Windows驱动程序,当首次插入电脑时,它们会被识别为一个闪存设备,然后开始安装存储于其中的驱动程序。

一、介绍

USB_ModeSwitch是一种模式切换工具,用于控制具有“多种模式”的USB设备。

越来越多的USB设备(特别是高速WAN上网卡,它基于一些手机芯片,能够改变它们的USB连接模式)都会板载它们自己的MS Windows驱动程序,当首次插入电脑时,它们会被识别为一个闪存设备,然后开始安装存储于其中的驱动程序。在安装完驱动程序之后(后面还需要再插拔一次),驱动程序就会再内部切换USB设备的连接模式,存储设备会消失(大多数情况下),然后会出现一个新的设备(例如,一个USB调制解调器)。调制解调器制造商会“可选地”调用“ZeroCD (TM)”特性,因为它会消除对用于承载一个独立驱动程序载体的需求。

起初,这方面的东西没有任何形式的文档记录,而且也几乎没有任何Linux支持可用。

从好的方面来看,大多数已知的设备在两种模式下都可以工作,使用诸如“usb-storage”或“option”(一种经过优化的串行驱动程序,高速3G调制解调器的Linux标准)的Linux驱动程序。

那么唯一的问题便是如何从存储设备切换至调制解调器设备,或者其他应该做的事情。

幸运的是,我们还有人类的理性、USB嗅探程序和“libusb”。MS Windows的驱动程序存在通信被窃听的可能性,但是,在Linux或BSD变种系统的规则之下,可以隔离触发模式切换的命令或动作,并且可以复制相同的东西。

在“libusb”的有力帮助之下,USB_ModeSwitch可以从一个配置文件中获取重要的参数,然后完成全部的初始化和通信工作,这样便使得用户可以轻松地处理这个过程。

它主要是自动使用的 — 通过udev事件和规则 — 不需要任何用户操作便能完成模式切换。但是它还可以作为一个命令行工具来运行,通常会在尝试使用某种未知设备时使用这种方式。

这个工具是大多数主流发型版的部件之一,你应当不用从源码包进行编译安装,除非运行时遇到问题,或者想要使用最新的版本。

你在提交任何问题之前,请首先仔细阅读本页面上的所有信息! 如果你使用一个新的设备,那么它会帮助你理解这个工具内部的工作原理,它也会反过来更加轻松地找到相关的切换命令,并且可以添加一条新的配置条目。

如果想要了解关于如何实现自己的USB嗅探,请查看下面的“ 贡献” 章节。

二、下载

重要: 想要完成一次高效的安装,你需要同时拥有程序和数据包!

对配置文件的修改和更新的频率可能会比发布新程序版本的频率高得多,这些配置文件包含已知USB设备的大多数信息。这也是为什么会单独提供这些配置文件。

请下载 usb-modeswitch-2.2.1.tar.bz2,源代码的发布日期为2015-01-15,Debian的软件仓库中很快也会有相应的Debian软件包。它支持很多种架构(诸如amd64或ia64)。

请下载 usb-modeswitch-data 数据包(2015-01-15)。它包含设备数据库和规则文件,包括完整的路径。你需要2.2.0版本以上的程序,因为引入了新的参数。

可选的 device_reference.txt文件(2013-11-13),它是较早设备的配置集合,分别由相应的贡献者添加;如果你想要使用某个新设备,那么你也可以将这个文件作为首选资源。

如果你的系统上没有安装 libusb-1.x,请不要忘记安装这个软件包。在大多数发行版本中,很可能有一个名为“libusb1-dev”或“libusb1-devel”的软件包(或类似的)。

较老的版本基于 libusb-0.1.12,但是自从2.0.0版本以来,只会支持libusb1.x。

有一点复杂的是,libusb1有一段时间还有一个兼容分支,叫做“libusbx”。更多信息可阅读:
http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?p=12912#p12912

如果你有一个带有USB主机端口的Android平板,并且Android版本至少为2.2,你可以尝试使用“ PPP Widget”,可以从Google Play下载使用。它包括USB_ModeSwitch和PPPD,使得你能够相对轻松地通过3G上网卡或手机连上网络,即使是在仅支持WiFi的设备上。

如果你是一个系统集成者(包维护者),你可以使用这个XML文件来检查新的版本:usb-modeswitch-versions.xml。

USB_ModeSwitch的Debian软件包的维护者已经建立起一个PPA,提供大多数最近发布的版本,请查看论坛中的这个帖子:
http://www.draisberghof.de/usb_modeswitch/bb/viewtopic.php?p=12609#p12609

三、如何安装

如果你已经安装了一个较早的版本,推荐卸载掉已安装的版本(运行 make uninstall 命令)。1.1.0版本中修改了若干文件的位置,如果不管旧版本的话,那么旧版本的文件就可能会被孤立。如果你以前安装的是1.1.0或更新的版本,那么你仅仅需要更新和覆盖所有已有的文件。

解压缩程序的源码文件(谁会想到!)。在新创建的目录中,以root或超级用户的身份运行以下命令:

# make install

这样会安装一个用于udev的小型shell脚本、较大的包装器脚本、一个配置文件、man(使用说明)页面,以及全新编译的二进制文件。重要:如果你以这种方式安装,那么你将需要“tcl”软件包,用于处理大型的分配器脚本。还有很多种不依赖于“tcl”软件包的安装方式。请参考包含在源码包中的README文件,以便于了解更多的安装选项吧!

现在,请对数据包进行相同的操作。它将会在“/usr/share/usb_modeswitch”目录中安装配置文件,在“/lib/udev/rules.d”目录中安装udev规则文件。较早的“/etc/usb_modeswitch.d”目录被用于保存自定义配置文件(新的或修改的)。

你已经设置成功了,如果你的设备是已知的,那么你应当能够将其插入并使用。如果它不能立即使用,那么我们将会找出原因。

想要手动使用,只需要安装程序即可。在命令行界面中使用或者使用一个自定义的配置文件。如果你想要创建自己的配置,那么“device_reference”文件(请参考“下载”章节)会是一个很好的切入点。这个文件中有很多注释,会告诉你如何进行操作。

你的自定义配置文件可以用任何文件名,也可以放在任何地方;只需要用 -c 参数告诉 usb_modeswitch 如何找到这个配置文件即可。

手动使用的主要目的是测试和分析。请参考下一章。

四、如何使用

在大多数情况下,你可以不用进行任何操作(除了将设备插入)就能够使用你的设备。

如果你认为你的设备是受支持的,但是设备并没有按照预期正常工作,那么你可以首先打开日志,正如在“故障排查”章节中所述的。

若想要测试、调试你的新设备,你可以在手动模式下使用USB_ModeSwitch的二进制部分。

有两种方法:使用一个配置文件或使用命令行。

运行“usb-modeswitch -h”命令,便可列出命令行参数。如果使用了除 -W、-D、-I 和 -q 之外的命令行参数,那么通过 -c 命令行参数指定的配置文件就会被忽略,你必须在命令行上提供所有的必须参数。你还可以参考内藏的使用手册页面。

想要使用某个配置文件,你可以使用“/usr/share/usb_modeswitch”目录中的小文件,或者自己创建一个文件。然后使用 -c 选项,为 usb_modeswitch 命令指定这个文件的文件名和路径。你还可以在 device_reference.txt 文档中找到一些关于型号系列的提示,以及命令行参数的解释。

重要:
USB_ModeSwitch — 就像使用 libusb 的所有程序那样 — 当手动调用这个命令时,必须以 root 身份运行(或者使用“sudo”命令)。否则,会出现奇怪的错误消息,并且设备和程序不会正常工作。当试验切换命令和策略时,可能在具有root权限的shell中进行操作会更加便利(“sudo bash”或“su -”)。

自动化方法由若干种协同工作的组件构成,以用途的逻辑顺序列出:

/lib/udev/rules.d/40-usb_modeswitch.rules — 如果识别出一个已知的设备ID(制造商/产品),那么udev规则便会启动包装器。若想要为一个新的调制解调器添加一个触发器(具有有效的配置文件),你可以新加一行,内容为它的USB ID,就像在已有条目中看到的那样。如果被切换的设备提供标准的串行端口,那么一个二级规则会再次调用包装器,然后添加一条指向正确连接端口的符号链接(见下文)。

/lib/udev/usb_modeswitch — 一个shell脚本,分叉至真实的包装器脚本。从1.1.6版本以来,脚本是和在Ubuntu中使用的“dash”shell完全兼容的,除此之外还兼容于较老的“bash”变种。为了将usb_modeswitch和udev进程分开运行,最近的版本会利用upstart或systemd特性。

/usr/sbin/usb_modeswitch_dispatcher — 这样会进行额外的设备检查,然后使用二进制文件,根据选中的设备配置文件来切换设备状态。
如果在模式切换之后,没有任何驱动程序来处理这个设备,那么分配器将会试图加载和绑定“可选的”串行驱动程序,以便于使得设备可用。

/etc/usb_modeswitch.conf — 当排查故障时,用于启用扩展日志的一个全局配置文件,或者用于禁用切换功能(主要是为了访问设备的安装部件)。

/usr/share/usb_modeswitch — 一个包含每个设备个体设置信息文件的目录,根据设备ID和可能更深入的身份标识来命名(为了解决已知的二义性)。如果你的设备ID在某个文件的文件名中出现了,那么表明你的设备是受支持的,即使它的型号或品牌并不匹配。

/etc/usb_modeswitch.d — 一个存放自定义配置文件的目录。你可以将新建的或修改的配置文件放在这儿,它们将会比 /usr/share/usb_modeswitch 目录中的配置文件被优先使用。

/usr/sbin/usb_modeswitch — 实现切换功能的二进制程序。它被设计为独立于内核或系统细节,应当可以移植到非Linux平台上,只要libusb可用即可。

在模式切换和驱动程序加载之后,系统需要负责发现新的(主要是串行的)设备。

当前的NetworkManager版本(或者它的ModemManager组件)通常非常适合于使用无线调制解调器。甚至一些已经不再使用PPP接口的新型号也能够被识别,并且能被无缝地整合。

当试图自动侦测USB调制解调器和使用它们时,使用较老版本的这些程序就很有可能发生问题。

如果你坚持使用一个较老的系统,那么请禁用NM和MM。你将能够顺利使用wvdial、UMTSmon和若干种提供PPP用户界面的工具(诸如kppp),虽然这些程序中的某些可能需要有一点基本知识。

从1.1.2版本开始,如果设备提供标准的串行端口,usb_modeswitch将会添加一条指向使用中断传输的正确端口的符号链接。这条链接的名称为 /dev/gsmmodem,如果连接了多个设备,那么在名称之后会紧跟一个编号。

你可以在连接帮助程序(诸如wvdial)中使用这个名称。注意,在很多情况下,你可能需要手动编辑配置文件。

如果你设法得到一个新型的或支持很差的设备,并且想要以手动模式正确地进行切换,那么你可以自己添加一条udev规则和一个配置文件。但是也请将其报告给我们,分享你的成果!

请查看“ 贡献 ”章节。

五、已知的适用硬件

非常重要的提示:
就个人来说,我不可能测试绝大多数的受支持设备。此处的列表 — 除了必需的数据之外 — 还要依赖于第三方团体(或用户)的报告。因此,即使你的设备在此列出,你也很有可能遇到一些问题。
也就是说,这个小工具的用户基数有着非常可观的增加,因此任何数据相关的问题通常会很快地显现出来。

迄今为止,初始化切换进程有三种已知的方法:

向存储设备发送一条很少使用或看起来怪异的标准存储命令(相当于SCSI)(例如“eject”)。

向设备发送一条或多条制造商特定的控制消息。

主动地从设备中移除(断开连接)存储驱动程序(仅适用于某些早期的设备)。

再次,如果你没有在列表中找到你设备的名称,它仍然是可能受支持的。

当然,最好能够在配置文件目录中找到你的设备的USB ID。请仔细地浏览最新的数据包(请参考“下载”章节)。

下面是受支持的设备列表,同时还有相应贡献者的信息:device_reference.txt。

六、故障排查

注意:如果在遵循本页面的建议之后,你仍然需要技术支持,那么请使用论坛!

电子邮箱智能用于投稿设备/配置文件 — 不能处理技术支持问题!
已知的问题

只有版本为2.6.27以及更新版本内核的自动串口驱动程序分配才能和针对3G优化过的驱动程序协同工作。如果你的内核版本较老,并且在模式切换之后,你的调制解调器没有被任何驱动程序识别出来,那么就会使用通用的“usbserial”驱动程序作为一种备用方案。

在版本为2.6.26至2.6.28的内核中,处理ID为 19d2:2000 的设备时会遇到一些问题。这通常会影响到大多数的ZTE设备,并且会使得“usb-storage”驱动程序忽略这个ID。而这将会妨碍正确的初始化,可能会导致切换失败。你没有其他办法,只能对内核代码进行少许修改,然后重新编译你自己的内核。请参考下面内核相关的问题,以了解详细的信息。

针对于自动化系统整合的调试,请在文本编辑器中将(以root身份或者使用su命令)/etc/usb_modeswitch.conf 文件中的以下行:

EnableLogging=0

修改为:

EnableLogging=1

这样便使得你可以在/var/log/usb_modeswitch_日志文件中看到非常详细的设备热插拔活动日志。

如果你接下来确定你的设备具有合适的取值,并且你已经遵循所有的提示(请参考“已知的适用硬件”章节)进行操作,并且USB_ModeSwitch看起来每次运行时都在做一些事情,但是却毫无效果,那么你就很有可能遇到系统相关的问题。

首先怀疑的应当是已有的用于调制解调器的系统规则,这些规则可能没有正确地处理一些东西。

如果你拥有的设备的未切换ID为 05c6:1000 ,那么它可能会在较老的系统中调用切换命令出错。有四种不同类型的切换设备,它们都具有相同的ID;在大型的发行版中,在尝试过四五次失败之后,它们都会被看做是“可选”(制造商)的型号。甚至有些手机也具有这样的ID,将这些手机连接至USB端口时,它们可能会被错误地处理。

若想要解决这样的问题,你可以尝试从 “ /lib/udev/rules.d ”目录中删除相应的规则文件,这些文件中包含对“modem-modeswitch”命令的调用。

除了USB ID之外,USB_ModeSwitch将会进行额外的检查,并且会以正确的方式处理所有已知的不明确的设备。例如,它将会对ID为 05c6:1000 的未知设备置之不理。

另一个众所周知的设备ID是 19d2:2000 。它可能会在一个已有的规则控制之下切换正常,但如果你的设备型号是新型的,这个设备的ID还尚未添加至“可选”模块中,那么系统就不会为这个设备加载驱动程序。

禁用运行“弹出”的规则,这个设备的ID将会由usb_modeswitch进行处理。
内核相关的问题

在某些较新的内核中,某些设备(上述的设备,有些是可选厂商,有些是华为的,有些是ZTE的)会在USB存储设备的代码中得到特殊处理,会立即启用切换功能。对于这些特殊的设备来说,你可能不再需要USB_ModeSwitch,从另一方面来说,你必须访问你的设备的“CD-ROM”部件。另外,特殊处理没有产生任何效果,而且被妨碍的USB_ModeSwitch后来又工作正常的情况也是存在的(ZTE设备产生错误“-2”时可能会出现这种情况)。

当发生问题时,请查看你的内核源码的“ drivers/usb/storage ”目录中的“unusual_devs.h”文件。如果你的默认设备ID(存储部件的厂商和产品ID)可以在上述文件中找到,并且当运行USB_ModeSwitch时会出现错误消息,那么首先尝试将“usb-storage”加入黑名单。

如果这么做有用,那么你应当考虑重新构建你的内核,停用“unusual_devs.h”文件中的相应条目。唯一会发生的是,以后USB存储会以默认的方式工作。

我在Gentoo的俄语版维基中找到一条提示,这条提示完全按照我刚刚的建议进行操作,使用的设备为ZTE MF626。

顺便说一下,USB开发者之间一度达成共识,如果必要的步骤可以在“用户空间”中完成,那么就会将所有未来的模式切换代码独立于内核驱动程序之外。

另一种能够影响内核行为的方法是“usb-storage”的“delay_use”参数,这个参数会设置存储设备插入系统到实际使用(可能会自动挂载)之间的延迟时间,以秒为单位。默认值为5,这个参数可能会影响某些条件下的切换结果。

若想要修改默认值,则在/etc/modeprobe.conf文件中添加以下内容:
options usb-storage delay_use=1 (or 10, or other)
老系统(例如,CentOS 5 或 Xandros 6)

如果你使用的系统比不是非常的新(内核版本低于2.6.27),那么你可能偶尔会遇到“udev”版本之间的不兼容性,它是设备管理器。如果你没有任何迹象表明usb_modeswitch正在做任何事情(没有日志文件),那么请遵循以下步骤:

检查“ /lib/udev/rules.d ”目录中,除了“40-usb_modeswitch.rules”文件之外,还有没有其他文件。
如果并非如此,那么请将文件移入“/etc/udev/rules.d”目录中。
如果仍然没有任何动作,请查看“/etc/udev/rules.d”目录中是否有其他文件包含字符串“ATTRS”。

如果并非如此,那么请编辑“40-usb_modeswitch.rules”文件,将文件中所有的“ATTR”和“ATTRS”替换为“SYSFS”。保存修改,检查当你再次插入设备时,是否有些事情发生。

在特别难解决的“没有动作”的情况下,很有可能需要分析udev的动作;你可以编辑“/etc/udev/udev.conf”文件,将日志等级修改为“debug”即可。
七、贡献

即使USB_ModeSwitch还尚未支持你自己的硬件设备,它也可以非常方便地进行实验。

第一个普遍尝试的步骤就是使用已知设备的切换方法,例如,在BandLuxe的配置“1a8d:1000”中找到的“弹出”动作序列。如果你的设备原本是由华为制造的,那么你可以尝试使用“12d1:1446”的动作序列。

不用担心,使用可能错误的动作序列几乎不可能损坏任何东西。只需要确保在每次尝试之后,重新插拔你的设备。

如果所有的这些方法都没有用,你可以尝试这种方法:

注意,设备的厂商ID和产品ID可以在“/proc/bus/usb/devices”文件中查看(也可以查看“ lsusb ”命令的输出),被分配的驱动程序通常是“usb-device”。然后,在MS Windows中监听具有相同ID的设备的USB通信,监听之前需要安装设备板载的驱动程序。设备一定会在那时切换模式,你需要将那个时刻的日志记录下来。

我推荐这个工具:“SniffUSB”。

这是一个较短的版本。Mark A. Ziesemer编写过一个非常好的应用示例,如下所示:
Alltel UM175AL USB EVDO under Ubuntu Hardy Heron。

请向 Mode Switch Forum 论坛提交任何改进建议、新设备信息和/或缺陷报告。
如果你不需要技术支持,你可以使用一种更加古老,更加保密的通信方式 — 电子邮件。

您可能感兴趣的与本文相关的镜像

Wan2.2-T2V-A5B

Wan2.2-T2V-A5B

文生视频
Wan2.2

Wan2.2是由通义万相开源高效文本到视频生成模型,是有​50亿参数的轻量级视频生成模型,专为快速内容创作优化。支持480P视频生成,具备优秀的时序连贯性和运动推理能力

/* # Copyright 2022 Unisoc (Shanghai) Technologies Co., Ltd. # Licensed under the Unisoc General Software License, version 1.0 (the License); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # https://www.unisoc.com/en_us/license/UNISOC_GENERAL_LICENSE_V1.0-EN_US # Software distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OF ANY KIND, either express or implied. # See the Unisoc General Software License, version 1.0 for more details. */ #include <app.h> #include <asm/arch/check_reboot.h> #include <boot_mode.h> #include <lk/debug.h> #include <stdlib.h> #include "boot_mode.h" #include "boot_parse.h" #include <logo_bin.h> #include <lib/console.h> #include <string.h> #include "fastboot.h" #include <sprd_common.h> #include <sprd_sysdump.h> #include <dl_common.h> #include <sprd_wdt.h> #include <asm/types.h> #include <sprd_regulator.h> #include "calibration_detect.h" #include <sprd_battery.h> #include <sprd_keys.h> #include <sprd_common_rw.h> #include <miscdata_def.h> #include <sprd_ddr_debug.h> #include <linux/kernel.h> #include <gpio_plus.h> #include <sprd_adc.h> #ifdef CONFIG_ANDROID_AB #include <android_ab.h> #include <chipram_env.h> #include <sprd_pmic_misc.h> char g_env_slot[3] = {"_a"}; #endif #ifdef CONFIG_DOWNLOAD_FOR_CUSTOMER extern int pctool_connected(void); #endif #ifdef CONFIG_TEECFG #include <teecfg_parse.h> #endif #ifdef SPRD_MINI_SYSDUMP extern void handle_minidump_before_boot(int rst_mode); #endif #ifdef CONFIG_USB_SPRD_DWC31_PHY extern void usb_phy_enable(u32 is_on); extern int usb_phy_enabled(void); #endif #define NTC_VOL_CH 0 #define NTC_VOL_SCALE 0 #define NTC_VOL_MUX 0 #define NTC_VOL_CAL_TYPE 0 extern int read_boot_flag(void); extern CBOOT_FUNC s_boot_func_array[CHECK_BOOTMODE_FUN_NUM]; extern void board_boot_mode_regist(CBOOT_MODE_ENTRY *array); extern const char *bootcause_cmdline; extern int sprdbat_get_shutdown_charge_flag(void); extern int sprdbat_get_auto_poweron_flag(void); extern int is_hw_smpl_enable(void); static unsigned int get_gpio_status(unsigned int GPIO_NUM); #ifdef PROJECT_24717 #define BOARD_ID1 147 #define BOARD_ID2 113 #define BOARD_ID3 112 #define Modem_ID_0 173 #define Modem_ID_1 130 #define Modem_ID_2 131 #endif #ifdef PROJECT_23728 #define BOARD_ID1 147 #define BOARD_ID2 113 #define BOARD_ID3 80 #define Modem_ID_0 173 #define Modem_ID_1 130 #define Modem_ID_2 131 #endif extern void dl_set_wdtflag(void); extern unsigned ota_processing; #define USBPHY_VDDUSB33_NORMAL 3300 #define USBPHY_VDDUSB33_FULLSPEED_TUNE 2700 #define LOWPOWER_LOGO_VOL 3000 #define LOWPOWER_LOGO_ENABLE_TIME 15 #define LOWPOWER_LOGO_DISABLE_TIME 0 #define CONF_0 171 #define CONF_1 172 #ifdef VENDOR_EDIT extern cdt_t cdt_table; #endif static const char *g_mode_str[CMD_MAX_MODE+1] = { "UNDEFINED_MODE", "POWER_DOWN_DEVICE", "NORMAL_MODE", "DOWNLOAD_MODE", "RECOVERY_MODE", "FASTBOOT_MODE", "ALARM_MODE", "CHARGE_MODE", "ENGTEST_MODE", "WATCHDOG_REBOOT", "AP_WATCHDOG_REBOOT", "SPECIAL_MODE", "UNKNOW_REBOOT_MODE", "PANIC_REBOOT", "VMM_PANIC_MODE", "TOS_PANIC_MODE", "EXT_RSTN_REBOOT_MODE", "CALIBRATION_MODE", "USB_MUX_MODE", "AUTODLOADER_REBOOT", "AUTOTEST_MODE", "IQ_REBOOT_MODE", "SLEEP_MODE", "SPRDISK_MODE", "APKMMI_MODE", "UPT_MODE", "APKMMI_AUTO_MODE", "ABNORMAL_REBOOT_MODE", "SILENT_MODE", "BOOTLOADER_PANIC_MODE", "SML_PANIC_MODE", "MAX_MODE", }; #ifdef VENDOR_EDIT uint32_t supported_ProcNo[] = { 24660, 24661, 24662, 24663, 24664, 24665, 24666, 24667, 24668, 24674, 24717, 24725, 24726, 24729, 24730, 24731, 24734, 24735, 24736, 24737, 24741, 22716, 22717, 22718, 22720, 22721, 22722, 22723, 22724, 22726, 22729, 22734, 23665, 23666, 23711, 23712, 23713, 23633, 23728, 23714, 24760, 24768, 24761, 24762, 24763, 24764, 24758, 24767, 24759, 24765, 24766, 25702, 25703 }; int check_project_is_supported(void) { int i = 0; for (; i < ARRAY_SIZE(supported_ProcNo); i++) { if (supported_ProcNo[i] == cdt_table.project_no) { debugf("The project number:%x is supported\n", cdt_table.project_no); return 0; } } errorf("The project number:%x is not supported\n", cdt_table.project_no); return -1; } int cdt_table_analysis(void) { #ifdef PROJECT_24717 unsigned int board_id1, board_id2, board_id3; unsigned int modem_id_0,modem_id_1,modem_id_2; #endif #ifdef PROJECT_23728 unsigned int board_id1, board_id2, board_id3; unsigned int modem_id_0, modem_id_1, modem_id_2; #endif memset(&cdt_table, 0, sizeof(cdt_table)); errorf("read partition cdt start\n"); if (0 != common_raw_read("ocdt_a", sizeof(cdt_table), 0, &cdt_table)) { errorf("read partition cdt failed\n"); return -1; } if (CDT_MAGIC != cdt_table.cdt_magic) { errorf("cdt_table magic didn't correct\n"); return -1; } if (-1 == check_project_is_supported()) { debugf("power down device\n"); write_log(); power_down_devices(0); } #ifdef PROJECT_24717 board_id1 = get_gpio_status(BOARD_ID1); board_id2 = get_gpio_status(BOARD_ID2); board_id3 = get_gpio_status(BOARD_ID3); modem_id_0 = get_gpio_status(Modem_ID_0); modem_id_1 = get_gpio_status(Modem_ID_1); modem_id_2 = get_gpio_status(Modem_ID_2); debugf("cdt_table board id1,id2,id3 ,modem id0,id1,id2=(%d,%d,%d,%d,%d,%d)\n", board_id1, board_id2, board_id3, modem_id_0, modem_id_1, modem_id_2); if ((1==board_id1) && (1==board_id2) && (0==board_id3) && (((0==modem_id_0) && (0==modem_id_1) && (1==modem_id_2)) || ((0==modem_id_0) && (1==modem_id_1) && (1==modem_id_2)))) { cdt_table.project_no = 24717; cdt_table.dtsi_no = 24717; cdt_table.audioIdx = 24717; }else if((1==board_id1) && (1==board_id2) && (0==board_id3) && (((1==modem_id_0) && (0==modem_id_1) && (0==modem_id_2)) || ((1==modem_id_0) && (0==modem_id_1) && (1==modem_id_2)))){ cdt_table.project_no = 24730; cdt_table.dtsi_no = 24730; cdt_table.audioIdx = 24730; } #endif #ifdef PROJECT_23728 board_id1 = get_gpio_status(BOARD_ID1); board_id2 = get_gpio_status(BOARD_ID2); board_id3 = get_gpio_status(BOARD_ID3); modem_id_0 = get_gpio_status(Modem_ID_0); modem_id_1 = get_gpio_status(Modem_ID_1); modem_id_2 = get_gpio_status(Modem_ID_2); debugf("cdt_table board id1,id2,id3 modem id0,id1,id2=(%d,%d,%d,%d,%d,%d)\n", board_id1, board_id2, board_id3, modem_id_0, modem_id_1, modem_id_2); if ((1 == board_id1) && (1 == board_id2) && (0 == board_id3) && (0 == modem_id_0) && (0 == modem_id_1) && (1 == modem_id_2)) { cdt_table.project_no = 23728; cdt_table.dtsi_no = 23728; cdt_table.audioIdx = 23728; } else if ((1 == board_id1) && (1 == board_id2) && (0 == board_id3) && (0 == modem_id_0) && (1 == modem_id_1) && (0 == modem_id_2)) { cdt_table.project_no = 23714; cdt_table.dtsi_no = 23714; cdt_table.audioIdx = 23714; } #endif return 0; } #endif CBOOT_FUNC s_boot_func_array[CHECK_BOOTMODE_FUN_NUM] = { /* 0 get mode from vol+/vol- autodloader*/ get_mode_to_autodloader, /* 1 get mode from chipram_env*/ get_mode_from_chipram_env, /* 2 get mode from bat low*/ get_mode_from_bat_low, /* 3 get mode from sysdump*/ write_sysdump_before_boot_extend, /* 4 get mode from miscdata flag*/ get_mode_from_miscdata_boot_flag, /* 5 get mode from file*/ get_mode_from_file_extend, /* 6 get mode from watch dog*/ get_mode_from_watchdog, /* 7 get mode from alarm register*/ get_mode_from_alarm_register, /* 8 get mode from calibration detect*/ get_mode_from_pctool, /* 9 get mode from smpl*/ get_mode_from_smpl, /* 10 get mode from bbat,cali*/ get_mode_from_gpio_bbat_cali, /* 11 get mode from charger*/ get_mode_from_charger, /* 12 get mode from keypad*/ get_mode_from_keypad, /* 13 get mode from gpio*/ get_mode_from_gpio_extend, 0 }; void board_boot_mode_regist(CBOOT_MODE_ENTRY *array) { MODE_REGIST(CMD_NORMAL_MODE, normal_mode); MODE_REGIST(CMD_DOWNLOAD_MODE, download_mode); MODE_REGIST(CMD_RECOVERY_MODE, recovery_mode); MODE_REGIST(CMD_FASTBOOT_MODE, fastboot_mode); MODE_REGIST(CMD_WATCHDOG_REBOOT, watchdog_mode); MODE_REGIST(CMD_AP_WATCHDOG_REBOOT, ap_watchdog_mode); MODE_REGIST(CMD_UNKNOW_REBOOT_MODE, unknow_reboot_mode); MODE_REGIST(CMD_PANIC_REBOOT, panic_reboot_mode); MODE_REGIST(CMD_AUTODLOADER_REBOOT, autodloader_mode); MODE_REGIST(CMD_SPECIAL_MODE, special_mode); MODE_REGIST(CMD_CHARGE_MODE, charge_mode); MODE_REGIST(CMD_ENGTEST_MODE,engtest_mode); MODE_REGIST(CMD_CALIBRATION_MODE, calibration_mode); MODE_REGIST(CMD_EXT_RSTN_REBOOT_MODE, normal_mode); MODE_REGIST(CMD_IQ_REBOOT_MODE, iq_mode); MODE_REGIST(CMD_ALARM_MODE, alarm_mode); MODE_REGIST(CMD_SPRDISK_MODE, sprdisk_mode); MODE_REGIST(CMD_AUTOTEST_MODE, autotest_mode); MODE_REGIST(CMD_APKMMI_MODE, apkmmi_mode); MODE_REGIST(CMD_UPT_MODE, upt_mode); MODE_REGIST(CMD_APKMMI_AUTO_MODE, apkmmi_auto_mode); MODE_REGIST(CMD_ABNORMAL_REBOOT_MODE, abnormal_reboot_mode); MODE_REGIST(CMD_SILENT_MODE, silent_mode); MODE_REGIST(CMD_BOOTLOADER_PANIC_MODE, bootloader_panic_reboot_mode); MODE_REGIST(CMD_SML_PANIC_MODE, sml_panic_reboot_mode); return ; } boot_mode_enum_type get_mode_from_arg(char* mode_name) { dprintf(INFO,"cboot:get mode from argument:%s\n",mode_name); if(!strcmp(mode_name,"normal")) return CMD_NORMAL_MODE; if(!strcmp(mode_name,"recovery")) return CMD_RECOVERY_MODE; if(!strcmp(mode_name,"fastboot")) return CMD_FASTBOOT_MODE; if(!strcmp(mode_name,"charge")) return CMD_CHARGE_MODE; if(!strcmp(mode_name,"sprdisk")) return CMD_SPRDISK_MODE; /*just for debug*/ #ifdef SPRD_SYSDUMP if(!strcmp(mode_name,"sysdump")) write_sysdump_before_boot(CMD_UNKNOW_REBOOT_MODE); #endif return CMD_UNDEFINED_MODE; } int is_abnormal_temp(void) { int32_t ntc_vol; #ifdef CONFIG_NTC_VOL ntc_vol = sprd_chan_adc_to_vol(NTC_VOL_CH, NTC_VOL_SCALE, NTC_VOL_MUX, NTC_VOL_CAL_TYPE); debugf("is_abnormal_temp: ntc_vol = %d\n", ntc_vol); if (ntc_vol >= 0 && ntc_vol < 227) { debugf("is_abnormal_temp: temperature over 65 degrees\n"); return 1; } else if (ntc_vol > 620) { debugf("is_abnormal_temp: temperature below 0 degrees\n"); return 1; } else return 0; #else return 0; #endif } unsigned reboot_mode_check(void) { static unsigned rst_mode = 0; static unsigned check_times = 0; if(!check_times) { rst_mode = check_reboot_mode(); check_times++; } dprintf(INFO,"reboot_mode_check rst_mode=0x%x\n",rst_mode); return rst_mode; } void low_power_charge(int temp_status, enum sprd_adapter_type usb_type) { int32_t vbat_vol; vbat_vol = sprdfgu_read_vbat_vol(); #ifdef CONFIG_BATTERY_TEMP if(temp_status == DISBOOTING_TEMP) { } else { #endif if((usb_type != ADP_TYPE_SDP && usb_type != ADP_TYPE_UNKNOW) || vbat_vol > LOWPOWER_LOGO_VOL ) { sprdbat_show_lowpower_charge_logo(LOWPOWER_LOGO_ENABLE_TIME); debugf("cboot:vbat greater than 3V or other charger type\n"); } else { sprdbat_show_lowpower_charge_logo(LOWPOWER_LOGO_DISABLE_TIME); debugf("cboot:vbat less than 3V and charge type is SDP or UNKNOW\n"); } #ifdef CONFIG_BATTERY_TEMP } #endif sprdbat_lowbat_chg(temp_status, usb_type); mdelay(SPRDBAT_CHG_POLLING_T); } boot_mode_enum_type check_mode_from_keypad(void) { uint32_t key_mode = 0; int key_code = 0; volatile int i; if (boot_pwr_check() >= PWR_KEY_DETECT_CNT) { mdelay(50); for (i = 0; i < 10; i++) { key_code = board_key_scan(); if(key_code != KEY_RESERVED) break; } key_mode = check_key_boot(key_code); if (!key_mode) key_mode = CMD_NORMAL_MODE; } return key_mode; } // get mode from chipram_env boot_mode_enum_type get_mode_from_chipram_env(void) { boot_mode_t boot_role; char buf[DL_PROCESS_LEN] = {0}; dl_get_downloadflag(buf); dprintf(INFO,"==== in [%s] \n", __func__); boot_role = get_boot_role(); if (boot_role == BOOTLOADER_MODE_DOWNLOAD) { return CMD_DOWNLOAD_MODE; } else if (!strncmp("enable", buf, strlen("enable"))) { dl_clear_downloadflag(); return CMD_AUTODLOADER_REBOOT; } else if (check_mode_from_keypad() == CMD_FASTBOOT_MODE) { return CMD_FASTBOOT_MODE; } else if (boot_role == BOOTLOADER_MODE_UNKNOW) { errorf("unkown uboot role!!!!!!!!!!!!!!!!!\n"); } return CMD_UNDEFINED_MODE; } // 0 get mode from pc tool boot_mode_enum_type get_mode_from_pctool(void) { int ret, to_vol; dprintf(INFO,"==== in [%s] \n", __func__); #if defined(PLATFORM_SHARKLE) || defined(PLATFORM_SHARKL3) \ || defined(PLATFORM_QOGIRL6) || defined(PLATFORM_QOGIRN6PRO) || defined(PLATFORM_QOGIRN6L) to_vol = USBPHY_VDDUSB33_NORMAL; #else to_vol = USBPHY_VDDUSB33_FULLSPEED_TUNE; #endif regulator_set_voltage("vddusb33", to_vol); ret = pctool_mode_detect(); regulator_set_voltage("vddusb33", USBPHY_VDDUSB33_NORMAL); if (ret < 0) return CMD_UNDEFINED_MODE; else { bootcause_cmdline="The pctools sends control commands"; return ret; } } #ifndef CONFIG_ZEBU boot_mode_enum_type get_mode_from_smpl(void) { dprintf(INFO,"==== in [%s] \n", __func__); if(is_smpl_bootup()) { debugf("is_hw_smpl_enable %d\n", is_hw_smpl_enable()); lr_cause = LR_ABNORMAL; bootcause_cmdline="Sudden momentary power loss"; debugf("SMPL bootup!\n"); return CMD_NORMAL_MODE; } return CMD_UNDEFINED_MODE; } #else boot_mode_enum_type get_mode_from_smpl(void) { return CMD_UNDEFINED_MODE; } #endif boot_mode_enum_type get_mode_from_bat_low(void) { int i; dprintf(INFO,"==== in [%s] \n", __func__); #ifndef CONFIG_FPGA //jump loop #ifdef OPLUS_FEATURE_CHG_BASIC int is_bat_low_flag, temp_status, batt_temp; u32 wdt_status = 0; enum sprd_adapter_type charger_type = ADP_TYPE_UNKNOW; wdt_status = status_watchdog(); if (charger_connected()) charger_type = sprdchg_charger_is_adapter(); while(1) { is_bat_low_flag = is_bat_low(); batt_temp = sprdbat_get_battery_temp(); #ifdef CONFIG_BATTERY_TEMP dprintf(INFO,"sprd_chg:%s batt_temp=%d\n", __func__, batt_temp); if (batt_temp >= DISBOOTING_HIGH_TEMP) { #else if (batt_temp >= DISBOOTING_TEMP_77) { #endif logo_display(LOGO_HIGH_BATTERY_TEMP, BACKLIGHT_ON, LCD_DISPLAY_ENABLE); temp_status = DISBOOTING_TEMP; } else if (batt_temp < DISCHARGING_LOW_TEMP_NEGATIVE10 || batt_temp >= DISCHARGING_HIGH_TEMP_53) temp_status = DISCHARGING_TEMP; else temp_status = NORMAL_TEMP; #else int is_bat_low_flag, temp_status, ibat_cur; u32 wdt_status = 0; enum sprd_adapter_type charger_type = ADP_TYPE_UNKNOW; int bat_low_count = 0; wdt_status = status_watchdog(); if (charger_connected()) charger_type = sprdchg_charger_is_adapter(); while(is_bat_low()) { bat_low_count++; ibat_cur = sprdfgu_read_ibat_cur(); if (ibat_cur <= IBAT_CUR_STEP2_700 || bat_low_count > 10) break; dprintf(INFO,"sprd_chg: %s,ibat_cur = %d\n", __func__, ibat_cur); mdelay(50); } while(1) { temp_status = sprdbat_get_battery_temp_status(); is_bat_low_flag = is_bat_low(); #endif if (!is_bat_low_flag && !temp_status) break; #ifdef OPLUS_FEATURE_CHG_BASIC #ifdef CONFIG_BATTERY_TEMP if(batt_temp >= DISBOOTING_HIGH_TEMP && (!power_button_pressed())) break; #endif #endif if (temp_status && is_bat_low_flag) { if(charger_connected() || get_mode_from_vchg()) { dprintf(INFO,"cboot:low battery and abnormal temerature,stop charging...\n"); low_power_charge(temp_status, charger_type); } else { dprintf(INFO, "cboot:low battery and abnormal temerature,shutdown\n"); logo_display(LOGO_LOW_VOL, BACKLIGHT_ON, LCD_DISPLAY_ENABLE); mdelay(LOW_VOL_DISPLAY_DELAY_TIME); return CMD_POWER_DOWN_DEVICE; } } else if (temp_status && !is_bat_low_flag) { dprintf(INFO, "cboot:abnormal temerature,stop charging...\n"); sprdbat_lowbat_chg(temp_status, charger_type); if (temp_status == DISCHARGING_TEMP) return CMD_UNDEFINED_MODE; dprintf(INFO, "cboot:abnormal temerature,disbooting\n"); mdelay(SPRDBAT_CHG_POLLING_T); } else if (!temp_status && is_bat_low_flag) { if(charger_connected() || get_mode_from_vchg()) { dprintf(INFO, "cboot:low battery,charging...\n"); low_power_charge(temp_status, charger_type); } else { dprintf(INFO, "cboot:low battery and shutdown\n"); for (i = 0; i < 3; i++ ) { logo_display(LOGO_LOW_VOL, BACKLIGHT_ON, LCD_DISPLAY_ENABLE); mdelay(400); logo_display(LOGO_LOW_VOL_02, BACKLIGHT_ON, LCD_DISPLAY_ENABLE); mdelay(400); } return CMD_POWER_DOWN_DEVICE; } } if (wdt_status) load_watchdog(300 * 1000); } #endif /* CONFIG_FPGA */ sprdbat_chg_led(0); return CMD_UNDEFINED_MODE; } #ifndef CONFIG_ZEBU boot_mode_enum_type write_sysdump_before_boot_extend(void) { dprintf(INFO,"==== in [%s] \n", __func__); #ifdef CONFIG_CRYPTO_CHECK int enableDump = read_enableDump_from_miscdata(); if (!enableDump) { dprintf(INFO,"write_sysdump_before_boot_extend enableDump = %d, not allow dump \n", enableDump); return CMD_UNDEFINED_MODE; } else { dprintf(INFO,"write_sysdump_before_boot_extend enableDump = %d, allow dump \n", enableDump); } #endif unsigned rst_mode = reboot_mode_check(); #ifdef SPRD_MINI_SYSDUMP handle_minidump_before_boot(rst_mode); #endif #ifdef SPRD_SYSDUMP write_sysdump_before_boot(rst_mode); #endif return CMD_UNDEFINED_MODE; } #else boot_mode_enum_type write_sysdump_before_boot_extend(void) { return CMD_UNDEFINED_MODE; } #endif /* get mode from miscdata */ boot_mode_enum_type get_mode_from_miscdata_boot_flag(void) { dprintf(INFO,"==== in [%s] \n", __func__); #if defined(CONFIG_CUSTOMER_PHONE) && defined(CONFIG_AUTOBOOT) extern unsigned reboot_reg; if ((reboot_reg & 0xFF) == HWRST_STATUS_AUTODLOADER) { dprintf(INFO,"%s:rst_mode is autodloader\n", __func__); return CMD_AUTODLOADER_REBOOT; } #elif defined CONFIG_AUTOBOOT dprintf(INFO," AUTOBOOT ENABLE! \n"); return CMD_NORMAL_MODE; #endif boot_mode_enum_type first_mode = read_boot_flag(); if (first_mode != CMD_UNDEFINED_MODE) { bootcause_cmdline="Detect the firsrt_mode flag in the miscdata partition"; dprintf(INFO,"get mode from firstmode field: %s\n", g_mode_str[first_mode]); return first_mode; } return CMD_UNDEFINED_MODE; } /*1 get mode from file, just for recovery mode now*/ boot_mode_enum_type get_mode_from_file_extend(void) { dprintf(INFO,"==== in [%s] \n", __func__); switch (get_mode_from_file()) { case CMD_RECOVERY_MODE: dprintf(INFO,"cboot:get mode from file:recovery\n"); bootcause_cmdline="Detect the recovery message in the misc partition"; return CMD_RECOVERY_MODE; default: return CMD_UNDEFINED_MODE; } return CMD_UNDEFINED_MODE; } // 2 get mode from watch dog boot_mode_enum_type get_mode_from_watchdog(void) { dprintf(INFO,"==== in [%s] \n", __func__); unsigned rst_mode = reboot_mode_check(); int flag; switch (rst_mode) { case CMD_RECOVERY_MODE: case CMD_FASTBOOT_MODE: case CMD_NORMAL_MODE: case CMD_WATCHDOG_REBOOT: case CMD_AP_WATCHDOG_REBOOT: case CMD_ABNORMAL_REBOOT_MODE: case CMD_UNKNOW_REBOOT_MODE: case CMD_PANIC_REBOOT: case CMD_AUTODLOADER_REBOOT: case CMD_SPECIAL_MODE: case CMD_EXT_RSTN_REBOOT_MODE: case CMD_IQ_REBOOT_MODE: case CMD_SPRDISK_MODE: case CMD_SILENT_MODE: case CMD_BOOTLOADER_PANIC_MODE: case CMD_SML_PANIC_MODE: return rst_mode; case CMD_ALARM_MODE: if ((flag = alarm_flag_check())) { dprintf(INFO,"get_mode_from_watchdog flag=%d\n", flag); if (flag == 1) { bootcause_cmdline="PMIC reg reset and poweroff alarm"; return CMD_ALARM_MODE; } else if (flag == 2) { bootcause_cmdline="PMIC reg reset but Shutdown alarm is abnormal"; return CMD_NORMAL_MODE; } } default: return CMD_UNDEFINED_MODE; } } boot_mode_enum_type get_mode_to_autodloader(void) { int key_code = 0; volatile int i; dprintf(INFO,"==== in [%s] \n", __func__); for (i = 0; i < 10; i++) { key_code = board_key_scan(); if(key_code != KEY_RESERVED) break; } if(key_code==(KEY_VOLUMEUP+KEY_VOLUMEDOWN)) return CMD_AUTODLOADER_REBOOT; return CMD_UNDEFINED_MODE; } // 3 get mode from alarm register boot_mode_enum_type get_mode_from_alarm_register(void) { int flag; dprintf(INFO,"==== in [%s] \n", __func__); if (alarm_triggered() && (flag = alarm_flag_check())) { dprintf(INFO,"get_mode_from_alarm_register flag=%d\n", flag); if (flag == 1) { bootcause_cmdline="RTC poweroff alarm expiry"; return CMD_ALARM_MODE; } else if (flag == 2) { bootcause_cmdline="Shutdown alarm is abnormal"; return CMD_NORMAL_MODE; } } return CMD_UNDEFINED_MODE; } static unsigned int get_gpio_status(unsigned int GPIO_NUM) { int value = -1; int ret = 0; ret = sprd_gpio_request(GPIO_NUM); if (ret < 0) { debugf("cboot: gpio request return ERROR!\n"); return -1; } ret = sprd_gpio_direction_input(GPIO_NUM); if (ret < 0) { debugf("cboot: gpio input return ERROR!\n"); return -1; } value = sprd_gpio_get(GPIO_NUM); return value; } /* get mode from bbat detect*/ boot_mode_enum_type get_mode_from_gpio_bbat_cali(void) { int conf0 = -1; int conf1 = -1; conf0 = get_gpio_status(CONF_0); conf1 = get_gpio_status(CONF_1); debugf("cboot: gpio conf0 = %d, gpio conf1 = %d\n", conf0, conf1); if (conf0 == 0) { bootcause_cmdline = "autotest mode from gpio"; return CMD_AUTOTEST_MODE; } else if (conf0 == 1 && conf1 == 0) { bootcause_cmdline = "caliberation mode from gpio"; return CMD_CALIBRATION_MODE; } else { return CMD_UNDEFINED_MODE; } } /* 4 get mode from charger*/ boot_mode_enum_type get_mode_from_charger(void) { int shutdown_charge_flag = 0, auto_poweron_flag = 0; boot_mode_enum_type bootmode = CMD_UNDEFINED_MODE; dprintf(INFO,"==== in [%s] \n", __func__); auto_poweron_flag = sprdbat_get_auto_poweron_flag(); shutdown_charge_flag = sprdbat_get_shutdown_charge_flag(); dprintf(INFO,"get_shutdown_charge_flag flag=%d\n", shutdown_charge_flag); /* add rtc helper function for power-off charging wakeup alarm debug */ sprd_rtc_alarm_status_check(); if ((!charger_connected()) && (!get_mode_from_vchg())) return bootmode; if (!auto_poweron_flag) { dprintf(INFO,"auto_poweron_flag get mode from charger\n"); bootcause_cmdline="in charging during shutdown the devices"; bootmode = CMD_CHARGE_MODE; } else { dprintf(INFO,"get_auto_poweron_flag auto_poweron_flag=%d\n", auto_poweron_flag); if (shutdown_charge_flag) { dprintf(INFO,"get mode from charger\n"); bootcause_cmdline="in charging during shutdown the devices"; bootmode = CMD_CHARGE_MODE; } else { bootcause_cmdline="Charger connected"; bootmode = CMD_NORMAL_MODE; } } #ifdef CONFIG_DOWNLOAD_FOR_CUSTOMER if (bootmode == CMD_CHARGE_MODE && (board_key_scan() == (KEY_VOLUMEUP + KEY_VOLUMEDOWN)) && (pctool_connected())) { dprintf(ALWAYS, "KEY_VOLUMEUP + KEY_VOLUMEDOWN trigger to download\n"); bootmode = CMD_AUTODLOADER_REBOOT; } #endif return bootmode; } /*5 get mode from keypad*/ boot_mode_enum_type get_mode_from_keypad(void) { uint32_t key_mode = 0; dprintf(INFO,"==== in [%s] \n", __func__); key_mode = check_mode_from_keypad(); dprintf(INFO,"cboot:get mode from keypad:%d, %s\n",key_mode, g_mode_str[key_mode]); if (!key_mode) return CMD_UNDEFINED_MODE; switch(key_mode) { case CMD_RECOVERY_MODE: bootcause_cmdline="Keypad trigger to recovery"; return CMD_RECOVERY_MODE; default: bootcause_cmdline="Pbint triggered"; return CMD_NORMAL_MODE; } } // 6 get mode from gpio boot_mode_enum_type get_mode_from_gpio_extend(void) { dprintf(INFO,"==== in [%s] \n", __func__); if (get_mode_from_gpio()) { bootcause_cmdline="pbint2 triggered"; dprintf(INFO,"Pbint2 triggered, do normal mode\n"); return CMD_NORMAL_MODE; } else { return CMD_UNDEFINED_MODE; } } #if defined CONFIG_ANDROID_AB void do_select_ab(void) { int ret; char slot[3]; #if defined (CONFIG_FPGA) && defined (CONFIG_DDR_BOOT) ret = 0; #else ret = ab_select_slot(); #endif if (ret < 0) { errorf("Android boot failed, error %d.\n", ret); return; } /* Android standard slot names are 'a', 'b', ... */ slot[0] = '_'; slot[1] = BOOT_SLOT_NAME(ret); slot[2] = '\0'; memcpy(g_env_slot, slot, sizeof(slot)); dprintf(CRITICAL,"ANDROID: Booting slot%s\n", slot); } #endif #ifdef CONFIG_MMC_POWP_SUPPORT extern int g_part_protected; extern char *g_part_name; static void do_emmc_powp(void) { if (g_part_protected) { if (common_set_powp(g_part_name)) { errorf("partition %s can't be protected, pls check it\n", g_part_name); return; } debugf("do emmc powp success\n"); } } #endif uint8_t check_payjoy_flag(void); uint8_t check_payjoy_flag() { uint64_t offset; uint8_t val; //PayJoy Control Byte is 12,025 to the tail of persist offset = 2048*1024 - 1 - 1000 - 1024 - 10000; // read payjoy flag from persistent partition. // you may change the actual number of offset according to the size of FRP or persistent partition common_raw_read("persist", 1, offset, &val); // call mmc_read printf("check_payjoy_flag:%d,%d\n",sizeof(val),val); return val; } int sprd_boot(void) { volatile int i; boot_mode_enum_type bootmode = CMD_UNDEFINED_MODE; CBOOT_MODE_ENTRY boot_mode_array[CMD_MAX_MODE] ={0}; FTL_Savepoint_Private(PHASE_SPRDBOOT_INIT); #ifdef CONFIG_AUTOLOAD_MODE autoload_mode(); #endif #ifdef CONFIG_ANDROID_AB if(adjust_spl_slot()) return -1; do_select_ab(); if (ota_processing) dl_set_wdtflag(); #endif if (get_boot_role() == BOOTLOADER_MODE_LOAD){ #ifndef CONFIG_ZEBU reconfig_baudrate(); /* switch baudrate by following kernel menu */ #endif ddr_eng_mode_debug(); // config ddr paras from eng mode #ifdef CONFIG_USB_SPRD_DWC31_PHY if (usb_phy_enabled()) usb_phy_enable(0); #endif } #if defined CONFIG_ZEBU normal_mode(); errorf("normal mode exit with exception!!!\n"); while(1); #endif #ifndef CONFIG_FPGA boot_pwr_check(); #endif for (i = 0; i < CHECK_BOOTMODE_FUN_NUM; i++) { if (0 == s_boot_func_array[i]) { bootmode = CMD_POWER_DOWN_DEVICE; dprintf(INFO,"==== get boot mode in boot func array[%d]\n",i); break; } bootmode = s_boot_func_array[i](); if (CMD_UNDEFINED_MODE == bootmode) { continue; } else { dprintf(INFO,"get boot mode in boot func array[%d]\n",i); break; } } #ifdef VENDOR_EDIT if(bootmode != CMD_POWER_DOWN_DEVICE && bootmode != CMD_DOWNLOAD_MODE){ if (cdt_table_analysis()) return 0; } #endif board_boot_mode_regist(boot_mode_array); /* Don't let phone get into recovery mode if the payjoy flag has been set to 1. Attention: only prevents users enter recovery mode by command "adb reboot recovery" or pressing power and volume buttons, should not affect entering recovery mode by system OTA upgrading or factory reset from Settings. That means the bootloader should check payjoy flag in persistent/frp partition at first, then check BCB(Bootloader Control Block) in misc partition. */ if (1 == check_payjoy_flag() && bootmode == CMD_FASTBOOT_MODE) { bootmode = CMD_NORMAL_MODE; } dprintf(ALWAYS,"enter boot mode g_mode_str[%d]:%s\n", bootmode, g_mode_str[bootmode]); #ifdef CONFIG_MMC_POWP_SUPPORT if (get_boot_role() == BOOTLOADER_MODE_LOAD) do_emmc_powp(); #endif if ((bootmode > CMD_POWER_DOWN_DEVICE) &&(bootmode < CMD_MAX_MODE) && (0 != boot_mode_array[bootmode])) { boot_mode_array[bootmode](); } else { #ifdef CONFIG_FPGA /*FPGA has no power button ,if hasn't detect any mode ,use normal mode*/ dprintf(INFO, "FPGA use normal mode instead of power down.\n"); normal_mode(); #else dprintf(ALWAYS, "power down device\n"); power_down_devices(0); dprintf(ALWAYS, "===== after regist, loop forever!!! \n"); while(1); #endif } dprintf(ALWAYS, "==== [%s]: Power down device. Do not run here forever!!!\n", __func__); power_down_devices(0); return 0; } static void boot_init(const struct app_descriptor *app) { console_init(); sprd_boot(); } APP_START(sprdboot) .init = boot_init, APP_END
08-12
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值