ADD package
This commit is contained in:
parent
7ffba5befc
commit
11896d714a
@ -33,11 +33,21 @@ KDIR=$(KERNEL_BUILD_DIR)
|
||||
KDIR_TMP=$(KDIR)/tmp
|
||||
DTS_DIR:=$(LINUX_DIR)/arch/$(LINUX_KARCH)/boot/dts
|
||||
|
||||
# 获取当前日期
|
||||
BUILD_DATE := $(shell date +"%Y%m%d")
|
||||
|
||||
# 从根目录的 fish 文件中获取版本号
|
||||
FISH_VERSION := $(shell grep 'VERSION' $(TOPDIR)/fish | cut -d '=' -f2)
|
||||
|
||||
|
||||
# 组合版本号和日期
|
||||
FULL_VERSION := $(FISH_VERSION)-$(BUILD_DATE)
|
||||
|
||||
IMG_PREFIX_EXTRA:=$(if $(EXTRA_IMAGE_NAME),$(call sanitize,$(EXTRA_IMAGE_NAME))-)
|
||||
IMG_PREFIX_VERNUM:=$(if $(CONFIG_VERSION_FILENAMES),$(call sanitize,$(VERSION_NUMBER))-)
|
||||
IMG_PREFIX_VERCODE:=$(if $(CONFIG_VERSION_CODE_FILENAMES),$(call sanitize,$(VERSION_CODE))-)
|
||||
|
||||
IMG_PREFIX:=$(VERSION_DIST_SANITIZED)-$(IMG_PREFIX_VERNUM)$(IMG_PREFIX_VERCODE)$(IMG_PREFIX_EXTRA)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
|
||||
IMG_PREFIX:=$(FULL_VERSION)-$(VERSION_DIST_SANITIZED)-$(IMG_PREFIX_VERNUM)$(IMG_PREFIX_VERCODE)$(IMG_PREFIX_EXTRA)$(BOARD)$(if $(SUBTARGET),-$(SUBTARGET))
|
||||
IMG_ROOTFS:=$(IMG_PREFIX)-rootfs
|
||||
IMG_COMBINED:=$(IMG_PREFIX)-combined
|
||||
ifeq ($(DUMP),)
|
||||
|
||||
@ -25,8 +25,18 @@ sanitize = $(call tolower,$(subst _,-,$(subst $(space),-,$(1))))
|
||||
VERSION_NUMBER:=$(call qstrip,$(CONFIG_VERSION_NUMBER))
|
||||
VERSION_NUMBER:=$(if $(VERSION_NUMBER),$(VERSION_NUMBER),23.05.4)
|
||||
|
||||
# 获取当前日期
|
||||
BUILD_DATE := $(shell date +"%Y%m%d")
|
||||
|
||||
# 从根目录的 fish 文件中获取版本号
|
||||
FISH_VERSION := $(shell grep 'VERSION' $(TOPDIR)/fish | cut -d '=' -f2)
|
||||
|
||||
|
||||
# 组合版本号和日期
|
||||
FULL_VERSION := $(FISH_VERSION)-$(BUILD_DATE)
|
||||
|
||||
VERSION_CODE:=$(call qstrip,$(CONFIG_VERSION_CODE))
|
||||
VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),r28061-399f9a1db3)
|
||||
VERSION_CODE:=$(if $(VERSION_CODE),$(VERSION_CODE),$(FULL_VERSION) By Fish)
|
||||
|
||||
VERSION_REPO:=$(call qstrip,$(CONFIG_VERSION_REPO))
|
||||
VERSION_REPO:=$(if $(VERSION_REPO),$(VERSION_REPO),https://downloads.immortalwrt.org/releases/23.05.4)
|
||||
|
||||
42
package/base-files/files/etc/uci-defaults/14_h69k-oled
Executable file
42
package/base-files/files/etc/uci-defaults/14_h69k-oled
Executable file
@ -0,0 +1,42 @@
|
||||
#!/bin/sh
|
||||
|
||||
# 检查当前的板子型号
|
||||
board_name=$(cat /proc/device-tree/model | tr -d '\0')
|
||||
|
||||
# 根据型号进行设置
|
||||
case "$board_name" in
|
||||
"hinlink,opc-h69k")
|
||||
# 设置 OLED 配置
|
||||
uci batch <<EOF
|
||||
set oled.@oled[0].path='/dev/i2c-5'
|
||||
set oled.@oled[0].enable='1'
|
||||
set oled.@oled[0].drawline='0'
|
||||
set oled.@oled[0].drawrect='0'
|
||||
set oled.@oled[0].fillrect='0'
|
||||
set oled.@oled[0].drawcircle='0'
|
||||
set oled.@oled[0].drawroundrect='0'
|
||||
set oled.@oled[0].fillroundrect='0'
|
||||
set oled.@oled[0].drawtriangle='0'
|
||||
set oled.@oled[0].filltriangle='0'
|
||||
set oled.@oled[0].displaybitmap='0'
|
||||
set oled.@oled[0].displayinvertnormal='0'
|
||||
set oled.@oled[0].drawbitmapeg='0'
|
||||
set oled.@oled[0].date='1'
|
||||
set oled.@oled[0].netspeed='1'
|
||||
set oled.@oled[0].lanip='1'
|
||||
set oled.@oled[0].cpufreq='1'
|
||||
set oled.@oled[0].cputemp='1'
|
||||
set oled.@oled[0].time='60'
|
||||
set oled.@oled[0].autoswitch='0'
|
||||
set oled.@oled[0].rotate='1'
|
||||
set oled.@oled[0].scroll='0'
|
||||
set oled.@oled[0].netsource='eth0'
|
||||
EOF
|
||||
|
||||
# 保存配置并应用
|
||||
uci commit oled
|
||||
;;
|
||||
esac
|
||||
|
||||
# 删除当前脚本以确保只执行一次
|
||||
rm -f /etc/uci-defaults/99-oled-configss
|
||||
@ -0,0 +1,21 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
|
||||
#include "rk356x-u-boot.dtsi"
|
||||
|
||||
/ {
|
||||
chosen {
|
||||
stdout-path = &uart2;
|
||||
u-boot,spl-boot-order = "same-as-spl", &sdhci;
|
||||
};
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
cap-mmc-highspeed;
|
||||
mmc-hs200-1_8v;
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
clock-frequency = <24000000>;
|
||||
bootph-all;
|
||||
status = "okay";
|
||||
};
|
||||
@ -0,0 +1,619 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
|
||||
/*
|
||||
* Copyright (c) 2022 AmadeusGhost <amadeus@jmu.edu.cn>
|
||||
*/
|
||||
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/input/input.h>
|
||||
#include <dt-bindings/pinctrl/rockchip.h>
|
||||
#include <dt-bindings/soc/rockchip,vop2.h>
|
||||
#include "rk3568.dtsi"
|
||||
|
||||
/ {
|
||||
aliases {
|
||||
mmc0 = &sdhci;
|
||||
mmc1 = &sdmmc0;
|
||||
|
||||
led-boot = &power_led;
|
||||
led-failsafe = &power_led;
|
||||
led-running = &power_led;
|
||||
led-upgrade = &power_led;
|
||||
};
|
||||
|
||||
chosen {
|
||||
stdout-path = "serial2:1500000n8";
|
||||
};
|
||||
|
||||
hdmi-con {
|
||||
compatible = "hdmi-connector";
|
||||
type = "a";
|
||||
|
||||
port {
|
||||
hdmi_con_in: endpoint {
|
||||
remote-endpoint = <&hdmi_out_con>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
gpio-keys {
|
||||
compatible = "gpio-keys";
|
||||
pinctrl-0 = <&reset_button_pin>;
|
||||
pinctrl-names = "default";
|
||||
|
||||
reset {
|
||||
label = "reset";
|
||||
gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
|
||||
linux,code = <KEY_RESTART>;
|
||||
debounce-interval = <50>;
|
||||
};
|
||||
};
|
||||
|
||||
gpio-leds {
|
||||
compatible = "gpio-leds";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&led_lan_pin>, <&led_power_pin>, <&led_wan_pin>;
|
||||
|
||||
led-lan {
|
||||
label = "amber:lan";
|
||||
gpios = <&gpio3 RK_PA7 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
power_led: led-power {
|
||||
label = "green:power";
|
||||
gpios = <&gpio3 RK_PB0 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
|
||||
led-wan {
|
||||
label = "blue:wan";
|
||||
gpios = <&gpio3 RK_PA5 GPIO_ACTIVE_HIGH>;
|
||||
};
|
||||
};
|
||||
|
||||
pwm-fan {
|
||||
compatible = "pwm-fan";
|
||||
cooling-levels = <0 100 150 200 255>;
|
||||
#cooling-cells = <2>;
|
||||
pwms = <&pwm0 0 50000 0>;
|
||||
};
|
||||
|
||||
vcc12v_dcin: vcc12v-dcin-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <12000000>;
|
||||
regulator-max-microvolt = <12000000>;
|
||||
regulator-name = "vcc12v_dcin";
|
||||
};
|
||||
|
||||
vcc3v3_sys: vcc3v3-sys-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-name = "vcc3v3_sys";
|
||||
vin-supply = <&vcc12v_dcin>;
|
||||
};
|
||||
|
||||
vcc5v0_sys: vcc5v0-sys-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-name = "vcc5v0_sys";
|
||||
vin-supply = <&vcc12v_dcin>;
|
||||
};
|
||||
|
||||
vcc5v0_usb: vcc5v0-usb-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-name = "vcc5v0_usb";
|
||||
vin-supply = <&vcc12v_dcin>;
|
||||
};
|
||||
|
||||
vcc5v0_usb_host: vcc5v0-usb-host-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
gpio = <&gpio0 RK_PA5 GPIO_ACTIVE_HIGH>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&vcc5v0_usb_host_en>;
|
||||
regulator-min-microvolt = <5000000>;
|
||||
regulator-max-microvolt = <5000000>;
|
||||
regulator-name = "vcc5v0_usb_host";
|
||||
vin-supply = <&vcc5v0_usb>;
|
||||
};
|
||||
|
||||
vcc3v3_pcie: vcc3v3-pcie-regulator {
|
||||
compatible = "regulator-fixed";
|
||||
enable-active-high;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-name = "vcc3v3_pcie";
|
||||
startup-delay-us = <5000>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
};
|
||||
};
|
||||
|
||||
&combphy0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&combphy1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&combphy2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&cpu0 {
|
||||
cpu-supply = <&vdd_cpu>;
|
||||
};
|
||||
|
||||
&cpu1 {
|
||||
cpu-supply = <&vdd_cpu>;
|
||||
};
|
||||
|
||||
&cpu2 {
|
||||
cpu-supply = <&vdd_cpu>;
|
||||
};
|
||||
|
||||
&cpu3 {
|
||||
cpu-supply = <&vdd_cpu>;
|
||||
};
|
||||
|
||||
&gpu {
|
||||
mali-supply = <&vdd_gpu>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&hdmi {
|
||||
avdd-0v9-supply = <&vdda0v9_image>;
|
||||
avdd-1v8-supply = <&vcca1v8_image>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&hdmi_in {
|
||||
hdmi_in_vp0: endpoint {
|
||||
remote-endpoint = <&vp0_out_hdmi>;
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi_out {
|
||||
hdmi_out_con: endpoint {
|
||||
remote-endpoint = <&hdmi_con_in>;
|
||||
};
|
||||
};
|
||||
|
||||
&hdmi_sound {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2c0 {
|
||||
status = "okay";
|
||||
|
||||
vdd_cpu: regulator@1c {
|
||||
compatible = "tcs,tcs4525";
|
||||
reg = <0x1c>;
|
||||
fcs,suspend-voltage-selector = <1>;
|
||||
regulator-name = "vdd_cpu";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <712500>;
|
||||
regulator-max-microvolt = <1390000>;
|
||||
regulator-ramp-delay = <2300>;
|
||||
vin-supply = <&vcc5v0_sys>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
rk809: pmic@20 {
|
||||
compatible = "rockchip,rk809";
|
||||
reg = <0x20>;
|
||||
interrupt-parent = <&gpio0>;
|
||||
interrupts = <RK_PA3 IRQ_TYPE_LEVEL_LOW>;
|
||||
assigned-clocks = <&cru I2S1_MCLKOUT_TX>;
|
||||
assigned-clock-parents = <&cru CLK_I2S1_8CH_TX>;
|
||||
#clock-cells = <1>;
|
||||
clock-names = "mclk";
|
||||
clocks = <&cru I2S1_MCLKOUT_TX>;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&pmic_int>, <&i2s1m0_mclk>;
|
||||
rockchip,system-power-controller;
|
||||
#sound-dai-cells = <0>;
|
||||
wakeup-source;
|
||||
|
||||
vcc1-supply = <&vcc3v3_sys>;
|
||||
vcc2-supply = <&vcc3v3_sys>;
|
||||
vcc3-supply = <&vcc3v3_sys>;
|
||||
vcc4-supply = <&vcc3v3_sys>;
|
||||
vcc5-supply = <&vcc3v3_sys>;
|
||||
vcc6-supply = <&vcc3v3_sys>;
|
||||
vcc7-supply = <&vcc3v3_sys>;
|
||||
vcc8-supply = <&vcc3v3_sys>;
|
||||
vcc9-supply = <&vcc3v3_sys>;
|
||||
|
||||
regulators {
|
||||
vdd_logic: DCDC_REG1 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
regulator-name = "vdd_logic";
|
||||
regulator-ramp-delay = <6001>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_gpu: DCDC_REG2 {
|
||||
regulator-always-on;
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
regulator-name = "vdd_gpu";
|
||||
regulator-ramp-delay = <6001>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_ddr: DCDC_REG3 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-name = "vcc_ddr";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdd_npu: DCDC_REG4 {
|
||||
regulator-init-microvolt = <900000>;
|
||||
regulator-initial-mode = <0x2>;
|
||||
regulator-min-microvolt = <500000>;
|
||||
regulator-max-microvolt = <1350000>;
|
||||
regulator-name = "vdd_npu";
|
||||
regulator-ramp-delay = <6001>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_1v8: DCDC_REG5 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-name = "vcc_1v8";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdda0v9_image: LDO_REG1 {
|
||||
regulator-name = "vdda0v9_image";
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdda_0v9: LDO_REG2 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
regulator-name = "vdda_0v9";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vdda0v9_pmu: LDO_REG3 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <900000>;
|
||||
regulator-max-microvolt = <900000>;
|
||||
regulator-name = "vdda0v9_pmu";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <900000>;
|
||||
};
|
||||
};
|
||||
|
||||
vccio_acodec: LDO_REG4 {
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-name = "vccio_acodec";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vccio_sd: LDO_REG5 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-name = "vccio_sd";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc3v3_pmu: LDO_REG6 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <3300000>;
|
||||
regulator-max-microvolt = <3300000>;
|
||||
regulator-name = "vcc3v3_pmu";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <3300000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcca_1v8: LDO_REG7 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-name = "vcca_1v8";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcca1v8_pmu: LDO_REG8 {
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-name = "vcca1v8_pmu";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-on-in-suspend;
|
||||
regulator-suspend-microvolt = <1800000>;
|
||||
};
|
||||
};
|
||||
|
||||
vcca1v8_image: LDO_REG9 {
|
||||
regulator-min-microvolt = <1800000>;
|
||||
regulator-max-microvolt = <1800000>;
|
||||
regulator-name = "vcca1v8_image";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc_3v3: SWITCH_REG1 {
|
||||
regulator-name = "vcc_3v3";
|
||||
regulator-always-on;
|
||||
regulator-boot-on;
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
|
||||
vcc3v3_sd: SWITCH_REG2 {
|
||||
regulator-name = "vcc3v3_sd";
|
||||
|
||||
regulator-state-mem {
|
||||
regulator-off-in-suspend;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&i2c5 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&i2s0_8ch {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie2x1 {
|
||||
reset-gpios = <&gpio2 RK_PD6 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc3v3_pcie>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie30phy {
|
||||
data-lanes = <1 2>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie3x1 {
|
||||
num-lanes = <1>;
|
||||
reset-gpios = <&gpio3 RK_PA4 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc3v3_pcie>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pcie3x2 {
|
||||
num-lanes = <1>;
|
||||
reset-gpios = <&gpio2 RK_PD0 GPIO_ACTIVE_HIGH>;
|
||||
vpcie3v3-supply = <&vcc3v3_pcie>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pinctrl {
|
||||
leds {
|
||||
led_lan_pin: led-lan-pin {
|
||||
rockchip,pins = <3 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
led_power_pin: led-power-pin {
|
||||
rockchip,pins = <3 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
|
||||
led_wan_pin: led-wan-pin {
|
||||
rockchip,pins = <3 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
|
||||
pmic {
|
||||
pmic_int: pmic-int {
|
||||
rockchip,pins = <0 RK_PA3 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
rockchip-key {
|
||||
reset_button_pin: reset-button-pin {
|
||||
rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
|
||||
};
|
||||
};
|
||||
|
||||
usb {
|
||||
vcc5v0_usb_host_en: vcc5v0-usb-host-en {
|
||||
rockchip,pins = <0 RK_PA5 RK_FUNC_GPIO &pcfg_pull_none>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
&pmu_io_domains {
|
||||
pmuio1-supply = <&vcc3v3_pmu>;
|
||||
pmuio2-supply = <&vcc3v3_pmu>;
|
||||
vccio1-supply = <&vccio_acodec>;
|
||||
vccio2-supply = <&vcc_1v8>;
|
||||
vccio3-supply = <&vccio_sd>;
|
||||
vccio4-supply = <&vcc_1v8>;
|
||||
vccio5-supply = <&vcc_3v3>;
|
||||
vccio6-supply = <&vcc_1v8>;
|
||||
vccio7-supply = <&vcc_3v3>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&pwm0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&saradc {
|
||||
vref-supply = <&vcca_1v8>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sata0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdhci {
|
||||
bus-width = <8>;
|
||||
cap-mmc-highspeed;
|
||||
max-frequency = <200000000>;
|
||||
mmc-hs200-1_8v;
|
||||
no-sdio;
|
||||
no-sd;
|
||||
non-removable;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&emmc_bus8 &emmc_clk &emmc_cmd &emmc_datastrobe>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&sdmmc0 {
|
||||
bus-width = <4>;
|
||||
cap-sd-highspeed;
|
||||
cd-gpios = <&gpio0 RK_PA4 GPIO_ACTIVE_LOW>;
|
||||
disable-wp;
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&sdmmc0_bus4 &sdmmc0_clk &sdmmc0_cmd &sdmmc0_det>;
|
||||
sd-uhs-sdr50;
|
||||
vmmc-supply = <&vcc3v3_sd>;
|
||||
vqmmc-supply = <&vccio_sd>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&tsadc {
|
||||
rockchip,hw-tshut-mode = <1>;
|
||||
rockchip,hw-tshut-polarity = <0>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&uart2 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_ehci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host0_ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host1_ehci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host1_ohci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb_host1_xhci {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy0_host {
|
||||
phy-supply = <&vcc5v0_usb_host>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy1 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy1_host {
|
||||
phy-supply = <&vcc5v0_usb_host>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&usb2phy1_otg {
|
||||
phy-supply = <&vcc5v0_usb_host>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vop {
|
||||
assigned-clocks = <&cru DCLK_VOP0>, <&cru DCLK_VOP1>;
|
||||
assigned-clock-parents = <&pmucru PLL_HPLL>, <&cru PLL_VPLL>;
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vop_mmu {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&vp0 {
|
||||
vp0_out_hdmi: endpoint@ROCKCHIP_VOP2_EP_HDMI0 {
|
||||
reg = <ROCKCHIP_VOP2_EP_HDMI0>;
|
||||
remote-endpoint = <&hdmi_in_vp0>;
|
||||
};
|
||||
};
|
||||
26
package/fish/fibocom-dial/Makefile
Normal file
26
package/fish/fibocom-dial/Makefile
Normal file
@ -0,0 +1,26 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=fibocom-dial
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/fibocom-dial
|
||||
SECTION:=utils
|
||||
CATEGORY:=Utilities
|
||||
TITLE:=Fibocom Dial
|
||||
endef
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Package/fibocom-dial/install
|
||||
$(INSTALL_DIR) $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/fibocom-dial $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/fibo_qmimsg_server $(1)/usr/bin
|
||||
$(INSTALL_BIN) $(PKG_BUILD_DIR)/multi-pdn-manager $(1)/usr/bin
|
||||
endef
|
||||
|
||||
$(eval $(call BuildPackage,fibocom-dial))
|
||||
275
package/fish/fibocom-dial/src/GobiNetCM.c
Normal file
275
package/fish/fibocom-dial/src/GobiNetCM.c
Normal file
@ -0,0 +1,275 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include "QMIThread.h"
|
||||
|
||||
#ifdef CONFIG_GOBINET
|
||||
|
||||
// IOCTL to generate a client ID for this service type
|
||||
#define IOCTL_QMI_GET_SERVICE_FILE 0x8BE0 + 1
|
||||
|
||||
// IOCTL to get the VIDPID of the device
|
||||
#define IOCTL_QMI_GET_DEVICE_VIDPID 0x8BE0 + 2
|
||||
|
||||
// IOCTL to get the MEID of the device
|
||||
#define IOCTL_QMI_GET_DEVICE_MEID 0x8BE0 + 3
|
||||
|
||||
static int GobiNetSendQMI(PQCQMIMSG pRequest)
|
||||
{
|
||||
int ret, fd;
|
||||
|
||||
static int send_count = 0;
|
||||
fd = qmiclientId[pRequest->QMIHdr.QMIType];
|
||||
|
||||
if (fd <= 0) {
|
||||
dbg_time("%s QMIType: %d has no clientID", __func__,
|
||||
pRequest->QMIHdr.QMIType);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
// Always ready to write
|
||||
re_write:
|
||||
if (1 == 1) {
|
||||
ssize_t nwrites =
|
||||
le16_to_cpu(pRequest->QMIHdr.Length) + 1 - sizeof(QCQMI_HDR);
|
||||
ret = write(fd, &pRequest->MUXMsg, nwrites);
|
||||
if (ret == nwrites)
|
||||
{
|
||||
ret = 0;
|
||||
send_count = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
send_count++;
|
||||
dbg_time("%s write=%d, errno: %d (%s) send_count %d", __func__, ret, errno, strerror(errno), send_count);
|
||||
if (send_count < 3)
|
||||
{
|
||||
sleep(1);
|
||||
goto re_write;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int GobiNetGetClientID(const char *qcqmi, UCHAR QMIType)
|
||||
{
|
||||
int ClientId;
|
||||
ClientId = open(qcqmi, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (ClientId == -1) {
|
||||
dbg_time("failed to open %s, errno: %d (%s)", qcqmi, errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ioctl(ClientId, IOCTL_QMI_GET_SERVICE_FILE, QMIType) != 0) {
|
||||
dbg_time("failed to get ClientID for 0x%02x errno: %d (%s)", QMIType,
|
||||
errno, strerror(errno));
|
||||
close(ClientId);
|
||||
ClientId = 0;
|
||||
}
|
||||
|
||||
dbg_time("%s: QMIType = %d clientid %d", __func__, QMIType, ClientId);
|
||||
|
||||
switch (QMIType) {
|
||||
case QMUX_TYPE_WDS:
|
||||
dbg_time("Get clientWDS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_DMS:
|
||||
dbg_time("Get clientDMS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_NAS:
|
||||
dbg_time("Get clientNAS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_QOS:
|
||||
dbg_time("Get clientQOS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_WMS:
|
||||
dbg_time("Get clientWMS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_PDS:
|
||||
dbg_time("Get clientPDS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_UIM:
|
||||
dbg_time("Get clientUIM = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_WDS_ADMIN:
|
||||
dbg_time("Get clientWDA = %d", ClientId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ClientId;
|
||||
}
|
||||
|
||||
static int GobiNetDeInit(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) {
|
||||
if (qmiclientId[i] != 0) {
|
||||
close(qmiclientId[i]);
|
||||
qmiclientId[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
static void *GobiNetThread(void *pData)
|
||||
{
|
||||
PROFILE_T *profile = (PROFILE_T *)pData;
|
||||
const char *qcqmi = (const char *)profile->qmichannel;
|
||||
int wait_for_request_quit = 0;
|
||||
dbg_time("%s %d", __func__, __LINE__);
|
||||
if (profile->ipv4_flag)
|
||||
qmiclientId[QMUX_TYPE_WDS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS);
|
||||
if (profile->ipv6_flag)
|
||||
qmiclientId[QMUX_TYPE_WDS_IPV6] = GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS);
|
||||
qmiclientId[QMUX_TYPE_DMS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_DMS);
|
||||
qmiclientId[QMUX_TYPE_NAS] = GobiNetGetClientID(qcqmi, QMUX_TYPE_NAS);
|
||||
qmiclientId[QMUX_TYPE_UIM] = GobiNetGetClientID(qcqmi, QMUX_TYPE_UIM);
|
||||
// qmiclientId[QMUX_TYPE_WDS_ADMIN] =
|
||||
// GobiNetGetClientID(qcqmi, QMUX_TYPE_WDS_ADMIN);
|
||||
|
||||
//if ((qmiclientId[QMUX_TYPE_WDS] == 0) && (qmiclientId[QMUX_TYPE_WDS_IPV6] == 0)) /*|| (clientWDA == -1)*/ {
|
||||
|
||||
if ((qmiclientId[QMUX_TYPE_DMS] == 0) ||
|
||||
(qmiclientId[QMUX_TYPE_NAS] == 0) ||
|
||||
(qmiclientId[QMUX_TYPE_UIM] == 0) ||
|
||||
(profile->ipv4_flag ? ((qmiclientId[QMUX_TYPE_WDS] == 0) ? 1 : 0):0)||
|
||||
(profile->ipv6_flag ? ((qmiclientId[QMUX_TYPE_WDS_IPV6] == 0) ? 1 : 0):0))
|
||||
{
|
||||
GobiNetDeInit();
|
||||
dbg_time("%s Failed to open %s, errno: %d (%s)", __func__, qcqmi, errno,strerror(errno));
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
|
||||
|
||||
while (1) {
|
||||
struct pollfd pollfds[16] = {{qmidevice_control_fd[1], POLLIN, 0}};
|
||||
int ne, ret, nevents = 1;
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) {
|
||||
if (qmiclientId[i] != 0) {
|
||||
pollfds[nevents].fd = qmiclientId[i];
|
||||
pollfds[nevents].events = POLLIN;
|
||||
pollfds[nevents].revents = 0;
|
||||
nevents++;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
ret = poll(pollfds, nevents, wait_for_request_quit ? 1000 : -1);
|
||||
} while ((ret < 0) && (errno == EINTR));
|
||||
|
||||
if (ret == 0 && wait_for_request_quit) {
|
||||
QmiThreadRecvQMI(
|
||||
NULL); // main thread may pending on QmiThreadSendQMI()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ret <= 0) {
|
||||
dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
for (ne = 0; ne < nevents; ne++) {
|
||||
int fd = pollfds[ne].fd;
|
||||
short revents = pollfds[ne].revents;
|
||||
|
||||
if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
||||
dbg_time("%s poll err/hup/inval", __func__);
|
||||
dbg_time("epoll fd = %d, events = 0x%04x", fd, revents);
|
||||
if (fd == qmidevice_control_fd[1]) {
|
||||
} else {
|
||||
}
|
||||
if (revents & (POLLERR | POLLHUP | POLLNVAL))
|
||||
goto __GobiNetThread_quit;
|
||||
}
|
||||
if ((revents & POLLIN) == 0)
|
||||
continue;
|
||||
|
||||
if (fd == qmidevice_control_fd[1]) {
|
||||
int triger_event;
|
||||
if (read(fd, &triger_event, sizeof(triger_event)) ==
|
||||
sizeof(triger_event)) {
|
||||
// DBG("triger_event = 0x%x", triger_event);
|
||||
switch (triger_event) {
|
||||
case RIL_REQUEST_QUIT:
|
||||
goto __GobiNetThread_quit;
|
||||
break;
|
||||
case SIGTERM:
|
||||
wait_for_request_quit = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
{
|
||||
ssize_t nreads;
|
||||
static UCHAR QMIBuf[4096];
|
||||
PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf;
|
||||
|
||||
nreads = read(fd, &pResponse->MUXMsg,
|
||||
sizeof(QMIBuf) - sizeof(QCQMI_HDR));
|
||||
if (nreads <= 0) {
|
||||
dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads,
|
||||
errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]);
|
||||
i++) {
|
||||
if (qmiclientId[i] == fd) {
|
||||
pResponse->QMIHdr.QMIType = i;
|
||||
}
|
||||
}
|
||||
|
||||
pResponse->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
|
||||
pResponse->QMIHdr.Length =
|
||||
cpu_to_le16(nreads + sizeof(QCQMI_HDR) - 1);
|
||||
pResponse->QMIHdr.CtlFlags = 0x00;
|
||||
pResponse->QMIHdr.ClientId = fd & 0xFF;
|
||||
|
||||
QmiThreadRecvQMI(pResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__GobiNetThread_quit:
|
||||
GobiNetDeInit();
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
|
||||
QmiThreadRecvQMI(NULL); // main thread may pending on QmiThreadSendQMI()
|
||||
dbg_time("%s exit", __func__);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
static int GobiNetSendQMI(PQCQMIMSG pRequest) { return -1; }
|
||||
static void *GobiNetThread(void *pData)
|
||||
{
|
||||
dbg_time("please set CONFIG_GOBINET");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct qmi_device_ops gobi_qmidev_ops = {
|
||||
.deinit = GobiNetDeInit,
|
||||
.send = GobiNetSendQMI,
|
||||
.read = GobiNetThread,
|
||||
};
|
||||
363
package/fish/fibocom-dial/src/MPQCTL.h
Normal file
363
package/fish/fibocom-dial/src/MPQCTL.h
Normal file
@ -0,0 +1,363 @@
|
||||
/*===========================================================================
|
||||
|
||||
M P Q C T L. H
|
||||
DESCRIPTION:
|
||||
|
||||
This module contains QMI QCTL module.
|
||||
|
||||
INITIALIZATION AND SEQUENCING REQUIREMENTS:
|
||||
|
||||
Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved.
|
||||
===========================================================================*/
|
||||
|
||||
#ifndef MPQCTL_H
|
||||
#define MPQCTL_H
|
||||
|
||||
#include "MPQMI.h"
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// ================= QMICTL ==================
|
||||
|
||||
// QMICTL Control Flags
|
||||
#define QMICTL_CTL_FLAG_CMD 0x00
|
||||
#define QMICTL_CTL_FLAG_RSP 0x01
|
||||
#define QMICTL_CTL_FLAG_IND 0x02
|
||||
|
||||
#if 0
|
||||
typedef struct _QMICTL_TRANSACTION_ITEM
|
||||
{
|
||||
LIST_ENTRY List;
|
||||
UCHAR TransactionId; // QMICTL transaction id
|
||||
PVOID Context; // Adapter or IocDev
|
||||
PIRP Irp;
|
||||
} QMICTL_TRANSACTION_ITEM, *PQMICTL_TRANSACTION_ITEM;
|
||||
#endif
|
||||
|
||||
typedef struct _QCQMICTL_MSG_HDR {
|
||||
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType;
|
||||
USHORT Length;
|
||||
} __attribute__((packed)) QCQMICTL_MSG_HDR, *PQCQMICTL_MSG_HDR;
|
||||
|
||||
#define QCQMICTL_MSG_HDR_SIZE sizeof(QCQMICTL_MSG_HDR)
|
||||
|
||||
typedef struct _QCQMICTL_MSG_HDR_RESP {
|
||||
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType;
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // 0x02 - result code
|
||||
USHORT TLVLength; // 4
|
||||
USHORT QMUXResult; // QMI_RESULT_SUCCESS
|
||||
// QMI_RESULT_FAILURE
|
||||
USHORT QMUXError; // QMI_ERR_INVALID_ARG
|
||||
// QMI_ERR_NO_MEMORY
|
||||
// QMI_ERR_INTERNAL
|
||||
// QMI_ERR_FAULT
|
||||
} __attribute__((packed)) QCQMICTL_MSG_HDR_RESP, *PQCQMICTL_MSG_HDR_RESP;
|
||||
|
||||
typedef struct _QCQMICTL_MSG {
|
||||
UCHAR CtlFlags; // 00-cmd, 01-rsp, 10-ind
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType;
|
||||
USHORT Length;
|
||||
UCHAR Payload;
|
||||
} __attribute__((packed)) QCQMICTL_MSG, *PQCQMICTL_MSG;
|
||||
|
||||
// TLV Header
|
||||
typedef struct _QCQMICTL_TLV_HDR {
|
||||
UCHAR TLVType;
|
||||
USHORT TLVLength;
|
||||
} __attribute__((packed)) QCQMICTL_TLV_HDR, *PQCQMICTL_TLV_HDR;
|
||||
|
||||
#define QCQMICTL_TLV_HDR_SIZE sizeof(QCQMICTL_TLV_HDR)
|
||||
|
||||
// QMICTL Type
|
||||
#define QMICTL_SET_INSTANCE_ID_REQ 0x0020
|
||||
#define QMICTL_SET_INSTANCE_ID_RESP 0x0020
|
||||
#define QMICTL_GET_VERSION_REQ 0x0021
|
||||
#define QMICTL_GET_VERSION_RESP 0x0021
|
||||
#define QMICTL_GET_CLIENT_ID_REQ 0x0022
|
||||
#define QMICTL_GET_CLIENT_ID_RESP 0x0022
|
||||
#define QMICTL_RELEASE_CLIENT_ID_REQ 0x0023
|
||||
#define QMICTL_RELEASE_CLIENT_ID_RESP 0x0023
|
||||
#define QMICTL_REVOKE_CLIENT_ID_IND 0x0024
|
||||
#define QMICTL_INVALID_CLIENT_ID_IND 0x0025
|
||||
#define QMICTL_SET_DATA_FORMAT_REQ 0x0026
|
||||
#define QMICTL_SET_DATA_FORMAT_RESP 0x0026
|
||||
#define QMICTL_SYNC_REQ 0x0027
|
||||
#define QMICTL_SYNC_RESP 0x0027
|
||||
#define QMICTL_SYNC_IND 0x0027
|
||||
|
||||
#define QMICTL_FLAG_REQUEST 0x00
|
||||
#define QMICTL_FLAG_RESPONSE 0x01
|
||||
#define QMICTL_FLAG_INDICATION 0x02
|
||||
|
||||
// QMICTL Message Definitions
|
||||
|
||||
typedef struct _QMICTL_SET_INSTANCE_ID_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_REQ
|
||||
USHORT Length; // 4
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR Value; // Host-unique QMI instance for this device driver
|
||||
} __attribute__((packed)) QMICTL_SET_INSTANCE_ID_REQ_MSG,
|
||||
*PQMICTL_SET_INSTANCE_ID_REQ_MSG;
|
||||
|
||||
typedef struct _QMICTL_SET_INSTANCE_ID_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_SET_INSTANCE_ID_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult;
|
||||
USHORT QMIError;
|
||||
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLV2Length; // 0x0002
|
||||
USHORT QMI_ID; // Upper byte is assigned by MSM,
|
||||
// lower assigned by host
|
||||
} __attribute__((packed)) QMICTL_SET_INSTANCE_ID_RESP_MSG,
|
||||
*PQMICTL_SET_INSTANCE_ID_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_GET_VERSION_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_GET_VERSION_REQ
|
||||
USHORT Length; // 0
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // var
|
||||
UCHAR QMUXTypes; // List of one byte QMUX_TYPE values
|
||||
// 0xFF returns a list of versions for all
|
||||
// QMUX_TYPEs implemented on the device
|
||||
} __attribute__((packed)) QMICTL_GET_VERSION_REQ_MSG,
|
||||
*PQMICTL_GET_VERSION_REQ_MSG;
|
||||
|
||||
typedef struct _QMUX_TYPE_VERSION_STRUCT {
|
||||
UCHAR QMUXType;
|
||||
USHORT MajorVersion;
|
||||
USHORT MinorVersion;
|
||||
} __attribute__((packed)) QMUX_TYPE_VERSION_STRUCT, *PQMUX_TYPE_VERSION_STRUCT;
|
||||
|
||||
typedef struct _ADDENDUM_VERSION_PREAMBLE {
|
||||
UCHAR LabelLength;
|
||||
UCHAR Label;
|
||||
} __attribute__((packed)) ADDENDUM_VERSION_PREAMBLE,
|
||||
*PADDENDUM_VERSION_PREAMBLE;
|
||||
|
||||
#define QMICTL_GET_VERSION_RSP_TLV_TYPE_VERSION 0x01
|
||||
#define QMICTL_GET_VERSION_RSP_TLV_TYPE_ADD_VERSION 0x10
|
||||
|
||||
typedef struct _QMICTL_GET_VERSION_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_GET_VERSION_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult;
|
||||
USHORT QMIError;
|
||||
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLV2Length; // var
|
||||
UCHAR NumElements; // Num of QMUX_TYPE_VERSION_STRUCT
|
||||
QMUX_TYPE_VERSION_STRUCT TypeVersion[0];
|
||||
} __attribute__((packed)) QMICTL_GET_VERSION_RESP_MSG,
|
||||
*PQMICTL_GET_VERSION_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_GET_CLIENT_ID_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_REQ
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR QMIType; // QMUX type
|
||||
} __attribute__((packed)) QMICTL_GET_CLIENT_ID_REQ_MSG,
|
||||
*PQMICTL_GET_CLIENT_ID_REQ_MSG;
|
||||
|
||||
typedef struct _QMICTL_GET_CLIENT_ID_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_GET_CLIENT_ID_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult; // result code
|
||||
USHORT QMIError; // error code
|
||||
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLV2Length; // 2
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QMICTL_GET_CLIENT_ID_RESP_MSG,
|
||||
*PQMICTL_GET_CLIENT_ID_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_RELEASE_CLIENT_ID_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_REQ
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 0x0002
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QMICTL_RELEASE_CLIENT_ID_REQ_MSG,
|
||||
*PQMICTL_RELEASE_CLIENT_ID_REQ_MSG;
|
||||
|
||||
typedef struct _QMICTL_RELEASE_CLIENT_ID_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_RELEASE_CLIENT_ID_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult; // result code
|
||||
USHORT QMIError; // error code
|
||||
UCHAR TLV2Type; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLV2Length; // 2
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QMICTL_RELEASE_CLIENT_ID_RESP_MSG,
|
||||
*PQMICTL_RELEASE_CLIENT_ID_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_REVOKE_CLIENT_ID_IND_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 0x0002
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QMICTL_REVOKE_CLIENT_ID_IND_MSG,
|
||||
*PQMICTL_REVOKE_CLIENT_ID_IND_MSG;
|
||||
|
||||
typedef struct _QMICTL_INVALID_CLIENT_ID_IND_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 0x0002
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QMICTL_INVALID_CLIENT_ID_IND_MSG,
|
||||
*PQMICTL_INVALID_CLIENT_ID_IND_MSG;
|
||||
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_REQ
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_REQUIRED_PARAMETER
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR DataFormat; // 0-default; 1-QoS hdr present
|
||||
} __attribute__((packed)) QMICTL_SET_DATA_FORMAT_REQ_MSG,
|
||||
*PQMICTL_SET_DATA_FORMAT_REQ_MSG;
|
||||
|
||||
#ifdef QC_IP_MODE
|
||||
#define SET_DATA_FORMAT_TLV_TYPE_LINK_PROTO 0x10
|
||||
#define SET_DATA_FORMAT_LINK_PROTO_ETH 0x0001
|
||||
#define SET_DATA_FORMAT_LINK_PROTO_IP 0x0002
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT {
|
||||
UCHAR TLVType; // Link-Layer Protocol
|
||||
USHORT TLVLength; // 2
|
||||
USHORT LinkProt; // 0x1: ETH; 0x2: IP
|
||||
} QMICTL_SET_DATA_FORMAT_TLV_LINK_PROT, *PQMICTL_SET_DATA_FORMAT_TLV_LINK_PROT;
|
||||
|
||||
#ifdef QCMP_UL_TLP
|
||||
#define SET_DATA_FORMAT_TLV_TYPE_UL_TLP 0x11
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_UL_TLP {
|
||||
UCHAR TLVType; // 0x11, Uplink TLP Setting
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR UlTlpSetting; // 0x0: Disable; 0x01: Enable
|
||||
} QMICTL_SET_DATA_FORMAT_TLV_UL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_UL_TLP;
|
||||
#endif // QCMP_UL_TLP
|
||||
|
||||
#ifdef QCMP_DL_TLP
|
||||
#define SET_DATA_FORMAT_TLV_TYPE_DL_TLP 0x13
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_DL_TLP {
|
||||
UCHAR TLVType; // 0x11, Uplink TLP Setting
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR DlTlpSetting; // 0x0: Disable; 0x01: Enable
|
||||
} QMICTL_SET_DATA_FORMAT_TLV_DL_TLP, *PQMICTL_SET_DATA_FORMAT_TLV_DL_TLP;
|
||||
#endif // QCMP_DL_TLP
|
||||
|
||||
#endif // QC_IP_MODE
|
||||
|
||||
#ifdef MP_QCQOS_ENABLED
|
||||
#define SET_DATA_FORMAT_TLV_TYPE_QOS_SETTING 0x12
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING {
|
||||
UCHAR TLVType; // 0x12, QoS setting
|
||||
USHORT TLVLength; // 1
|
||||
UCHAR QosSetting; // 0x0: Disable; 0x01: Enable
|
||||
} QMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING,
|
||||
*PQMICTL_SET_DATA_FORMAT_TLV_QOS_SETTING;
|
||||
#endif // MP_QCQOS_ENABLED
|
||||
|
||||
typedef struct _QMICTL_SET_DATA_FORMAT_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_SET_DATA_FORMAT_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult; // result code
|
||||
USHORT QMIError; // error code
|
||||
} __attribute__((packed)) QMICTL_SET_DATA_FORMAT_RESP_MSG,
|
||||
*PQMICTL_SET_DATA_FORMAT_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_SYNC_REQ_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_REQUEST
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_CTL_SYNC_REQ
|
||||
USHORT Length; // 0
|
||||
} __attribute__((packed)) QMICTL_SYNC_REQ_MSG, *PQMICTL_SYNC_REQ_MSG;
|
||||
|
||||
typedef struct _QMICTL_SYNC_RESP_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_RESPONSE
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_CTL_SYNC_RESP
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // QCTLV_TYPE_RESULT_CODE
|
||||
USHORT TLVLength; // 0x0004
|
||||
USHORT QMIResult;
|
||||
USHORT QMIError;
|
||||
} __attribute__((packed)) QMICTL_SYNC_RESP_MSG, *PQMICTL_SYNC_RESP_MSG;
|
||||
|
||||
typedef struct _QMICTL_SYNC_IND_MSG {
|
||||
UCHAR CtlFlags; // QMICTL_FLAG_INDICATION
|
||||
UCHAR TransactionId;
|
||||
USHORT QMICTLType; // QMICTL_REVOKE_CLIENT_ID_IND
|
||||
USHORT Length;
|
||||
} __attribute__((packed)) QMICTL_SYNC_IND_MSG, *PQMICTL_SYNC_IND_MSG;
|
||||
|
||||
typedef struct _QMICTL_MSG {
|
||||
union {
|
||||
// Message Header
|
||||
QCQMICTL_MSG_HDR QMICTLMsgHdr;
|
||||
QCQMICTL_MSG_HDR_RESP QMICTLMsgHdrRsp;
|
||||
|
||||
// QMICTL Message
|
||||
QMICTL_SET_INSTANCE_ID_REQ_MSG SetInstanceIdReq;
|
||||
QMICTL_SET_INSTANCE_ID_RESP_MSG SetInstanceIdRsp;
|
||||
QMICTL_GET_VERSION_REQ_MSG GetVersionReq;
|
||||
QMICTL_GET_VERSION_RESP_MSG GetVersionRsp;
|
||||
QMICTL_GET_CLIENT_ID_REQ_MSG GetClientIdReq;
|
||||
QMICTL_GET_CLIENT_ID_RESP_MSG GetClientIdRsp;
|
||||
QMICTL_RELEASE_CLIENT_ID_REQ_MSG ReleaseClientIdReq;
|
||||
QMICTL_RELEASE_CLIENT_ID_RESP_MSG ReleaseClientIdRsp;
|
||||
QMICTL_REVOKE_CLIENT_ID_IND_MSG RevokeClientIdInd;
|
||||
QMICTL_INVALID_CLIENT_ID_IND_MSG InvalidClientIdInd;
|
||||
QMICTL_SET_DATA_FORMAT_REQ_MSG SetDataFormatReq;
|
||||
QMICTL_SET_DATA_FORMAT_RESP_MSG SetDataFormatRsp;
|
||||
QMICTL_SYNC_REQ_MSG SyncReq;
|
||||
QMICTL_SYNC_RESP_MSG SyncRsp;
|
||||
QMICTL_SYNC_IND_MSG SyncInd;
|
||||
};
|
||||
} __attribute__((packed)) QMICTL_MSG, *PQMICTL_MSG;
|
||||
|
||||
#endif // MPQCTL_H
|
||||
287
package/fish/fibocom-dial/src/MPQMI.h
Normal file
287
package/fish/fibocom-dial/src/MPQMI.h
Normal file
@ -0,0 +1,287 @@
|
||||
/*===========================================================================
|
||||
|
||||
M P Q M I. H
|
||||
DESCRIPTION:
|
||||
|
||||
This module contains forward references to the QMI module.
|
||||
|
||||
INITIALIZATION AND SEQUENCING REQUIREMENTS:
|
||||
|
||||
Copyright (C) 2011 by Qualcomm Technologies, Incorporated. All Rights Reserved.
|
||||
===========================================================================*/
|
||||
/*===========================================================================
|
||||
|
||||
EDIT HISTORY FOR FILE
|
||||
$Header: //depot/QMI/win/qcdrivers/ndis/MPQMI.h#3 $
|
||||
|
||||
when who what, where, why
|
||||
-------- --- ----------------------------------------------------------
|
||||
11/20/04 hg Initial version.
|
||||
===========================================================================*/
|
||||
|
||||
#ifndef USBQMI_H
|
||||
#define USBQMI_H
|
||||
|
||||
typedef char CHAR;
|
||||
typedef unsigned char UCHAR;
|
||||
typedef unsigned short USHORT;
|
||||
typedef int INT;
|
||||
typedef unsigned int UINT;
|
||||
typedef long LONG;
|
||||
typedef unsigned int ULONG;
|
||||
typedef unsigned long long ULONG64;
|
||||
typedef char *PCHAR;
|
||||
typedef unsigned char *PUCHAR;
|
||||
typedef int *PINT;
|
||||
typedef int BOOL;
|
||||
|
||||
#define TRUE (1 == 1)
|
||||
#define FALSE (1 != 1)
|
||||
|
||||
#define QMICTL_SUPPORTED_MAJOR_VERSION 1
|
||||
#define QMICTL_SUPPORTED_MINOR_VERSION 0
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
// ========= USB Control Message ==========
|
||||
|
||||
#define USB_CTL_MSG_TYPE_QMI 0x01
|
||||
|
||||
// USB Control Message
|
||||
typedef struct _QCUSB_CTL_MSG_HDR {
|
||||
UCHAR IFType;
|
||||
} __attribute__((packed)) QCUSB_CTL_MSG_HDR, *PQCUSB_CTL_MSG_HDR;
|
||||
|
||||
#define QCUSB_CTL_MSG_HDR_SIZE sizeof(QCUSB_CTL_MSG_HDR)
|
||||
|
||||
typedef struct _QCUSB_CTL_MSG {
|
||||
UCHAR IFType;
|
||||
UCHAR Message;
|
||||
} __attribute__((packed)) QCUSB_CTL_MSG, *PQCUSB_CTL_MSG;
|
||||
|
||||
#define QCTLV_TYPE_REQUIRED_PARAMETER 0x01
|
||||
#define QCTLV_TYPE_RESULT_CODE 0x02
|
||||
|
||||
// ================= QMI ==================
|
||||
|
||||
// Define QMI Type
|
||||
typedef enum _QMI_SERVICE_TYPE {
|
||||
QMUX_TYPE_CTL = 0x00,
|
||||
QMUX_TYPE_WDS = 0x01,
|
||||
QMUX_TYPE_DMS = 0x02,
|
||||
QMUX_TYPE_NAS = 0x03,
|
||||
QMUX_TYPE_QOS = 0x04,
|
||||
QMUX_TYPE_WMS = 0x05,
|
||||
QMUX_TYPE_PDS = 0x06,
|
||||
QMUX_TYPE_UIM = 0x0B,
|
||||
QMUX_TYPE_WDS_IPV6 = 0x11,
|
||||
QMUX_TYPE_WDS_ADMIN = 0x1A,
|
||||
QMUX_TYPE_MAX = 0xFF,
|
||||
QMUX_TYPE_ALL = 0xFF
|
||||
} QMI_SERVICE_TYPE;
|
||||
|
||||
typedef enum _QMI_RESULT_CODE_TYPE {
|
||||
QMI_RESULT_SUCCESS = 0x0000,
|
||||
QMI_RESULT_FAILURE = 0x0001
|
||||
} QMI_RESULT_CODE_TYPE;
|
||||
|
||||
typedef enum _QMI_ERROR_CODE_TYPE {
|
||||
QMI_ERR_NONE = 0x0000,
|
||||
QMI_ERR_MALFORMED_MSG = 0x0001,
|
||||
QMI_ERR_NO_MEMORY = 0x0002,
|
||||
QMI_ERR_INTERNAL = 0x0003,
|
||||
QMI_ERR_ABORTED = 0x0004,
|
||||
QMI_ERR_CLIENT_IDS_EXHAUSTED = 0x0005,
|
||||
QMI_ERR_UNABORTABLE_TRANSACTION = 0x0006,
|
||||
QMI_ERR_INVALID_CLIENT_ID = 0x0007,
|
||||
QMI_ERR_NO_THRESHOLDS = 0x0008,
|
||||
QMI_ERR_INVALID_HANDLE = 0x0009,
|
||||
QMI_ERR_INVALID_PROFILE = 0x000A,
|
||||
QMI_ERR_INVALID_PINID = 0x000B,
|
||||
QMI_ERR_INCORRECT_PIN = 0x000C,
|
||||
QMI_ERR_NO_NETWORK_FOUND = 0x000D,
|
||||
QMI_ERR_CALL_FAILED = 0x000E,
|
||||
QMI_ERR_OUT_OF_CALL = 0x000F,
|
||||
QMI_ERR_NOT_PROVISIONED = 0x0010,
|
||||
QMI_ERR_MISSING_ARG = 0x0011,
|
||||
QMI_ERR_ARG_TOO_LONG = 0x0013,
|
||||
QMI_ERR_INVALID_TX_ID = 0x0016,
|
||||
QMI_ERR_DEVICE_IN_USE = 0x0017,
|
||||
QMI_ERR_OP_NETWORK_UNSUPPORTED = 0x0018,
|
||||
QMI_ERR_OP_DEVICE_UNSUPPORTED = 0x0019,
|
||||
QMI_ERR_NO_EFFECT = 0x001A,
|
||||
QMI_ERR_NO_FREE_PROFILE = 0x001B,
|
||||
QMI_ERR_INVALID_PDP_TYPE = 0x001C,
|
||||
QMI_ERR_INVALID_TECH_PREF = 0x001D,
|
||||
QMI_ERR_INVALID_PROFILE_TYPE = 0x001E,
|
||||
QMI_ERR_INVALID_SERVICE_TYPE = 0x001F,
|
||||
QMI_ERR_INVALID_REGISTER_ACTION = 0x0020,
|
||||
QMI_ERR_INVALID_PS_ATTACH_ACTION = 0x0021,
|
||||
QMI_ERR_AUTHENTICATION_FAILED = 0x0022,
|
||||
QMI_ERR_PIN_BLOCKED = 0x0023,
|
||||
QMI_ERR_PIN_PERM_BLOCKED = 0x0024,
|
||||
QMI_ERR_SIM_NOT_INITIALIZED = 0x0025,
|
||||
QMI_ERR_MAX_QOS_REQUESTS_IN_USE = 0x0026,
|
||||
QMI_ERR_INCORRECT_FLOW_FILTER = 0x0027,
|
||||
QMI_ERR_NETWORK_QOS_UNAWARE = 0x0028,
|
||||
QMI_ERR_INVALID_QOS_ID = 0x0029,
|
||||
QMI_ERR_INVALID_ID = 0x0029,
|
||||
QMI_ERR_REQUESTED_NUM_UNSUPPORTED = 0x002A,
|
||||
QMI_ERR_INTERFACE_NOT_FOUND = 0x002B,
|
||||
QMI_ERR_FLOW_SUSPENDED = 0x002C,
|
||||
QMI_ERR_INVALID_DATA_FORMAT = 0x002D,
|
||||
QMI_ERR_GENERAL = 0x002E,
|
||||
QMI_ERR_UNKNOWN = 0x002F,
|
||||
QMI_ERR_INVALID_ARG = 0x0030,
|
||||
QMI_ERR_INVALID_INDEX = 0x0031,
|
||||
QMI_ERR_NO_ENTRY = 0x0032,
|
||||
QMI_ERR_DEVICE_STORAGE_FULL = 0x0033,
|
||||
QMI_ERR_DEVICE_NOT_READY = 0x0034,
|
||||
QMI_ERR_NETWORK_NOT_READY = 0x0035,
|
||||
QMI_ERR_CAUSE_CODE = 0x0036,
|
||||
QMI_ERR_MESSAGE_NOT_SENT = 0x0037,
|
||||
QMI_ERR_MESSAGE_DELIVERY_FAILURE = 0x0038,
|
||||
QMI_ERR_INVALID_MESSAGE_ID = 0x0039,
|
||||
QMI_ERR_ENCODING = 0x003A,
|
||||
QMI_ERR_AUTHENTICATION_LOCK = 0x003B,
|
||||
QMI_ERR_INVALID_TRANSITION = 0x003C,
|
||||
QMI_ERR_NOT_A_MCAST_IFACE = 0x003D,
|
||||
QMI_ERR_MAX_MCAST_REQUESTS_IN_USE = 0x003E,
|
||||
QMI_ERR_INVALID_MCAST_HANDLE = 0x003F,
|
||||
QMI_ERR_INVALID_IP_FAMILY_PREF = 0x0040,
|
||||
QMI_ERR_SESSION_INACTIVE = 0x0041,
|
||||
QMI_ERR_SESSION_INVALID = 0x0042,
|
||||
QMI_ERR_SESSION_OWNERSHIP = 0x0043,
|
||||
QMI_ERR_INSUFFICIENT_RESOURCES = 0x0044,
|
||||
QMI_ERR_DISABLED = 0x0045,
|
||||
QMI_ERR_INVALID_OPERATION = 0x0046,
|
||||
QMI_ERR_INVALID_QMI_CMD = 0x0047,
|
||||
QMI_ERR_TPDU_TYPE = 0x0048,
|
||||
QMI_ERR_SMSC_ADDR = 0x0049,
|
||||
QMI_ERR_INFO_UNAVAILABLE = 0x004A,
|
||||
QMI_ERR_SEGMENT_TOO_LONG = 0x004B,
|
||||
QMI_ERR_SEGMENT_ORDER = 0x004C,
|
||||
QMI_ERR_BUNDLING_NOT_SUPPORTED = 0x004D,
|
||||
QMI_ERR_OP_PARTIAL_FAILURE = 0x004E,
|
||||
QMI_ERR_POLICY_MISMATCH = 0x004F,
|
||||
QMI_ERR_SIM_FILE_NOT_FOUND = 0x0050,
|
||||
QMI_ERR_EXTENDED_INTERNAL = 0x0051,
|
||||
QMI_ERR_ACCESS_DENIED = 0x0052,
|
||||
QMI_ERR_HARDWARE_RESTRICTED = 0x0053,
|
||||
QMI_ERR_ACK_NOT_SENT = 0x0054,
|
||||
QMI_ERR_INJECT_TIMEOUT = 0x0055,
|
||||
QMI_ERR_INCOMPATIBLE_STATE = 0x005A,
|
||||
QMI_ERR_FDN_RESTRICT = 0x005B,
|
||||
QMI_ERR_SUPS_FAILURE_CAUSE = 0x005C,
|
||||
QMI_ERR_NO_RADIO = 0x005D,
|
||||
QMI_ERR_NOT_SUPPORTED = 0x005E,
|
||||
QMI_ERR_NO_SUBSCRIPTION = 0x005F,
|
||||
QMI_ERR_CARD_CALL_CONTROL_FAILED = 0x0060,
|
||||
QMI_ERR_NETWORK_ABORTED = 0x0061,
|
||||
QMI_ERR_MSG_BLOCKED = 0x0062,
|
||||
QMI_ERR_INVALID_SESSION_TYPE = 0x0064,
|
||||
QMI_ERR_INVALID_PB_TYPE = 0x0065,
|
||||
QMI_ERR_NO_SIM = 0x0066,
|
||||
QMI_ERR_PB_NOT_READY = 0x0067,
|
||||
QMI_ERR_PIN_RESTRICTION = 0x0068,
|
||||
QMI_ERR_PIN2_RESTRICTION = 0x0069,
|
||||
QMI_ERR_PUK_RESTRICTION = 0x006A,
|
||||
QMI_ERR_PUK2_RESTRICTION = 0x006B,
|
||||
QMI_ERR_PB_ACCESS_RESTRICTED = 0x006C,
|
||||
QMI_ERR_PB_DELETE_IN_PROG = 0x006D,
|
||||
QMI_ERR_PB_TEXT_TOO_LONG = 0x006E,
|
||||
QMI_ERR_PB_NUMBER_TOO_LONG = 0x006F,
|
||||
QMI_ERR_PB_HIDDEN_KEY_RESTRICTION = 0x0070
|
||||
} QMI_ERROR_CODE_TYPE;
|
||||
|
||||
#define QCQMI_CTL_FLAG_SERVICE 0x80
|
||||
#define QCQMI_CTL_FLAG_CTL_POINT 0x00
|
||||
|
||||
typedef struct _QCQMI_HDR {
|
||||
UCHAR IFType;
|
||||
USHORT Length;
|
||||
UCHAR CtlFlags; // reserved
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
} __attribute__((packed)) QCQMI_HDR, *PQCQMI_HDR;
|
||||
|
||||
#define QCQMI_HDR_SIZE (sizeof(QCQMI_HDR) - 1)
|
||||
|
||||
typedef struct _QCQMI {
|
||||
UCHAR IFType;
|
||||
USHORT Length;
|
||||
UCHAR CtlFlags; // reserved
|
||||
UCHAR QMIType;
|
||||
UCHAR ClientId;
|
||||
UCHAR SDU;
|
||||
} __attribute__((packed)) QCQMI, *PQCQMI;
|
||||
|
||||
typedef struct _QMI_SERVICE_VERSION {
|
||||
USHORT Major;
|
||||
USHORT Minor;
|
||||
USHORT AddendumMajor;
|
||||
USHORT AddendumMinor;
|
||||
} __attribute__((packed)) QMI_SERVICE_VERSION, *PQMI_SERVICE_VERSION;
|
||||
|
||||
// ================= QMUX ==================
|
||||
|
||||
#define QMUX_MSG_OVERHEAD_BYTES 4 // Type(USHORT) Length(USHORT) -- header
|
||||
|
||||
#define QMUX_BROADCAST_CID 0xFF
|
||||
|
||||
typedef struct _QCQMUX_HDR {
|
||||
UCHAR CtlFlags; // 0: single QMUX Msg; 1:
|
||||
USHORT TransactionId;
|
||||
} __attribute__((packed)) QCQMUX_HDR, *PQCQMUX_HDR;
|
||||
|
||||
typedef struct _QCQMUX {
|
||||
UCHAR CtlFlags; // 0: single QMUX Msg; 1:
|
||||
USHORT TransactionId;
|
||||
UCHAR Message; // Type(2), Length(2), Value
|
||||
} __attribute__((packed)) QCQMUX, *PQCQMUX;
|
||||
|
||||
#define QCQMUX_HDR_SIZE sizeof(QCQMUX_HDR)
|
||||
|
||||
typedef struct _QCQMUX_MSG_HDR {
|
||||
USHORT Type;
|
||||
USHORT Length;
|
||||
} __attribute__((packed)) QCQMUX_MSG_HDR, *PQCQMUX_MSG_HDR;
|
||||
|
||||
#define QCQMUX_MSG_HDR_SIZE sizeof(QCQMUX_MSG_HDR)
|
||||
|
||||
typedef struct _QCQMUX_MSG_HDR_RESP {
|
||||
USHORT Type;
|
||||
USHORT Length;
|
||||
UCHAR TLVType; // 0x02 - result code
|
||||
USHORT TLVLength; // 4
|
||||
USHORT QMUXResult; // QMI_RESULT_SUCCESS
|
||||
// QMI_RESULT_FAILURE
|
||||
USHORT QMUXError; // QMI_ERR_INVALID_ARG
|
||||
// QMI_ERR_NO_MEMORY
|
||||
// QMI_ERR_INTERNAL
|
||||
// QMI_ERR_FAULT
|
||||
} __attribute__((packed)) QCQMUX_MSG_HDR_RESP, *PQCQMUX_MSG_HDR_RESP;
|
||||
|
||||
typedef struct _QCQMUX_TLV {
|
||||
UCHAR Type;
|
||||
USHORT Length;
|
||||
UCHAR Value;
|
||||
} __attribute__((packed)) QCQMUX_TLV, *PQCQMUX_TLV;
|
||||
|
||||
typedef struct _QMI_TLV_HDR {
|
||||
UCHAR TLVType;
|
||||
USHORT TLVLength;
|
||||
} __attribute__((packed)) QMI_TLV_HDR, *PQMI_TLV_HDR;
|
||||
|
||||
// QMUX Message Definitions -- QMI SDU
|
||||
#define QMUX_CTL_FLAG_SINGLE_MSG 0x00
|
||||
#define QMUX_CTL_FLAG_COMPOUND_MSG 0x01
|
||||
#define QMUX_CTL_FLAG_TYPE_CMD 0x00
|
||||
#define QMUX_CTL_FLAG_TYPE_RSP 0x02
|
||||
#define QMUX_CTL_FLAG_TYPE_IND 0x04
|
||||
#define QMUX_CTL_FLAG_MASK_COMPOUND 0x01
|
||||
#define QMUX_CTL_FLAG_MASK_TYPE 0x06 // 00-cmd, 01-rsp, 10-ind
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // USBQMI_H
|
||||
437
package/fish/fibocom-dial/src/MPQMUX.c
Normal file
437
package/fish/fibocom-dial/src/MPQMUX.c
Normal file
@ -0,0 +1,437 @@
|
||||
#include "QMIThread.h"
|
||||
static char line[1024];
|
||||
static pthread_mutex_t dumpQMIMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#undef dbg
|
||||
#define dbg(format, arg...) \
|
||||
do { \
|
||||
if (strlen(line) < sizeof(line)) \
|
||||
snprintf(&line[strlen(line)], sizeof(line) - strlen(line), format, \
|
||||
##arg); \
|
||||
} while (0)
|
||||
|
||||
PQMI_TLV_HDR GetTLV(PQCQMUX_MSG_HDR pQMUXMsgHdr, int TLVType);
|
||||
|
||||
typedef struct {
|
||||
UINT type;
|
||||
const char *name;
|
||||
} QMI_NAME_T;
|
||||
|
||||
#define qmi_name_item(type) \
|
||||
{ \
|
||||
type, #type \
|
||||
}
|
||||
|
||||
static const QMI_NAME_T qmux_ctl_QMICTLType[] = {
|
||||
// QMICTL Type
|
||||
qmi_name_item(QMICTL_SET_INSTANCE_ID_REQ), // 0x0020
|
||||
qmi_name_item(QMICTL_SET_INSTANCE_ID_RESP), // 0x0020
|
||||
qmi_name_item(QMICTL_GET_VERSION_REQ), // 0x0021
|
||||
qmi_name_item(QMICTL_GET_VERSION_RESP), // 0x0021
|
||||
qmi_name_item(QMICTL_GET_CLIENT_ID_REQ), // 0x0022
|
||||
qmi_name_item(QMICTL_GET_CLIENT_ID_RESP), // 0x0022
|
||||
qmi_name_item(QMICTL_RELEASE_CLIENT_ID_REQ), // 0x0023
|
||||
qmi_name_item(QMICTL_RELEASE_CLIENT_ID_RESP), // 0x0023
|
||||
qmi_name_item(QMICTL_REVOKE_CLIENT_ID_IND), // 0x0024
|
||||
qmi_name_item(QMICTL_INVALID_CLIENT_ID_IND), // 0x0025
|
||||
qmi_name_item(QMICTL_SET_DATA_FORMAT_REQ), // 0x0026
|
||||
qmi_name_item(QMICTL_SET_DATA_FORMAT_RESP), // 0x0026
|
||||
qmi_name_item(QMICTL_SYNC_REQ), // 0x0027
|
||||
qmi_name_item(QMICTL_SYNC_RESP), // 0x0027
|
||||
qmi_name_item(QMICTL_SYNC_IND), // 0x0027
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_CtlFlags[] = {
|
||||
qmi_name_item(QMUX_CTL_FLAG_TYPE_CMD),
|
||||
qmi_name_item(QMUX_CTL_FLAG_TYPE_RSP),
|
||||
qmi_name_item(QMUX_CTL_FLAG_TYPE_IND),
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_wds_Type[] = {
|
||||
qmi_name_item(QMIWDS_SET_EVENT_REPORT_REQ), // 0x0001
|
||||
qmi_name_item(QMIWDS_SET_EVENT_REPORT_RESP), // 0x0001
|
||||
qmi_name_item(QMIWDS_EVENT_REPORT_IND), // 0x0001
|
||||
qmi_name_item(QMIWDS_START_NETWORK_INTERFACE_REQ), // 0x0020
|
||||
qmi_name_item(QMIWDS_START_NETWORK_INTERFACE_RESP), // 0x0020
|
||||
qmi_name_item(QMIWDS_STOP_NETWORK_INTERFACE_REQ), // 0x0021
|
||||
qmi_name_item(QMIWDS_STOP_NETWORK_INTERFACE_RESP), // 0x0021
|
||||
qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_REQ), // 0x0022
|
||||
qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_RESP), // 0x0022
|
||||
qmi_name_item(QMIWDS_GET_PKT_SRVC_STATUS_IND), // 0x0022
|
||||
qmi_name_item(QMIWDS_GET_CURRENT_CHANNEL_RATE_REQ), // 0x0023
|
||||
qmi_name_item(QMIWDS_GET_CURRENT_CHANNEL_RATE_RESP), // 0x0023
|
||||
qmi_name_item(QMIWDS_GET_PKT_STATISTICS_REQ), // 0x0024
|
||||
qmi_name_item(QMIWDS_GET_PKT_STATISTICS_RESP), // 0x0024
|
||||
//begin modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610
|
||||
qmi_name_item(QMIWDS_CREATE_PROFILE_SETTINGS_REQ), // 0x0027
|
||||
qmi_name_item(QMIWDS_CREATE_PROFILE_SETTINGS_RESP), // 0x0027
|
||||
//end modified by zhangkaibo add create profile qmi. mantis 0049137,0048741 20200610
|
||||
qmi_name_item(QMIWDS_MODIFY_PROFILE_SETTINGS_REQ), // 0x0028
|
||||
qmi_name_item(QMIWDS_MODIFY_PROFILE_SETTINGS_RESP), // 0x0028
|
||||
qmi_name_item(QMIWDS_GET_PROFILE_SETTINGS_REQ), // 0x002B
|
||||
qmi_name_item(QMIWDS_GET_PROFILE_SETTINGS_RESP), // 0x002BD
|
||||
qmi_name_item(QMIWDS_GET_DEFAULT_SETTINGS_REQ), // 0x002C
|
||||
qmi_name_item(QMIWDS_GET_DEFAULT_SETTINGS_RESP), // 0x002C
|
||||
qmi_name_item(QMIWDS_GET_RUNTIME_SETTINGS_REQ), // 0x002D
|
||||
qmi_name_item(QMIWDS_GET_RUNTIME_SETTINGS_RESP), // 0x002D
|
||||
qmi_name_item(QMIWDS_GET_MIP_MODE_REQ), // 0x002F
|
||||
qmi_name_item(QMIWDS_GET_MIP_MODE_RESP), // 0x002F
|
||||
qmi_name_item(QMIWDS_GET_DATA_BEARER_REQ), // 0x0037
|
||||
qmi_name_item(QMIWDS_GET_DATA_BEARER_RESP), // 0x0037
|
||||
qmi_name_item(QMIWDS_DUN_CALL_INFO_REQ), // 0x0038
|
||||
qmi_name_item(QMIWDS_DUN_CALL_INFO_RESP), // 0x0038
|
||||
qmi_name_item(QMIWDS_DUN_CALL_INFO_IND), // 0x0038
|
||||
qmi_name_item(QMIWDS_SET_CLIENT_IP_FAMILY_PREF_REQ), // 0x004D
|
||||
qmi_name_item(QMIWDS_SET_CLIENT_IP_FAMILY_PREF_RESP), // 0x004D
|
||||
qmi_name_item(QMIWDS_SET_AUTO_CONNECT_REQ), // 0x0051
|
||||
qmi_name_item(QMIWDS_SET_AUTO_CONNECT_RESP), // 0x0051
|
||||
qmi_name_item(QMIWDS_BIND_MUX_DATA_PORT_REQ), // 0x00A2
|
||||
qmi_name_item(QMIWDS_BIND_MUX_DATA_PORT_RESP), // 0x00A2
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_dms_Type[] = {
|
||||
// ======================= DMS ==============================
|
||||
qmi_name_item(QMIDMS_SET_EVENT_REPORT_REQ), // 0x0001
|
||||
qmi_name_item(QMIDMS_SET_EVENT_REPORT_RESP), // 0x0001
|
||||
qmi_name_item(QMIDMS_EVENT_REPORT_IND), // 0x0001
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_CAP_REQ), // 0x0020
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_CAP_RESP), // 0x0020
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_MFR_REQ), // 0x0021
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_MFR_RESP), // 0x0021
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_MODEL_ID_REQ), // 0x0022
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_MODEL_ID_RESP), // 0x0022
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_REV_ID_REQ), // 0x0023
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_REV_ID_RESP), // 0x0023
|
||||
qmi_name_item(QMIDMS_GET_MSISDN_REQ), // 0x0024
|
||||
qmi_name_item(QMIDMS_GET_MSISDN_RESP), // 0x0024
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_SERIAL_NUMBERS_REQ), // 0x0025
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_SERIAL_NUMBERS_RESP), // 0x0025
|
||||
qmi_name_item(QMIDMS_UIM_SET_PIN_PROTECTION_REQ), // 0x0027
|
||||
qmi_name_item(QMIDMS_UIM_SET_PIN_PROTECTION_RESP), // 0x0027
|
||||
qmi_name_item(QMIDMS_UIM_VERIFY_PIN_REQ), // 0x0028
|
||||
qmi_name_item(QMIDMS_UIM_VERIFY_PIN_RESP), // 0x0028
|
||||
qmi_name_item(QMIDMS_UIM_UNBLOCK_PIN_REQ), // 0x0029
|
||||
qmi_name_item(QMIDMS_UIM_UNBLOCK_PIN_RESP), // 0x0029
|
||||
qmi_name_item(QMIDMS_UIM_CHANGE_PIN_REQ), // 0x002A
|
||||
qmi_name_item(QMIDMS_UIM_CHANGE_PIN_RESP), // 0x002A
|
||||
qmi_name_item(QMIDMS_UIM_GET_PIN_STATUS_REQ), // 0x002B
|
||||
qmi_name_item(QMIDMS_UIM_GET_PIN_STATUS_RESP), // 0x002B
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_HARDWARE_REV_REQ), // 0x002C
|
||||
qmi_name_item(QMIDMS_GET_DEVICE_HARDWARE_REV_RESP), // 0x002C
|
||||
qmi_name_item(QMIDMS_GET_OPERATING_MODE_REQ), // 0x002D
|
||||
qmi_name_item(QMIDMS_GET_OPERATING_MODE_RESP), // 0x002D
|
||||
qmi_name_item(QMIDMS_SET_OPERATING_MODE_REQ), // 0x002E
|
||||
qmi_name_item(QMIDMS_SET_OPERATING_MODE_RESP), // 0x002E
|
||||
qmi_name_item(QMIDMS_GET_ACTIVATED_STATUS_REQ), // 0x0031
|
||||
qmi_name_item(QMIDMS_GET_ACTIVATED_STATUS_RESP), // 0x0031
|
||||
qmi_name_item(QMIDMS_ACTIVATE_AUTOMATIC_REQ), // 0x0032
|
||||
qmi_name_item(QMIDMS_ACTIVATE_AUTOMATIC_RESP), // 0x0032
|
||||
qmi_name_item(QMIDMS_ACTIVATE_MANUAL_REQ), // 0x0033
|
||||
qmi_name_item(QMIDMS_ACTIVATE_MANUAL_RESP), // 0x0033
|
||||
qmi_name_item(QMIDMS_UIM_GET_ICCID_REQ), // 0x003C
|
||||
qmi_name_item(QMIDMS_UIM_GET_ICCID_RESP), // 0x003C
|
||||
qmi_name_item(QMIDMS_UIM_GET_CK_STATUS_REQ), // 0x0040
|
||||
qmi_name_item(QMIDMS_UIM_GET_CK_STATUS_RESP), // 0x0040
|
||||
qmi_name_item(QMIDMS_UIM_SET_CK_PROTECTION_REQ), // 0x0041
|
||||
qmi_name_item(QMIDMS_UIM_SET_CK_PROTECTION_RESP), // 0x0041
|
||||
qmi_name_item(QMIDMS_UIM_UNBLOCK_CK_REQ), // 0x0042
|
||||
qmi_name_item(QMIDMS_UIM_UNBLOCK_CK_RESP), // 0x0042
|
||||
qmi_name_item(QMIDMS_UIM_GET_IMSI_REQ), // 0x0043
|
||||
qmi_name_item(QMIDMS_UIM_GET_IMSI_RESP), // 0x0043
|
||||
qmi_name_item(QMIDMS_UIM_GET_STATE_REQ), // 0x0044
|
||||
qmi_name_item(QMIDMS_UIM_GET_STATE_RESP), // 0x0044
|
||||
qmi_name_item(QMIDMS_GET_BAND_CAP_REQ), // 0x0045
|
||||
qmi_name_item(QMIDMS_GET_BAND_CAP_RESP), // 0x0045
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_nas_Type[] = {
|
||||
// ======================= NAS ==============================
|
||||
qmi_name_item(QMINAS_SET_EVENT_REPORT_REQ), // 0x0002
|
||||
qmi_name_item(QMINAS_SET_EVENT_REPORT_RESP), // 0x0002
|
||||
qmi_name_item(QMINAS_EVENT_REPORT_IND), // 0x0002
|
||||
qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_REQ), // 0x0020
|
||||
qmi_name_item(QMINAS_GET_SIGNAL_STRENGTH_RESP), // 0x0020
|
||||
qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_REQ), // 0x0021
|
||||
qmi_name_item(QMINAS_PERFORM_NETWORK_SCAN_RESP), // 0x0021
|
||||
qmi_name_item(QMINAS_INITIATE_NW_REGISTER_REQ), // 0x0022
|
||||
qmi_name_item(QMINAS_INITIATE_NW_REGISTER_RESP), // 0x0022
|
||||
qmi_name_item(QMINAS_INITIATE_ATTACH_REQ), // 0x0023
|
||||
qmi_name_item(QMINAS_INITIATE_ATTACH_RESP), // 0x0023
|
||||
qmi_name_item(QMINAS_GET_SERVING_SYSTEM_REQ), // 0x0024
|
||||
qmi_name_item(QMINAS_GET_SERVING_SYSTEM_RESP), // 0x0024
|
||||
qmi_name_item(QMINAS_SERVING_SYSTEM_IND), // 0x0024
|
||||
qmi_name_item(QMINAS_GET_HOME_NETWORK_REQ), // 0x0025
|
||||
qmi_name_item(QMINAS_GET_HOME_NETWORK_RESP), // 0x0025
|
||||
qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_REQ), // 0x0026
|
||||
qmi_name_item(QMINAS_GET_PREFERRED_NETWORK_RESP), // 0x0026
|
||||
qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_REQ), // 0x0027
|
||||
qmi_name_item(QMINAS_SET_PREFERRED_NETWORK_RESP), // 0x0027
|
||||
qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_REQ), // 0x0028
|
||||
qmi_name_item(QMINAS_GET_FORBIDDEN_NETWORK_RESP), // 0x0028
|
||||
qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_REQ), // 0x0029
|
||||
qmi_name_item(QMINAS_SET_FORBIDDEN_NETWORK_RESP), // 0x0029
|
||||
qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_REQ), // 0x002A
|
||||
qmi_name_item(QMINAS_SET_TECHNOLOGY_PREF_RESP), // 0x002A
|
||||
qmi_name_item(QMINAS_GET_RF_BAND_INFO_REQ), // 0x0031
|
||||
qmi_name_item(QMINAS_GET_RF_BAND_INFO_RESP), // 0x0031
|
||||
qmi_name_item(QMINAS_GET_PLMN_NAME_REQ), // 0x0044
|
||||
qmi_name_item(QMINAS_GET_PLMN_NAME_RESP), // 0x0044
|
||||
qmi_name_item(FIBO_PACKET_TRANSFER_START_IND), // 0X100
|
||||
qmi_name_item(FIBO_PACKET_TRANSFER_END_IND), // 0X101
|
||||
qmi_name_item(QMINAS_GET_SYS_INFO_REQ), // 0x004D
|
||||
qmi_name_item(QMINAS_GET_SYS_INFO_RESP), // 0x004D
|
||||
qmi_name_item(QMINAS_SYS_INFO_IND), // 0x004D
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_wms_Type[] = {
|
||||
// ======================= WMS ==============================
|
||||
qmi_name_item(QMIWMS_SET_EVENT_REPORT_REQ), // 0x0001
|
||||
qmi_name_item(QMIWMS_SET_EVENT_REPORT_RESP), // 0x0001
|
||||
qmi_name_item(QMIWMS_EVENT_REPORT_IND), // 0x0001
|
||||
qmi_name_item(QMIWMS_RAW_SEND_REQ), // 0x0020
|
||||
qmi_name_item(QMIWMS_RAW_SEND_RESP), // 0x0020
|
||||
qmi_name_item(QMIWMS_RAW_WRITE_REQ), // 0x0021
|
||||
qmi_name_item(QMIWMS_RAW_WRITE_RESP), // 0x0021
|
||||
qmi_name_item(QMIWMS_RAW_READ_REQ), // 0x0022
|
||||
qmi_name_item(QMIWMS_RAW_READ_RESP), // 0x0022
|
||||
qmi_name_item(QMIWMS_MODIFY_TAG_REQ), // 0x0023
|
||||
qmi_name_item(QMIWMS_MODIFY_TAG_RESP), // 0x0023
|
||||
qmi_name_item(QMIWMS_DELETE_REQ), // 0x0024
|
||||
qmi_name_item(QMIWMS_DELETE_RESP), // 0x0024
|
||||
qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_REQ), // 0x0030
|
||||
qmi_name_item(QMIWMS_GET_MESSAGE_PROTOCOL_RESP), // 0x0030
|
||||
qmi_name_item(QMIWMS_LIST_MESSAGES_REQ), // 0x0031
|
||||
qmi_name_item(QMIWMS_LIST_MESSAGES_RESP), // 0x0031
|
||||
qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_REQ), // 0x0034
|
||||
qmi_name_item(QMIWMS_GET_SMSC_ADDRESS_RESP), // 0x0034
|
||||
qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_REQ), // 0x0035
|
||||
qmi_name_item(QMIWMS_SET_SMSC_ADDRESS_RESP), // 0x0035
|
||||
qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_REQ), // 0x0036
|
||||
qmi_name_item(QMIWMS_GET_STORE_MAX_SIZE_RESP), // 0x0036
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_wds_admin_Type[] = {
|
||||
qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_REQ), // 0x0020
|
||||
qmi_name_item(QMIWDS_ADMIN_SET_DATA_FORMAT_RESP), // 0x0020
|
||||
qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_REQ), // 0x0021
|
||||
qmi_name_item(QMIWDS_ADMIN_GET_DATA_FORMAT_RESP), // 0x0021
|
||||
qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_REQ), // 0x002B
|
||||
qmi_name_item(QMIWDS_ADMIN_SET_QMAP_SETTINGS_RESP), // 0x002B
|
||||
qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_REQ), // 0x002C
|
||||
qmi_name_item(QMIWDS_ADMIN_GET_QMAP_SETTINGS_RESP), // 0x002C
|
||||
};
|
||||
|
||||
static const QMI_NAME_T qmux_uim_Type[] = {
|
||||
qmi_name_item(QMIUIM_READ_TRANSPARENT_REQ), // 0x0020
|
||||
qmi_name_item(QMIUIM_READ_TRANSPARENT_RESP), // 0x0020
|
||||
qmi_name_item(QMIUIM_READ_TRANSPARENT_IND), // 0x0020
|
||||
qmi_name_item(QMIUIM_READ_RECORD_REQ), // 0x0021
|
||||
qmi_name_item(QMIUIM_READ_RECORD_RESP), // 0x0021
|
||||
qmi_name_item(QMIUIM_READ_RECORD_IND), // 0x0021
|
||||
qmi_name_item(QMIUIM_WRITE_TRANSPARENT_REQ), // 0x0022
|
||||
qmi_name_item(QMIUIM_WRITE_TRANSPARENT_RESP), // 0x0022
|
||||
qmi_name_item(QMIUIM_WRITE_TRANSPARENT_IND), // 0x0022
|
||||
qmi_name_item(QMIUIM_WRITE_RECORD_REQ), // 0x0023
|
||||
qmi_name_item(QMIUIM_WRITE_RECORD_RESP), // 0x0023
|
||||
qmi_name_item(QMIUIM_WRITE_RECORD_IND), // 0x0023
|
||||
qmi_name_item(QMIUIM_SET_PIN_PROTECTION_REQ), // 0x0025
|
||||
qmi_name_item(QMIUIM_SET_PIN_PROTECTION_RESP), // 0x0025
|
||||
qmi_name_item(QMIUIM_SET_PIN_PROTECTION_IND), // 0x0025
|
||||
qmi_name_item(QMIUIM_VERIFY_PIN_REQ), // 0x0026
|
||||
qmi_name_item(QMIUIM_VERIFY_PIN_RESP), // 0x0026
|
||||
qmi_name_item(QMIUIM_VERIFY_PIN_IND), // 0x0026
|
||||
qmi_name_item(QMIUIM_UNBLOCK_PIN_REQ), // 0x0027
|
||||
qmi_name_item(QMIUIM_UNBLOCK_PIN_RESP), // 0x0027
|
||||
qmi_name_item(QMIUIM_UNBLOCK_PIN_IND), // 0x0027
|
||||
qmi_name_item(QMIUIM_CHANGE_PIN_REQ), // 0x0028
|
||||
qmi_name_item(QMIUIM_CHANGE_PIN_RESP), // 0x0028
|
||||
qmi_name_item(QMIUIM_CHANGE_PIN_IND), // 0x0028
|
||||
qmi_name_item(QMIUIM_DEPERSONALIZATION_REQ), // 0x0029
|
||||
qmi_name_item(QMIUIM_DEPERSONALIZATION_RESP), // 0x0029
|
||||
qmi_name_item(QMIUIM_EVENT_REG_REQ), // 0x002E
|
||||
qmi_name_item(QMIUIM_EVENT_REG_RESP), // 0x002E
|
||||
qmi_name_item(QMIUIM_GET_CARD_STATUS_REQ), // 0x002F
|
||||
qmi_name_item(QMIUIM_GET_CARD_STATUS_RESP), // 0x002F
|
||||
qmi_name_item(QMIUIM_STATUS_CHANGE_IND), // 0x0032
|
||||
};
|
||||
|
||||
static const char *qmi_name_get(const QMI_NAME_T *table, size_t size, int type,
|
||||
const char *tag)
|
||||
{
|
||||
static char unknow[40];
|
||||
size_t i;
|
||||
|
||||
if (qmux_CtlFlags == table) {
|
||||
if (!strcmp(tag, "_REQ"))
|
||||
tag = "_CMD";
|
||||
else if (!strcmp(tag, "_RESP"))
|
||||
tag = "_RSP";
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
if (table[i].type == (UINT)type) {
|
||||
if (!tag || (strstr(table[i].name, tag)))
|
||||
return table[i].name;
|
||||
}
|
||||
}
|
||||
sprintf(unknow, "unknow_%x", type);
|
||||
return unknow;
|
||||
}
|
||||
|
||||
#define QMI_NAME(table, type) \
|
||||
qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, 0)
|
||||
#define QMUX_NAME(table, type, tag) \
|
||||
qmi_name_get(table, sizeof(table) / sizeof(table[0]), type, tag)
|
||||
|
||||
void dump_tlv(PQCQMUX_MSG_HDR pQMUXMsgHdr)
|
||||
{
|
||||
int TLVFind = 0;
|
||||
int i;
|
||||
// dbg("QCQMUX_TLV-----------------------------------\n");
|
||||
// dbg("{Type,\tLength,\tValue}\n");
|
||||
|
||||
while (1) {
|
||||
PQMI_TLV_HDR TLVHdr = GetTLV(pQMUXMsgHdr, 0x1000 + (++TLVFind));
|
||||
if (TLVHdr == NULL)
|
||||
break;
|
||||
|
||||
// if ((TLVHdr->TLVType == 0x02) && ((USHORT *)(TLVHdr+1))[0])
|
||||
{
|
||||
dbg("{%02x,\t%04x,\t", TLVHdr->TLVType,
|
||||
le16_to_cpu(TLVHdr->TLVLength));
|
||||
for (i = 0; i < le16_to_cpu(TLVHdr->TLVLength); i++) {
|
||||
dbg("%02x ", ((UCHAR *)(TLVHdr + 1))[i]);
|
||||
}
|
||||
dbg("}\n");
|
||||
}
|
||||
} // while
|
||||
}
|
||||
|
||||
void dump_ctl(PQCQMICTL_MSG_HDR CTLHdr)
|
||||
{
|
||||
const char *tag;
|
||||
|
||||
// dbg("QCQMICTL_MSG--------------------------------------------\n");
|
||||
// dbg("CtlFlags: %02x\t\t%s\n", CTLHdr->CtlFlags,
|
||||
// QMI_NAME(qmi_ctl_CtlFlags, CTLHdr->CtlFlags));
|
||||
dbg("TransactionId: %02x\n", CTLHdr->TransactionId);
|
||||
switch (CTLHdr->CtlFlags) {
|
||||
case QMICTL_FLAG_REQUEST:
|
||||
tag = "_REQ";
|
||||
break;
|
||||
case QMICTL_FLAG_RESPONSE:
|
||||
tag = "_RESP";
|
||||
break;
|
||||
case QMICTL_FLAG_INDICATION:
|
||||
tag = "_IND";
|
||||
break;
|
||||
default:
|
||||
tag = 0;
|
||||
break;
|
||||
}
|
||||
dbg("QMICTLType: %04x\t%s\n", le16_to_cpu(CTLHdr->QMICTLType),
|
||||
QMUX_NAME(qmux_ctl_QMICTLType, le16_to_cpu(CTLHdr->QMICTLType), tag));
|
||||
dbg("Length: %04x\n", le16_to_cpu(CTLHdr->Length));
|
||||
|
||||
dump_tlv((PQCQMUX_MSG_HDR)(&CTLHdr->QMICTLType));
|
||||
}
|
||||
|
||||
int dump_qmux(QMI_SERVICE_TYPE serviceType, PQCQMUX_HDR QMUXHdr)
|
||||
{
|
||||
PQCQMUX_MSG_HDR QMUXMsgHdr = (PQCQMUX_MSG_HDR)(QMUXHdr + 1);
|
||||
CHAR *tag;
|
||||
|
||||
// dbg("QCQMUX--------------------------------------------\n");
|
||||
switch (QMUXHdr->CtlFlags & QMUX_CTL_FLAG_MASK_TYPE) {
|
||||
case QMUX_CTL_FLAG_TYPE_CMD:
|
||||
tag = "_REQ";
|
||||
break;
|
||||
case QMUX_CTL_FLAG_TYPE_RSP:
|
||||
tag = "_RESP";
|
||||
break;
|
||||
case QMUX_CTL_FLAG_TYPE_IND:
|
||||
tag = "_IND";
|
||||
break;
|
||||
default:
|
||||
tag = 0;
|
||||
break;
|
||||
}
|
||||
// dbg("CtlFlags: %02x\t\t%s\n", QMUXHdr->CtlFlags,
|
||||
// QMUX_NAME(qmux_CtlFlags, QMUXHdr->CtlFlags, tag));
|
||||
dbg("TransactionId: %04x\n", le16_to_cpu(QMUXHdr->TransactionId));
|
||||
|
||||
// dbg("QCQMUX_MSG_HDR-----------------------------------\n");
|
||||
switch (serviceType) {
|
||||
case QMUX_TYPE_DMS:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_dms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_NAS:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_nas_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_WDS:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_wds_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_WMS:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_wms_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_WDS_ADMIN:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_wds_admin_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_UIM:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
QMUX_NAME(qmux_uim_Type, le16_to_cpu(QMUXMsgHdr->Type), tag));
|
||||
break;
|
||||
case QMUX_TYPE_PDS:
|
||||
case QMUX_TYPE_QOS:
|
||||
case QMUX_TYPE_CTL:
|
||||
default:
|
||||
dbg("Type: %04x\t%s\n", le16_to_cpu(QMUXMsgHdr->Type),
|
||||
"PDS/QOS/CTL/unknown!");
|
||||
break;
|
||||
}
|
||||
dbg("Length: %04x\n", le16_to_cpu(QMUXMsgHdr->Length));
|
||||
|
||||
dump_tlv(QMUXMsgHdr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dump_qmi(void *dataBuffer, int dataLen)
|
||||
{
|
||||
PQCQMI_HDR QMIHdr = (PQCQMI_HDR)dataBuffer;
|
||||
PQCQMUX_HDR QMUXHdr = (PQCQMUX_HDR)(QMIHdr + 1);
|
||||
PQCQMICTL_MSG_HDR CTLHdr = (PQCQMICTL_MSG_HDR)(QMIHdr + 1);
|
||||
|
||||
int i;
|
||||
|
||||
if (!debug_qmi)
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&dumpQMIMutex);
|
||||
line[0] = 0;
|
||||
for (i = 0; i < dataLen; i++) {
|
||||
dbg("%02x ", ((unsigned char *)dataBuffer)[i]);
|
||||
}
|
||||
dbg_time("%s", line);
|
||||
line[0] = 0;
|
||||
|
||||
// dbg("QCQMI_HDR-----------------------------------------");
|
||||
// dbg("IFType: %02x\t\t%s", QMIHdr->IFType,
|
||||
// QMI_NAME(qmi_IFType, QMIHdr->IFType)); dbg("Length: %04x",
|
||||
// le16_to_cpu(QMIHdr->Length)); dbg("CtlFlags: %02x\t\t%s",
|
||||
// QMIHdr->CtlFlags, QMI_NAME(qmi_CtlFlags, QMIHdr->CtlFlags));
|
||||
// dbg("QMIType: %02x\t\t%s", QMIHdr->QMIType, QMI_NAME(qmi_QMIType,
|
||||
// QMIHdr->QMIType)); dbg("ClientId: %02x", QMIHdr->ClientId);
|
||||
|
||||
if (QMIHdr->QMIType == QMUX_TYPE_CTL) {
|
||||
dump_ctl(CTLHdr);
|
||||
} else {
|
||||
dump_qmux(QMIHdr->QMIType, QMUXHdr);
|
||||
}
|
||||
dbg_time("%s", line);
|
||||
pthread_mutex_unlock(&dumpQMIMutex);
|
||||
}
|
||||
3671
package/fish/fibocom-dial/src/MPQMUX.h
Normal file
3671
package/fish/fibocom-dial/src/MPQMUX.h
Normal file
File diff suppressed because it is too large
Load Diff
42
package/fish/fibocom-dial/src/Makefile
Normal file
42
package/fish/fibocom-dial/src/Makefile
Normal file
@ -0,0 +1,42 @@
|
||||
ifneq ($(CROSS_COMPILE),)
|
||||
CROSS-COMPILE:=$(CROSS_COMPILE)
|
||||
endif
|
||||
|
||||
CFLAGS += -DGHT_FEATURE_PCIE_AUTO
|
||||
|
||||
ifeq ($(CC),cc)
|
||||
CC:=$(CROSS-COMPILE)gcc
|
||||
endif
|
||||
LD:=$(CROSS-COMPILE)ld
|
||||
|
||||
SRC=QmiWwanCM.c GobiNetCM.c main.c MPQMUX.c QMIThread.c util.c qmap_bridge_mode.c query_pcie_mode.c
|
||||
|
||||
FB_DHCP=udhcpc.c
|
||||
|
||||
FIBO_PROXY_SRC=fibo_qmimsg_server.c
|
||||
|
||||
LIBMNL=libmnl/ifutils.c libmnl/attr.c libmnl/callback.c libmnl/nlmsg.c libmnl/socket.c
|
||||
FB_NDHCP=udhcpc_netlink.c
|
||||
FB_NDHCP+=${LIBMNL}
|
||||
|
||||
release: clean
|
||||
$(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_NDHCP} -o fibocom-dial -lpthread -ldl
|
||||
$(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.c util.c -o multi-pdn-manager -lpthread -ldl
|
||||
$(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl
|
||||
|
||||
dhcp: clean
|
||||
$(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_DHCP} -o fibocom-dial -lpthread -ldl
|
||||
$(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.c util.c -o multi-pdn-manager -lpthread -ldl
|
||||
$(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl
|
||||
|
||||
ndhcp: clean
|
||||
$(CC) $(CFLAGS) -Wall -s ${SRC} ${FB_NDHCP} -o fibocom-dial -lpthread -ldl
|
||||
$(CC) -Wall -s multi-pdn-manager.c query_pcie_mode.cutil.c -o multi-pdn-manager -lpthread -ldl
|
||||
$(CC) -Wall -s ${FIBO_PROXY_SRC} -o fibo_qmimsg_server -lpthread -ldl
|
||||
|
||||
qmi-proxy:
|
||||
$(CC) -Wall -s fibo-qmi-proxy.c -o fibo-qmi-proxy -lpthread -ldl
|
||||
|
||||
clean:
|
||||
rm -rf fibocom-dial *~ multi-pdn-manager fibo_qmimsg_server
|
||||
|
||||
2551
package/fish/fibocom-dial/src/QMIThread.c
Normal file
2551
package/fish/fibocom-dial/src/QMIThread.c
Normal file
File diff suppressed because it is too large
Load Diff
260
package/fish/fibocom-dial/src/QMIThread.h
Normal file
260
package/fish/fibocom-dial/src/QMIThread.h
Normal file
@ -0,0 +1,260 @@
|
||||
#ifndef __QMI_THREAD_H__
|
||||
#define __QMI_THREAD_H__
|
||||
|
||||
#define CONFIG_GOBINET
|
||||
#define CONFIG_QMIWWAN
|
||||
#define CONFIG_SIM
|
||||
#define CONFIG_APN
|
||||
#define CONFIG_VERSION
|
||||
//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817
|
||||
#define CONFIG_IMSI_ICCID
|
||||
//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817
|
||||
#define CONFIG_DEFAULT_PDP 1
|
||||
#define CONFIG_DEFAULT_PDPINDEX 1
|
||||
//#define CONFIG_IMSI_ICCID
|
||||
|
||||
#define CONFIG_RESET_RADIO \
|
||||
(45) // Reset Radiao(AT+CFUN=4,AT+CFUN=1) when cann not register network or
|
||||
// setup data call in 45 seconds
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/poll.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "MPQCTL.h"
|
||||
#include "MPQMI.h"
|
||||
#include "MPQMUX.h"
|
||||
|
||||
#define DEVICE_CLASS_UNKNOWN 0
|
||||
#define DEVICE_CLASS_CDMA 1
|
||||
#define DEVICE_CLASS_GSM 2
|
||||
|
||||
#define WWAN_DATA_CLASS_NONE 0x00000000
|
||||
#define WWAN_DATA_CLASS_GPRS 0x00000001
|
||||
#define WWAN_DATA_CLASS_EDGE 0x00000002 /* EGPRS */
|
||||
#define WWAN_DATA_CLASS_UMTS 0x00000004
|
||||
#define WWAN_DATA_CLASS_HSDPA 0x00000008
|
||||
#define WWAN_DATA_CLASS_HSUPA 0x00000010
|
||||
#define WWAN_DATA_CLASS_LTE 0x00000020
|
||||
//begin modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605
|
||||
#define WWAN_DATA_CLASS_5G 0x00000040
|
||||
//end modified by zhangkaibo add 5G network detect feature on x55 platform. 20200605
|
||||
#define WWAN_DATA_CLASS_1XRTT 0x00010000
|
||||
#define WWAN_DATA_CLASS_1XEVDO 0x00020000
|
||||
#define WWAN_DATA_CLASS_1XEVDO_REVA 0x00040000
|
||||
#define WWAN_DATA_CLASS_1XEVDV 0x00080000
|
||||
#define WWAN_DATA_CLASS_3XRTT 0x00100000
|
||||
#define WWAN_DATA_CLASS_1XEVDO_REVB 0x00200000 /* for future use */
|
||||
#define WWAN_DATA_CLASS_UMB 0x00400000
|
||||
#define WWAN_DATA_CLASS_CUSTOM 0x80000000
|
||||
|
||||
struct wwan_data_class_str {
|
||||
ULONG class;
|
||||
CHAR *str;
|
||||
};
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct _QCQMIMSG {
|
||||
QCQMI_HDR QMIHdr;
|
||||
union {
|
||||
QMICTL_MSG CTLMsg;
|
||||
QMUX_MSG MUXMsg;
|
||||
//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817
|
||||
QMUX_MSG QMUXMsgHdrResp;
|
||||
//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817
|
||||
};
|
||||
} __attribute__((packed)) QCQMIMSG, *PQCQMIMSG;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef struct __IPV4 {
|
||||
uint32_t Address;
|
||||
uint32_t Gateway;
|
||||
uint32_t SubnetMask;
|
||||
uint32_t DnsPrimary;
|
||||
uint32_t DnsSecondary;
|
||||
uint32_t Mtu;
|
||||
} IPV4_T;
|
||||
|
||||
typedef struct __IPV6 {
|
||||
UCHAR Address[16];
|
||||
UCHAR Gateway[16];
|
||||
UCHAR SubnetMask[16];
|
||||
UCHAR DnsPrimary[16];
|
||||
UCHAR DnsSecondary[16];
|
||||
UCHAR PrefixLengthIPAddr;
|
||||
UCHAR PrefixLengthGateway;
|
||||
ULONG Mtu;
|
||||
} IPV6_T;
|
||||
|
||||
#define IpFamilyV4 (0x04)
|
||||
#define IpFamilyV6 (0x06)
|
||||
|
||||
struct __PROFILE;
|
||||
struct qmi_device_ops {
|
||||
int (*init)(struct __PROFILE *profile);
|
||||
int (*deinit)(void);
|
||||
int (*send)(PQCQMIMSG pRequest);
|
||||
void *(*read)(void *pData);
|
||||
};
|
||||
extern int (*qmidev_send)(PQCQMIMSG pRequest);
|
||||
|
||||
#ifndef bool
|
||||
#define bool uint8_t
|
||||
#endif
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037
|
||||
typedef struct {
|
||||
unsigned int size;
|
||||
unsigned int rx_urb_size;
|
||||
unsigned int ep_type;
|
||||
unsigned int iface_id;
|
||||
unsigned int qmap_mode;
|
||||
unsigned int qmap_version;
|
||||
unsigned int dl_minimum_padding;
|
||||
char ifname[8][16];
|
||||
unsigned char mux_id[8];
|
||||
} RMNET_INFO;
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037
|
||||
|
||||
typedef struct __PROFILE {
|
||||
char *qmichannel;
|
||||
char *usbnet_adapter;
|
||||
char *qmapnet_adapter;
|
||||
const char *driver_name;
|
||||
int qmap_mode;
|
||||
int qmap_size;
|
||||
int qmap_version;
|
||||
const char *apn;
|
||||
const char *user;
|
||||
const char *password;
|
||||
const char *pincode;
|
||||
int auth;
|
||||
int pdp;
|
||||
int pdpindex;
|
||||
int pdpnum;
|
||||
int curIpFamily;
|
||||
int rawIP;
|
||||
int muxid;
|
||||
IPV4_T ipv4;
|
||||
IPV6_T ipv6;
|
||||
int ipv4_flag;
|
||||
int ipv6_flag;
|
||||
|
||||
//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001
|
||||
int ipv6_prigateway_flag;
|
||||
//2021-02-25 willa.liu@fibocom.com changed begin for support eipd SN-20210129001
|
||||
|
||||
int dual_flag;
|
||||
int apntype;
|
||||
const struct qmi_device_ops *qmi_ops;
|
||||
bool loopback_state;
|
||||
int replication_factor;
|
||||
//2021-02-08 zhangkaibo@fibocom.com changed begin for mantis 0070613
|
||||
int interfacenum;
|
||||
//2021-02-08 zhangkaibo@fibocom.com changed end for mantis 0070613
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037
|
||||
RMNET_INFO rmnet_info;
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037
|
||||
} PROFILE_T;
|
||||
|
||||
typedef enum {
|
||||
SIM_ABSENT = 0,
|
||||
SIM_NOT_READY = 1,
|
||||
SIM_READY =
|
||||
2, /* SIM_READY means the radio state is RADIO_STATE_SIM_READY */
|
||||
SIM_PIN = 3,
|
||||
SIM_PUK = 4,
|
||||
SIM_NETWORK_PERSONALIZATION = 5,
|
||||
SIM_BAD = 6,
|
||||
} SIM_Status;
|
||||
//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817
|
||||
typedef enum {
|
||||
SIM_Card0 = 0,
|
||||
SIM_Card1 = 1
|
||||
} SIM_Select;
|
||||
//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817
|
||||
#define WDM_DEFAULT_BUFSIZE 256
|
||||
#define RIL_REQUEST_QUIT 0x1000
|
||||
#define RIL_INDICATE_DEVICE_CONNECTED 0x1002
|
||||
#define RIL_INDICATE_DEVICE_DISCONNECTED 0x1003
|
||||
#define RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED 0x1004
|
||||
#define RIL_UNSOL_DATA_CALL_LIST_CHANGED 0x1005
|
||||
|
||||
extern int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
unsigned msecs);
|
||||
extern int QmiThreadSendQMI(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse);
|
||||
extern int QmiThreadSendQMITimeout(PQCQMIMSG pRequest, PQCQMIMSG *ppResponse,
|
||||
unsigned msecs);
|
||||
extern void QmiThreadRecvQMI(PQCQMIMSG pResponse);
|
||||
extern int fibo_raw_ip_mode_check(const char *ifname);
|
||||
extern void udhcpc_start(PROFILE_T *profile);
|
||||
extern void udhcpc_stop(PROFILE_T *profile);
|
||||
extern void udhcpc_start_pcie(PROFILE_T *profile);
|
||||
extern void udhcpc_stop_pcie(PROFILE_T *profile);
|
||||
|
||||
extern void dump_qmi(void *dataBuffer, int dataLen);
|
||||
extern void qmidevice_send_event_to_main(int triger_event);
|
||||
extern int requestSetEthMode(PROFILE_T *profile);
|
||||
//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817
|
||||
//extern int requestGetSIMStatus(SIM_Status *pSIMStatus);
|
||||
extern int requestGetSIMStatus(SIM_Status *pSIMStatus , const int sim_select);
|
||||
//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817
|
||||
extern int requestEnterSimPin(const CHAR *pPinCode);
|
||||
extern int requestGetICCID(void);
|
||||
extern int requestGetIMSI(void);
|
||||
extern int requestRegistrationState(UCHAR *pPSAttachedState);
|
||||
extern int requestQueryDataCall(UCHAR *pConnectionStatus, int curIpFamily);
|
||||
extern int requestSetupDataCall(PROFILE_T *profile, int curIpFamily);
|
||||
extern int requestDeactivateDefaultPDP(PROFILE_T *profile, int curIpFamily);
|
||||
extern int requestSetProfile(PROFILE_T *profile);
|
||||
extern int requestGetProfile(PROFILE_T *profile);
|
||||
extern int requestBaseBandVersion(const char **pp_reversion);
|
||||
extern int requestGetIPAddress(PROFILE_T *profile, int curIpFamily);
|
||||
extern int requestSetOperatingMode(UCHAR OperatingMode);
|
||||
int requestRegistrationState2(UCHAR *pPSAttachedState);
|
||||
|
||||
extern int fibo_qmap_mode_set(PROFILE_T *profile);
|
||||
extern int fibo_bridge_mode_detect(PROFILE_T *profile);
|
||||
extern int fibo_qmap_mode_detect(PROFILE_T *profile);
|
||||
extern const struct qmi_device_ops qmiwwan_qmidev_ops;
|
||||
|
||||
#define qmidev_is_gobinet(_qmichannel) \
|
||||
(strncmp(_qmichannel, "/dev/qcqmi", strlen("/dev/qcqmi")) == 0)
|
||||
#define qmidev_is_qmiwwan(_qmichannel) \
|
||||
(strncmp(_qmichannel, "/dev/cdc-wdm", strlen("/dev/cdc-wdm")) == 0)
|
||||
#define qmidev_is_pciemhi(_qmichannel) \
|
||||
(strncmp(_qmichannel, "/dev/mhi_", strlen("/dev/mhi_")) == 0)
|
||||
|
||||
#define driver_is_qmi(_drv_name) \
|
||||
(strncasecmp(_drv_name, "qmi_wwan", strlen("qmi_wwan")) == 0)
|
||||
#define driver_is_mbim(_drv_name) \
|
||||
(strncasecmp(_drv_name, "cdc_mbim", strlen("cdc_mbim")) == 0)
|
||||
|
||||
extern FILE *logfilefp;
|
||||
extern int debug_qmi;
|
||||
extern USHORT g_MobileCountryCode;
|
||||
extern USHORT g_MobileNetworkCode;
|
||||
extern int qmidevice_control_fd[2];
|
||||
extern int qmiclientId[QMUX_TYPE_WDS_ADMIN + 1];
|
||||
extern void dbg_time(const char *fmt, ...);
|
||||
extern USHORT le16_to_cpu(USHORT v16);
|
||||
extern UINT le32_to_cpu(UINT v32);
|
||||
extern USHORT cpu_to_le16(USHORT v16);
|
||||
extern UINT cpu_to_le32(UINT v32);
|
||||
#endif
|
||||
426
package/fish/fibocom-dial/src/QmiWwanCM.c
Normal file
426
package/fish/fibocom-dial/src/QmiWwanCM.c
Normal file
@ -0,0 +1,426 @@
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
typedef unsigned short sa_family_t;
|
||||
#include <linux/un.h>
|
||||
|
||||
#include "QMIThread.h"
|
||||
|
||||
#ifdef CONFIG_QMIWWAN
|
||||
#define FIBO_QMI_PROXY "fibo_qmimsg_server"
|
||||
static int cdc_wdm_fd = -1;
|
||||
|
||||
static UCHAR GetQCTLTransactionId(void)
|
||||
{
|
||||
static int TransactionId = 0;
|
||||
if (++TransactionId > 0xFF)
|
||||
TransactionId = 1;
|
||||
return TransactionId;
|
||||
}
|
||||
|
||||
typedef USHORT (*CUSTOMQCTL)(PQMICTL_MSG pCTLMsg, void *arg);
|
||||
|
||||
static PQCQMIMSG ComposeQCTLMsg(USHORT QMICTLType,
|
||||
CUSTOMQCTL customQctlMsgFunction, void *arg)
|
||||
{
|
||||
UCHAR QMIBuf[WDM_DEFAULT_BUFSIZE];
|
||||
PQCQMIMSG pRequest = (PQCQMIMSG)QMIBuf;
|
||||
int Length;
|
||||
|
||||
pRequest->QMIHdr.IFType = USB_CTL_MSG_TYPE_QMI;
|
||||
pRequest->QMIHdr.CtlFlags = 0x00;
|
||||
pRequest->QMIHdr.QMIType = QMUX_TYPE_CTL;
|
||||
pRequest->QMIHdr.ClientId = 0x00;
|
||||
|
||||
pRequest->CTLMsg.QMICTLMsgHdr.CtlFlags = QMICTL_FLAG_REQUEST;
|
||||
pRequest->CTLMsg.QMICTLMsgHdr.TransactionId = GetQCTLTransactionId();
|
||||
pRequest->CTLMsg.QMICTLMsgHdr.QMICTLType = cpu_to_le16(QMICTLType);
|
||||
if (customQctlMsgFunction)
|
||||
pRequest->CTLMsg.QMICTLMsgHdr.Length =
|
||||
cpu_to_le16(customQctlMsgFunction(&pRequest->CTLMsg, arg) -
|
||||
sizeof(QCQMICTL_MSG_HDR));
|
||||
else
|
||||
pRequest->CTLMsg.QMICTLMsgHdr.Length = cpu_to_le16(0x0000);
|
||||
|
||||
pRequest->QMIHdr.Length =
|
||||
cpu_to_le16(le16_to_cpu(pRequest->CTLMsg.QMICTLMsgHdr.Length) +
|
||||
sizeof(QCQMICTL_MSG_HDR) + sizeof(QCQMI_HDR) - 1);
|
||||
Length = le16_to_cpu(pRequest->QMIHdr.Length) + 1;
|
||||
|
||||
pRequest = (PQCQMIMSG)malloc(Length);
|
||||
if (pRequest == NULL) {
|
||||
dbg_time("%s fail to malloc", __func__);
|
||||
} else {
|
||||
memcpy(pRequest, QMIBuf, Length);
|
||||
}
|
||||
|
||||
return pRequest;
|
||||
}
|
||||
|
||||
static USHORT CtlGetVersionReq(PQMICTL_MSG QCTLMsg, void *arg)
|
||||
{
|
||||
QCTLMsg->GetVersionReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
|
||||
QCTLMsg->GetVersionReq.TLVLength = cpu_to_le16(0x0001);
|
||||
QCTLMsg->GetVersionReq.QMUXTypes = QMUX_TYPE_ALL;
|
||||
return sizeof(QMICTL_GET_VERSION_REQ_MSG);
|
||||
}
|
||||
|
||||
static USHORT CtlGetClientIdReq(PQMICTL_MSG QCTLMsg, void *arg)
|
||||
{
|
||||
QCTLMsg->GetClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
|
||||
QCTLMsg->GetClientIdReq.TLVLength = cpu_to_le16(0x0001);
|
||||
QCTLMsg->GetClientIdReq.QMIType = ((UCHAR *)arg)[0];
|
||||
return sizeof(QMICTL_GET_CLIENT_ID_REQ_MSG);
|
||||
}
|
||||
|
||||
static USHORT CtlReleaseClientIdReq(PQMICTL_MSG QCTLMsg, void *arg)
|
||||
{
|
||||
QCTLMsg->ReleaseClientIdReq.TLVType = QCTLV_TYPE_REQUIRED_PARAMETER;
|
||||
QCTLMsg->ReleaseClientIdReq.TLVLength = cpu_to_le16(0x0002);
|
||||
QCTLMsg->ReleaseClientIdReq.QMIType = ((UCHAR *)arg)[0];
|
||||
QCTLMsg->ReleaseClientIdReq.ClientId = ((UCHAR *)arg)[1];
|
||||
return sizeof(QMICTL_RELEASE_CLIENT_ID_REQ_MSG);
|
||||
}
|
||||
|
||||
static int QmiWwanSendQMI(PQCQMIMSG pRequest)
|
||||
{
|
||||
struct pollfd pollfds[] = {{cdc_wdm_fd, POLLOUT, 0}};
|
||||
int ret;
|
||||
|
||||
if (cdc_wdm_fd == -1) {
|
||||
dbg_time("%s cdc_wdm_fd = -1", __func__);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
if (pRequest->QMIHdr.QMIType == QMUX_TYPE_WDS_IPV6)
|
||||
pRequest->QMIHdr.QMIType = QMUX_TYPE_WDS;
|
||||
|
||||
do {
|
||||
ret = poll(pollfds, sizeof(pollfds) / sizeof(pollfds[0]), 5000);
|
||||
} while ((ret < 0) && (errno == EINTR));
|
||||
|
||||
if (pollfds[0].revents & POLLOUT) {
|
||||
ssize_t nwrites = le16_to_cpu(pRequest->QMIHdr.Length) + 1;
|
||||
ret = write(cdc_wdm_fd, pRequest, nwrites);
|
||||
if (ret == nwrites) {
|
||||
ret = 0;
|
||||
} else {
|
||||
dbg_time("%s write=%d, errno: %d (%s)", __func__, ret, errno,
|
||||
strerror(errno));
|
||||
}
|
||||
} else {
|
||||
dbg_time("%s poll=%d, revents = 0x%x, errno: %d (%s)", __func__, ret,
|
||||
pollfds[0].revents, errno, strerror(errno));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int QmiWwanGetClientID(UCHAR QMIType)
|
||||
{
|
||||
PQCQMIMSG pResponse;
|
||||
|
||||
QmiThreadSendQMI(
|
||||
ComposeQCTLMsg(QMICTL_GET_CLIENT_ID_REQ, CtlGetClientIdReq, &QMIType),
|
||||
&pResponse);
|
||||
|
||||
if (pResponse) {
|
||||
USHORT QMUXResult = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp
|
||||
.QMUXResult); // QMI_RESULT_SUCCESS
|
||||
USHORT QMUXError = cpu_to_le16(pResponse->CTLMsg.QMICTLMsgHdrRsp
|
||||
.QMUXError); // QMI_ERR_INVALID_ARG
|
||||
// UCHAR QMIType = pResponse->CTLMsg.GetClientIdRsp.QMIType;
|
||||
UCHAR ClientId = pResponse->CTLMsg.GetClientIdRsp.ClientId;
|
||||
|
||||
dbg_time("%s: QMIType = %d clientid %d", __func__, QMIType, ClientId);
|
||||
|
||||
if (!QMUXResult && !QMUXError &&
|
||||
(QMIType == pResponse->CTLMsg.GetClientIdRsp.QMIType)) {
|
||||
switch (QMIType) {
|
||||
case QMUX_TYPE_WDS:
|
||||
dbg_time("Get clientWDS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_DMS:
|
||||
dbg_time("Get clientDMS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_NAS:
|
||||
dbg_time("Get clientNAS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_QOS:
|
||||
dbg_time("Get clientQOS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_WMS:
|
||||
dbg_time("Get clientWMS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_PDS:
|
||||
dbg_time("Get clientPDS = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_UIM:
|
||||
dbg_time("Get clientUIM = %d", ClientId);
|
||||
break;
|
||||
case QMUX_TYPE_WDS_ADMIN:
|
||||
dbg_time("Get clientWDA = %d", ClientId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ClientId;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int QmiWwanReleaseClientID(QMI_SERVICE_TYPE QMIType, UCHAR ClientId)
|
||||
{
|
||||
UCHAR argv[] = {QMIType, ClientId};
|
||||
QmiThreadSendQMI(ComposeQCTLMsg(QMICTL_RELEASE_CLIENT_ID_REQ,
|
||||
CtlReleaseClientIdReq, argv),
|
||||
NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int QmiWwanInit(PROFILE_T *profile)
|
||||
{
|
||||
unsigned i;
|
||||
int ret;
|
||||
PQCQMIMSG pResponse;
|
||||
|
||||
if (profile->qmap_mode == 0 || profile->qmap_mode == 1) {
|
||||
for (i = 0; i < 10; i++) {
|
||||
ret = QmiThreadSendQMITimeout(
|
||||
ComposeQCTLMsg(QMICTL_SYNC_REQ, NULL, NULL), NULL, 1 * 1000);
|
||||
if (!ret)
|
||||
break;
|
||||
sleep(1);
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
QmiThreadSendQMI(
|
||||
ComposeQCTLMsg(QMICTL_GET_VERSION_REQ, CtlGetVersionReq, NULL),
|
||||
&pResponse);
|
||||
if (profile->qmap_mode) {
|
||||
if (pResponse) {
|
||||
if (pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXResult == 0 &&
|
||||
pResponse->CTLMsg.QMICTLMsgHdrRsp.QMUXError == 0) {
|
||||
uint8_t NumElements = 0;
|
||||
|
||||
for (NumElements = 0;
|
||||
NumElements < pResponse->CTLMsg.GetVersionRsp.NumElements;
|
||||
NumElements++) {
|
||||
if (pResponse->CTLMsg.GetVersionRsp.TypeVersion[NumElements]
|
||||
.QMUXType == QMUX_TYPE_WDS_ADMIN)
|
||||
profile->qmap_version = (pResponse->CTLMsg.GetVersionRsp
|
||||
.TypeVersion[NumElements]
|
||||
.MinorVersion > 16);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (pResponse)
|
||||
free(pResponse);
|
||||
if (profile->ipv4_flag)
|
||||
qmiclientId[QMUX_TYPE_WDS] = QmiWwanGetClientID(QMUX_TYPE_WDS);
|
||||
if (profile->ipv6_flag)
|
||||
qmiclientId[QMUX_TYPE_WDS_IPV6] = QmiWwanGetClientID(QMUX_TYPE_WDS);
|
||||
qmiclientId[QMUX_TYPE_DMS] = QmiWwanGetClientID(QMUX_TYPE_DMS);
|
||||
qmiclientId[QMUX_TYPE_NAS] = QmiWwanGetClientID(QMUX_TYPE_NAS);
|
||||
qmiclientId[QMUX_TYPE_UIM] = QmiWwanGetClientID(QMUX_TYPE_UIM);
|
||||
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
|
||||
qmiclientId[QMUX_TYPE_WDS_ADMIN] =
|
||||
QmiWwanGetClientID(QMUX_TYPE_WDS_ADMIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int QmiWwanDeInit(void)
|
||||
{
|
||||
unsigned int i;
|
||||
for (i = 0; i < sizeof(qmiclientId) / sizeof(qmiclientId[0]); i++) {
|
||||
if (qmiclientId[i] != 0) {
|
||||
QmiWwanReleaseClientID(i, qmiclientId[i]);
|
||||
qmiclientId[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qmi_proxy_open(const char *name)
|
||||
{
|
||||
int sockfd = -1;
|
||||
int reuse_addr = 1;
|
||||
struct sockaddr_un sockaddr;
|
||||
socklen_t alen;
|
||||
|
||||
/*Create server socket*/
|
||||
(sockfd = socket(AF_LOCAL, SOCK_STREAM, 0));
|
||||
if (sockfd < 0)
|
||||
return sockfd;
|
||||
|
||||
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||
sockaddr.sun_family = AF_LOCAL;
|
||||
sockaddr.sun_path[0] = 0;
|
||||
memcpy(sockaddr.sun_path + 1, name, strlen(name));
|
||||
|
||||
alen = strlen(name) + offsetof(struct sockaddr_un, sun_path) + 1;
|
||||
if (connect(sockfd, (struct sockaddr *)&sockaddr, alen) < 0) {
|
||||
close(sockfd);
|
||||
dbg_time("%s connect %s errno: %d (%s)\n", __func__, name, errno,
|
||||
strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &reuse_addr,
|
||||
sizeof(reuse_addr)));
|
||||
|
||||
dbg_time("connect to %s sockfd = %d\n", name, sockfd);
|
||||
|
||||
return sockfd;
|
||||
}
|
||||
|
||||
static ssize_t qmi_proxy_read(int fd, void *buf, size_t size)
|
||||
{
|
||||
ssize_t nreads;
|
||||
PQCQMI_HDR pHdr = (PQCQMI_HDR)buf;
|
||||
|
||||
nreads = read(fd, pHdr, sizeof(QCQMI_HDR));
|
||||
if (nreads == sizeof(QCQMI_HDR)) {
|
||||
nreads += read(fd, pHdr + 1,
|
||||
le16_to_cpu(pHdr->Length) + 1 - sizeof(QCQMI_HDR));
|
||||
}
|
||||
|
||||
return nreads;
|
||||
}
|
||||
|
||||
static void *QmiWwanThread(void *pData)
|
||||
{
|
||||
PROFILE_T *profile = (PROFILE_T *)pData;
|
||||
const char *cdc_wdm = (const char *)profile->qmichannel;
|
||||
|
||||
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
|
||||
cdc_wdm_fd = open(cdc_wdm, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
else
|
||||
cdc_wdm_fd = qmi_proxy_open(FIBO_QMI_PROXY);
|
||||
|
||||
if (cdc_wdm_fd == -1) {
|
||||
dbg_time("%s Failed to open %s, errno: %d (%s)", __func__, cdc_wdm,
|
||||
errno, strerror(errno));
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fcntl(cdc_wdm_fd, F_SETFL, fcntl(cdc_wdm_fd, F_GETFL) | O_NONBLOCK);
|
||||
fcntl(cdc_wdm_fd, F_SETFD, FD_CLOEXEC);
|
||||
|
||||
dbg_time("cdc_wdm_fd = %d", cdc_wdm_fd);
|
||||
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_CONNECTED);
|
||||
|
||||
while (1) {
|
||||
struct pollfd pollfds[] = {{qmidevice_control_fd[1], POLLIN, 0},
|
||||
{cdc_wdm_fd, POLLIN, 0}};
|
||||
int ne, ret, nevents = sizeof(pollfds) / sizeof(pollfds[0]);
|
||||
|
||||
do {
|
||||
ret = poll(pollfds, nevents, -1);
|
||||
} while ((ret < 0) && (errno == EINTR));
|
||||
|
||||
if (ret <= 0) {
|
||||
dbg_time("%s poll=%d, errno: %d (%s)", __func__, ret, errno,
|
||||
strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
for (ne = 0; ne < nevents; ne++) {
|
||||
int fd = pollfds[ne].fd;
|
||||
short revents = pollfds[ne].revents;
|
||||
|
||||
// dbg_time("{%d, %x, %x}", pollfds[ne].fd, pollfds[ne].events,
|
||||
// pollfds[ne].revents);
|
||||
|
||||
if (revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
||||
dbg_time("%s poll err/hup/inval", __func__);
|
||||
dbg_time("poll fd = %d, events = 0x%04x", fd, revents);
|
||||
if (fd == cdc_wdm_fd) {
|
||||
} else {
|
||||
}
|
||||
if (revents &
|
||||
(POLLHUP | POLLNVAL)) // EC20 bug, Can get POLLERR
|
||||
goto __QmiWwanThread_quit;
|
||||
}
|
||||
|
||||
if ((revents & POLLIN) == 0)
|
||||
continue;
|
||||
|
||||
if (fd == qmidevice_control_fd[1]) {
|
||||
int triger_event;
|
||||
if (read(fd, &triger_event, sizeof(triger_event)) ==
|
||||
sizeof(triger_event)) {
|
||||
// DBG("triger_event = 0x%x", triger_event);
|
||||
switch (triger_event) {
|
||||
case RIL_REQUEST_QUIT:
|
||||
goto __QmiWwanThread_quit;
|
||||
break;
|
||||
case SIGTERM:
|
||||
case SIGHUP:
|
||||
case SIGINT:
|
||||
QmiThreadRecvQMI(NULL);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == cdc_wdm_fd) {
|
||||
ssize_t nreads;
|
||||
UCHAR QMIBuf[4096];
|
||||
PQCQMIMSG pResponse = (PQCQMIMSG)QMIBuf;
|
||||
|
||||
if (profile->qmap_mode == 0 || profile->qmap_mode == 1)
|
||||
nreads = read(fd, QMIBuf, sizeof(QMIBuf));
|
||||
else
|
||||
nreads = qmi_proxy_read(fd, QMIBuf, sizeof(QMIBuf));
|
||||
// dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads,
|
||||
// errno, strerror(errno));
|
||||
if (nreads <= 0) {
|
||||
dbg_time("%s read=%d errno: %d (%s)", __func__, (int)nreads,
|
||||
errno, strerror(errno));
|
||||
break;
|
||||
}
|
||||
|
||||
if (nreads != (le16_to_cpu(pResponse->QMIHdr.Length) + 1)) {
|
||||
dbg_time("%s nreads=%d, pQCQMI->QMIHdr.Length = %d",
|
||||
__func__, (int)nreads,
|
||||
le16_to_cpu(pResponse->QMIHdr.Length));
|
||||
continue;
|
||||
}
|
||||
|
||||
QmiThreadRecvQMI(pResponse);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__QmiWwanThread_quit:
|
||||
if (cdc_wdm_fd != -1) {
|
||||
close(cdc_wdm_fd);
|
||||
cdc_wdm_fd = -1;
|
||||
}
|
||||
qmidevice_send_event_to_main(RIL_INDICATE_DEVICE_DISCONNECTED);
|
||||
QmiThreadRecvQMI(NULL); // main thread may pending on QmiThreadSendQMI()
|
||||
dbg_time("%s exit", __func__);
|
||||
pthread_exit(NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
const struct qmi_device_ops qmiwwan_qmidev_ops = {
|
||||
.init = QmiWwanInit,
|
||||
.deinit = QmiWwanDeInit,
|
||||
.send = QmiWwanSendQMI,
|
||||
.read = QmiWwanThread,
|
||||
};
|
||||
63
package/fish/fibocom-dial/src/default.script
Normal file
63
package/fish/fibocom-dial/src/default.script
Normal file
@ -0,0 +1,63 @@
|
||||
#!/bin/sh
|
||||
# Busybox udhcpc dispatcher script. Copyright (C) 2009 by Axel Beckert.
|
||||
#
|
||||
# Based on the busybox example scripts and the old udhcp source
|
||||
# package default.* scripts.
|
||||
|
||||
RESOLV_CONF="/etc/resolv.conf"
|
||||
|
||||
case $1 in
|
||||
bound|renew)
|
||||
[ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
|
||||
[ -n "$subnet" ] && NETMASK="netmask $subnet"
|
||||
|
||||
/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
|
||||
|
||||
if [ -n "$router" ]; then
|
||||
echo "$0: Resetting default routes"
|
||||
while /sbin/route del default gw 0.0.0.0 dev $interface; do :; done
|
||||
|
||||
metric=0
|
||||
for i in $router; do
|
||||
/sbin/route add default gw $i dev $interface metric $metric
|
||||
metric=$(($metric + 1))
|
||||
done
|
||||
fi
|
||||
|
||||
# Update resolver configuration file
|
||||
R=""
|
||||
[ -n "$domain" ] && R="domain $domain
|
||||
"
|
||||
for i in $dns; do
|
||||
echo "$0: Adding DNS $i"
|
||||
R="${R}nameserver $i
|
||||
"
|
||||
done
|
||||
|
||||
if [ -x /sbin/resolvconf ]; then
|
||||
echo -n "$R" | resolvconf -a "${interface}.udhcpc"
|
||||
else
|
||||
echo -n "$R" > "$RESOLV_CONF"
|
||||
fi
|
||||
;;
|
||||
|
||||
deconfig)
|
||||
if [ -x /sbin/resolvconf ]; then
|
||||
resolvconf -d "${interface}.udhcpc"
|
||||
fi
|
||||
/sbin/ifconfig $interface 0.0.0.0
|
||||
;;
|
||||
|
||||
leasefail)
|
||||
echo "$0: Lease failed: $message"
|
||||
;;
|
||||
|
||||
nak)
|
||||
echo "$0: Received a NAK: $message"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "$0: Unknown udhcpc command: $1";
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
1331
package/fish/fibocom-dial/src/fibo_qmimsg_server.c
Normal file
1331
package/fish/fibocom-dial/src/fibo_qmimsg_server.c
Normal file
File diff suppressed because it is too large
Load Diff
28
package/fish/fibocom-dial/src/libmnl/README
Normal file
28
package/fish/fibocom-dial/src/libmnl/README
Normal file
@ -0,0 +1,28 @@
|
||||
= What is libmnl? =
|
||||
|
||||
libmnl is a minimalistic user-space library oriented to Netlink developers.
|
||||
There are a lot of common tasks in parsing, validating, constructing of
|
||||
both the Netlink header and TLVs that are repetitive and easy to get wrong.
|
||||
This library aims to provide simple helpers that allows you to re-use code
|
||||
and to avoid re-inventing the wheel. The main features of this library are:
|
||||
|
||||
* Small: the shared library requires around 30KB for an x86-based computer.
|
||||
* Simple: this library avoids complexity and elaborated abstractions that
|
||||
tend to hide Netlink details.
|
||||
* Easy to use: the library simplifies the work for Netlink-wise developers.
|
||||
It provides functions to make socket handling, message building, validating,
|
||||
parsing and sequence tracking, easier.
|
||||
* Easy to re-use: you can use the library to build your own abstraction layer
|
||||
on top of this library.
|
||||
* Decoupling: the interdependency of the main bricks that compose the library
|
||||
is reduced, i.e. the library provides many helpers, but the programmer is not
|
||||
forced to use them.
|
||||
|
||||
= Example files =
|
||||
|
||||
You can find several example files under examples/ that you can compile by
|
||||
invoking `make check'.
|
||||
|
||||
--
|
||||
08/sep/2010
|
||||
Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
722
package/fish/fibocom-dial/src/libmnl/attr.c
Normal file
722
package/fish/fibocom-dial/src/libmnl/attr.c
Normal file
@ -0,0 +1,722 @@
|
||||
/*
|
||||
* (C) 2008-2012 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <limits.h> /* for INT_MAX */
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libmnl.h"
|
||||
|
||||
/**
|
||||
* \defgroup attr Netlink attribute helpers
|
||||
*
|
||||
* Netlink Type-Length-Value (TLV) attribute:
|
||||
* \verbatim
|
||||
|<-- 2 bytes -->|<-- 2 bytes -->|<-- variable -->|
|
||||
-------------------------------------------------
|
||||
| length | type | value |
|
||||
-------------------------------------------------
|
||||
|<--------- header ------------>|<-- payload --->|
|
||||
\endverbatim
|
||||
* The payload of the Netlink message contains sequences of attributes that are
|
||||
* expressed in TLV format.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_attr_get_type - get type of netlink attribute
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute type.
|
||||
*/
|
||||
uint16_t mnl_attr_get_type(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_type & NLA_TYPE_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_len - get length of netlink attribute
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute length that is the attribute header
|
||||
* plus the attribute payload.
|
||||
*/
|
||||
uint16_t mnl_attr_get_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_payload_len - get the attribute payload-value length
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the attribute payload-value length.
|
||||
*/
|
||||
uint16_t mnl_attr_get_payload_len(const struct nlattr *attr)
|
||||
{
|
||||
return attr->nla_len - MNL_ATTR_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_payload - get pointer to the attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function return a pointer to the attribute payload.
|
||||
*/
|
||||
void *mnl_attr_get_payload(const struct nlattr *attr)
|
||||
{
|
||||
return (void *)attr + MNL_ATTR_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_ok - check if there is room for an attribute in a buffer
|
||||
* \param attr attribute that we want to check if there is room for
|
||||
* \param len remaining bytes in a buffer that contains the attribute
|
||||
*
|
||||
* This function is used to check that a buffer, which is supposed to contain
|
||||
* an attribute, has enough room for the attribute that it stores, i.e. this
|
||||
* function can be used to verify that an attribute is neither malformed nor
|
||||
* truncated.
|
||||
*
|
||||
* This function does not set errno in case of error since it is intended
|
||||
* for iterations. Thus, it returns true on success and false on error.
|
||||
*
|
||||
* The len parameter may be negative in the case of malformed messages during
|
||||
* attribute iteration, that is why we use a signed integer.
|
||||
*/
|
||||
bool mnl_attr_ok(const struct nlattr *attr, int len)
|
||||
{
|
||||
return len >= (int)sizeof(struct nlattr) &&
|
||||
attr->nla_len >= sizeof(struct nlattr) &&
|
||||
(int)attr->nla_len <= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_next - get the next attribute in the payload of a netlink message
|
||||
* \param attr pointer to the current attribute
|
||||
*
|
||||
* This function returns a pointer to the next attribute after the one passed
|
||||
* as parameter. You have to use mnl_attr_ok() to ensure that the next
|
||||
* attribute is valid.
|
||||
*/
|
||||
struct nlattr *mnl_attr_next(const struct nlattr *attr)
|
||||
{
|
||||
return (struct nlattr *)((void *)attr + MNL_ALIGN(attr->nla_len));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_type_valid - check if the attribute type is valid
|
||||
* \param attr pointer to attribute to be checked
|
||||
* \param max maximum attribute type
|
||||
*
|
||||
* This function allows to check if the attribute type is higher than the
|
||||
* maximum supported type. If the attribute type is invalid, this function
|
||||
* returns -1 and errno is explicitly set. On success, this function returns 1.
|
||||
*
|
||||
* Strict attribute checking in user-space is not a good idea since you may
|
||||
* run an old application with a newer kernel that supports new attributes.
|
||||
* This leads to backward compatibility breakages in user-space. Better check
|
||||
* if you support an attribute, if not, skip it.
|
||||
*/
|
||||
int mnl_attr_type_valid(const struct nlattr *attr, uint16_t max)
|
||||
{
|
||||
if (mnl_attr_get_type(attr) > max) {
|
||||
errno = EOPNOTSUPP;
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int __mnl_attr_validate(const struct nlattr *attr,
|
||||
enum mnl_attr_data_type type, size_t exp_len)
|
||||
{
|
||||
uint16_t attr_len = mnl_attr_get_payload_len(attr);
|
||||
const char *attr_data = mnl_attr_get_payload(attr);
|
||||
|
||||
if (attr_len < exp_len) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
switch(type) {
|
||||
case MNL_TYPE_FLAG:
|
||||
if (attr_len > 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_NUL_STRING:
|
||||
if (attr_len == 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
if (attr_data[attr_len-1] != '\0') {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_STRING:
|
||||
if (attr_len == 0) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case MNL_TYPE_NESTED:
|
||||
/* empty nested attributes are OK. */
|
||||
if (attr_len == 0)
|
||||
break;
|
||||
/* if not empty, they must contain one header, eg. flag */
|
||||
if (attr_len < MNL_ATTR_HDRLEN) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* make gcc happy. */
|
||||
break;
|
||||
}
|
||||
if (exp_len && attr_len > exp_len) {
|
||||
errno = ERANGE;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const size_t mnl_attr_data_type_len[MNL_TYPE_MAX] = {
|
||||
[MNL_TYPE_U8] = sizeof(uint8_t),
|
||||
[MNL_TYPE_U16] = sizeof(uint16_t),
|
||||
[MNL_TYPE_U32] = sizeof(uint32_t),
|
||||
[MNL_TYPE_U64] = sizeof(uint64_t),
|
||||
[MNL_TYPE_MSECS] = sizeof(uint64_t),
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_attr_validate - validate netlink attribute (simplified version)
|
||||
* \param attr pointer to netlink attribute that we want to validate
|
||||
* \param type data type (see enum mnl_attr_data_type)
|
||||
*
|
||||
* The validation is based on the data type. Specifically, it checks that
|
||||
* integers (u8, u16, u32 and u64) have enough room for them. This function
|
||||
* returns -1 in case of error, and errno is explicitly set.
|
||||
*/
|
||||
int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type)
|
||||
{
|
||||
int exp_len;
|
||||
|
||||
if (type >= MNL_TYPE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
exp_len = mnl_attr_data_type_len[type];
|
||||
return __mnl_attr_validate(attr, type, exp_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_validate2 - validate netlink attribute (extended version)
|
||||
* \param attr pointer to netlink attribute that we want to validate
|
||||
* \param type attribute type (see enum mnl_attr_data_type)
|
||||
* \param exp_len expected attribute data size
|
||||
*
|
||||
* This function allows to perform a more accurate validation for attributes
|
||||
* whose size is variable. If the size of the attribute is not what we expect,
|
||||
* this functions returns -1 and errno is explicitly set.
|
||||
*/
|
||||
int mnl_attr_validate2(const struct nlattr *attr,
|
||||
enum mnl_attr_data_type type,
|
||||
size_t exp_len)
|
||||
{
|
||||
if (type >= MNL_TYPE_MAX) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return __mnl_attr_validate(attr, type, exp_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_parse - parse attributes
|
||||
* \param nlh pointer to netlink message
|
||||
* \param offset offset to start parsing from (if payload is after any header)
|
||||
* \param cb callback function that is called for each attribute
|
||||
* \param data pointer to data that is passed to the callback function
|
||||
*
|
||||
* This function allows to iterate over the sequence of attributes that compose
|
||||
* the Netlink message. You can then put the attribute in an array as it
|
||||
* usually happens at this stage or you can use any other data structure (such
|
||||
* as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int mnl_attr_parse(const struct nlmsghdr *nlh,
|
||||
unsigned int offset, mnl_attr_cb_t cb,
|
||||
void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each(attr, nlh, offset)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_parse_nested - parse attributes inside a nest
|
||||
* \param nested pointer to netlink attribute that contains a nest
|
||||
* \param cb callback function that is called for each attribute in the nest
|
||||
* \param data pointer to data passed to the callback function
|
||||
*
|
||||
* This function allows to iterate over the sequence of attributes that compose
|
||||
* the Netlink message. You can then put the attribute in an array as it
|
||||
* usually happens at this stage or you can use any other data structure (such
|
||||
* as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int mnl_attr_parse_nested(const struct nlattr *nested,
|
||||
mnl_attr_cb_t cb, void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each_nested(attr, nested)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_parse_payload - parse attributes in payload of Netlink message
|
||||
* \param payload pointer to payload of the Netlink message
|
||||
* \param payload_len payload length that contains the attributes
|
||||
* \param cb callback function that is called for each attribute
|
||||
* \param data pointer to data that is passed to the callback function
|
||||
*
|
||||
* This function takes a pointer to the area that contains the attributes,
|
||||
* commonly known as the payload of the Netlink message. Thus, you have to
|
||||
* pass a pointer to the Netlink message payload, instead of the entire
|
||||
* message.
|
||||
*
|
||||
* This function allows you to iterate over the sequence of attributes that are
|
||||
* located at some payload offset. You can then put the attributes in one array
|
||||
* as usual, or you can use any other data structure (such as lists or trees).
|
||||
*
|
||||
* This function propagates the return value of the callback, which can be
|
||||
* MNL_CB_ERROR, MNL_CB_OK or MNL_CB_STOP.
|
||||
*/
|
||||
int mnl_attr_parse_payload(const void *payload,
|
||||
size_t payload_len,
|
||||
mnl_attr_cb_t cb, void *data)
|
||||
{
|
||||
int ret = MNL_CB_OK;
|
||||
const struct nlattr *attr;
|
||||
|
||||
mnl_attr_for_each_payload(payload, payload_len)
|
||||
if ((ret = cb(attr, data)) <= MNL_CB_STOP)
|
||||
return ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u8 - returns 8-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 8-bit value of the attribute payload.
|
||||
*/
|
||||
uint8_t mnl_attr_get_u8(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint8_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u16 - returns 16-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 16-bit value of the attribute payload.
|
||||
*/
|
||||
uint16_t mnl_attr_get_u16(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint16_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u32 - returns 32-bit unsigned integer attribute payload
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 32-bit value of the attribute payload.
|
||||
*/
|
||||
uint32_t mnl_attr_get_u32(const struct nlattr *attr)
|
||||
{
|
||||
return *((uint32_t *)mnl_attr_get_payload(attr));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_u64 - returns 64-bit unsigned integer attribute.
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the 64-bit value of the attribute payload. This
|
||||
* function is align-safe, since accessing 64-bit Netlink attributes is a
|
||||
* common source of alignment issues.
|
||||
*/
|
||||
uint64_t mnl_attr_get_u64(const struct nlattr *attr)
|
||||
{
|
||||
uint64_t tmp;
|
||||
memcpy(&tmp, mnl_attr_get_payload(attr), sizeof(tmp));
|
||||
return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_get_str - returns pointer to string attribute.
|
||||
* \param attr pointer to netlink attribute
|
||||
*
|
||||
* This function returns the payload of string attribute value.
|
||||
*/
|
||||
const char *mnl_attr_get_str(const struct nlattr *attr)
|
||||
{
|
||||
return mnl_attr_get_payload(attr);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put - add an attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type that you want to add
|
||||
* \param len netlink attribute payload length
|
||||
* \param data pointer to the data that will be stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type,
|
||||
size_t len, const void *data)
|
||||
{
|
||||
struct nlattr *attr = mnl_nlmsg_get_payload_tail(nlh);
|
||||
uint16_t payload_len = MNL_ALIGN(sizeof(struct nlattr)) + len;
|
||||
int pad;
|
||||
|
||||
attr->nla_type = type;
|
||||
attr->nla_len = payload_len;
|
||||
memcpy(mnl_attr_get_payload(attr), data, len);
|
||||
pad = MNL_ALIGN(len) - len;
|
||||
if (pad > 0)
|
||||
memset(mnl_attr_get_payload(attr) + len, 0, pad);
|
||||
|
||||
nlh->nlmsg_len += MNL_ALIGN(payload_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u8 - add 8-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 8-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type,
|
||||
uint8_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint8_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u16 - add 16-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 16-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type,
|
||||
uint16_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint16_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u32 - add 32-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 32-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type,
|
||||
uint32_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint32_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u64 - add 64-bit unsigned integer attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data 64-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type,
|
||||
uint64_t data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, sizeof(uint64_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_str - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type,
|
||||
const char *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_strz - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function is similar to mnl_attr_put_str, but it includes the
|
||||
* NUL/zero ('\0') terminator at the end of the string.
|
||||
*
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type,
|
||||
const char *data)
|
||||
{
|
||||
mnl_attr_put(nlh, type, strlen(data)+1, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_start - start an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
*
|
||||
* This function adds the attribute header that identifies the beginning of
|
||||
* an attribute nest. This function always returns a valid pointer to the
|
||||
* beginning of the nest.
|
||||
*/
|
||||
struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh,
|
||||
uint16_t type)
|
||||
{
|
||||
struct nlattr *start = mnl_nlmsg_get_payload_tail(nlh);
|
||||
|
||||
/* set start->nla_len in mnl_attr_nest_end() */
|
||||
start->nla_type = NLA_F_NESTED | type;
|
||||
nlh->nlmsg_len += MNL_ALIGN(sizeof(struct nlattr));
|
||||
|
||||
return start;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_check - add an attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type that you want to add
|
||||
* \param len netlink attribute payload length
|
||||
* \param data pointer to the data that will be stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, size_t len,
|
||||
const void *data)
|
||||
{
|
||||
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN + MNL_ALIGN(len) > buflen)
|
||||
return false;
|
||||
mnl_attr_put(nlh, type, len, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u8_check - add 8-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 8-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint8_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint8_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u16_check - add 16-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 16-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint16_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint16_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u32_check - add 32-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 32-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint32_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint32_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_u64_check - add 64-bit unsigned int attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data 64-bit unsigned integer data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, uint64_t data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, sizeof(uint64_t), &data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_str_check - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
* This function updates the length field of the Netlink message (nlmsg_len)
|
||||
* by adding the size (header + payload) of the new attribute.
|
||||
*/
|
||||
bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, const char *data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, strlen(data), data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_put_strz_check - add string attribute to netlink message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param type netlink attribute type
|
||||
* \param data pointer to string data that is stored by the new attribute
|
||||
*
|
||||
* This function is similar to mnl_attr_put_str, but it includes the
|
||||
* NUL/zero ('\0') terminator at the end of the string.
|
||||
*
|
||||
* This function first checks that the data can be added to the message
|
||||
* (fits into the buffer) and then updates the length field of the Netlink
|
||||
* message (nlmsg_len) by adding the size (header + payload) of the new
|
||||
* attribute. The function returns true if the attribute could be added
|
||||
* to the message, otherwise false is returned.
|
||||
*/
|
||||
bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen,
|
||||
uint16_t type, const char *data)
|
||||
{
|
||||
return mnl_attr_put_check(nlh, buflen, type, strlen(data)+1, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_start_check - start an attribute nest
|
||||
* \param buflen size of buffer which stores the message
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param type netlink attribute type
|
||||
*
|
||||
* This function adds the attribute header that identifies the beginning of
|
||||
* an attribute nest. If the nested attribute cannot be added then NULL,
|
||||
* otherwise valid pointer to the beginning of the nest is returned.
|
||||
*/
|
||||
struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh,
|
||||
size_t buflen,
|
||||
uint16_t type)
|
||||
{
|
||||
if (nlh->nlmsg_len + MNL_ATTR_HDRLEN > buflen)
|
||||
return NULL;
|
||||
return mnl_attr_nest_start(nlh, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_end - end an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param start pointer to the attribute nest returned by mnl_attr_nest_start()
|
||||
*
|
||||
* This function updates the attribute header that identifies the nest.
|
||||
*/
|
||||
void mnl_attr_nest_end(struct nlmsghdr *nlh,
|
||||
struct nlattr *start)
|
||||
{
|
||||
start->nla_len = mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_attr_nest_cancel - cancel an attribute nest
|
||||
* \param nlh pointer to the netlink message
|
||||
* \param start pointer to the attribute nest returned by mnl_attr_nest_start()
|
||||
*
|
||||
* This function updates the attribute header that identifies the nest.
|
||||
*/
|
||||
void mnl_attr_nest_cancel(struct nlmsghdr *nlh,
|
||||
struct nlattr *start)
|
||||
{
|
||||
nlh->nlmsg_len -= mnl_nlmsg_get_payload_tail(nlh) - (void *)start;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
167
package/fish/fibocom-dial/src/libmnl/callback.c
Normal file
167
package/fish/fibocom-dial/src/libmnl/callback.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include "libmnl.h"
|
||||
|
||||
static int mnl_cb_noop(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int mnl_cb_error(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
|
||||
|
||||
if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr))) {
|
||||
errno = EBADMSG;
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
/* Netlink subsystems returns the errno value with different signess */
|
||||
if (err->error < 0)
|
||||
errno = -err->error;
|
||||
else
|
||||
errno = err->error;
|
||||
|
||||
return err->error == 0 ? MNL_CB_STOP : MNL_CB_ERROR;
|
||||
}
|
||||
|
||||
static int mnl_cb_stop(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
return MNL_CB_STOP;
|
||||
}
|
||||
|
||||
static const mnl_cb_t default_cb_array[NLMSG_MIN_TYPE] = {
|
||||
[NLMSG_NOOP] = mnl_cb_noop,
|
||||
[NLMSG_ERROR] = mnl_cb_error,
|
||||
[NLMSG_DONE] = mnl_cb_stop,
|
||||
[NLMSG_OVERRUN] = mnl_cb_noop,
|
||||
};
|
||||
|
||||
static inline int __mnl_cb_run(const void *buf, size_t numbytes,
|
||||
unsigned int seq, unsigned int portid,
|
||||
mnl_cb_t cb_data, void *data,
|
||||
const mnl_cb_t *cb_ctl_array,
|
||||
unsigned int cb_ctl_array_len)
|
||||
{
|
||||
int ret = MNL_CB_OK, len = numbytes;
|
||||
const struct nlmsghdr *nlh = buf;
|
||||
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
/* check message source */
|
||||
if (!mnl_nlmsg_portid_ok(nlh, portid)) {
|
||||
errno = ESRCH;
|
||||
return -1;
|
||||
}
|
||||
/* perform sequence tracking */
|
||||
if (!mnl_nlmsg_seq_ok(nlh, seq)) {
|
||||
errno = EPROTO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* dump was interrupted */
|
||||
if (nlh->nlmsg_flags & NLM_F_DUMP_INTR) {
|
||||
errno = EINTR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* netlink data message handling */
|
||||
if (nlh->nlmsg_type >= NLMSG_MIN_TYPE) {
|
||||
if (cb_data){
|
||||
ret = cb_data(nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
} else if (nlh->nlmsg_type < cb_ctl_array_len) {
|
||||
if (cb_ctl_array && cb_ctl_array[nlh->nlmsg_type]) {
|
||||
ret = cb_ctl_array[nlh->nlmsg_type](nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
} else if (default_cb_array[nlh->nlmsg_type]) {
|
||||
ret = default_cb_array[nlh->nlmsg_type](nlh, data);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
goto out;
|
||||
}
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* \defgroup callback Callback helpers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_cb_run2 - callback runqueue for netlink messages
|
||||
* \param buf buffer that contains the netlink messages
|
||||
* \param numbytes number of bytes stored in the buffer
|
||||
* \param seq sequence number that we expect to receive
|
||||
* \param portid Netlink PortID that we expect to receive
|
||||
* \param cb_data callback handler for data messages
|
||||
* \param data pointer to data that will be passed to the data callback handler
|
||||
* \param cb_ctl_array array of custom callback handlers from control messages
|
||||
* \param cb_ctl_array_len array length of custom control callback handlers
|
||||
*
|
||||
* You can set the cb_ctl_array to NULL if you want to use the default control
|
||||
* callback handlers, in that case, the parameter cb_ctl_array_len is not
|
||||
* checked.
|
||||
*
|
||||
* Your callback may return three possible values:
|
||||
* - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
|
||||
* - MNL_CB_STOP (=0): stop callback runqueue.
|
||||
* - MNL_CB_OK (>=1): no problem has occurred.
|
||||
*
|
||||
* This function propagates the callback return value. On error, it returns
|
||||
* -1 and errno is explicitly set. If the portID is not the expected, errno
|
||||
* is set to ESRCH. If the sequence number is not the expected, errno is set
|
||||
* to EPROTO. If the dump was interrupted, errno is set to EINTR and you should
|
||||
* request a new fresh dump again.
|
||||
*/
|
||||
int mnl_cb_run2(const void *buf, size_t numbytes,
|
||||
unsigned int seq, unsigned int portid,
|
||||
mnl_cb_t cb_data, void *data,
|
||||
const mnl_cb_t *cb_ctl_array,
|
||||
unsigned int cb_ctl_array_len)
|
||||
{
|
||||
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data,
|
||||
cb_ctl_array, cb_ctl_array_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_cb_run - callback runqueue for netlink messages (simplified version)
|
||||
* \param buf buffer that contains the netlink messages
|
||||
* \param numbytes number of bytes stored in the buffer
|
||||
* \param seq sequence number that we expect to receive
|
||||
* \param portid Netlink PortID that we expect to receive
|
||||
* \param cb_data callback handler for data messages
|
||||
* \param data pointer to data that will be passed to the data callback handler
|
||||
*
|
||||
* This function is like mnl_cb_run2() but it does not allow you to set
|
||||
* the control callback handlers.
|
||||
*
|
||||
* Your callback may return three possible values:
|
||||
* - MNL_CB_ERROR (<=-1): an error has occurred. Stop callback runqueue.
|
||||
* - MNL_CB_STOP (=0): stop callback runqueue.
|
||||
* - MNL_CB_OK (>=1): no problems has occurred.
|
||||
*
|
||||
* This function propagates the callback return value.
|
||||
*/
|
||||
int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data)
|
||||
{
|
||||
return __mnl_cb_run(buf, numbytes, seq, portid, cb_data, data, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
5
package/fish/fibocom-dial/src/libmnl/dhcp/dhcp.h
Normal file
5
package/fish/fibocom-dial/src/libmnl/dhcp/dhcp.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef __DHCP_H__
|
||||
#define __DHCP_H__
|
||||
|
||||
int do_dhcp(char *iname);
|
||||
#endif //__DHCP_H__
|
||||
515
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpclient.c
Normal file
515
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpclient.c
Normal file
@ -0,0 +1,515 @@
|
||||
/*
|
||||
* Copyright 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <net/if.h>
|
||||
|
||||
#include "../ifutils.h"
|
||||
#include "dhcpmsg.h"
|
||||
#include "packet.h"
|
||||
|
||||
#define VERBOSE 2
|
||||
|
||||
static int verbose = 1;
|
||||
static char errmsg[2048];
|
||||
|
||||
typedef unsigned long long msecs_t;
|
||||
#if VERBOSE
|
||||
void dump_dhcp_msg();
|
||||
#endif
|
||||
|
||||
msecs_t get_msecs(void)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
|
||||
return 0;
|
||||
} else {
|
||||
return (((msecs_t) ts.tv_sec) * ((msecs_t) 1000)) +
|
||||
(((msecs_t) ts.tv_nsec) / ((msecs_t) 1000000));
|
||||
}
|
||||
}
|
||||
|
||||
void printerr(char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vsnprintf(errmsg, sizeof(errmsg), fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
printf("%s\n", errmsg);
|
||||
}
|
||||
|
||||
const char *dhcp_lasterror()
|
||||
{
|
||||
return errmsg;
|
||||
}
|
||||
|
||||
int fatal(const char *reason)
|
||||
{
|
||||
printerr("%s: %s\n", reason, strerror(errno));
|
||||
return -1;
|
||||
// exit(1);
|
||||
}
|
||||
|
||||
typedef struct dhcp_info dhcp_info;
|
||||
|
||||
struct dhcp_info {
|
||||
uint32_t type;
|
||||
|
||||
uint32_t ipaddr;
|
||||
uint32_t gateway;
|
||||
uint32_t prefixLength;
|
||||
|
||||
uint32_t dns1;
|
||||
uint32_t dns2;
|
||||
|
||||
uint32_t serveraddr;
|
||||
uint32_t lease;
|
||||
};
|
||||
|
||||
dhcp_info last_good_info;
|
||||
|
||||
void get_dhcp_info(uint32_t *ipaddr, uint32_t *gateway, uint32_t *prefixLength,
|
||||
uint32_t *dns1, uint32_t *dns2, uint32_t *server,
|
||||
uint32_t *lease)
|
||||
{
|
||||
*ipaddr = last_good_info.ipaddr;
|
||||
*gateway = last_good_info.gateway;
|
||||
*prefixLength = last_good_info.prefixLength;
|
||||
*dns1 = last_good_info.dns1;
|
||||
*dns2 = last_good_info.dns2;
|
||||
*server = last_good_info.serveraddr;
|
||||
*lease = last_good_info.lease;
|
||||
}
|
||||
|
||||
static int dhcp_configure(const char *ifname, dhcp_info *info)
|
||||
{
|
||||
last_good_info = *info;
|
||||
return if_set_network_v4(ifname, info->ipaddr, info->prefixLength, info->gateway,
|
||||
info->dns1, info->dns2);
|
||||
}
|
||||
|
||||
static const char *dhcp_type_to_name(uint32_t type)
|
||||
{
|
||||
switch(type) {
|
||||
case DHCPDISCOVER: return "discover";
|
||||
case DHCPOFFER: return "offer";
|
||||
case DHCPREQUEST: return "request";
|
||||
case DHCPDECLINE: return "decline";
|
||||
case DHCPACK: return "ack";
|
||||
case DHCPNAK: return "nak";
|
||||
case DHCPRELEASE: return "release";
|
||||
case DHCPINFORM: return "inform";
|
||||
default: return "???";
|
||||
}
|
||||
}
|
||||
|
||||
void dump_dhcp_info(dhcp_info *info)
|
||||
{
|
||||
char addr[20], gway[20];
|
||||
printf("--- dhcp %s (%d) ---\n",
|
||||
dhcp_type_to_name(info->type), info->type);
|
||||
strcpy(addr, ipaddr_to_string_v4(info->ipaddr));
|
||||
strcpy(gway, ipaddr_to_string_v4(info->gateway));
|
||||
printf("ip %s gw %s prefixLength %d\n", addr, gway, info->prefixLength);
|
||||
if (info->dns1) printf("dns1: %s\n", ipaddr_to_string_v4(info->dns1));
|
||||
if (info->dns2) printf("dns2: %s\n", ipaddr_to_string_v4(info->dns2));
|
||||
printf("server %s, lease %d seconds\n",
|
||||
ipaddr_to_string_v4(info->serveraddr), info->lease);
|
||||
}
|
||||
|
||||
|
||||
int decode_dhcp_msg(dhcp_msg *msg, int len, dhcp_info *info)
|
||||
{
|
||||
uint8_t *x;
|
||||
unsigned int opt;
|
||||
int optlen;
|
||||
|
||||
memset(info, 0, sizeof(dhcp_info));
|
||||
if (len < (DHCP_MSG_FIXED_SIZE + 4)) return -1;
|
||||
|
||||
len -= (DHCP_MSG_FIXED_SIZE + 4);
|
||||
|
||||
if (msg->options[0] != OPT_COOKIE1) return -1;
|
||||
if (msg->options[1] != OPT_COOKIE2) return -1;
|
||||
if (msg->options[2] != OPT_COOKIE3) return -1;
|
||||
if (msg->options[3] != OPT_COOKIE4) return -1;
|
||||
|
||||
x = msg->options + 4;
|
||||
|
||||
while (len > 2) {
|
||||
opt = *x++;
|
||||
if (opt == OPT_PAD) {
|
||||
len--;
|
||||
continue;
|
||||
}
|
||||
if (opt == OPT_END) {
|
||||
break;
|
||||
}
|
||||
optlen = *x++;
|
||||
len -= 2;
|
||||
if (optlen > len) {
|
||||
break;
|
||||
}
|
||||
switch(opt) {
|
||||
case OPT_SUBNET_MASK:
|
||||
if (optlen >= 4) {
|
||||
in_addr_t mask;
|
||||
memcpy(&mask, x, 4);
|
||||
info->prefixLength = mask_to_prefix_v4(mask);
|
||||
}
|
||||
break;
|
||||
case OPT_GATEWAY:
|
||||
if (optlen >= 4) memcpy(&info->gateway, x, 4);
|
||||
break;
|
||||
case OPT_DNS:
|
||||
if (optlen >= 4) memcpy(&info->dns1, x + 0, 4);
|
||||
if (optlen >= 8) memcpy(&info->dns2, x + 4, 4);
|
||||
break;
|
||||
case OPT_LEASE_TIME:
|
||||
if (optlen >= 4) {
|
||||
memcpy(&info->lease, x, 4);
|
||||
info->lease = ntohl(info->lease);
|
||||
}
|
||||
break;
|
||||
case OPT_SERVER_ID:
|
||||
if (optlen >= 4) memcpy(&info->serveraddr, x, 4);
|
||||
break;
|
||||
case OPT_MESSAGE_TYPE:
|
||||
info->type = *x;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
x += optlen;
|
||||
len -= optlen;
|
||||
}
|
||||
|
||||
info->ipaddr = msg->yiaddr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if VERBOSE
|
||||
|
||||
static void hex2str(char *buf, size_t buf_size, const unsigned char *array, int len)
|
||||
{
|
||||
int i;
|
||||
char *cp = buf;
|
||||
char *buf_end = buf + buf_size;
|
||||
for (i = 0; i < len; i++) {
|
||||
cp += snprintf(cp, buf_end - cp, " %02x ", array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void dump_dhcp_msg(dhcp_msg *msg, int len)
|
||||
{
|
||||
unsigned char *x;
|
||||
unsigned int n,c;
|
||||
int optsz;
|
||||
const char *name;
|
||||
char buf[2048];
|
||||
|
||||
if (len < DHCP_MSG_FIXED_SIZE) {
|
||||
printf("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
len -= DHCP_MSG_FIXED_SIZE;
|
||||
|
||||
if (msg->op == OP_BOOTREQUEST)
|
||||
name = "BOOTREQUEST";
|
||||
else if (msg->op == OP_BOOTREPLY)
|
||||
name = "BOOTREPLY";
|
||||
else
|
||||
name = "????";
|
||||
|
||||
c = msg->hlen > 16 ? 16 : msg->hlen;
|
||||
hex2str(buf, sizeof(buf), msg->chaddr, c);
|
||||
|
||||
for (n = 0; n < 64; n++) {
|
||||
unsigned char x = msg->sname[n];
|
||||
if ((x < ' ') || (x > 127)) {
|
||||
if (x == 0) break;
|
||||
msg->sname[n] = '.';
|
||||
}
|
||||
}
|
||||
msg->sname[63] = 0;
|
||||
|
||||
for (n = 0; n < 128; n++) {
|
||||
unsigned char x = msg->file[n];
|
||||
if ((x < ' ') || (x > 127)) {
|
||||
if (x == 0) break;
|
||||
msg->file[n] = '.';
|
||||
}
|
||||
}
|
||||
msg->file[127] = 0;
|
||||
|
||||
if (len < 4) return;
|
||||
len -= 4;
|
||||
x = msg->options + 4;
|
||||
|
||||
while (len > 2) {
|
||||
if (*x == 0) {
|
||||
x++;
|
||||
len--;
|
||||
continue;
|
||||
}
|
||||
if (*x == OPT_END) {
|
||||
break;
|
||||
}
|
||||
len -= 2;
|
||||
optsz = x[1];
|
||||
if (optsz > len) break;
|
||||
if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
|
||||
if ((unsigned int)optsz < sizeof(buf) - 1) {
|
||||
n = optsz;
|
||||
} else {
|
||||
n = sizeof(buf) - 1;
|
||||
}
|
||||
memcpy(buf, &x[2], n);
|
||||
buf[n] = '\0';
|
||||
} else {
|
||||
hex2str(buf, sizeof(buf), &x[2], optsz);
|
||||
}
|
||||
if (x[0] == OPT_MESSAGE_TYPE)
|
||||
name = dhcp_type_to_name(x[2]);
|
||||
else
|
||||
name = NULL;
|
||||
len -= optsz;
|
||||
x = x + optsz + 2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int send_message(int sock, int if_index, dhcp_msg *msg, int size)
|
||||
{
|
||||
#if VERBOSE > 1
|
||||
dump_dhcp_msg(msg, size);
|
||||
#endif
|
||||
return send_packet(sock, if_index, msg, size, INADDR_ANY, INADDR_BROADCAST,
|
||||
PORT_BOOTP_CLIENT, PORT_BOOTP_SERVER);
|
||||
}
|
||||
|
||||
static int is_valid_reply(dhcp_msg *msg, dhcp_msg *reply, int sz)
|
||||
{
|
||||
if (sz < DHCP_MSG_FIXED_SIZE) {
|
||||
if (verbose) printf("Wrong size %d != %d\n", sz, DHCP_MSG_FIXED_SIZE);
|
||||
return 0;
|
||||
}
|
||||
if (reply->op != OP_BOOTREPLY) {
|
||||
if (verbose) printf("Wrong Op %d != %d\n", reply->op, OP_BOOTREPLY);
|
||||
return 0;
|
||||
}
|
||||
if (reply->xid != msg->xid) {
|
||||
if (verbose) printf("Wrong Xid 0x%x != 0x%x\n", ntohl(reply->xid),
|
||||
ntohl(msg->xid));
|
||||
return 0;
|
||||
}
|
||||
if (reply->htype != msg->htype) {
|
||||
if (verbose) printf("Wrong Htype %d != %d\n", reply->htype, msg->htype);
|
||||
return 0;
|
||||
}
|
||||
if (reply->hlen != msg->hlen) {
|
||||
if (verbose) printf("Wrong Hlen %d != %d\n", reply->hlen, msg->hlen);
|
||||
return 0;
|
||||
}
|
||||
if (memcmp(msg->chaddr, reply->chaddr, msg->hlen)) {
|
||||
if (verbose) printf("Wrong chaddr %x != %x\n", *(reply->chaddr),*(msg->chaddr));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define STATE_SELECTING 1
|
||||
#define STATE_REQUESTING 2
|
||||
|
||||
#define TIMEOUT_INITIAL 4000
|
||||
#define TIMEOUT_MAX 32000
|
||||
|
||||
int dhcp_init_ifc(const char *ifname)
|
||||
{
|
||||
dhcp_msg discover_msg;
|
||||
dhcp_msg request_msg;
|
||||
dhcp_msg reply;
|
||||
dhcp_msg *msg;
|
||||
dhcp_info info;
|
||||
int s, r, size;
|
||||
int valid_reply;
|
||||
uint32_t xid;
|
||||
unsigned char hwaddr[6];
|
||||
struct pollfd pfd;
|
||||
unsigned int state;
|
||||
unsigned int timeout;
|
||||
int if_index;
|
||||
|
||||
xid = (uint32_t) get_msecs();
|
||||
|
||||
if (if_get_hwaddr(ifname, hwaddr)) {
|
||||
return fatal("cannot obtain interface address");
|
||||
}
|
||||
if ((if_index = if_nametoindex(ifname)) == 0) {
|
||||
return fatal("cannot obtain interface index");
|
||||
}
|
||||
|
||||
s = open_raw_socket(ifname, hwaddr, if_index);
|
||||
|
||||
timeout = TIMEOUT_INITIAL;
|
||||
state = STATE_SELECTING;
|
||||
info.type = 0;
|
||||
goto transmit;
|
||||
|
||||
for (;;) {
|
||||
pfd.fd = s;
|
||||
pfd.events = POLLIN;
|
||||
pfd.revents = 0;
|
||||
r = poll(&pfd, 1, timeout);
|
||||
|
||||
if (r == 0) {
|
||||
#if VERBOSE
|
||||
printerr("TIMEOUT\n");
|
||||
#endif
|
||||
if (timeout >= TIMEOUT_MAX) {
|
||||
printerr("timed out\n");
|
||||
if ( info.type == DHCPOFFER ) {
|
||||
printerr("no acknowledgement from DHCP server\nconfiguring %s with offered parameters\n", ifname);
|
||||
return dhcp_configure(ifname, &info);
|
||||
}
|
||||
errno = ETIME;
|
||||
close(s);
|
||||
return -1;
|
||||
}
|
||||
timeout = timeout * 2;
|
||||
|
||||
transmit:
|
||||
size = 0;
|
||||
msg = NULL;
|
||||
switch(state) {
|
||||
case STATE_SELECTING:
|
||||
msg = &discover_msg;
|
||||
size = init_dhcp_discover_msg(msg, hwaddr, xid);
|
||||
break;
|
||||
case STATE_REQUESTING:
|
||||
msg = &request_msg;
|
||||
size = init_dhcp_request_msg(msg, hwaddr, xid, info.ipaddr, info.serveraddr);
|
||||
break;
|
||||
default:
|
||||
r = 0;
|
||||
}
|
||||
if (size != 0) {
|
||||
r = send_message(s, if_index, msg, size);
|
||||
if (r < 0) {
|
||||
printerr("error sending dhcp msg: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
if ((errno == EAGAIN) || (errno == EINTR)) {
|
||||
continue;
|
||||
}
|
||||
return fatal("poll failed");
|
||||
}
|
||||
|
||||
errno = 0;
|
||||
r = receive_packet(s, &reply);
|
||||
if (r < 0) {
|
||||
if (errno != 0) {
|
||||
printf("receive_packet failed (%d): %s", r, strerror(errno));
|
||||
if (errno == ENETDOWN || errno == ENXIO) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
#if VERBOSE > 1
|
||||
dump_dhcp_msg(&reply, r);
|
||||
#endif
|
||||
decode_dhcp_msg(&reply, r, &info);
|
||||
|
||||
if (state == STATE_SELECTING) {
|
||||
valid_reply = is_valid_reply(&discover_msg, &reply, r);
|
||||
} else {
|
||||
valid_reply = is_valid_reply(&request_msg, &reply, r);
|
||||
}
|
||||
if (!valid_reply) {
|
||||
printerr("invalid reply\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (verbose) dump_dhcp_info(&info);
|
||||
|
||||
switch(state) {
|
||||
case STATE_SELECTING:
|
||||
if (info.type == DHCPOFFER) {
|
||||
state = STATE_REQUESTING;
|
||||
timeout = TIMEOUT_INITIAL;
|
||||
xid++;
|
||||
goto transmit;
|
||||
}
|
||||
break;
|
||||
case STATE_REQUESTING:
|
||||
if (info.type == DHCPACK) {
|
||||
printerr("configuring %s\n", ifname);
|
||||
close(s);
|
||||
return dhcp_configure(ifname, &info);
|
||||
} else if (info.type == DHCPNAK) {
|
||||
printerr("configuration request denied\n");
|
||||
close(s);
|
||||
return -1;
|
||||
} else {
|
||||
printerr("ignoring %s message in state %d\n",
|
||||
dhcp_type_to_name(info.type), state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
close(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_dhcp(char *iname)
|
||||
{
|
||||
if (if_set_addr_v4(iname, 0, 32)) {
|
||||
printerr("failed to set ip addr for %s to 0.0.0.0: %s\n", iname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (if_link_up(iname)) {
|
||||
printerr("failed to bring up interface %s: %s\n", iname, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dhcp_init_ifc(iname);
|
||||
}
|
||||
100
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c
Normal file
100
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpmsg.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include "dhcpmsg.h"
|
||||
|
||||
static void *init_dhcp_msg(dhcp_msg *msg, int type, void *hwaddr, uint32_t xid)
|
||||
{
|
||||
uint8_t *x;
|
||||
|
||||
memset(msg, 0, sizeof(dhcp_msg));
|
||||
|
||||
msg->op = OP_BOOTREQUEST;
|
||||
msg->htype = HTYPE_ETHER;
|
||||
msg->hlen = 6;
|
||||
msg->hops = 0;
|
||||
|
||||
msg->flags = htons(FLAGS_BROADCAST);
|
||||
|
||||
msg->xid = xid;
|
||||
|
||||
memcpy(msg->chaddr, hwaddr, 6);
|
||||
|
||||
x = msg->options;
|
||||
|
||||
*x++ = OPT_COOKIE1;
|
||||
*x++ = OPT_COOKIE2;
|
||||
*x++ = OPT_COOKIE3;
|
||||
*x++ = OPT_COOKIE4;
|
||||
|
||||
*x++ = OPT_MESSAGE_TYPE;
|
||||
*x++ = 1;
|
||||
*x++ = type;
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid)
|
||||
{
|
||||
uint8_t *x;
|
||||
|
||||
x = init_dhcp_msg(msg, DHCPDISCOVER, hwaddr, xid);
|
||||
|
||||
*x++ = OPT_PARAMETER_LIST;
|
||||
*x++ = 4;
|
||||
*x++ = OPT_SUBNET_MASK;
|
||||
*x++ = OPT_GATEWAY;
|
||||
*x++ = OPT_DNS;
|
||||
*x++ = OPT_BROADCAST_ADDR;
|
||||
|
||||
*x++ = OPT_END;
|
||||
|
||||
return DHCP_MSG_FIXED_SIZE + (x - msg->options);
|
||||
}
|
||||
|
||||
int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
|
||||
uint32_t ipaddr, uint32_t serveraddr)
|
||||
{
|
||||
uint8_t *x;
|
||||
|
||||
x = init_dhcp_msg(msg, DHCPREQUEST, hwaddr, xid);
|
||||
|
||||
*x++ = OPT_PARAMETER_LIST;
|
||||
*x++ = 4;
|
||||
*x++ = OPT_SUBNET_MASK;
|
||||
*x++ = OPT_GATEWAY;
|
||||
*x++ = OPT_DNS;
|
||||
*x++ = OPT_BROADCAST_ADDR;
|
||||
|
||||
*x++ = OPT_REQUESTED_IP;
|
||||
*x++ = 4;
|
||||
memcpy(x, &ipaddr, 4);
|
||||
x += 4;
|
||||
|
||||
*x++ = OPT_SERVER_ID;
|
||||
*x++ = 4;
|
||||
memcpy(x, &serveraddr, 4);
|
||||
x += 4;
|
||||
|
||||
*x++ = OPT_END;
|
||||
|
||||
return DHCP_MSG_FIXED_SIZE + (x - msg->options);
|
||||
}
|
||||
106
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h
Normal file
106
package/fish/fibocom-dial/src/libmnl/dhcp/dhcpmsg.h
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _WIFI_DHCP_H_
|
||||
#define _WIFI_DHCP_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define PORT_BOOTP_SERVER 67
|
||||
#define PORT_BOOTP_CLIENT 68
|
||||
|
||||
/* RFC 2131 p 9 */
|
||||
typedef struct dhcp_msg dhcp_msg;
|
||||
|
||||
#define OP_BOOTREQUEST 1
|
||||
#define OP_BOOTREPLY 2
|
||||
|
||||
#define FLAGS_BROADCAST 0x8000
|
||||
|
||||
#define HTYPE_ETHER 1
|
||||
|
||||
struct dhcp_msg
|
||||
{
|
||||
uint8_t op; /* BOOTREQUEST / BOOTREPLY */
|
||||
uint8_t htype; /* hw addr type */
|
||||
uint8_t hlen; /* hw addr len */
|
||||
uint8_t hops; /* client set to 0 */
|
||||
|
||||
uint32_t xid; /* transaction id */
|
||||
|
||||
uint16_t secs; /* seconds since start of acq */
|
||||
uint16_t flags;
|
||||
|
||||
uint32_t ciaddr; /* client IP addr */
|
||||
uint32_t yiaddr; /* your (client) IP addr */
|
||||
uint32_t siaddr; /* ip addr of next server */
|
||||
/* (DHCPOFFER and DHCPACK) */
|
||||
uint32_t giaddr; /* relay agent IP addr */
|
||||
|
||||
uint8_t chaddr[16]; /* client hw addr */
|
||||
char sname[64]; /* asciiz server hostname */
|
||||
char file[128]; /* asciiz boot file name */
|
||||
|
||||
uint8_t options[1024]; /* optional parameters */
|
||||
};
|
||||
|
||||
#define DHCP_MSG_FIXED_SIZE 236
|
||||
|
||||
/* first four bytes of options are a cookie to indicate that
|
||||
** the payload are DHCP options as opposed to some other BOOTP
|
||||
** extension.
|
||||
*/
|
||||
#define OPT_COOKIE1 0x63
|
||||
#define OPT_COOKIE2 0x82
|
||||
#define OPT_COOKIE3 0x53
|
||||
#define OPT_COOKIE4 0x63
|
||||
|
||||
/* BOOTP/DHCP options - see RFC 2132 */
|
||||
#define OPT_PAD 0
|
||||
|
||||
#define OPT_SUBNET_MASK 1 /* 4 <ipaddr> */
|
||||
#define OPT_TIME_OFFSET 2 /* 4 <seconds> */
|
||||
#define OPT_GATEWAY 3 /* 4*n <ipaddr> * n */
|
||||
#define OPT_DNS 6 /* 4*n <ipaddr> * n */
|
||||
#define OPT_DOMAIN_NAME 15 /* n <domainnamestring> */
|
||||
#define OPT_BROADCAST_ADDR 28 /* 4 <ipaddr> */
|
||||
|
||||
#define OPT_REQUESTED_IP 50 /* 4 <ipaddr> */
|
||||
#define OPT_LEASE_TIME 51 /* 4 <seconds> */
|
||||
#define OPT_MESSAGE_TYPE 53 /* 1 <msgtype> */
|
||||
#define OPT_SERVER_ID 54 /* 4 <ipaddr> */
|
||||
#define OPT_PARAMETER_LIST 55 /* n <optcode> * n */
|
||||
#define OPT_MESSAGE 56 /* n <errorstring> */
|
||||
#define OPT_CLASS_ID 60 /* n <opaque> */
|
||||
#define OPT_CLIENT_ID 61 /* n <opaque> */
|
||||
#define OPT_END 255
|
||||
|
||||
/* DHCP message types */
|
||||
#define DHCPDISCOVER 1
|
||||
#define DHCPOFFER 2
|
||||
#define DHCPREQUEST 3
|
||||
#define DHCPDECLINE 4
|
||||
#define DHCPACK 5
|
||||
#define DHCPNAK 6
|
||||
#define DHCPRELEASE 7
|
||||
#define DHCPINFORM 8
|
||||
|
||||
int init_dhcp_discover_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid);
|
||||
|
||||
int init_dhcp_request_msg(dhcp_msg *msg, void *hwaddr, uint32_t xid,
|
||||
uint32_t ipaddr, uint32_t serveraddr);
|
||||
|
||||
#endif
|
||||
247
package/fish/fibocom-dial/src/libmnl/dhcp/packet.c
Normal file
247
package/fish/fibocom-dial/src/libmnl/dhcp/packet.c
Normal file
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Copyright 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/uio.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netinet/ip.h>
|
||||
#include <netinet/udp.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "dhcpmsg.h"
|
||||
|
||||
int fatal();
|
||||
|
||||
int open_raw_socket(const char *ifname __attribute__((unused)), uint8_t *hwaddr, int if_index)
|
||||
{
|
||||
int s;
|
||||
struct sockaddr_ll bindaddr;
|
||||
|
||||
if((s = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP))) < 0) {
|
||||
return fatal("socket(PF_PACKET)");
|
||||
}
|
||||
|
||||
memset(&bindaddr, 0, sizeof(bindaddr));
|
||||
bindaddr.sll_family = AF_PACKET;
|
||||
bindaddr.sll_protocol = htons(ETH_P_IP);
|
||||
bindaddr.sll_halen = ETH_ALEN;
|
||||
memcpy(bindaddr.sll_addr, hwaddr, ETH_ALEN);
|
||||
bindaddr.sll_ifindex = if_index;
|
||||
|
||||
if (bind(s, (struct sockaddr *)&bindaddr, sizeof(bindaddr)) < 0) {
|
||||
return fatal("Cannot bind raw socket to interface");
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static uint32_t checksum(void *buffer, unsigned int count, uint32_t startsum)
|
||||
{
|
||||
uint16_t *up = (uint16_t *)buffer;
|
||||
uint32_t sum = startsum;
|
||||
uint32_t upper16;
|
||||
|
||||
while (count > 1) {
|
||||
sum += *up++;
|
||||
count -= 2;
|
||||
}
|
||||
if (count > 0) {
|
||||
sum += (uint16_t) *(uint8_t *)up;
|
||||
}
|
||||
while ((upper16 = (sum >> 16)) != 0) {
|
||||
sum = (sum & 0xffff) + upper16;
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
static uint32_t finish_sum(uint32_t sum)
|
||||
{
|
||||
return ~sum & 0xffff;
|
||||
}
|
||||
|
||||
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
|
||||
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport)
|
||||
{
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
struct iovec iov[3];
|
||||
uint32_t udpsum;
|
||||
uint16_t temp;
|
||||
struct msghdr msghdr;
|
||||
struct sockaddr_ll destaddr;
|
||||
|
||||
ip.version = IPVERSION;
|
||||
ip.ihl = sizeof(ip) >> 2;
|
||||
ip.tos = 0;
|
||||
ip.tot_len = htons(sizeof(ip) + sizeof(udp) + size);
|
||||
ip.id = 0;
|
||||
ip.frag_off = 0;
|
||||
ip.ttl = IPDEFTTL;
|
||||
ip.protocol = IPPROTO_UDP;
|
||||
ip.check = 0;
|
||||
ip.saddr = saddr;
|
||||
ip.daddr = daddr;
|
||||
ip.check = finish_sum(checksum(&ip, sizeof(ip), 0));
|
||||
|
||||
udp.source = htons(sport);
|
||||
udp.dest = htons(dport);
|
||||
udp.len = htons(sizeof(udp) + size);
|
||||
udp.check = 0;
|
||||
|
||||
/* Calculate checksum for pseudo header */
|
||||
udpsum = checksum(&ip.saddr, sizeof(ip.saddr), 0);
|
||||
udpsum = checksum(&ip.daddr, sizeof(ip.daddr), udpsum);
|
||||
temp = htons(IPPROTO_UDP);
|
||||
udpsum = checksum(&temp, sizeof(temp), udpsum);
|
||||
temp = udp.len;
|
||||
udpsum = checksum(&temp, sizeof(temp), udpsum);
|
||||
|
||||
/* Add in the checksum for the udp header */
|
||||
udpsum = checksum(&udp, sizeof(udp), udpsum);
|
||||
|
||||
/* Add in the checksum for the data */
|
||||
udpsum = checksum(msg, size, udpsum);
|
||||
udp.check = finish_sum(udpsum);
|
||||
|
||||
iov[0].iov_base = (char *)&ip;
|
||||
iov[0].iov_len = sizeof(ip);
|
||||
iov[1].iov_base = (char *)&udp;
|
||||
iov[1].iov_len = sizeof(udp);
|
||||
iov[2].iov_base = (char *)msg;
|
||||
iov[2].iov_len = size;
|
||||
memset(&destaddr, 0, sizeof(destaddr));
|
||||
destaddr.sll_family = AF_PACKET;
|
||||
destaddr.sll_protocol = htons(ETH_P_IP);
|
||||
destaddr.sll_ifindex = if_index;
|
||||
destaddr.sll_halen = ETH_ALEN;
|
||||
memcpy(destaddr.sll_addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN);
|
||||
|
||||
msghdr.msg_name = &destaddr;
|
||||
msghdr.msg_namelen = sizeof(destaddr);
|
||||
msghdr.msg_iov = iov;
|
||||
msghdr.msg_iovlen = sizeof(iov) / sizeof(struct iovec);
|
||||
msghdr.msg_flags = 0;
|
||||
msghdr.msg_control = 0;
|
||||
msghdr.msg_controllen = 0;
|
||||
return sendmsg(s, &msghdr, 0);
|
||||
}
|
||||
|
||||
int receive_packet(int s, struct dhcp_msg *msg)
|
||||
{
|
||||
int nread;
|
||||
int is_valid;
|
||||
struct dhcp_packet {
|
||||
struct iphdr ip;
|
||||
struct udphdr udp;
|
||||
struct dhcp_msg dhcp;
|
||||
} packet;
|
||||
int dhcp_size;
|
||||
uint32_t sum;
|
||||
uint16_t temp;
|
||||
uint32_t saddr, daddr;
|
||||
|
||||
nread = read(s, &packet, sizeof(packet));
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* The raw packet interface gives us all packets received by the
|
||||
* network interface. We need to filter out all packets that are
|
||||
* not meant for us.
|
||||
*/
|
||||
is_valid = 0;
|
||||
if (nread < (int)(sizeof(struct iphdr) + sizeof(struct udphdr))) {
|
||||
#if VERBOSE
|
||||
ALOGD("Packet is too small (%d) to be a UDP datagram", nread);
|
||||
#endif
|
||||
} else if (packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2)) {
|
||||
#if VERBOSE
|
||||
ALOGD("Not a valid IP packet");
|
||||
#endif
|
||||
} else if (nread < ntohs(packet.ip.tot_len)) {
|
||||
#if VERBOSE
|
||||
ALOGD("Packet was truncated (read %d, needed %d)", nread, ntohs(packet.ip.tot_len));
|
||||
#endif
|
||||
} else if (packet.ip.protocol != IPPROTO_UDP) {
|
||||
#if VERBOSE
|
||||
ALOGD("IP protocol (%d) is not UDP", packet.ip.protocol);
|
||||
#endif
|
||||
} else if (packet.udp.dest != htons(PORT_BOOTP_CLIENT)) {
|
||||
#if VERBOSE
|
||||
ALOGD("UDP dest port (%d) is not DHCP client", ntohs(packet.udp.dest));
|
||||
#endif
|
||||
} else {
|
||||
is_valid = 1;
|
||||
}
|
||||
|
||||
if (!is_valid) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Seems like it's probably a valid DHCP packet */
|
||||
/* validate IP header checksum */
|
||||
sum = finish_sum(checksum(&packet.ip, sizeof(packet.ip), 0));
|
||||
if (sum != 0) {
|
||||
printf("IP header checksum failure (0x%x)\n", packet.ip.check);
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
* Validate the UDP checksum.
|
||||
* Since we don't need the IP header anymore, we "borrow" it
|
||||
* to construct the pseudo header used in the checksum calculation.
|
||||
*/
|
||||
dhcp_size = ntohs(packet.udp.len) - sizeof(packet.udp);
|
||||
/*
|
||||
* check validity of dhcp_size.
|
||||
* 1) cannot be negative or zero.
|
||||
* 2) src buffer contains enough bytes to copy
|
||||
* 3) cannot exceed destination buffer
|
||||
*/
|
||||
if ((dhcp_size <= 0) ||
|
||||
((int)(nread - sizeof(struct iphdr) - sizeof(struct udphdr)) < dhcp_size) ||
|
||||
((int)sizeof(struct dhcp_msg) < dhcp_size)) {
|
||||
#if VERBOSE
|
||||
printf("Malformed Packet\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
saddr = packet.ip.saddr;
|
||||
daddr = packet.ip.daddr;
|
||||
nread = ntohs(packet.ip.tot_len);
|
||||
memset(&packet.ip, 0, sizeof(packet.ip));
|
||||
packet.ip.saddr = saddr;
|
||||
packet.ip.daddr = daddr;
|
||||
packet.ip.protocol = IPPROTO_UDP;
|
||||
packet.ip.tot_len = packet.udp.len;
|
||||
temp = packet.udp.check;
|
||||
packet.udp.check = 0;
|
||||
sum = finish_sum(checksum(&packet, nread, 0));
|
||||
packet.udp.check = temp;
|
||||
if (!sum)
|
||||
sum = finish_sum(sum);
|
||||
if (temp != sum) {
|
||||
printf("UDP header checksum failure (0x%x should be 0x%x)\n", sum, temp);
|
||||
return -1;
|
||||
}
|
||||
memcpy(msg, &packet.dhcp, dhcp_size);
|
||||
return dhcp_size;
|
||||
}
|
||||
25
package/fish/fibocom-dial/src/libmnl/dhcp/packet.h
Normal file
25
package/fish/fibocom-dial/src/libmnl/dhcp/packet.h
Normal file
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright 2008, The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _WIFI_PACKET_H_
|
||||
#define _WIFI_PACKET_H_
|
||||
|
||||
int open_raw_socket(const char *ifname, uint8_t *hwaddr, int if_index);
|
||||
int send_packet(int s, int if_index, struct dhcp_msg *msg, int size,
|
||||
uint32_t saddr, uint32_t daddr, uint32_t sport, uint32_t dport);
|
||||
int receive_packet(int s, struct dhcp_msg *msg);
|
||||
|
||||
#endif
|
||||
748
package/fish/fibocom-dial/src/libmnl/ifutils.c
Normal file
748
package/fish/fibocom-dial/src/libmnl/ifutils.c
Normal file
@ -0,0 +1,748 @@
|
||||
/* This example is placed in the public domain. */
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <strings.h>
|
||||
#include <net/if.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <linux/if_link.h>
|
||||
#include <linux/if_ether.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
//#include <linux/if.h>
|
||||
|
||||
#include "libmnl.h"
|
||||
#include "ifutils.h"
|
||||
|
||||
#define ERRMSG(v...) printf("%s-%d: error=%s %s\n", __func__, __LINE__, strerror(errno), ##v)
|
||||
extern void dbg_time(const char *fmt, ...);
|
||||
int mask_to_prefix_v4(uint32_t mask)
|
||||
{
|
||||
int ret = 0;
|
||||
while (mask)
|
||||
{
|
||||
mask = mask & (mask - 1);
|
||||
ret++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *ipaddr_to_string_v4(in_addr_t ipaddr)
|
||||
{
|
||||
static char buf[INET6_ADDRSTRLEN] = {'\0'};
|
||||
buf[0] = '\0';
|
||||
uint32_t addr = ipaddr;
|
||||
return inet_ntop(AF_INET, &addr, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
const char *ipaddr_to_string_v6(uint8_t *ipaddr)
|
||||
{
|
||||
static char buf[INET6_ADDRSTRLEN] = {'\0'};
|
||||
buf[0] = '\0';
|
||||
return inet_ntop(AF_INET6, ipaddr, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
static void ifc_init_ifr(const char *name, struct ifreq *ifr)
|
||||
{
|
||||
memset(ifr, 0, sizeof(struct ifreq));
|
||||
strncpy(ifr->ifr_name, name, IFNAMSIZ);
|
||||
ifr->ifr_name[IFNAMSIZ - 1] = 0;
|
||||
}
|
||||
|
||||
int if_get_hwaddr(const char *name, void *ptr)
|
||||
{
|
||||
int r;
|
||||
struct ifreq ifr;
|
||||
ifc_init_ifr(name, &ifr);
|
||||
|
||||
int ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||
if (ifc_ctl_sock < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
r = ioctl(ifc_ctl_sock, SIOCGIFHWADDR, &ifr);
|
||||
if (r < 0)
|
||||
return -1;
|
||||
|
||||
memcpy(ptr, &ifr.ifr_hwaddr.sa_data, ETH_ALEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int if_act_on_link(const char *ifname, int state)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
struct ifinfomsg *ifm;
|
||||
int ret;
|
||||
unsigned int seq, portid, change = 0, flags = 0;
|
||||
static int oldstate = -1;
|
||||
|
||||
if (state == oldstate)
|
||||
return 0;
|
||||
oldstate = state;
|
||||
|
||||
if (state)
|
||||
{
|
||||
change |= IFF_UP;
|
||||
flags |= IFF_UP;
|
||||
}
|
||||
else
|
||||
{
|
||||
change |= IFF_UP;
|
||||
flags &= ~IFF_UP;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_NEWLINK;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(*ifm));
|
||||
ifm->ifi_family = AF_UNSPEC;
|
||||
ifm->ifi_change = change;
|
||||
ifm->ifi_flags = flags;
|
||||
|
||||
mnl_attr_put_str(nlh, IFLA_IFNAME, ifname);
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL)
|
||||
{
|
||||
ERRMSG("mnl_socket_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_bind");
|
||||
return -1;
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
if (ret == -1)
|
||||
{
|
||||
ERRMSG(" mnl_socket_recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
|
||||
if (ret == -1)
|
||||
{
|
||||
ERRMSG(" mnl_cb_run");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_link_up(const char *ifname)
|
||||
{
|
||||
dbg_time("if_link_up %s",ifname);
|
||||
return if_act_on_link(ifname, 1);
|
||||
}
|
||||
|
||||
int if_link_down(const char *ifname)
|
||||
{
|
||||
|
||||
dbg_time("if_link_down %s",ifname);
|
||||
return if_act_on_link(ifname, 0);
|
||||
}
|
||||
|
||||
int if_set_mtu(const char *ifname, uint32_t mtu)
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
unsigned int seq, portid;
|
||||
struct mnl_socket *nl;
|
||||
struct nlmsghdr *nlh;
|
||||
struct ifinfomsg *ifm;
|
||||
int ret;
|
||||
int iface;
|
||||
static uint32_t oldmtu = 1500;
|
||||
|
||||
if (mtu == oldmtu)
|
||||
return 0;
|
||||
oldmtu = mtu;
|
||||
|
||||
iface = if_nametoindex(ifname);
|
||||
if (iface == 0)
|
||||
{
|
||||
ERRMSG(" if_nametoindex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_NEWLINK;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifinfomsg));
|
||||
ifm->ifi_family = AF_UNSPEC;
|
||||
ifm->ifi_index = iface;
|
||||
ifm->ifi_change = 0xFFFFFFFF;
|
||||
ifm->ifi_type = 0;
|
||||
ifm->ifi_flags = IFF_NOARP | IFF_MULTICAST;
|
||||
|
||||
mnl_attr_put_u32(nlh, IFLA_MTU, mtu);
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL)
|
||||
{
|
||||
ERRMSG(" mnl_socket_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_bind");
|
||||
return -1;
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
if (ret == -1)
|
||||
{
|
||||
ERRMSG(" mnl_socket_recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
|
||||
if (ret == -1)
|
||||
{
|
||||
ERRMSG(" mnl_cb_run");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the ip addr object
|
||||
*
|
||||
* @param operate
|
||||
* 0 -> add address on interface
|
||||
* 1 -> delete address on interface
|
||||
* @param ifname
|
||||
* @param ipaddr
|
||||
* @param prefix
|
||||
* @return int
|
||||
*/
|
||||
static int if_act_on_addr(bool operate, int proto, const char *ifname, addr_t *ipaddr, uint32_t prefix)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
struct ifaddrmsg *ifm;
|
||||
uint32_t seq, portid;
|
||||
int ret, family = proto;
|
||||
|
||||
int iface;
|
||||
|
||||
iface = if_nametoindex(ifname);
|
||||
if (iface == 0)
|
||||
{
|
||||
ERRMSG(" if_nametoindex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
if (operate)
|
||||
nlh->nlmsg_type = RTM_NEWADDR;
|
||||
else
|
||||
nlh->nlmsg_type = RTM_DELADDR;
|
||||
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_REPLACE | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
|
||||
ifm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct ifaddrmsg));
|
||||
|
||||
ifm->ifa_family = family;
|
||||
ifm->ifa_prefixlen = prefix;
|
||||
ifm->ifa_flags = IFA_F_PERMANENT;
|
||||
|
||||
ifm->ifa_scope = RT_SCOPE_UNIVERSE;
|
||||
ifm->ifa_index = iface;
|
||||
|
||||
/*
|
||||
* The exact meaning of IFA_LOCAL and IFA_ADDRESS depend
|
||||
* on the address family being used and the device type.
|
||||
* For broadcast devices (like the interfaces we use),
|
||||
* for IPv4 we specify both and they are used interchangeably.
|
||||
* For IPv6, only IFA_ADDRESS needs to be set.
|
||||
*/
|
||||
if (family == AF_INET)
|
||||
{
|
||||
mnl_attr_put_u32(nlh, IFA_LOCAL, ipaddr->ip);
|
||||
mnl_attr_put_u32(nlh, IFA_ADDRESS, ipaddr->ip);
|
||||
}
|
||||
else
|
||||
{
|
||||
mnl_attr_put(nlh, IFA_ADDRESS, sizeof(struct in6_addr), ipaddr);
|
||||
}
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL)
|
||||
{
|
||||
ERRMSG(" mnl_socket_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_bind");
|
||||
return -1;
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERRMSG(" mnl_cb_run");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_set_addr_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix)
|
||||
{
|
||||
addr_t addr;
|
||||
addr.ip = ipaddr;
|
||||
return if_act_on_addr(1, AF_INET, ifname, &addr, prefix);
|
||||
}
|
||||
|
||||
int if_del_addr_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix)
|
||||
{
|
||||
addr_t addr;
|
||||
addr.ip = ipaddr;
|
||||
return if_act_on_addr(0, AF_INET, ifname, &addr, prefix);
|
||||
}
|
||||
|
||||
int if_set_addr_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix)
|
||||
{
|
||||
addr_t addr;
|
||||
memcpy(&addr.ip6, ipaddr, 16);
|
||||
return if_act_on_addr(1, AF_INET6, ifname, &addr, prefix);
|
||||
}
|
||||
|
||||
int if_del_addr_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix)
|
||||
{
|
||||
addr_t addr;
|
||||
memcpy(&addr.ip6, ipaddr, 16);
|
||||
return if_act_on_addr(0, AF_INET6, ifname, &addr, prefix);
|
||||
}
|
||||
|
||||
static int data_attr_cb(const struct nlattr *attr, void *data)
|
||||
{
|
||||
const struct nlattr **tb = data;
|
||||
int type = mnl_attr_get_type(attr);
|
||||
|
||||
/* skip unsupported attribute in user-space */
|
||||
if (mnl_attr_type_valid(attr, IFA_MAX) < 0)
|
||||
return MNL_CB_OK;
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case IFA_ADDRESS:
|
||||
if (mnl_attr_validate(attr, MNL_TYPE_BINARY) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_attr_validate");
|
||||
return MNL_CB_ERROR;
|
||||
}
|
||||
break;
|
||||
}
|
||||
tb[type] = attr;
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
static int data_cb(const struct nlmsghdr *nlh, void *data)
|
||||
{
|
||||
struct nlattr *tb[IFA_MAX + 1] = {};
|
||||
struct ifaddrmsg *ifa = mnl_nlmsg_get_payload(nlh);
|
||||
struct addrinfo_t *addrinfo = (struct addrinfo_t *)data;
|
||||
void *addr = NULL;
|
||||
|
||||
mnl_attr_parse(nlh, sizeof(*ifa), data_attr_cb, tb);
|
||||
if (tb[IFA_ADDRESS])
|
||||
{
|
||||
char out[INET6_ADDRSTRLEN];
|
||||
|
||||
addr = mnl_attr_get_payload(tb[IFLA_ADDRESS]);
|
||||
addr = mnl_attr_get_payload(tb[IFA_ADDRESS]);
|
||||
if (!inet_ntop(ifa->ifa_family, addr, out, sizeof(out)))
|
||||
ERRMSG("inet_ntop");
|
||||
// printf("%d %d-> %d %s\n", addrinfo->iface, ifa->ifa_index, ifa->ifa_scope, out);
|
||||
|
||||
addrinfo->addrs[addrinfo->num].prefix = ifa->ifa_prefixlen;
|
||||
if (ifa->ifa_index == addrinfo->iface)
|
||||
{
|
||||
if (ifa->ifa_family == AF_INET6)
|
||||
memcpy(addrinfo->addrs[addrinfo->num].address.ip6.s6_addr, addr, 16);
|
||||
if (ifa->ifa_family == AF_INET)
|
||||
memcpy(&(addrinfo->addrs[addrinfo->num].address.ip), addr, 4);
|
||||
addrinfo->num++;
|
||||
}
|
||||
}
|
||||
|
||||
// ifa->ifa_scope
|
||||
// 0: global
|
||||
// 200: site
|
||||
// 253: link
|
||||
// 254: host
|
||||
// 255: nowhere
|
||||
|
||||
return MNL_CB_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* @param ifname
|
||||
* @param proto
|
||||
* AF_INET -> for IPv4
|
||||
* AF_INET6 -> for IPv6
|
||||
* @return int
|
||||
*/
|
||||
static int if_get_addr(const char *ifname, int proto, struct addrinfo_t *addrinfo)
|
||||
{
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
unsigned int seq, portid;
|
||||
struct mnl_socket *nl;
|
||||
struct nlmsghdr *nlh;
|
||||
struct rtgenmsg *rt;
|
||||
int ret;
|
||||
|
||||
addrinfo->iface = if_nametoindex(ifname);
|
||||
if (addrinfo->iface == 0)
|
||||
{
|
||||
ERRMSG(" if_nametoindex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
nlh->nlmsg_type = RTM_GETADDR;
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
rt = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtgenmsg));
|
||||
if (proto == AF_INET)
|
||||
rt->rtgen_family = AF_INET;
|
||||
else if (proto == AF_INET6)
|
||||
rt->rtgen_family = AF_INET6;
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL)
|
||||
{
|
||||
ERRMSG(" mnl_socket_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_bind");
|
||||
return -1;
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
while (ret > 0)
|
||||
{
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, data_cb, addrinfo);
|
||||
if (ret <= MNL_CB_STOP)
|
||||
break;
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
}
|
||||
if (ret == -1)
|
||||
{
|
||||
ERRMSG(" error");
|
||||
return -1;
|
||||
}
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_flush_v4_addr(const char *ifname)
|
||||
{
|
||||
struct addrinfo_t addrinfo;
|
||||
int i = 0;
|
||||
|
||||
memset(&addrinfo, 0, sizeof(struct addrinfo_t));
|
||||
if_get_addr(ifname, AF_INET, &addrinfo);
|
||||
for (; i < addrinfo.num; i++)
|
||||
{
|
||||
// printf("remove address: %s\n", ipaddr_to_string_v4(addrinfo.addrs[i].address.ip));
|
||||
if_del_addr_v4(ifname, addrinfo.addrs[i].address.ip, addrinfo.addrs[i].prefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_flush_v6_addr(const char *ifname)
|
||||
{
|
||||
struct addrinfo_t addrinfo;
|
||||
int i = 0;
|
||||
|
||||
memset(&addrinfo, 0, sizeof(struct addrinfo_t));
|
||||
if_get_addr(ifname, AF_INET6, &addrinfo);
|
||||
for (; i < addrinfo.num; i++)
|
||||
{
|
||||
// printf("remove address: %s\n", ipaddr_to_string_v6(addrinfo.addrs[i].address.ip6.s6_addr));
|
||||
if_del_addr_v6(ifname, addrinfo.addrs[i].address.ip6.s6_addr, addrinfo.addrs[i].prefix);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the route addr object
|
||||
* Usage:
|
||||
* iface destination cidr [gateway]
|
||||
* Example:
|
||||
* eth0 10.0.1.12 32 10.0.1.11
|
||||
* eth0 ffff::10.0.1.12 128 fdff::1
|
||||
* @param operate
|
||||
* add or del
|
||||
* @param ifname
|
||||
* @param dstaddr
|
||||
* @param prefix
|
||||
* @param gwaddr
|
||||
* @return int
|
||||
*/
|
||||
int if_act_on_route(bool operate, int proto, const char *ifname, addr_t *dstaddr, uint32_t prefix, addr_t *gwaddr)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
struct nlmsghdr *nlh;
|
||||
struct rtmsg *rtm;
|
||||
uint32_t seq, portid;
|
||||
int iface, ret, family = proto;
|
||||
|
||||
iface = if_nametoindex(ifname);
|
||||
if (iface == 0)
|
||||
{
|
||||
ERRMSG(" if_nametoindex");
|
||||
return -1;
|
||||
}
|
||||
|
||||
nlh = mnl_nlmsg_put_header(buf);
|
||||
if (operate)
|
||||
nlh->nlmsg_type = RTM_NEWROUTE;
|
||||
else
|
||||
nlh->nlmsg_type = RTM_DELROUTE;
|
||||
|
||||
nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
|
||||
nlh->nlmsg_seq = seq = time(NULL);
|
||||
|
||||
rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
|
||||
rtm->rtm_family = family;
|
||||
rtm->rtm_dst_len = prefix;
|
||||
rtm->rtm_src_len = 0;
|
||||
rtm->rtm_tos = 0;
|
||||
rtm->rtm_protocol = RTPROT_STATIC;
|
||||
rtm->rtm_table = RT_TABLE_MAIN;
|
||||
rtm->rtm_type = RTN_UNICAST;
|
||||
/* is there any gateway? */
|
||||
rtm->rtm_scope = gwaddr ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK;
|
||||
rtm->rtm_flags = 0;
|
||||
|
||||
if (family == AF_INET)
|
||||
mnl_attr_put_u32(nlh, RTA_DST, dstaddr->ip);
|
||||
else
|
||||
mnl_attr_put(nlh, RTA_DST, sizeof(struct in6_addr), dstaddr);
|
||||
|
||||
mnl_attr_put_u32(nlh, RTA_OIF, iface);
|
||||
if (gwaddr)
|
||||
{
|
||||
if (family == AF_INET)
|
||||
mnl_attr_put_u32(nlh, RTA_GATEWAY, gwaddr->ip);
|
||||
else
|
||||
{
|
||||
mnl_attr_put(nlh, RTA_GATEWAY, sizeof(struct in6_addr), gwaddr);
|
||||
}
|
||||
}
|
||||
|
||||
nl = mnl_socket_open(NETLINK_ROUTE);
|
||||
if (nl == NULL)
|
||||
{
|
||||
ERRMSG(" mnl_socket_open");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_bind");
|
||||
return -1;
|
||||
}
|
||||
portid = mnl_socket_get_portid(nl);
|
||||
|
||||
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_sendto");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
|
||||
if (ret < 0)
|
||||
{
|
||||
ERRMSG(" mnl_socket_recvfrom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = mnl_cb_run(buf, ret, seq, portid, NULL, NULL);
|
||||
if (ret < 0)
|
||||
{
|
||||
ERRMSG(" mnl_cb_run");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mnl_socket_close(nl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_set_default_route_v4(const char *ifname)
|
||||
{
|
||||
return if_act_on_route(1, AF_INET, ifname, (addr_t *)&in6addr_any, 0, NULL);
|
||||
}
|
||||
|
||||
int if_del_default_route_v4(const char *ifname)
|
||||
{
|
||||
return if_act_on_route(0, AF_INET, ifname, (addr_t *)&in6addr_any, 0, NULL);
|
||||
}
|
||||
|
||||
int if_set_default_route_v6(const char *ifname)
|
||||
{
|
||||
return if_act_on_route(1, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, NULL);
|
||||
}
|
||||
|
||||
int if_del_default_route_v6(const char *ifname)
|
||||
{
|
||||
return if_act_on_route(0, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the default gwaddr object
|
||||
* set default gw
|
||||
* @param operate
|
||||
* @param ifname
|
||||
* @param gwaddr
|
||||
* gateway ip
|
||||
* @return int
|
||||
*/
|
||||
int if_set_route_gw_v4(const char *ifname, in_addr_t gwaddr)
|
||||
{
|
||||
addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr_t));
|
||||
addr.ip = gwaddr;
|
||||
return if_act_on_route(1, AF_INET, ifname, (addr_t *)&in6addr_any, 0, &addr);
|
||||
}
|
||||
|
||||
int if_del_route_gw_v4(const char *ifname, in_addr_t gwaddr)
|
||||
{
|
||||
addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr_t));
|
||||
addr.ip = gwaddr;
|
||||
return if_act_on_route(0, AF_INET, ifname, (addr_t *)&in6addr_any, 0, &addr);
|
||||
}
|
||||
|
||||
int if_set_route_gw_v6(const char *ifname, uint8_t *gwaddr)
|
||||
{
|
||||
addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr_t));
|
||||
memcpy(&addr.ip6, gwaddr, 16);
|
||||
return if_act_on_route(1, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, &addr);
|
||||
}
|
||||
|
||||
int if_del_route_gw_v6(const char *ifname, uint8_t *gwaddr)
|
||||
{
|
||||
addr_t addr;
|
||||
memset(&addr, 0, sizeof(addr_t));
|
||||
memcpy(&addr.ip6, gwaddr, 16);
|
||||
return if_act_on_route(0, AF_INET6, ifname, (addr_t *)&in6addr_any, 0, &addr);
|
||||
}
|
||||
|
||||
int if_set_dns(const char *dns1, const char *dns2)
|
||||
{
|
||||
int ret = 0;
|
||||
char buf[128] = {'\0'};
|
||||
int fd = open("/etc/resolv.conf", O_CREAT | O_WRONLY | O_TRUNC);
|
||||
if (fd < 0)
|
||||
{
|
||||
ERRMSG(" fail to open /etc/resolv.conf");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (dns1)
|
||||
snprintf(buf, sizeof(buf), "nameserver %s\n", dns1);
|
||||
if (dns2)
|
||||
snprintf(buf, sizeof(buf), "nameserver %s\n", dns2);
|
||||
ret = write(fd, buf, strlen(buf));
|
||||
if (ret < 0)
|
||||
{
|
||||
ERRMSG(" write dns");
|
||||
}
|
||||
close(fd);
|
||||
return ret > 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int if_set_network_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix,
|
||||
in_addr_t gwaddr, in_addr_t dns1, in_addr_t dns2)
|
||||
{
|
||||
if_link_up(ifname);
|
||||
sleep(2);
|
||||
if_set_addr_v4(ifname, ipaddr, prefix);
|
||||
if_set_default_route_v4(ifname);
|
||||
if_set_dns(ipaddr_to_string_v4(dns1), ipaddr_to_string_v4(dns2));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int if_set_network_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix,
|
||||
uint8_t *gwaddr, uint8_t *dns1, uint8_t *dns2)
|
||||
{
|
||||
if_link_up(ifname);
|
||||
sleep(2);
|
||||
if_set_addr_v6(ifname, ipaddr, prefix);
|
||||
if_set_default_route_v6(ifname);
|
||||
if_set_dns(ipaddr_to_string_v6(dns1), ipaddr_to_string_v6(dns2));
|
||||
return 0;
|
||||
}
|
||||
53
package/fish/fibocom-dial/src/libmnl/ifutils.h
Normal file
53
package/fish/fibocom-dial/src/libmnl/ifutils.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef __IFUTILS_H__
|
||||
#define __IFUTILS_H__
|
||||
|
||||
typedef union {
|
||||
in_addr_t ip;
|
||||
struct in6_addr ip6;
|
||||
} addr_t;
|
||||
|
||||
#define MAX_IP_NUM 32
|
||||
struct addrinfo_t
|
||||
{
|
||||
int iface;
|
||||
int num;
|
||||
struct
|
||||
{
|
||||
int prefix;
|
||||
addr_t address;
|
||||
} addrs[MAX_IP_NUM];
|
||||
};
|
||||
|
||||
const char *ipaddr_to_string_v4(in_addr_t ipaddr);
|
||||
const char *ipaddr_to_string_v6(uint8_t *ipaddr);
|
||||
int mask_to_prefix_v4(in_addr_t mask);
|
||||
|
||||
int if_get_hwaddr(const char *name, void *ptr);
|
||||
|
||||
int if_link_down(const char *ifname);
|
||||
int if_link_up(const char *ifname);
|
||||
int if_set_mtu(const char *ifname, uint32_t mtu);
|
||||
|
||||
int if_set_addr_v4(const char *name, in_addr_t address, uint32_t prefixlen);
|
||||
int if_del_addr_v4(const char *name, in_addr_t address, uint32_t prefixlen);
|
||||
int if_set_addr_v6(const char *name, uint8_t *address, uint32_t prefixlen);
|
||||
int if_del_addr_v6(const char *name, uint8_t *address, uint32_t prefixlen);
|
||||
int if_flush_v4_addr(const char *ifname);
|
||||
int if_flush_v6_addr(const char *ifname);
|
||||
|
||||
int if_set_route_gw_v4(const char *ifname, in_addr_t gwaddr);
|
||||
int if_del_route_gw_v4(const char *ifname, in_addr_t gwaddr);
|
||||
int if_set_default_route_v4(const char *ifname);
|
||||
int if_del_default_route_v4(const char *ifname);
|
||||
|
||||
int if_set_route_gw_v6(const char *ifname, uint8_t *gwaddr);
|
||||
int if_del_route_gw_v6(const char *ifname, uint8_t *gwaddr);
|
||||
int if_set_default_route_v6(const char *ifname);
|
||||
int if_del_default_route_v6(const char *ifname);
|
||||
|
||||
int if_set_network_v4(const char *ifname, in_addr_t ipaddr, uint32_t prefix,
|
||||
in_addr_t gwaddr, in_addr_t dns1, in_addr_t dns2);
|
||||
int if_set_network_v6(const char *ifname, uint8_t *ipaddr, uint32_t prefix,
|
||||
uint8_t *gwaddr, uint8_t *dns1, uint8_t *dns2);
|
||||
|
||||
#endif //__IFUTILS_H__
|
||||
202
package/fish/fibocom-dial/src/libmnl/libmnl.h
Normal file
202
package/fish/fibocom-dial/src/libmnl/libmnl.h
Normal file
@ -0,0 +1,202 @@
|
||||
#ifndef _LIBMNL_H_
|
||||
#define _LIBMNL_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h> /* for sa_family_t */
|
||||
#include <linux/netlink.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Netlink socket API
|
||||
*/
|
||||
|
||||
#define MNL_SOCKET_AUTOPID 0
|
||||
#define MNL_SOCKET_BUFFER_SIZE (sysconf(_SC_PAGESIZE) < 8192L ? sysconf(_SC_PAGESIZE) : 8192L)
|
||||
#define MNL_SOCKET_DUMP_SIZE 32768
|
||||
|
||||
struct mnl_socket;
|
||||
|
||||
extern struct mnl_socket *mnl_socket_open(int bus);
|
||||
extern struct mnl_socket *mnl_socket_open2(int bus, int flags);
|
||||
extern struct mnl_socket *mnl_socket_fdopen(int fd);
|
||||
extern int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups, pid_t pid);
|
||||
extern int mnl_socket_close(struct mnl_socket *nl);
|
||||
extern int mnl_socket_get_fd(const struct mnl_socket *nl);
|
||||
extern unsigned int mnl_socket_get_portid(const struct mnl_socket *nl);
|
||||
extern ssize_t mnl_socket_sendto(const struct mnl_socket *nl, const void *req, size_t siz);
|
||||
extern ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl, void *buf, size_t siz);
|
||||
extern int mnl_socket_setsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t len);
|
||||
extern int mnl_socket_getsockopt(const struct mnl_socket *nl, int type, void *buf, socklen_t *len);
|
||||
|
||||
/*
|
||||
* Netlink message API
|
||||
*/
|
||||
|
||||
#define MNL_ALIGNTO 4
|
||||
#define MNL_ALIGN(len) (((len)+MNL_ALIGNTO-1) & ~(MNL_ALIGNTO-1))
|
||||
#define MNL_NLMSG_HDRLEN MNL_ALIGN(sizeof(struct nlmsghdr))
|
||||
|
||||
extern size_t mnl_nlmsg_size(size_t len);
|
||||
extern size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh);
|
||||
|
||||
/* Netlink message header builder */
|
||||
extern struct nlmsghdr *mnl_nlmsg_put_header(void *buf);
|
||||
extern void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh, size_t size);
|
||||
|
||||
/* Netlink message iterators */
|
||||
extern bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len);
|
||||
extern struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh, int *len);
|
||||
|
||||
/* Netlink sequence tracking */
|
||||
extern bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh, unsigned int seq);
|
||||
|
||||
/* Netlink portID checking */
|
||||
extern bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh, unsigned int portid);
|
||||
|
||||
/* Netlink message getters */
|
||||
extern void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh);
|
||||
extern void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh, size_t offset);
|
||||
extern void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh);
|
||||
|
||||
/* Netlink message printer */
|
||||
extern void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen, size_t extra_header_size);
|
||||
|
||||
/* Message batch helpers */
|
||||
struct mnl_nlmsg_batch;
|
||||
extern struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf, size_t bufsiz);
|
||||
extern bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b);
|
||||
extern void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b);
|
||||
extern size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b);
|
||||
extern void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b);
|
||||
extern void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b);
|
||||
extern void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b);
|
||||
extern bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b);
|
||||
|
||||
/*
|
||||
* Netlink attributes API
|
||||
*/
|
||||
#define MNL_ATTR_HDRLEN MNL_ALIGN(sizeof(struct nlattr))
|
||||
|
||||
/* TLV attribute getters */
|
||||
extern uint16_t mnl_attr_get_type(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_len(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_payload_len(const struct nlattr *attr);
|
||||
extern void *mnl_attr_get_payload(const struct nlattr *attr);
|
||||
extern uint8_t mnl_attr_get_u8(const struct nlattr *attr);
|
||||
extern uint16_t mnl_attr_get_u16(const struct nlattr *attr);
|
||||
extern uint32_t mnl_attr_get_u32(const struct nlattr *attr);
|
||||
extern uint64_t mnl_attr_get_u64(const struct nlattr *attr);
|
||||
extern const char *mnl_attr_get_str(const struct nlattr *attr);
|
||||
|
||||
/* TLV attribute putters */
|
||||
extern void mnl_attr_put(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data);
|
||||
extern void mnl_attr_put_u8(struct nlmsghdr *nlh, uint16_t type, uint8_t data);
|
||||
extern void mnl_attr_put_u16(struct nlmsghdr *nlh, uint16_t type, uint16_t data);
|
||||
extern void mnl_attr_put_u32(struct nlmsghdr *nlh, uint16_t type, uint32_t data);
|
||||
extern void mnl_attr_put_u64(struct nlmsghdr *nlh, uint16_t type, uint64_t data);
|
||||
extern void mnl_attr_put_str(struct nlmsghdr *nlh, uint16_t type, const char *data);
|
||||
extern void mnl_attr_put_strz(struct nlmsghdr *nlh, uint16_t type, const char *data);
|
||||
|
||||
/* TLV attribute putters with buffer boundary checkings */
|
||||
extern bool mnl_attr_put_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, size_t len, const void *data);
|
||||
extern bool mnl_attr_put_u8_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint8_t data);
|
||||
extern bool mnl_attr_put_u16_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint16_t data);
|
||||
extern bool mnl_attr_put_u32_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint32_t data);
|
||||
extern bool mnl_attr_put_u64_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, uint64_t data);
|
||||
extern bool mnl_attr_put_str_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data);
|
||||
extern bool mnl_attr_put_strz_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type, const char *data);
|
||||
|
||||
/* TLV attribute nesting */
|
||||
extern struct nlattr *mnl_attr_nest_start(struct nlmsghdr *nlh, uint16_t type);
|
||||
extern struct nlattr *mnl_attr_nest_start_check(struct nlmsghdr *nlh, size_t buflen, uint16_t type);
|
||||
extern void mnl_attr_nest_end(struct nlmsghdr *nlh, struct nlattr *start);
|
||||
extern void mnl_attr_nest_cancel(struct nlmsghdr *nlh, struct nlattr *start);
|
||||
|
||||
/* TLV validation */
|
||||
extern int mnl_attr_type_valid(const struct nlattr *attr, uint16_t maxtype);
|
||||
|
||||
enum mnl_attr_data_type {
|
||||
MNL_TYPE_UNSPEC,
|
||||
MNL_TYPE_U8,
|
||||
MNL_TYPE_U16,
|
||||
MNL_TYPE_U32,
|
||||
MNL_TYPE_U64,
|
||||
MNL_TYPE_STRING,
|
||||
MNL_TYPE_FLAG,
|
||||
MNL_TYPE_MSECS,
|
||||
MNL_TYPE_NESTED,
|
||||
MNL_TYPE_NESTED_COMPAT,
|
||||
MNL_TYPE_NUL_STRING,
|
||||
MNL_TYPE_BINARY,
|
||||
MNL_TYPE_MAX,
|
||||
};
|
||||
|
||||
extern int mnl_attr_validate(const struct nlattr *attr, enum mnl_attr_data_type type);
|
||||
extern int mnl_attr_validate2(const struct nlattr *attr, enum mnl_attr_data_type type, size_t len);
|
||||
|
||||
/* TLV iterators */
|
||||
extern bool mnl_attr_ok(const struct nlattr *attr, int len);
|
||||
extern struct nlattr *mnl_attr_next(const struct nlattr *attr);
|
||||
|
||||
#define mnl_attr_for_each(attr, nlh, offset) \
|
||||
for ((attr) = mnl_nlmsg_get_payload_offset((nlh), (offset)); \
|
||||
mnl_attr_ok((attr), (char *)mnl_nlmsg_get_payload_tail(nlh) - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
#define mnl_attr_for_each_nested(attr, nest) \
|
||||
for ((attr) = mnl_attr_get_payload(nest); \
|
||||
mnl_attr_ok((attr), (char *)mnl_attr_get_payload(nest) + mnl_attr_get_payload_len(nest) - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
#define mnl_attr_for_each_payload(payload, payload_size) \
|
||||
for ((attr) = (payload); \
|
||||
mnl_attr_ok((attr), (char *)(payload) + payload_size - (char *)(attr)); \
|
||||
(attr) = mnl_attr_next(attr))
|
||||
|
||||
/* TLV callback-based attribute parsers */
|
||||
typedef int (*mnl_attr_cb_t)(const struct nlattr *attr, void *data);
|
||||
|
||||
extern int mnl_attr_parse(const struct nlmsghdr *nlh, unsigned int offset, mnl_attr_cb_t cb, void *data);
|
||||
extern int mnl_attr_parse_nested(const struct nlattr *attr, mnl_attr_cb_t cb, void *data);
|
||||
extern int mnl_attr_parse_payload(const void *payload, size_t payload_len, mnl_attr_cb_t cb, void *data);
|
||||
|
||||
/*
|
||||
* callback API
|
||||
*/
|
||||
#define MNL_CB_ERROR -1
|
||||
#define MNL_CB_STOP 0
|
||||
#define MNL_CB_OK 1
|
||||
|
||||
typedef int (*mnl_cb_t)(const struct nlmsghdr *nlh, void *data);
|
||||
|
||||
extern int mnl_cb_run(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data);
|
||||
|
||||
extern int mnl_cb_run2(const void *buf, size_t numbytes, unsigned int seq,
|
||||
unsigned int portid, mnl_cb_t cb_data, void *data,
|
||||
const mnl_cb_t *cb_ctl_array,
|
||||
unsigned int cb_ctl_array_len);
|
||||
|
||||
/*
|
||||
* other declarations
|
||||
*/
|
||||
|
||||
#ifndef SOL_NETLINK
|
||||
#define SOL_NETLINK 270
|
||||
#endif
|
||||
|
||||
#ifndef MNL_ARRAY_SIZE
|
||||
#define MNL_ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
556
package/fish/fibocom-dial/src/libmnl/nlmsg.c
Normal file
556
package/fish/fibocom-dial/src/libmnl/nlmsg.c
Normal file
@ -0,0 +1,556 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "libmnl.h"
|
||||
|
||||
/**
|
||||
* \defgroup nlmsg Netlink message helpers
|
||||
*
|
||||
* Netlink message:
|
||||
* \verbatim
|
||||
|<----------------- 4 bytes ------------------->|
|
||||
|<----- 2 bytes ------>|<------- 2 bytes ------>|
|
||||
|-----------------------------------------------|
|
||||
| Message length (including header) |
|
||||
|-----------------------------------------------|
|
||||
| Message type | Message flags |
|
||||
|-----------------------------------------------|
|
||||
| Message sequence number |
|
||||
|-----------------------------------------------|
|
||||
| Netlink PortID |
|
||||
|-----------------------------------------------|
|
||||
| |
|
||||
. Payload .
|
||||
|_______________________________________________|
|
||||
\endverbatim
|
||||
*
|
||||
* There is usually an extra header after the the Netlink header (at the
|
||||
* beginning of the payload). This extra header is specific of the Netlink
|
||||
* subsystem. After this extra header, it comes the sequence of attributes
|
||||
* that are expressed in Type-Length-Value (TLV) format.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_size - calculate the size of Netlink message (without alignment)
|
||||
* \param len length of the Netlink payload
|
||||
*
|
||||
* This function returns the size of a netlink message (header plus payload)
|
||||
* without alignment.
|
||||
*/
|
||||
size_t mnl_nlmsg_size(size_t len)
|
||||
{
|
||||
return len + MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_len - get the length of the Netlink payload
|
||||
* \param nlh pointer to the header of the Netlink message
|
||||
*
|
||||
* This function returns the Length of the netlink payload, ie. the length
|
||||
* of the full message minus the size of the Netlink header.
|
||||
*/
|
||||
size_t mnl_nlmsg_get_payload_len(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return nlh->nlmsg_len - MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_header - reserve and prepare room for Netlink header
|
||||
* \param buf memory already allocated to store the Netlink header
|
||||
*
|
||||
* This function sets to zero the room that is required to put the Netlink
|
||||
* header in the memory buffer passed as parameter. This function also
|
||||
* initializes the nlmsg_len field to the size of the Netlink header. This
|
||||
* function returns a pointer to the Netlink header structure.
|
||||
*/
|
||||
struct nlmsghdr *mnl_nlmsg_put_header(void *buf)
|
||||
{
|
||||
int len = MNL_ALIGN(sizeof(struct nlmsghdr));
|
||||
struct nlmsghdr *nlh = buf;
|
||||
|
||||
memset(buf, 0, len);
|
||||
nlh->nlmsg_len = len;
|
||||
return nlh;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_put_extra_header - reserve and prepare room for an extra header
|
||||
* \param nlh pointer to Netlink header
|
||||
* \param size size of the extra header that we want to put
|
||||
*
|
||||
* This function sets to zero the room that is required to put the extra
|
||||
* header after the initial Netlink header. This function also increases
|
||||
* the nlmsg_len field. You have to invoke mnl_nlmsg_put_header() before
|
||||
* you call this function. This function returns a pointer to the extra
|
||||
* header.
|
||||
*/
|
||||
void *mnl_nlmsg_put_extra_header(struct nlmsghdr *nlh,
|
||||
size_t size)
|
||||
{
|
||||
char *ptr = (char *)nlh + nlh->nlmsg_len;
|
||||
size_t len = MNL_ALIGN(size);
|
||||
nlh->nlmsg_len += len;
|
||||
memset(ptr, 0, len);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload - get a pointer to the payload of the netlink message
|
||||
* \param nlh pointer to a netlink header
|
||||
*
|
||||
* This function returns a pointer to the payload of the netlink message.
|
||||
*/
|
||||
void *mnl_nlmsg_get_payload(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_offset - get a pointer to the payload of the message
|
||||
* \param nlh pointer to a netlink header
|
||||
* \param offset offset to the payload of the attributes TLV set
|
||||
*
|
||||
* This function returns a pointer to the payload of the netlink message plus
|
||||
* a given offset.
|
||||
*/
|
||||
void *mnl_nlmsg_get_payload_offset(const struct nlmsghdr *nlh,
|
||||
size_t offset)
|
||||
{
|
||||
return (void *)nlh + MNL_NLMSG_HDRLEN + MNL_ALIGN(offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_ok - check a there is room for netlink message
|
||||
* \param nlh netlink message that we want to check
|
||||
* \param len remaining bytes in a buffer that contains the netlink message
|
||||
*
|
||||
* This function is used to check that a buffer that contains a netlink
|
||||
* message has enough room for the netlink message that it stores, ie. this
|
||||
* function can be used to verify that a netlink message is not malformed nor
|
||||
* truncated.
|
||||
*
|
||||
* This function does not set errno in case of error since it is intended
|
||||
* for iterations. Thus, it returns true on success and false on error.
|
||||
*
|
||||
* The len parameter may become negative in malformed messages during message
|
||||
* iteration, that is why we use a signed integer.
|
||||
*/
|
||||
bool mnl_nlmsg_ok(const struct nlmsghdr *nlh, int len)
|
||||
{
|
||||
return len >= (int)sizeof(struct nlmsghdr) &&
|
||||
nlh->nlmsg_len >= sizeof(struct nlmsghdr) &&
|
||||
(int)nlh->nlmsg_len <= len;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_next - get the next netlink message in a multipart message
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param len length of the remaining bytes in the buffer (passed by reference).
|
||||
*
|
||||
* This function returns a pointer to the next netlink message that is part
|
||||
* of a multi-part netlink message. Netlink can batch several messages into
|
||||
* one buffer so that the receiver has to iterate over the whole set of
|
||||
* Netlink messages.
|
||||
*
|
||||
* You have to use mnl_nlmsg_ok() to check if the next Netlink message is
|
||||
* valid.
|
||||
*/
|
||||
struct nlmsghdr *mnl_nlmsg_next(const struct nlmsghdr *nlh,
|
||||
int *len)
|
||||
{
|
||||
*len -= MNL_ALIGN(nlh->nlmsg_len);
|
||||
return (struct nlmsghdr *)((void *)nlh + MNL_ALIGN(nlh->nlmsg_len));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_get_payload_tail - get the ending of the netlink message
|
||||
* \param nlh pointer to netlink message
|
||||
*
|
||||
* This function returns a pointer to the netlink message tail. This is useful
|
||||
* to build a message since we continue adding attributes at the end of the
|
||||
* message.
|
||||
*/
|
||||
void *mnl_nlmsg_get_payload_tail(const struct nlmsghdr *nlh)
|
||||
{
|
||||
return (void *)nlh + MNL_ALIGN(nlh->nlmsg_len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_seq_ok - perform sequence tracking
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param seq last sequence number used to send a message
|
||||
*
|
||||
* This functions returns true if the sequence tracking is fulfilled, otherwise
|
||||
* false is returned. We skip the tracking for netlink messages whose sequence
|
||||
* number is zero since it is usually reserved for event-based kernel
|
||||
* notifications. On the other hand, if seq is set but the message sequence
|
||||
* number is not set (i.e. this is an event message coming from kernel-space),
|
||||
* then we also skip the tracking. This approach is good if we use the same
|
||||
* socket to send commands to kernel-space (that we want to track) and to
|
||||
* listen to events (that we do not track).
|
||||
*/
|
||||
bool mnl_nlmsg_seq_ok(const struct nlmsghdr *nlh,
|
||||
unsigned int seq)
|
||||
{
|
||||
return nlh->nlmsg_seq && seq ? nlh->nlmsg_seq == seq : true;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_portid_ok - perform portID origin check
|
||||
* \param nlh current netlink message that we are handling
|
||||
* \param portid netlink portid that we want to check
|
||||
*
|
||||
* This functions returns true if the origin is fulfilled, otherwise
|
||||
* false is returned. We skip the tracking for netlink message whose portID
|
||||
* is zero since it is reserved for event-based kernel notifications. On the
|
||||
* other hand, if portid is set but the message PortID is not (i.e. this
|
||||
* is an event message coming from kernel-space), then we also skip the
|
||||
* tracking. This approach is good if we use the same socket to send commands
|
||||
* to kernel-space (that we want to track) and to listen to events (that we
|
||||
* do not track).
|
||||
*/
|
||||
bool mnl_nlmsg_portid_ok(const struct nlmsghdr *nlh,
|
||||
unsigned int portid)
|
||||
{
|
||||
return nlh->nlmsg_pid && portid ? nlh->nlmsg_pid == portid : true;
|
||||
}
|
||||
|
||||
static void mnl_nlmsg_fprintf_header(FILE *fd, const struct nlmsghdr *nlh)
|
||||
{
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
fprintf(fd, "| %.010u |\t| message length |\n", nlh->nlmsg_len);
|
||||
fprintf(fd, "| %.05u | %c%c%c%c |\t| type | flags |\n",
|
||||
nlh->nlmsg_type,
|
||||
nlh->nlmsg_flags & NLM_F_REQUEST ? 'R' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_MULTI ? 'M' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_ACK ? 'A' : '-',
|
||||
nlh->nlmsg_flags & NLM_F_ECHO ? 'E' : '-');
|
||||
fprintf(fd, "| %.010u |\t| sequence number|\n", nlh->nlmsg_seq);
|
||||
fprintf(fd, "| %.010u |\t| port ID |\n", nlh->nlmsg_pid);
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
}
|
||||
|
||||
static void mnl_nlmsg_fprintf_payload(FILE *fd, const struct nlmsghdr *nlh,
|
||||
size_t extra_header_size)
|
||||
{
|
||||
int rem = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i=sizeof(struct nlmsghdr); i<nlh->nlmsg_len; i+=4) {
|
||||
char *b = (char *) nlh;
|
||||
struct nlattr *attr = (struct nlattr *) (b+i);
|
||||
|
||||
/* netlink control message. */
|
||||
if (nlh->nlmsg_type < NLMSG_MIN_TYPE) {
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| |\n");
|
||||
/* special handling for the extra header. */
|
||||
} else if (extra_header_size > 0) {
|
||||
extra_header_size -= 4;
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| extra header |\n");
|
||||
/* this seems like an attribute header. */
|
||||
} else if (rem == 0 && (attr->nla_type & NLA_TYPE_MASK) != 0) {
|
||||
fprintf(fd, "|%c[%d;%dm"
|
||||
"%.5u"
|
||||
"%c[%dm"
|
||||
"|"
|
||||
"%c[%d;%dm"
|
||||
"%c%c"
|
||||
"%c[%dm"
|
||||
"|"
|
||||
"%c[%d;%dm"
|
||||
"%.5u"
|
||||
"%c[%dm|\t",
|
||||
27, 1, 31,
|
||||
attr->nla_len,
|
||||
27, 0,
|
||||
27, 1, 32,
|
||||
attr->nla_type & NLA_F_NESTED ? 'N' : '-',
|
||||
attr->nla_type &
|
||||
NLA_F_NET_BYTEORDER ? 'B' : '-',
|
||||
27, 0,
|
||||
27, 1, 34,
|
||||
attr->nla_type & NLA_TYPE_MASK,
|
||||
27, 0);
|
||||
fprintf(fd, "|len |flags| type|\n");
|
||||
|
||||
if (!(attr->nla_type & NLA_F_NESTED)) {
|
||||
rem = NLA_ALIGN(attr->nla_len) -
|
||||
sizeof(struct nlattr);
|
||||
}
|
||||
/* this is the attribute payload. */
|
||||
} else if (rem > 0) {
|
||||
rem -= 4;
|
||||
fprintf(fd, "| %.2x %.2x %.2x %.2x |\t",
|
||||
0xff & b[i], 0xff & b[i+1],
|
||||
0xff & b[i+2], 0xff & b[i+3]);
|
||||
fprintf(fd, "| data |");
|
||||
fprintf(fd, "\t %c %c %c %c\n",
|
||||
isprint(b[i]) ? b[i] : ' ',
|
||||
isprint(b[i+1]) ? b[i+1] : ' ',
|
||||
isprint(b[i+2]) ? b[i+2] : ' ',
|
||||
isprint(b[i+3]) ? b[i+3] : ' ');
|
||||
}
|
||||
}
|
||||
fprintf(fd, "----------------\t------------------\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_fprintf - print netlink message to file
|
||||
* \param fd pointer to file type
|
||||
* \param data pointer to the buffer that contains messages to be printed
|
||||
* \param datalen length of data stored in the buffer
|
||||
* \param extra_header_size size of the extra header (if any)
|
||||
*
|
||||
* This function prints the netlink header to a file handle.
|
||||
* It may be useful for debugging purposes. One example of the output
|
||||
* is the following:
|
||||
*
|
||||
*\verbatim
|
||||
---------------- ------------------
|
||||
| 0000000040 | | message length |
|
||||
| 00016 | R-A- | | type | flags |
|
||||
| 1289148991 | | sequence number|
|
||||
| 0000000000 | | port ID |
|
||||
---------------- ------------------
|
||||
| 00 00 00 00 | | extra header |
|
||||
| 00 00 00 00 | | extra header |
|
||||
| 01 00 00 00 | | extra header |
|
||||
| 01 00 00 00 | | extra header |
|
||||
|00008|--|00003| |len |flags| type|
|
||||
| 65 74 68 30 | | data | e t h 0
|
||||
---------------- ------------------
|
||||
\endverbatim
|
||||
*
|
||||
* This example above shows the netlink message that is send to kernel-space
|
||||
* to set up the link interface eth0. The netlink and attribute header data
|
||||
* are displayed in base 10 whereas the extra header and the attribute payload
|
||||
* are expressed in base 16. The possible flags in the netlink header are:
|
||||
*
|
||||
* - R, that indicates that NLM_F_REQUEST is set.
|
||||
* - M, that indicates that NLM_F_MULTI is set.
|
||||
* - A, that indicates that NLM_F_ACK is set.
|
||||
* - E, that indicates that NLM_F_ECHO is set.
|
||||
*
|
||||
* The lack of one flag is displayed with '-'. On the other hand, the possible
|
||||
* attribute flags available are:
|
||||
*
|
||||
* - N, that indicates that NLA_F_NESTED is set.
|
||||
* - B, that indicates that NLA_F_NET_BYTEORDER is set.
|
||||
*/
|
||||
void mnl_nlmsg_fprintf(FILE *fd, const void *data, size_t datalen,
|
||||
size_t extra_header_size)
|
||||
{
|
||||
const struct nlmsghdr *nlh = data;
|
||||
int len = datalen;
|
||||
|
||||
while (mnl_nlmsg_ok(nlh, len)) {
|
||||
mnl_nlmsg_fprintf_header(fd, nlh);
|
||||
mnl_nlmsg_fprintf_payload(fd, nlh, extra_header_size);
|
||||
nlh = mnl_nlmsg_next(nlh, &len);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup batch Netlink message batch helpers
|
||||
*
|
||||
* This library provides helpers to batch several messages into one single
|
||||
* datagram. These helpers do not perform strict memory boundary checkings.
|
||||
*
|
||||
* The following figure represents a Netlink message batch:
|
||||
*
|
||||
* |<-------------- MNL_SOCKET_BUFFER_SIZE ------------->|
|
||||
* |<-------------------- batch ------------------>| |
|
||||
* |-----------|-----------|-----------|-----------|-----------|
|
||||
* |<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|<- nlmsg ->|
|
||||
* |-----------|-----------|-----------|-----------|-----------|
|
||||
* ^ ^
|
||||
* | |
|
||||
* message N message N+1
|
||||
*
|
||||
* To start the batch, you have to call mnl_nlmsg_batch_start() and you can
|
||||
* use mnl_nlmsg_batch_stop() to release it.
|
||||
*
|
||||
* You have to invoke mnl_nlmsg_batch_next() to get room for a new message
|
||||
* in the batch. If this function returns NULL, it means that the last
|
||||
* message that was added (message N+1 in the figure above) does not fit the
|
||||
* batch. Thus, you have to send the batch (which includes until message N)
|
||||
* and, then, you have to call mnl_nlmsg_batch_reset() to re-initialize
|
||||
* the batch (this moves message N+1 to the head of the buffer). For that
|
||||
* reason, the buffer that you have to use to store the batch must be double
|
||||
* of MNL_SOCKET_BUFFER_SIZE to ensure that the last message (message N+1)
|
||||
* that did not fit into the batch is written inside valid memory boundaries.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
struct mnl_nlmsg_batch {
|
||||
/* the buffer that is used to store the batch. */
|
||||
void *buf;
|
||||
size_t limit;
|
||||
size_t buflen;
|
||||
/* the current netlink message in the batch. */
|
||||
void *cur;
|
||||
bool overflow;
|
||||
};
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_start - initialize a batch
|
||||
* \param buf pointer to the buffer that will store this batch
|
||||
* \param limit maximum size of the batch (should be MNL_SOCKET_BUFFER_SIZE).
|
||||
*
|
||||
* The buffer that you pass must be double of MNL_SOCKET_BUFFER_SIZE. The
|
||||
* limit must be half of the buffer size, otherwise expect funny memory
|
||||
* corruptions 8-).
|
||||
*
|
||||
* You can allocate the buffer that you use to store the batch in the stack or
|
||||
* the heap, no restrictions in this regard. This function returns NULL on
|
||||
* error.
|
||||
*/
|
||||
struct mnl_nlmsg_batch *mnl_nlmsg_batch_start(void *buf,
|
||||
size_t limit)
|
||||
{
|
||||
struct mnl_nlmsg_batch *b;
|
||||
|
||||
b = malloc(sizeof(struct mnl_nlmsg_batch));
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
|
||||
b->buf = buf;
|
||||
b->limit = limit;
|
||||
b->buflen = 0;
|
||||
b->cur = buf;
|
||||
b->overflow = false;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_stop - release a batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function releases the batch allocated by mnl_nlmsg_batch_start().
|
||||
*/
|
||||
void mnl_nlmsg_batch_stop(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
free(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_next - get room for the next message in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns false if the last message did not fit into the
|
||||
* batch. Otherwise, it prepares the batch to provide room for the new
|
||||
* Netlink message in the batch and returns true.
|
||||
*
|
||||
* You have to put at least one message in the batch before calling this
|
||||
* function, otherwise your application is likely to crash.
|
||||
*/
|
||||
bool mnl_nlmsg_batch_next(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
struct nlmsghdr *nlh = b->cur;
|
||||
|
||||
if (b->buflen + nlh->nlmsg_len > b->limit) {
|
||||
b->overflow = true;
|
||||
return false;
|
||||
}
|
||||
b->cur = b->buf + b->buflen + nlh->nlmsg_len;
|
||||
b->buflen += nlh->nlmsg_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_reset - reset the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function allows to reset a batch, so you can reuse it to create a
|
||||
* new one. This function moves the last message which does not fit the
|
||||
* batch to the head of the buffer, if any.
|
||||
*/
|
||||
void mnl_nlmsg_batch_reset(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
if (b->overflow) {
|
||||
struct nlmsghdr *nlh = b->cur;
|
||||
memcpy(b->buf, b->cur, nlh->nlmsg_len);
|
||||
b->buflen = nlh->nlmsg_len;
|
||||
b->cur = b->buf + b->buflen;
|
||||
b->overflow = false;
|
||||
} else {
|
||||
b->buflen = 0;
|
||||
b->cur = b->buf;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_size - get current size of the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns the current size of the batch.
|
||||
*/
|
||||
size_t mnl_nlmsg_batch_size(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buflen;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_head - get head of this batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns a pointer to the head of the batch, which is the
|
||||
* beginning of the buffer that is used.
|
||||
*/
|
||||
void *mnl_nlmsg_batch_head(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_current - returns current position in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns a pointer to the current position in the buffer
|
||||
* that is used to store the batch.
|
||||
*/
|
||||
void *mnl_nlmsg_batch_current(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->cur;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_nlmsg_batch_is_empty - check if there is any message in the batch
|
||||
* \param b pointer to batch
|
||||
*
|
||||
* This function returns true if the batch is empty.
|
||||
*/
|
||||
bool mnl_nlmsg_batch_is_empty(struct mnl_nlmsg_batch *b)
|
||||
{
|
||||
return b->buflen == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
351
package/fish/fibocom-dial/src/libmnl/socket.c
Normal file
351
package/fish/fibocom-dial/src/libmnl/socket.c
Normal file
@ -0,0 +1,351 @@
|
||||
/*
|
||||
* (C) 2008-2010 by Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
*
|
||||
* This program 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; either version 2.1 of the License, or
|
||||
* (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "libmnl.h"
|
||||
|
||||
/**
|
||||
* \mainpage
|
||||
*
|
||||
* libmnl is a minimalistic user-space library oriented to Netlink developers.
|
||||
* There are a lot of common tasks in parsing, validating, constructing of
|
||||
* both the Netlink header and TLVs that are repetitive and easy to get wrong.
|
||||
* This library aims to provide simple helpers that allows you to avoid
|
||||
* re-inventing the wheel in common Netlink tasks.
|
||||
*
|
||||
* \verbatim
|
||||
"Simplify, simplify" -- Henry David Thoureau. Walden (1854)
|
||||
\endverbatim
|
||||
*
|
||||
* The acronym libmnl stands for LIBrary Minimalistic NetLink.
|
||||
*
|
||||
* libmnl homepage is:
|
||||
* http://www.netfilter.org/projects/libmnl/
|
||||
*
|
||||
* \section features Main Features
|
||||
* - Small: the shared library requires around 30KB for an x86-based computer.
|
||||
* - Simple: this library avoids complex abstractions that tend to hide Netlink
|
||||
* details. It avoids elaborated object-oriented infrastructure and complex
|
||||
* callback-based workflow.
|
||||
* - Easy to use: the library simplifies the work for Netlink-wise developers.
|
||||
* It provides functions to make socket handling, message building,
|
||||
* validating, parsing and sequence tracking, easier.
|
||||
* - Easy to re-use: you can use this library to build your own abstraction
|
||||
* layer upon this library, if you want to provide another library that
|
||||
* hides Netlink details to your users.
|
||||
* - Decoupling: the interdependency of the main bricks that compose this
|
||||
* library is reduced, i.e. the library provides many helpers, but the
|
||||
* programmer is not forced to use them.
|
||||
*
|
||||
* \section licensing Licensing terms
|
||||
* This library is released under the LGPLv2.1 or any later (at your option).
|
||||
*
|
||||
* \section Dependencies
|
||||
* You have to install the Linux kernel headers that you want to use to develop
|
||||
* your application. Moreover, this library requires that you have some basics
|
||||
* on Netlink.
|
||||
*
|
||||
* \section scm Git Tree
|
||||
* The current development version of libmnl can be accessed at:
|
||||
* http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=summary
|
||||
*
|
||||
* \section using Using libmnl
|
||||
* You can access several example files under examples/ in the libmnl source
|
||||
* code tree.
|
||||
*/
|
||||
|
||||
struct mnl_socket {
|
||||
int fd;
|
||||
struct sockaddr_nl addr;
|
||||
};
|
||||
|
||||
/**
|
||||
* \defgroup socket Netlink socket helpers
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* mnl_socket_get_fd - obtain file descriptor from netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* This function returns the file descriptor of a given netlink socket.
|
||||
*/
|
||||
int mnl_socket_get_fd(const struct mnl_socket *nl)
|
||||
{
|
||||
return nl->fd;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_get_portid - obtain Netlink PortID from netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* This function returns the Netlink PortID of a given netlink socket.
|
||||
* It's a common mistake to assume that this PortID equals the process ID
|
||||
* which is not always true. This is the case if you open more than one
|
||||
* socket that is binded to the same Netlink subsystem from the same process.
|
||||
*/
|
||||
unsigned int mnl_socket_get_portid(const struct mnl_socket *nl)
|
||||
{
|
||||
return nl->addr.nl_pid;
|
||||
}
|
||||
|
||||
static struct mnl_socket *__mnl_socket_open(int bus, int flags)
|
||||
{
|
||||
struct mnl_socket *nl;
|
||||
|
||||
nl = calloc(1, sizeof(struct mnl_socket));
|
||||
if (nl == NULL)
|
||||
return NULL;
|
||||
|
||||
nl->fd = socket(AF_NETLINK, SOCK_RAW | flags, bus);
|
||||
if (nl->fd == -1) {
|
||||
free(nl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nl;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_open - open a netlink socket
|
||||
* \param bus the netlink socket bus ID (see NETLINK_* constants)
|
||||
*
|
||||
* On error, it returns NULL and errno is appropriately set. Otherwise, it
|
||||
* returns a valid pointer to the mnl_socket structure.
|
||||
*/
|
||||
struct mnl_socket *mnl_socket_open(int bus)
|
||||
{
|
||||
return __mnl_socket_open(bus, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_open2 - open a netlink socket with appropriate flags
|
||||
* \param bus the netlink socket bus ID (see NETLINK_* constants)
|
||||
* \param flags the netlink socket flags (see SOCK_* constants in socket(2))
|
||||
*
|
||||
* This is similar to mnl_socket_open(), but allows to set flags like
|
||||
* SOCK_CLOEXEC at socket creation time (useful for multi-threaded programs
|
||||
* performing exec calls).
|
||||
*
|
||||
* On error, it returns NULL and errno is appropriately set. Otherwise, it
|
||||
* returns a valid pointer to the mnl_socket structure.
|
||||
*/
|
||||
struct mnl_socket *mnl_socket_open2(int bus, int flags)
|
||||
{
|
||||
return __mnl_socket_open(bus, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_fdopen - associates a mnl_socket object with pre-existing socket.
|
||||
* \param fd pre-existing socket descriptor.
|
||||
*
|
||||
* On error, it returns NULL and errno is appropriately set. Otherwise, it
|
||||
* returns a valid pointer to the mnl_socket structure. It also sets the portID
|
||||
* if the socket fd is already bound and it is AF_NETLINK.
|
||||
*
|
||||
* Note that mnl_socket_get_portid() returns 0 if this function is used with
|
||||
* non-netlink socket.
|
||||
*/
|
||||
struct mnl_socket *mnl_socket_fdopen(int fd)
|
||||
{
|
||||
int ret;
|
||||
struct mnl_socket *nl;
|
||||
struct sockaddr_nl addr;
|
||||
socklen_t addr_len = sizeof(struct sockaddr_nl);
|
||||
|
||||
ret = getsockname(fd, (struct sockaddr *) &addr, &addr_len);
|
||||
if (ret == -1)
|
||||
return NULL;
|
||||
|
||||
nl = calloc(1, sizeof(struct mnl_socket));
|
||||
if (nl == NULL)
|
||||
return NULL;
|
||||
|
||||
nl->fd = fd;
|
||||
if (addr.nl_family == AF_NETLINK)
|
||||
nl->addr = addr;
|
||||
|
||||
return nl;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_bind - bind netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param groups the group of message you're interested in
|
||||
* \param pid the port ID you want to use (use zero for automatic selection)
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set. On
|
||||
* success, 0 is returned. You can use MNL_SOCKET_AUTOPID which is 0 for
|
||||
* automatic port ID selection.
|
||||
*/
|
||||
int mnl_socket_bind(struct mnl_socket *nl, unsigned int groups,
|
||||
pid_t pid)
|
||||
{
|
||||
int ret;
|
||||
socklen_t addr_len;
|
||||
|
||||
nl->addr.nl_family = AF_NETLINK;
|
||||
nl->addr.nl_groups = groups;
|
||||
nl->addr.nl_pid = pid;
|
||||
|
||||
ret = bind(nl->fd, (struct sockaddr *) &nl->addr, sizeof (nl->addr));
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
addr_len = sizeof(nl->addr);
|
||||
ret = getsockname(nl->fd, (struct sockaddr *) &nl->addr, &addr_len);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (addr_len != sizeof(nl->addr)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (nl->addr.nl_family != AF_NETLINK) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_sendto - send a netlink message of a certain size
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param buf buffer containing the netlink message to be sent
|
||||
* \param len number of bytes in the buffer that you want to send
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. Otherwise, it
|
||||
* returns the number of bytes sent.
|
||||
*/
|
||||
ssize_t mnl_socket_sendto(const struct mnl_socket *nl,
|
||||
const void *buf, size_t len)
|
||||
{
|
||||
static const struct sockaddr_nl snl = {
|
||||
.nl_family = AF_NETLINK
|
||||
};
|
||||
return sendto(nl->fd, buf, len, 0,
|
||||
(struct sockaddr *) &snl, sizeof(snl));
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_recvfrom - receive a netlink message
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param buf buffer that you want to use to store the netlink message
|
||||
* \param bufsiz size of the buffer passed to store the netlink message
|
||||
*
|
||||
* On error, it returns -1 and errno is appropriately set. If errno is set
|
||||
* to ENOSPC, it means that the buffer that you have passed to store the
|
||||
* netlink message is too small, so you have received a truncated message.
|
||||
* To avoid this, you have to allocate a buffer of MNL_SOCKET_BUFFER_SIZE
|
||||
* (which is 8KB, see linux/netlink.h for more information). Using this
|
||||
* buffer size ensures that your buffer is big enough to store the netlink
|
||||
* message without truncating it.
|
||||
*/
|
||||
ssize_t mnl_socket_recvfrom(const struct mnl_socket *nl,
|
||||
void *buf, size_t bufsiz)
|
||||
{
|
||||
ssize_t ret;
|
||||
struct sockaddr_nl addr;
|
||||
struct iovec iov = {
|
||||
.iov_base = buf,
|
||||
.iov_len = bufsiz,
|
||||
};
|
||||
struct msghdr msg = {
|
||||
.msg_name = &addr,
|
||||
.msg_namelen = sizeof(struct sockaddr_nl),
|
||||
.msg_iov = &iov,
|
||||
.msg_iovlen = 1,
|
||||
.msg_control = NULL,
|
||||
.msg_controllen = 0,
|
||||
.msg_flags = 0,
|
||||
};
|
||||
ret = recvmsg(nl->fd, &msg, 0);
|
||||
if (ret == -1)
|
||||
return ret;
|
||||
|
||||
if (msg.msg_flags & MSG_TRUNC) {
|
||||
errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
if (msg.msg_namelen != sizeof(struct sockaddr_nl)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_close - close a given netlink socket
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
* On success, it returns 0.
|
||||
*/
|
||||
int mnl_socket_close(struct mnl_socket *nl)
|
||||
{
|
||||
int ret = close(nl->fd);
|
||||
free(nl);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_setsockopt - set Netlink socket option
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param type type of Netlink socket options
|
||||
* \param buf the buffer that contains the data about this option
|
||||
* \param len the size of the buffer passed
|
||||
*
|
||||
* This function allows you to set some Netlink socket option. As of writing
|
||||
* this (see linux/netlink.h), the existing options are:
|
||||
*
|
||||
* - \#define NETLINK_ADD_MEMBERSHIP 1
|
||||
* - \#define NETLINK_DROP_MEMBERSHIP 2
|
||||
* - \#define NETLINK_PKTINFO 3
|
||||
* - \#define NETLINK_BROADCAST_ERROR 4
|
||||
* - \#define NETLINK_NO_ENOBUFS 5
|
||||
*
|
||||
* In the early days, Netlink only supported 32 groups expressed in a
|
||||
* 32-bits mask. However, since 2.6.14, Netlink may have up to 2^32 multicast
|
||||
* groups but you have to use setsockopt() with NETLINK_ADD_MEMBERSHIP to
|
||||
* join a given multicast group. This function internally calls setsockopt()
|
||||
* to join a given netlink multicast group. You can still use mnl_bind()
|
||||
* and the 32-bit mask to join a set of Netlink multicast groups.
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
*/
|
||||
int mnl_socket_setsockopt(const struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t len)
|
||||
{
|
||||
return setsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* mnl_socket_getsockopt - get a Netlink socket option
|
||||
* \param nl netlink socket obtained via mnl_socket_open()
|
||||
* \param type type of Netlink socket options
|
||||
* \param buf pointer to the buffer to store the value of this option
|
||||
* \param len size of the information written in the buffer
|
||||
*
|
||||
* On error, this function returns -1 and errno is appropriately set.
|
||||
*/
|
||||
int mnl_socket_getsockopt(const struct mnl_socket *nl, int type,
|
||||
void *buf, socklen_t *len)
|
||||
{
|
||||
return getsockopt(nl->fd, SOL_NETLINK, type, buf, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
1770
package/fish/fibocom-dial/src/main.c
Normal file
1770
package/fish/fibocom-dial/src/main.c
Normal file
File diff suppressed because it is too large
Load Diff
1019
package/fish/fibocom-dial/src/multi-pdn-manager.c
Normal file
1019
package/fish/fibocom-dial/src/multi-pdn-manager.c
Normal file
File diff suppressed because it is too large
Load Diff
67
package/fish/fibocom-dial/src/multi-pdn.ini
Normal file
67
package/fish/fibocom-dial/src/multi-pdn.ini
Normal file
@ -0,0 +1,67 @@
|
||||
[Setting]
|
||||
qmap_num=4
|
||||
|
||||
[profile1]
|
||||
apn=1234567890
|
||||
user=qwertyuio
|
||||
password=asdfghjkl
|
||||
auth=2
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile2]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=0
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile3]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=0
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile4]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=0
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile5]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile6]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile7]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
[profile8]
|
||||
apn=ctnet
|
||||
user=
|
||||
password=
|
||||
auth=
|
||||
ipfamily=1
|
||||
pin=
|
||||
|
||||
438
package/fish/fibocom-dial/src/qmap_bridge_mode.c
Normal file
438
package/fish/fibocom-dial/src/qmap_bridge_mode.c
Normal file
@ -0,0 +1,438 @@
|
||||
#include "QMIThread.h"
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037
|
||||
#include <net/if.h>
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037
|
||||
|
||||
static size_t fibo_fread(const char *filename, void *buf, size_t size)
|
||||
{
|
||||
FILE *fp = fopen(filename, "r");
|
||||
size_t n = 0;
|
||||
|
||||
memset(buf, 0x00, size);
|
||||
|
||||
if (fp) {
|
||||
n = fread(buf, 1, size, fp);
|
||||
if (n <= 0 || n == size) {
|
||||
dbg_time(
|
||||
"warnning: fail to fread(%s), fread=%zd, buf_size=%zd, "
|
||||
"errno: %d (%s)",
|
||||
__func__, filename, n, size, errno, strerror(errno));
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return n > 0 ? n : 0;
|
||||
}
|
||||
|
||||
static size_t fibo_fwrite(const char *filename, const void *buf, size_t size)
|
||||
{
|
||||
FILE *fp = fopen(filename, "w");
|
||||
size_t n = 0;
|
||||
|
||||
if (fp) {
|
||||
n = fwrite(buf, 1, size, fp);
|
||||
if (n != size) {
|
||||
dbg_time(
|
||||
"warnning: fail to fwrite(%s), fwrite=%zd, buf_size=%zd, "
|
||||
"errno: %d (%s)",
|
||||
__func__, filename, n, size, errno, strerror(errno));
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
return n > 0 ? n : 0;
|
||||
}
|
||||
|
||||
static int fibo_iface_is_in_bridge(const char *iface)
|
||||
{
|
||||
char filename[256];
|
||||
|
||||
snprintf(filename, sizeof(filename), "/sys/class/net/%s/brport", iface);
|
||||
return (access(filename, F_OK) == 0 || errno != ENOENT);
|
||||
}
|
||||
|
||||
int fibo_bridge_mode_detect(PROFILE_T *profile)
|
||||
{
|
||||
const char *ifname = profile->qmapnet_adapter ? profile->qmapnet_adapter
|
||||
: profile->usbnet_adapter;
|
||||
const char *driver;
|
||||
char bridge_mode[128];
|
||||
char bridge_ipv4[128];
|
||||
char ipv4[128];
|
||||
char buf[64];
|
||||
size_t n;
|
||||
int in_bridge;
|
||||
|
||||
driver = profile->driver_name;
|
||||
snprintf(bridge_mode, sizeof(bridge_mode), "/sys/class/net/%s/bridge_mode",
|
||||
ifname);
|
||||
snprintf(bridge_ipv4, sizeof(bridge_ipv4), "/sys/class/net/%s/bridge_ipv4",
|
||||
ifname);
|
||||
|
||||
if (access(bridge_mode, F_OK) && errno == ENOENT) {
|
||||
snprintf(bridge_mode, sizeof(bridge_mode),
|
||||
"/sys/module/%s/parameters/bridge_mode", driver);
|
||||
snprintf(bridge_ipv4, sizeof(bridge_ipv4),
|
||||
"/sys/module/%s/parameters/bridge_ipv4", driver);
|
||||
|
||||
if (access(bridge_mode, F_OK) && errno == ENOENT) {
|
||||
bridge_mode[0] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
in_bridge = fibo_iface_is_in_bridge(ifname);
|
||||
if (in_bridge) {
|
||||
dbg_time("notice: iface %s had add to bridge\n", ifname);
|
||||
}
|
||||
|
||||
if (in_bridge && bridge_mode[0] == '\0') {
|
||||
dbg_time("warnning: can not find bride_mode file for %s\n", ifname);
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = fibo_fread(bridge_mode, buf, sizeof(buf));
|
||||
|
||||
if (in_bridge) {
|
||||
if (n <= 0 || buf[0] == '0') {
|
||||
dbg_time("warnning: should set 1 to bride_mode file for %s\n",
|
||||
ifname);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (n <= 0 || buf[0] == '0') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
memset(ipv4, 0, sizeof(ipv4));
|
||||
|
||||
if (strstr(bridge_ipv4, "/sys/class/net/") || profile->qmap_mode == 0 ||
|
||||
profile->qmap_mode == 1) {
|
||||
snprintf(ipv4, sizeof(ipv4), "0x%x", profile->ipv4.Address);
|
||||
dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
|
||||
fibo_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
|
||||
} else {
|
||||
snprintf(ipv4, sizeof(ipv4), "0x%x:%d", profile->ipv4.Address,
|
||||
profile->muxid);
|
||||
dbg_time("echo '%s' > %s", ipv4, bridge_ipv4);
|
||||
fibo_fwrite(bridge_ipv4, ipv4, strlen(ipv4));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037
|
||||
void fibo_get_driver_info(PROFILE_T *profile, RMNET_INFO *rmnet_info) {
|
||||
int ifc_ctl_sock;
|
||||
struct ifreq ifr;
|
||||
int rc;
|
||||
int request = 0x89F3;
|
||||
unsigned char data[512];
|
||||
|
||||
memset(rmnet_info, 0x00, sizeof(*rmnet_info));
|
||||
|
||||
ifc_ctl_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if (ifc_ctl_sock <= 0) {
|
||||
dbg_time("socket() failed: %s\n", strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
strncpy(ifr.ifr_name, profile->usbnet_adapter, IFNAMSIZ);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = 0;
|
||||
ifr.ifr_ifru.ifru_data = (void *)data;
|
||||
rc = ioctl(ifc_ctl_sock, request, &ifr);
|
||||
if (rc < 0) {
|
||||
dbg_time("ioctl(0x%x, qmap_settings) failed: %s, rc=%d", request, strerror(errno), rc);
|
||||
}
|
||||
else {
|
||||
memcpy(rmnet_info, data, sizeof(*rmnet_info));
|
||||
}
|
||||
|
||||
close(ifc_ctl_sock);
|
||||
}
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037
|
||||
int fibo_qmap_mode_detect(PROFILE_T *profile)
|
||||
{
|
||||
int n;
|
||||
char buf[128];
|
||||
char qmap_netcard[128];
|
||||
struct {
|
||||
char filename[255 * 2];
|
||||
char linkname[255 * 2];
|
||||
} * pl;
|
||||
|
||||
pl = (typeof(pl))malloc(sizeof(*pl));
|
||||
|
||||
snprintf(pl->linkname, sizeof(pl->linkname),
|
||||
"/sys/class/net/%s/device/driver", profile->usbnet_adapter);
|
||||
n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
|
||||
pl->filename[n] = '\0';
|
||||
while (pl->filename[n] != '/') n--;
|
||||
profile->driver_name = strdup(&pl->filename[n + 1]);
|
||||
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed begin for oa 20210311037
|
||||
fibo_get_driver_info(profile, &profile->rmnet_info);
|
||||
if (profile->rmnet_info.size) {
|
||||
profile->qmap_mode = profile->rmnet_info.qmap_mode;
|
||||
if (profile->qmap_mode) {
|
||||
int offset_id = profile->pdp - 1;
|
||||
|
||||
if (profile->qmap_mode == 1)
|
||||
offset_id = 0;
|
||||
profile->muxid = profile->rmnet_info.mux_id[offset_id];
|
||||
profile->qmapnet_adapter = strdup( profile->rmnet_info.ifname[offset_id]);
|
||||
profile->qmap_size = profile->rmnet_info.rx_urb_size;
|
||||
profile->qmap_version = profile->rmnet_info.qmap_version;
|
||||
}
|
||||
|
||||
goto _out;
|
||||
}
|
||||
//2021-03-15 zhangkaibo@fibocom.com changed end for oa 20210311037
|
||||
|
||||
if (qmidev_is_pciemhi(profile->qmichannel)) {
|
||||
profile->qmap_mode = 1;
|
||||
|
||||
if (profile->muxid == 0 || profile->muxid == 0x81)
|
||||
{
|
||||
profile->muxid = 0x81;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (profile->muxid < 0x80)
|
||||
profile->muxid += 0x81;
|
||||
profile->qmap_mode = 2;
|
||||
}
|
||||
|
||||
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
|
||||
goto _final_process;
|
||||
}
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_num",
|
||||
profile->usbnet_adapter);
|
||||
|
||||
//2021-01-27 willa.liu@fibocom.com changed begin for support mantis 0068849
|
||||
if (access(pl->filename, F_OK) == 0) {
|
||||
dbg_time("access %s", pl->filename);
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno,
|
||||
strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837
|
||||
/*
|
||||
snprintf(pl->filename, sizeof(pl->filename),
|
||||
"/sys/module/%s/parameters/qmap_num", profile->driver_name);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename,
|
||||
errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
pl->filename, sizeof(pl->filename),
|
||||
"/sys/class/net/%s/device/driver/module/parameters/qmap_num",
|
||||
profile->usbnet_adapter);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename,
|
||||
errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
//2021-02-01 willa.liu@fibocom.com changed end for support mantis 0069837
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_mode",
|
||||
profile->usbnet_adapter);
|
||||
|
||||
if (access(pl->filename, F_OK) == 0) {
|
||||
dbg_time("access %s", pl->filename);
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno,
|
||||
strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!access(pl->filename, R_OK))
|
||||
{
|
||||
n = fibo_fread(pl->filename, buf, sizeof(buf));
|
||||
if(n > 0)
|
||||
{
|
||||
profile->qmap_mode = atoi(buf);
|
||||
if(profile->qmap_mode >= 1 && qmidev_is_pciemhi(profile->qmichannel))
|
||||
{
|
||||
profile->muxid =
|
||||
profile->pdp + 0x80;
|
||||
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
}
|
||||
if(qmidev_is_gobinet(profile->qmichannel) || qmidev_is_qmiwwan(profile->qmichannel))
|
||||
{
|
||||
if(profile->qmap_mode > 1)
|
||||
{
|
||||
profile->muxid =
|
||||
profile->pdp + 0x80;
|
||||
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
}
|
||||
if(profile->qmap_mode == 1)
|
||||
{
|
||||
profile->muxid = 0x81;
|
||||
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (0) {
|
||||
profile->qmap_mode = atoi(buf);
|
||||
|
||||
if (profile->qmap_mode > 1 && qmidev_is_gobinet(profile->qmichannel)) {
|
||||
profile->muxid =
|
||||
profile->pdp + 0x80; // muxis is 0x8X for PDN-X
|
||||
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
}
|
||||
if (profile->qmap_mode >= 1 && !qmidev_is_gobinet(profile->qmichannel)) {
|
||||
profile->muxid =
|
||||
profile->pdp + 0x80; // muxis is 0x8X for PDN-X
|
||||
sprintf(qmap_netcard, "%s.%d", profile->usbnet_adapter,profile->pdp);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
}
|
||||
if (profile->qmap_mode == 1 && qmidev_is_gobinet(profile->qmichannel)) {
|
||||
profile->muxid = 0x81;
|
||||
profile->qmapnet_adapter = strdup(profile->usbnet_adapter);
|
||||
//2021-01-27 willa.liu@fibocom.com changed end for support mantis 0068849
|
||||
|
||||
}
|
||||
}
|
||||
} else if (qmidev_is_qmiwwan(profile->qmichannel)) {
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/qmimux%d",
|
||||
profile->pdp - 1);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename,
|
||||
errno, strerror(errno));
|
||||
}
|
||||
goto _out;
|
||||
}
|
||||
|
||||
// upstream Kernel Style QMAP qmi_wwan.c
|
||||
snprintf(pl->filename, sizeof(pl->filename),
|
||||
"/sys/class/net/%s/qmi/add_mux", profile->usbnet_adapter);
|
||||
n = fibo_fread(pl->filename, buf, sizeof(buf));
|
||||
if (n >= 5) {
|
||||
profile->qmap_mode = n / 5; // 0x81\n0x82\n0x83\n
|
||||
if (profile->qmap_mode > 1) {
|
||||
// PDN-X map to qmimux-X
|
||||
profile->muxid = (buf[5 * (profile->pdp - 1) + 2] - '0') * 16 +
|
||||
(buf[5 * (profile->pdp - 1) + 3] - '0');
|
||||
sprintf(qmap_netcard, "qmimux%d", profile->pdp - 1);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
} else if (profile->qmap_mode == 1) {
|
||||
profile->muxid =
|
||||
(buf[5 * 0 + 2] - '0') * 16 + (buf[5 * 0 + 3] - '0');
|
||||
sprintf(qmap_netcard, "qmimux%d", 0);
|
||||
profile->qmapnet_adapter = strdup(qmap_netcard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_out:
|
||||
if (profile->qmap_mode) {
|
||||
profile->qmap_size = 16 * 1024;
|
||||
snprintf(pl->filename, sizeof(pl->filename),
|
||||
"/sys/class/net/%s/qmap_size", profile->usbnet_adapter);
|
||||
if (!access(pl->filename, R_OK)) {
|
||||
size_t n;
|
||||
char buf[32];
|
||||
n = fibo_fread(pl->filename, buf, sizeof(buf));
|
||||
if (n > 0) {
|
||||
profile->qmap_size = atoi(buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_final_process:
|
||||
if (profile->qmap_mode)
|
||||
dbg_time("qmap_mode = %d, muxid = 0x%02x, qmap_netcard = %s",
|
||||
profile->qmap_mode, profile->muxid, profile->qmapnet_adapter);
|
||||
|
||||
free(pl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fibo_qmap_mode_set(PROFILE_T *profile)
|
||||
{
|
||||
int n;
|
||||
char buf[128];
|
||||
struct {
|
||||
char filename[255 * 2];
|
||||
char linkname[255 * 2];
|
||||
} * pl;
|
||||
|
||||
if (qmidev_is_pciemhi(profile->qmichannel))
|
||||
{
|
||||
dbg_time("pcie mode exit fibo_qmap_mode_set ");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pl = (typeof(pl))malloc(sizeof(*pl));
|
||||
|
||||
snprintf(pl->linkname, sizeof(pl->linkname),
|
||||
"/sys/class/net/%s/device/driver", profile->usbnet_adapter);
|
||||
n = readlink(pl->linkname, pl->filename, sizeof(pl->filename));
|
||||
pl->filename[n] = '\0';
|
||||
while (pl->filename[n] != '/') n--;
|
||||
profile->driver_name = strdup(&pl->filename[n + 1]);
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename), "/sys/class/net/%s/qmap_num",
|
||||
profile->usbnet_adapter);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename, errno,
|
||||
strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(pl->filename, sizeof(pl->filename),
|
||||
"/sys/module/%s/parameters/qmap_mnum", profile->driver_name);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename,
|
||||
errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
pl->filename, sizeof(pl->filename),
|
||||
"/sys/class/net/%s/device/driver/module/parameters/qmap_num",
|
||||
profile->usbnet_adapter);
|
||||
if (access(pl->filename, R_OK)) {
|
||||
if (errno != ENOENT) {
|
||||
dbg_time("fail to access %s, errno: %d (%s)", pl->filename,
|
||||
errno, strerror(errno));
|
||||
goto _out;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!access(pl->filename, R_OK)) {
|
||||
snprintf(buf, sizeof(buf), "%d", profile->pdpnum);
|
||||
n = fibo_fwrite(pl->filename, buf, strlen(buf));
|
||||
}
|
||||
|
||||
_out:
|
||||
|
||||
free(pl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
160
package/fish/fibocom-dial/src/query_pcie_mode.c
Normal file
160
package/fish/fibocom-dial/src/query_pcie_mode.c
Normal file
@ -0,0 +1,160 @@
|
||||
//2021-03-24 willa.liu@fibocom.com changed begin for support mantis 0071817
|
||||
#include "QMIThread.h"
|
||||
#include "query_pcie_mode.h"
|
||||
int speed_arr[] = { B115200, B19200, B9600, B4800, B2400, B1200, B300,//
|
||||
B38400, B19200, B9600, B4800, B2400, B1200, B300,
|
||||
};
|
||||
int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300,
|
||||
38400, 19200, 9600, 4800, 2400, 1200, 300,
|
||||
};
|
||||
|
||||
int get_pcie_mode_debug = 0;
|
||||
|
||||
//2021-02-24 willa.liu@fibocom.com changed begin for support eipd SN-20210129001
|
||||
int get_private_gateway_debug = 1;
|
||||
//2021-02-24 willa.liu@fibocom.com changed end for support eipd SN-20210129001
|
||||
|
||||
//static int xset1(int fd, struct termios *tio, const char *device)
|
||||
int xset1(int fd, struct termios *tio, const char *device)
|
||||
{
|
||||
int ret = tcsetattr(fd, TCSAFLUSH, tio);
|
||||
|
||||
if (ret) {
|
||||
printf("can't tcsetattr for %s", device);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// set raw tty mode
|
||||
//static void xget1(int fd, struct termios *t, struct termios *oldt)
|
||||
void xget1(int fd, struct termios *t, struct termios *oldt)
|
||||
{
|
||||
tcgetattr(fd, oldt);
|
||||
*t = *oldt;
|
||||
cfmakeraw(t);
|
||||
// t->c_lflag &= ~(ISIG|ICANON|ECHO|IEXTEN);
|
||||
// t->c_iflag &= ~(BRKINT|IXON|ICRNL);
|
||||
// t->c_oflag &= ~(ONLCR);
|
||||
// t->c_cc[VMIN] = 1;
|
||||
// t->c_cc[VTIME] = 0;
|
||||
}
|
||||
|
||||
//static int get_pcie_mode()
|
||||
int get_pcie_mode()
|
||||
//2021-03-24 willa.liu@fibocom.com changed end for support mantis 0071817
|
||||
{
|
||||
int i;
|
||||
int fd;
|
||||
int ret;
|
||||
char buffer[409600] = {0};
|
||||
int rate;
|
||||
char* sendbuffer;
|
||||
int totallen = 0;
|
||||
fd_set readfds;
|
||||
struct timeval timeout;
|
||||
struct termios tio0, tiosfd, tio;
|
||||
|
||||
int timeoutVal = 5;
|
||||
|
||||
char *dev = "/dev/ttyUSB1"; //The port under Linux is operated by opening the device file
|
||||
rate = 115200;
|
||||
sendbuffer = "at+gtpcie=3";
|
||||
printf ( "dev: %s\nrate:%d\nsendbuffer:%s\n", dev,rate,sendbuffer);
|
||||
|
||||
fd = open(dev, O_RDWR | O_NOCTTY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
goto ERR;
|
||||
fcntl(fd, F_SETFL, O_RDWR);
|
||||
|
||||
// put device to "raw mode"
|
||||
xget1(fd, &tio, &tiosfd);
|
||||
// set device speed
|
||||
for ( i = 0;i < sizeof ( speed_arr ) / sizeof ( int );i++ )
|
||||
{
|
||||
if ( rate == name_arr[i] ) //Judge if the pass is equal to the pass
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(i >= sizeof ( speed_arr ) / sizeof ( int ))
|
||||
{
|
||||
printf("bound rate set failed\n");
|
||||
goto ERR;
|
||||
}
|
||||
|
||||
cfsetspeed(&tio, speed_arr[i]);
|
||||
if (xset1(fd, &tio, dev))
|
||||
goto ERR;
|
||||
|
||||
tcflush ( fd, TCIOFLUSH );
|
||||
|
||||
sprintf(buffer, "%s\r", sendbuffer);
|
||||
ret = write ( fd, buffer, strlen(buffer) );
|
||||
if(ret < 0)
|
||||
{
|
||||
printf ( "write failed\n" );
|
||||
goto ERR;
|
||||
}
|
||||
if(get_pcie_mode_debug)printf("write %d\n", ret);
|
||||
|
||||
FD_ZERO ( &readfds );
|
||||
FD_SET ( fd, &readfds );
|
||||
|
||||
while(1)
|
||||
{
|
||||
timeout.tv_sec = timeoutVal;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
ret = select ( fd+1, &readfds, ( fd_set * ) 0, ( fd_set * ) 0, &timeout );
|
||||
if(ret > 0)
|
||||
{
|
||||
ret = read ( fd, buffer+totallen, sizeof(buffer)-totallen-1 );
|
||||
if(ret < 0)
|
||||
{
|
||||
printf ( "read failed\n" );
|
||||
goto ERR;
|
||||
}
|
||||
|
||||
if(ret == 0)
|
||||
{
|
||||
goto ERR;
|
||||
}
|
||||
|
||||
totallen += ret;
|
||||
buffer[totallen] = '\0';
|
||||
if(get_pcie_mode_debug)printf("read %d(%s)\n", ret, &buffer[totallen-ret]);
|
||||
if(totallen == sizeof(buffer)-1)
|
||||
break;
|
||||
|
||||
if(strstr(buffer,"\nOK") || strstr(buffer,"\nERROR")
|
||||
|| strstr(buffer,"\n+CME ERROR:") || strstr(buffer,"\n+CMS ERROR:"))
|
||||
{
|
||||
if(get_pcie_mode_debug)printf("match OK/ERROR");
|
||||
if(get_pcie_mode_debug)printf("%s", buffer);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ( "select timeout\n" );
|
||||
goto ERR;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tcsetattr(fd, TCSAFLUSH, &tiosfd);
|
||||
//printf("buffer:\n %s\n", buffer);
|
||||
printf("%s\n", buffer);
|
||||
if(strstr(buffer,"\nERROR") || strstr(buffer,"\n+CME ERROR:") || strstr(buffer,"\n+CMS ERROR:"))
|
||||
goto ERR;
|
||||
|
||||
close ( fd );
|
||||
return 0;
|
||||
ERR:
|
||||
if(fd > 0)
|
||||
close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
17
package/fish/fibocom-dial/src/query_pcie_mode.h
Normal file
17
package/fish/fibocom-dial/src/query_pcie_mode.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef __QUERY_PCIE_MODE__
|
||||
#define __QUERY_PCIE_MODE__
|
||||
|
||||
extern int speed_arr[14];
|
||||
extern int name_arr[14];
|
||||
|
||||
extern int get_pcie_mode_debug;
|
||||
|
||||
extern int get_private_gateway_debug;
|
||||
|
||||
extern int xset1(int fd, struct termios *tio, const char *device);
|
||||
|
||||
// set raw tty mode
|
||||
extern void xget1(int fd, struct termios *t, struct termios *oldt);
|
||||
extern int get_pcie_mode();
|
||||
|
||||
#endif
|
||||
289
package/fish/fibocom-dial/src/udhcpc.c
Normal file
289
package/fish/fibocom-dial/src/udhcpc.c
Normal file
@ -0,0 +1,289 @@
|
||||
#include <arpa/inet.h>
|
||||
#include <endian.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "QMIThread.h"
|
||||
#include "util.h"
|
||||
|
||||
static int dibbler_client_alive = 0;
|
||||
|
||||
static int fibo_system(const char *shell_cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
dbg_time("%s", shell_cmd);
|
||||
ret = system(shell_cmd);
|
||||
if (ret) {
|
||||
// dbg_time("Fail to system(\"%s\") = %d, errno: %d (%s)", shell_cmd,
|
||||
// ret, errno, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void fibo_set_mtu(const char *ifname, int ifru_mtu)
|
||||
{
|
||||
int inet_sock;
|
||||
struct ifreq ifr;
|
||||
|
||||
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (inet_sock > 0) {
|
||||
strcpy(ifr.ifr_name, ifname);
|
||||
|
||||
if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) {
|
||||
if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) {
|
||||
dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu,
|
||||
ifru_mtu);
|
||||
ifr.ifr_ifru.ifru_mtu = ifru_mtu;
|
||||
ioctl(inet_sock, SIOCSIFMTU, &ifr);
|
||||
}
|
||||
}
|
||||
|
||||
close(inet_sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void *udhcpc_thread_function(void *arg)
|
||||
{
|
||||
FILE *udhcpc_fp;
|
||||
char *udhcpc_cmd = (char *)arg;
|
||||
|
||||
if (udhcpc_cmd == NULL)
|
||||
return NULL;
|
||||
|
||||
dbg_time("%s", udhcpc_cmd);
|
||||
udhcpc_fp = popen(udhcpc_cmd, "r");
|
||||
free(udhcpc_cmd);
|
||||
if (udhcpc_fp) {
|
||||
char buf[0xff];
|
||||
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
while ((fgets(buf, sizeof(buf) - 1, udhcpc_fp)) != NULL) {
|
||||
if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n'))
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
dbg_time("%s", buf);
|
||||
}
|
||||
|
||||
pclose(udhcpc_fp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void fibo_set_driver_link_state(PROFILE_T *profile, int link_state)
|
||||
{
|
||||
char link_file[128];
|
||||
int fd;
|
||||
int new_state = 0;
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state",
|
||||
profile->usbnet_adapter);
|
||||
fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd == -1) {
|
||||
if (errno != ENOENT)
|
||||
dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno,
|
||||
strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile->qmap_mode <= 1)
|
||||
new_state = !!link_state;
|
||||
else {
|
||||
// 0x80 means link off this pdp
|
||||
new_state = (link_state ? 0x00 : 0x80) + profile->pdp;
|
||||
}
|
||||
|
||||
snprintf(link_file, sizeof(link_file), "%d\n", new_state);
|
||||
write(fd, link_file, sizeof(link_file));
|
||||
|
||||
if (link_state == 0 && profile->qmap_mode > 1) {
|
||||
size_t rc;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
rc = read(fd, link_file, sizeof(link_file));
|
||||
if (rc > 1 && (!strcasecmp(link_file, "0\n") ||
|
||||
!strcasecmp(link_file, "0x0\n"))) {
|
||||
// snprintf(link_file, sizeof(link_file), "busybox ifconfig %s down",
|
||||
// profile->usbnet_adapter);
|
||||
// fibo_system(link_file);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int fibo_raw_ip_mode_check(const char *ifname)
|
||||
{
|
||||
int fd;
|
||||
char raw_ip[128];
|
||||
char shell_cmd[128];
|
||||
char mode[2] = "X";
|
||||
int mode_change = 0;
|
||||
|
||||
snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname);
|
||||
if (access(raw_ip, F_OK))
|
||||
return 0;
|
||||
|
||||
fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd < 0) {
|
||||
dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__,
|
||||
raw_ip, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
read(fd, mode, 2);
|
||||
if (mode[0] == '0' || mode[0] == 'N') {
|
||||
snprintf(shell_cmd, sizeof(shell_cmd), "busybox ifconfig %s down", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
|
||||
mode[0] = 'Y';
|
||||
write(fd, mode, 2);
|
||||
mode_change = 1;
|
||||
snprintf(shell_cmd, sizeof(shell_cmd), "busybox ifconfig %s up", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return mode_change;
|
||||
}
|
||||
|
||||
void udhcpc_start(PROFILE_T *profile)
|
||||
{
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
char shell_cmd[128];
|
||||
|
||||
fibo_set_driver_link_state(profile, 1);
|
||||
if (profile->qmapnet_adapter) {
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
dbg_time("1 %s", profile->qmichannel);
|
||||
if (qmidev_is_qmiwwan(profile->qmichannel)) {
|
||||
dbg_time("2 %s", ifname);
|
||||
fibo_raw_ip_mode_check(ifname);
|
||||
}
|
||||
|
||||
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) {
|
||||
fibo_set_mtu(ifname, (profile->ipv4.Mtu));
|
||||
}
|
||||
|
||||
fibo_system("echo 1 > /sys/module/fibo_mhi/parameters/macaddr_check");
|
||||
|
||||
//begin modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605
|
||||
// if (strcmp(ifname, profile->usbnet_adapter)) {
|
||||
// snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s up",
|
||||
// profile->usbnet_adapter);
|
||||
// fibo_system(shell_cmd);
|
||||
// }
|
||||
//begin modified by zhangkaibo fix ipv6 dial process flow. mantis 0048789 20200605
|
||||
// For IPv6, down & up will send protocol packets, and that's needed.
|
||||
if (profile->ipv6_flag) {
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s up", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
//begin modified by zhangming Added NOARP and Multilcast on flag bit commands. mantis 0050106 20200713
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s arp off multicast on", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
//begin modified by zhangming Added NOARP and Multilcast on flag bit commands. mantis 0050106 20200713
|
||||
//Modified unicom dual stack dialing unsuccessful problem
|
||||
|
||||
// for bridge mode, only one public IP, so do udhcpc manually
|
||||
if (fibo_bridge_mode_detect(profile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do DHCP using busybox tools */
|
||||
{
|
||||
char udhcpc_cmd[128];
|
||||
pthread_attr_t udhcpc_thread_attr;
|
||||
pthread_t udhcpc_thread_id;
|
||||
|
||||
pthread_attr_init(&udhcpc_thread_attr);
|
||||
pthread_attr_setdetachstate(&udhcpc_thread_attr,
|
||||
PTHREAD_CREATE_DETACHED);
|
||||
|
||||
if (profile->ipv4.Address) {
|
||||
if (access("/usr/share/udhcpc/default.script", X_OK)) {
|
||||
dbg_time(
|
||||
"Fail to access /usr/share/udhcpc/default.script, "
|
||||
"errno: %d (%s)",
|
||||
errno, strerror(errno));
|
||||
}
|
||||
|
||||
//-f,--foreground Run in foreground
|
||||
//-b,--background Background if lease is not obtained
|
||||
//-n,--now Exit if lease is not obtained
|
||||
//-q,--quit Exit after obtaining lease
|
||||
//-t,--retries N Send up to N discover packets (default 3)
|
||||
snprintf(udhcpc_cmd, sizeof(udhcpc_cmd),
|
||||
"busybox udhcpc -f -n -q -t 5 -i %s", ifname);
|
||||
|
||||
if (!access("/lib/netifd/dhcp.script", X_OK) &&
|
||||
!access("/sbin/ifup", X_OK) &&
|
||||
!access("/sbin/ifstatus", X_OK)) {
|
||||
dbg_time("you are use OpenWrt?");
|
||||
dbg_time("should not calling udhcpc manually?");
|
||||
dbg_time("should modify /etc/config/network as below?");
|
||||
dbg_time("config interface wan");
|
||||
dbg_time("\toption ifname %s", ifname);
|
||||
dbg_time("\toption proto dhcp");
|
||||
dbg_time(
|
||||
"should use \"/sbin/ifstaus wan\" to check %s 's status?",
|
||||
ifname);
|
||||
}
|
||||
|
||||
pthread_create(&udhcpc_thread_id, NULL, udhcpc_thread_function,
|
||||
(void *)strdup(udhcpc_cmd));
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
if (profile->ipv6.Address[0] && profile->ipv6.PrefixLengthIPAddr) {
|
||||
// module do not support DHCPv6, only support 'Router Solicit'
|
||||
// and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding,
|
||||
// Kernel do not send RS
|
||||
const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
|
||||
int forward_fd = open(forward_file, O_RDONLY);
|
||||
if (forward_fd > 0) {
|
||||
char forward_state[2];
|
||||
read(forward_fd, forward_state, 2);
|
||||
if (forward_state[0] == '1') {
|
||||
dbg_time(
|
||||
"%s enabled, kernel maybe donot send 'Router Solicit'",
|
||||
forward_file);
|
||||
}
|
||||
close(forward_fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void udhcpc_stop(PROFILE_T *profile)
|
||||
{
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
char shell_cmd[128];
|
||||
char reset_ip[128];
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
if (profile->qmapnet_adapter) {
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
|
||||
if (dibbler_client_alive) {
|
||||
system("killall dibbler-client");
|
||||
dibbler_client_alive = 0;
|
||||
}
|
||||
//snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down",
|
||||
// profile->usbnet_adapter);
|
||||
//fibo_system(shell_cmd);
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "busybox ifconfig %s down", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
snprintf(reset_ip, sizeof(reset_ip) - 1, "busybox ifconfig %s 0.0.0.0", ifname);
|
||||
fibo_system(reset_ip);
|
||||
}
|
||||
421
package/fish/fibocom-dial/src/udhcpc_netlink.c
Normal file
421
package/fish/fibocom-dial/src/udhcpc_netlink.c
Normal file
@ -0,0 +1,421 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <endian.h>
|
||||
|
||||
#include "libmnl/ifutils.h"
|
||||
#include "libmnl/dhcp/dhcp.h"
|
||||
#include "util.h"
|
||||
#include "QMIThread.h"
|
||||
|
||||
static int fibo_system(const char *shell_cmd)
|
||||
{
|
||||
int ret = 0;
|
||||
dbg_time("%s", shell_cmd);
|
||||
ret = system(shell_cmd);
|
||||
if (ret) {
|
||||
// dbg_time("Fail to system(\"%s\") = %d, errno: %d (%s)", shell_cmd,
|
||||
// ret, errno, strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fibo_raw_ip_mode_check(const char *ifname)
|
||||
{
|
||||
int fd;
|
||||
char raw_ip[128];
|
||||
char mode[2] = "X";
|
||||
int mode_change = 0;
|
||||
|
||||
snprintf(raw_ip, sizeof(raw_ip), "/sys/class/net/%s/qmi/raw_ip", ifname);
|
||||
if (access(raw_ip, F_OK))
|
||||
return 0;
|
||||
|
||||
fd = open(raw_ip, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd < 0)
|
||||
{
|
||||
dbg_time("%s %d fail to open(%s), errno:%d (%s)", __FILE__, __LINE__, raw_ip, errno, strerror(errno));
|
||||
return 0;
|
||||
}
|
||||
|
||||
read(fd, mode, 2);
|
||||
if (mode[0] == '0' || mode[0] == 'N')
|
||||
{
|
||||
if_link_down(ifname);
|
||||
dbg_time("echo Y > /sys/class/net/%s/qmi/raw_ip", ifname);
|
||||
mode[0] = 'Y';
|
||||
write(fd, mode, 2);
|
||||
mode_change = 1;
|
||||
if_link_up(ifname);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
return mode_change;
|
||||
}
|
||||
|
||||
static void fibo_set_driver_link_state(PROFILE_T *profile, int link_state)
|
||||
{
|
||||
char link_file[128];
|
||||
int fd;
|
||||
int new_state = 0;
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
snprintf(link_file, sizeof(link_file), "/sys/class/net/%s/link_state", profile->usbnet_adapter);
|
||||
fd = open(link_file, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd == -1)
|
||||
{
|
||||
if (errno != ENOENT)
|
||||
dbg_time("Fail to access %s, errno: %d (%s)", link_file, errno, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile->qmap_mode <= 1)
|
||||
new_state = !!link_state;
|
||||
else
|
||||
{
|
||||
//0x80 means link off this pdp
|
||||
new_state = (link_state ? 0x00 : 0x80) + profile->pdp;
|
||||
}
|
||||
|
||||
snprintf(link_file, sizeof(link_file), "%d\n", new_state);
|
||||
write(fd, link_file, sizeof(link_file));
|
||||
|
||||
if (link_state == 0 && profile->qmap_mode > 1)
|
||||
{
|
||||
size_t rc;
|
||||
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
rc = read(fd, link_file, sizeof(link_file));
|
||||
if (rc > 1 && (!strcasecmp(link_file, "0\n") || !strcasecmp(link_file, "0x0\n")))
|
||||
{
|
||||
// if_link_down(profile->usbnet_adapter);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
void udhcpc_start(PROFILE_T *profile)
|
||||
{
|
||||
//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
char shell_cmd[512];
|
||||
|
||||
fibo_set_driver_link_state(profile, 1);
|
||||
fibo_raw_ip_mode_check(ifname);
|
||||
|
||||
if (profile->qmapnet_adapter)
|
||||
{
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu)
|
||||
{
|
||||
if_set_mtu(ifname, (profile->ipv4.Mtu));
|
||||
}
|
||||
|
||||
if (strcmp(ifname, profile->usbnet_adapter))
|
||||
{
|
||||
//if_link_up(profile->usbnet_adapter);
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", profile->usbnet_adapter);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
//2021-02-01 willa.liu@fibocom.com changed begin for support mantis 0069837
|
||||
if_link_up(ifname);
|
||||
|
||||
#if 1 //for bridge mode, only one public IP, so do udhcpc manually
|
||||
if (fibo_bridge_mode_detect(profile))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
// if use DHCP(should make with ${DHCP} src files)
|
||||
// do_dhcp(ifname);
|
||||
// return 0;
|
||||
/* IPv4 Addr Info */
|
||||
if (profile->ipv4.Address)
|
||||
{
|
||||
dbg_time("IPv4 MTU: %d", profile->ipv4.Mtu);
|
||||
dbg_time("IPv4 Address: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Address)));
|
||||
dbg_time("IPv4 Netmask: %d", mask_to_prefix_v4(ntohl(profile->ipv4.SubnetMask)));
|
||||
dbg_time("IPv4 Gateway: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.Gateway)));
|
||||
dbg_time("IPv4 DNS1: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsPrimary)));
|
||||
dbg_time("IPv4 DNS2: %s", ipaddr_to_string_v4(ntohl(profile->ipv4.DnsSecondary)));
|
||||
if_set_network_v4(ifname, ntohl(profile->ipv4.Address),
|
||||
mask_to_prefix_v4(profile->ipv4.SubnetMask),
|
||||
ntohl(profile->ipv4.Gateway),
|
||||
ntohl(profile->ipv4.DnsPrimary),
|
||||
ntohl(profile->ipv4.DnsSecondary));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_time("The IPv4 Address in profile is NULL");
|
||||
}
|
||||
|
||||
if (profile->ipv6.Address && (profile->ipv6.PrefixLengthIPAddr != 0))
|
||||
{
|
||||
//module do not support DHCPv6, only support 'Router Solicit'
|
||||
//and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS
|
||||
const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
|
||||
int forward_fd = open(forward_file, O_RDONLY);
|
||||
if (forward_fd > 0)
|
||||
{
|
||||
char forward_state[2];
|
||||
read(forward_fd, forward_state, 2);
|
||||
if (forward_state[0] == '1')
|
||||
{
|
||||
dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
|
||||
}
|
||||
close(forward_fd);
|
||||
}
|
||||
|
||||
dbg_time("IPv6 MTU: %d", profile->ipv6.Mtu);
|
||||
dbg_time("IPv6 Address: %s", ipaddr_to_string_v6(profile->ipv6.Address));
|
||||
dbg_time("IPv6 PrefixLengthIPAddr: %d", profile->ipv6.PrefixLengthIPAddr);
|
||||
dbg_time("IPv6 Gateway: %s", ipaddr_to_string_v6(profile->ipv6.Gateway));
|
||||
dbg_time("IPv6 DNS1: %s", ipaddr_to_string_v6(profile->ipv6.DnsPrimary));
|
||||
dbg_time("IPv6 DNS2: %s", ipaddr_to_string_v6(profile->ipv6.DnsSecondary));
|
||||
if_set_network_v6(ifname, profile->ipv6.Address, profile->ipv6.PrefixLengthIPAddr,
|
||||
profile->ipv6.Gateway, profile->ipv6.DnsPrimary, profile->ipv6.DnsSecondary);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbg_time("The IPv6 Address in profile is NULL");
|
||||
}
|
||||
}
|
||||
|
||||
void udhcpc_stop(PROFILE_T *profile)
|
||||
{
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
fibo_set_driver_link_state(profile, 0);
|
||||
|
||||
if (profile->qmapnet_adapter)
|
||||
{
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
|
||||
if_flush_v4_addr(ifname);
|
||||
if_flush_v6_addr(ifname);
|
||||
if_link_down(ifname);
|
||||
}
|
||||
|
||||
static void fibo_set_mtu(const char *ifname, int ifru_mtu) {
|
||||
int inet_sock;
|
||||
struct ifreq ifr;
|
||||
|
||||
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
if (inet_sock > 0) {
|
||||
strcpy(ifr.ifr_name, ifname);
|
||||
|
||||
if (!ioctl(inet_sock, SIOCGIFMTU, &ifr)) {
|
||||
if (ifr.ifr_ifru.ifru_mtu != ifru_mtu) {
|
||||
dbg_time("change mtu %d -> %d", ifr.ifr_ifru.ifru_mtu , ifru_mtu);
|
||||
ifr.ifr_ifru.ifru_mtu = ifru_mtu;
|
||||
ioctl(inet_sock, SIOCSIFMTU, &ifr);
|
||||
}
|
||||
}
|
||||
|
||||
close(inet_sock);
|
||||
}
|
||||
}
|
||||
|
||||
static void* udhcpc_thread_function(void* arg) {
|
||||
FILE * udhcpc_fp;
|
||||
char *udhcpc_cmd = (char *)arg;
|
||||
|
||||
if (udhcpc_cmd == NULL)
|
||||
return NULL;
|
||||
|
||||
dbg_time("%s", udhcpc_cmd);
|
||||
udhcpc_fp = popen(udhcpc_cmd, "r");
|
||||
free(udhcpc_cmd);
|
||||
if (udhcpc_fp) {
|
||||
char buf[0xff];
|
||||
|
||||
buf[sizeof(buf)-1] = '\0';
|
||||
while((fgets(buf, sizeof(buf)-1, udhcpc_fp)) != NULL) {
|
||||
if ((strlen(buf) > 1) && (buf[strlen(buf) - 1] == '\n'))
|
||||
buf[strlen(buf) - 1] = '\0';
|
||||
dbg_time("%s", buf);
|
||||
}
|
||||
|
||||
pclose(udhcpc_fp);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void udhcpc_start_pcie(PROFILE_T *profile) {
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
char sub_intf_name[100] = {0};
|
||||
int intf_id = 0;
|
||||
char shell_cmd[512];
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
if (profile->qmapnet_adapter) {
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
|
||||
if (profile->muxid > 0x81)
|
||||
{
|
||||
intf_id = profile->muxid - 0x81;
|
||||
snprintf(sub_intf_name, sizeof(sub_intf_name) - 1, "%s.%d", ifname, intf_id);
|
||||
}
|
||||
|
||||
if (profile->rawIP && profile->ipv4.Address && profile->ipv4.Mtu) {
|
||||
fibo_set_mtu(ifname, (profile->ipv4.Mtu));
|
||||
}
|
||||
|
||||
fibo_system("echo 1 > /sys/module/fibo_mhi/parameters/macaddr_check");
|
||||
|
||||
if (strcmp(ifname, profile->usbnet_adapter)) {
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", profile->usbnet_adapter);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
|
||||
// For IPv6, down & up will send protocol packets, and that's needed.
|
||||
if (profile->ipv6_flag && profile->muxid <= 0x81) {
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s down", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s up", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
//for bridge mode, only one public IP, so do udhcpc manually
|
||||
if (fibo_bridge_mode_detect(profile)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Do DHCP using busybox tools */
|
||||
{
|
||||
char udhcpc_cmd[128];
|
||||
pthread_attr_t udhcpc_thread_attr;
|
||||
pthread_t udhcpc_thread_id;
|
||||
|
||||
pthread_attr_init(&udhcpc_thread_attr);
|
||||
pthread_attr_setdetachstate(&udhcpc_thread_attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
if (profile->ipv4.Address)
|
||||
{
|
||||
char v4add_str[32] = {0};
|
||||
char v4gw_str[32] = {0};
|
||||
char v4_netmask_str[32] = {0};
|
||||
uint32_t Address = ntohl(profile->ipv4.Address);
|
||||
uint32_t Gateway = ntohl(profile->ipv4.Gateway);
|
||||
uint32_t SubnetMask = ntohl(profile->ipv4.SubnetMask);
|
||||
inet_ntop(AF_INET, &Address, v4add_str, sizeof(v4add_str));
|
||||
inet_ntop(AF_INET, &Gateway, v4gw_str, sizeof(v4gw_str));
|
||||
inet_ntop(AF_INET, &SubnetMask, v4_netmask_str, sizeof(v4_netmask_str));
|
||||
|
||||
if (profile->muxid == 0x81)
|
||||
{
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s %s netmask %s", ifname, v4add_str, v4_netmask_str);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route add default gw %s dev %s", v4gw_str, ifname);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
else if (profile->muxid > 0x81)
|
||||
{
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link add link %s name %s type vlan id %d", ifname, sub_intf_name, intf_id);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", sub_intf_name);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s %s netmask %s", sub_intf_name, v4add_str, v4_netmask_str);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
if (profile->ipv6.PrefixLengthIPAddr)
|
||||
{
|
||||
//module do not support DHCPv6, only support 'Router Solicit'
|
||||
//and it seem if enable /proc/sys/net/ipv6/conf/all/forwarding, Kernel do not send RS
|
||||
const char *forward_file = "/proc/sys/net/ipv6/conf/all/forwarding";
|
||||
int forward_fd = open(forward_file, O_RDONLY);
|
||||
if (forward_fd > 0) {
|
||||
char forward_state[2];
|
||||
read(forward_fd, forward_state, 2);
|
||||
if (forward_state[0] == '1') {
|
||||
dbg_time("%s enabled, kernel maybe donot send 'Router Solicit'", forward_file);
|
||||
}
|
||||
close(forward_fd);
|
||||
}
|
||||
|
||||
{
|
||||
char v6add_str[100] = {0};
|
||||
char v6gw_str[100] = {0};
|
||||
inet_ntop(AF_INET6, profile->ipv6.Address, v6add_str, sizeof(v6add_str));
|
||||
inet_ntop(AF_INET6, profile->ipv6.Gateway, v6gw_str, sizeof(v6gw_str));
|
||||
|
||||
if (profile->muxid == 0x81)
|
||||
{
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s add %s/%d", ifname, v6add_str, profile->ipv6.PrefixLengthIPAddr);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route -A inet6 add ::/0 gw %s dev %s", v6gw_str, ifname);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
else if (profile->muxid > 0x81)
|
||||
{
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link add link %s name %s type vlan id %d", ifname, sub_intf_name, intf_id);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link set %s up", sub_intf_name);
|
||||
fibo_system(shell_cmd);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s add %s/%d", sub_intf_name, v6add_str, profile->ipv6.PrefixLengthIPAddr);
|
||||
fibo_system(shell_cmd);
|
||||
/* start 2021-01-21 add by haopengfei to fix mantis 69056 */
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "route -A inet6 add ::/0 gw %s dev %s", v6gw_str, sub_intf_name);
|
||||
fibo_system(shell_cmd);
|
||||
/* end 2021-01-21 add by haopengfei to fix mantis 69056 */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void udhcpc_stop_pcie(PROFILE_T *profile) {
|
||||
char *ifname = profile->usbnet_adapter;
|
||||
char shell_cmd[128];
|
||||
char reset_ip[128];
|
||||
dbg_time("enter %s ", __func__);
|
||||
|
||||
if (profile->qmapnet_adapter) {
|
||||
ifname = profile->qmapnet_adapter;
|
||||
}
|
||||
|
||||
if (profile->muxid == 0x81)
|
||||
{
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ifconfig %s down", ifname);
|
||||
fibo_system(shell_cmd);
|
||||
snprintf(reset_ip, sizeof(reset_ip) - 1, "ifconfig %s 0.0.0.0", ifname);
|
||||
fibo_system(reset_ip);
|
||||
}
|
||||
else if (profile->muxid > 0x81)
|
||||
{
|
||||
char sub_intf_name[100];
|
||||
int intf_id = profile->muxid - 0x81;
|
||||
snprintf(sub_intf_name, sizeof(sub_intf_name) - 1, "%s.%d", ifname, intf_id);
|
||||
|
||||
snprintf(shell_cmd, sizeof(shell_cmd) - 1, "ip link del link dev %s", sub_intf_name);
|
||||
fibo_system(shell_cmd);
|
||||
}
|
||||
}
|
||||
|
||||
142
package/fish/fibocom-dial/src/util.c
Normal file
142
package/fish/fibocom-dial/src/util.c
Normal file
@ -0,0 +1,142 @@
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "QMIThread.h"
|
||||
|
||||
#if defined(__STDC__)
|
||||
#include <stdarg.h>
|
||||
#define __V(x) x
|
||||
#else
|
||||
#include <varargs.h>
|
||||
#define __V(x) (va_alist) va_dcl
|
||||
#define const
|
||||
#define volatile
|
||||
#endif
|
||||
|
||||
#include <syslog.h>
|
||||
|
||||
#define is_bigendian() ((*(char *)&i) == 0)
|
||||
FILE *logfilefp = NULL;
|
||||
static pthread_mutex_t printfMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static char line[1024];
|
||||
const int i = 1;
|
||||
|
||||
// defined in atchannel.c
|
||||
static void setTimespecRelative(struct timespec *p_ts, long long msec)
|
||||
{
|
||||
struct timeval tv;
|
||||
|
||||
gettimeofday(&tv, (struct timezone *)NULL);
|
||||
|
||||
/* what's really funny about this is that I know
|
||||
pthread_cond_timedwait just turns around and makes this
|
||||
a relative time again */
|
||||
p_ts->tv_sec = tv.tv_sec + (msec / 1000);
|
||||
p_ts->tv_nsec = (tv.tv_usec + (msec % 1000) * 1000L) * 1000L;
|
||||
}
|
||||
|
||||
int pthread_cond_timeout_np(pthread_cond_t *cond, pthread_mutex_t *mutex,
|
||||
unsigned msecs)
|
||||
{
|
||||
if (msecs != 0) {
|
||||
struct timespec ts;
|
||||
setTimespecRelative(&ts, msecs);
|
||||
return pthread_cond_timedwait(cond, mutex, &ts);
|
||||
} else {
|
||||
return pthread_cond_wait(cond, mutex);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *get_time(void)
|
||||
{
|
||||
static char time_buf[50];
|
||||
struct timeval tv;
|
||||
time_t time;
|
||||
suseconds_t millitm;
|
||||
struct tm *ti;
|
||||
|
||||
gettimeofday(&tv, NULL);
|
||||
|
||||
time = tv.tv_sec;
|
||||
millitm = (tv.tv_usec + 500) / 1000;
|
||||
|
||||
if (millitm == 1000) {
|
||||
++time;
|
||||
millitm = 0;
|
||||
}
|
||||
|
||||
ti = localtime(&time);
|
||||
sprintf(time_buf, "[%02d-%02d_%02d:%02d:%02d:%03d]", ti->tm_mon + 1,
|
||||
ti->tm_mday, ti->tm_hour, ti->tm_min, ti->tm_sec, (int)millitm);
|
||||
return time_buf;
|
||||
}
|
||||
|
||||
void dbg_time(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
|
||||
pthread_mutex_lock(&printfMutex);
|
||||
|
||||
snprintf(line, sizeof(line), "%s ", get_time());
|
||||
|
||||
vsnprintf(line + strlen(line), sizeof(line) - strlen(line), fmt, args);
|
||||
fprintf(stdout, "%s\n", line);
|
||||
|
||||
if (logfilefp) {
|
||||
fprintf(logfilefp, "%s\n", line);
|
||||
}
|
||||
fflush(logfilefp);
|
||||
pthread_mutex_unlock(&printfMutex);
|
||||
}
|
||||
|
||||
USHORT le16_to_cpu(USHORT v16)
|
||||
{
|
||||
USHORT tmp = v16;
|
||||
if (is_bigendian()) {
|
||||
unsigned char *s = (unsigned char *)(&v16);
|
||||
unsigned char *d = (unsigned char *)(&tmp);
|
||||
d[0] = s[1];
|
||||
d[1] = s[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
UINT le32_to_cpu(UINT v32)
|
||||
{
|
||||
UINT tmp = v32;
|
||||
if (is_bigendian()) {
|
||||
unsigned char *s = (unsigned char *)(&v32);
|
||||
unsigned char *d = (unsigned char *)(&tmp);
|
||||
d[0] = s[3];
|
||||
d[1] = s[2];
|
||||
d[2] = s[1];
|
||||
d[3] = s[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
USHORT cpu_to_le16(USHORT v16)
|
||||
{
|
||||
USHORT tmp = v16;
|
||||
if (is_bigendian()) {
|
||||
unsigned char *s = (unsigned char *)(&v16);
|
||||
unsigned char *d = (unsigned char *)(&tmp);
|
||||
d[0] = s[1];
|
||||
d[1] = s[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
UINT cpu_to_le32(UINT v32)
|
||||
{
|
||||
UINT tmp = v32;
|
||||
if (is_bigendian()) {
|
||||
unsigned char *s = (unsigned char *)(&v32);
|
||||
unsigned char *d = (unsigned char *)(&tmp);
|
||||
d[0] = s[3];
|
||||
d[1] = s[2];
|
||||
d[2] = s[1];
|
||||
d[3] = s[0];
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
53
package/fish/fibocom-dial/src/util.h
Normal file
53
package/fish/fibocom-dial/src/util.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef _UTILS_H_
|
||||
#define _UTILS_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
struct listnode {
|
||||
struct listnode *next;
|
||||
struct listnode *prev;
|
||||
};
|
||||
|
||||
#define node_to_item(node, container, member) \
|
||||
(container *)(((char *)(node)) - offsetof(container, member))
|
||||
|
||||
#define list_declare(name) \
|
||||
struct listnode name = { \
|
||||
.next = &name, \
|
||||
.prev = &name, \
|
||||
}
|
||||
|
||||
#define list_for_each(node, list) \
|
||||
for (node = (list)->next; node != (list); node = node->next)
|
||||
|
||||
#define list_for_each_reverse(node, list) \
|
||||
for (node = (list)->prev; node != (list); node = node->prev)
|
||||
void dbg_time(const char *fmt, ...);
|
||||
void list_init(struct listnode *list);
|
||||
void list_add_tail(struct listnode *list, struct listnode *item);
|
||||
void list_add_head(struct listnode *head, struct listnode *item);
|
||||
void list_remove(struct listnode *item);
|
||||
|
||||
#define list_empty(list) ((list) == (list)->next)
|
||||
#define list_head(list) ((list)->next)
|
||||
#define list_tail(list) ((list)->prev)
|
||||
|
||||
int epoll_register(int epoll_fd, int fd, unsigned int events);
|
||||
int epoll_deregister(int epoll_fd, int fd);
|
||||
#endif
|
||||
47
package/fish/fibocom_MHI/Makefile
Normal file
47
package/fish/fibocom_MHI/Makefile
Normal file
@ -0,0 +1,47 @@
|
||||
#
|
||||
# Copyright (C) 2015 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=pcie_mhi_fb
|
||||
PKG_VERSION:=3.2
|
||||
PKG_RELEASE:=1
|
||||
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define KernelPackage/pcie_mhi_fb
|
||||
SUBMENU:=WWAN Support
|
||||
TITLE:=Kernel pcie driver for MHI device
|
||||
DEPENDS:=+pciids +pciutils +fibocom-dial
|
||||
FILES:=$(PKG_BUILD_DIR)/pcie_mhi_fb.ko
|
||||
AUTOLOAD:=$(call AutoLoad,90,pcie_mhi_fb)
|
||||
endef
|
||||
|
||||
define KernelPackage/pcie_mhi_fb/description
|
||||
Kernel module for register a custom pciemhi platform device.
|
||||
endef
|
||||
|
||||
MAKE_OPTS:= \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
CXXFLAGS="$(TARGET_CXXFLAGS)" \
|
||||
M="$(PKG_BUILD_DIR)" \
|
||||
$(EXTRA_KCONFIG)
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C "$(LINUX_DIR)" \
|
||||
$(MAKE_OPTS) \
|
||||
modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,pcie_mhi_fb))
|
||||
14
package/fish/fibocom_MHI/src/Kconfig
Normal file
14
package/fish/fibocom_MHI/src/Kconfig
Normal file
@ -0,0 +1,14 @@
|
||||
menu "pcie mhi device Drivers"
|
||||
|
||||
config PCIE_MHI
|
||||
tristate "MHI dev net interface"
|
||||
help
|
||||
This modules enables userspace software clients to communicate
|
||||
with devices supporting the MHI protocol. Userspace clients
|
||||
may open the device nodes exposed by MHI UCI and perform
|
||||
read, write and ioctl operations to communicate with the
|
||||
attached device.
|
||||
|
||||
endmenu
|
||||
|
||||
|
||||
29
package/fish/fibocom_MHI/src/Makefile
Normal file
29
package/fish/fibocom_MHI/src/Makefile
Normal file
@ -0,0 +1,29 @@
|
||||
ccflags-y += -g -Wno-incompatible-pointer-types -Wno-unused-variable
|
||||
#ccflags-y += -DCONFIG_MHI_NETDEV_MBIM
|
||||
#obj-${CONFIG_PCIE_MHI} := fibo_mhi.o
|
||||
obj-m := fibo_mhi.o
|
||||
fibo_mhi-objs := core/mhi_init.o core/mhi_main.o core/mhi_pm.o core/mhi_boot.o core/mhi_dtr.o devices/mhi_netdev.o devices/mhi_uci.o controllers/mhi_qcom.o
|
||||
|
||||
PWD := $(shell pwd)
|
||||
ifeq ($(ARCH),)
|
||||
ARCH := $(shell uname -m)
|
||||
endif
|
||||
ifeq ($(CROSS_COMPILE),)
|
||||
CROSS_COMPILE :=
|
||||
endif
|
||||
ifeq ($(KDIR),)
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
endif
|
||||
|
||||
|
||||
fibo_mhi: clean
|
||||
ifeq ($(findstring 86,$(ARCH)), 86)
|
||||
cp -f $(PWD)/controllers/mhi_qcom_x86.h $(PWD)/controllers/mhi_qcom.h
|
||||
else
|
||||
cp -f $(PWD)/controllers/mhi_qcom_arm.h $(PWD)/controllers/mhi_qcom.h
|
||||
endif
|
||||
#ln -sf makefile Makefile
|
||||
$(MAKE) ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
clean:
|
||||
$(MAKE) ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -C $(KDIR) M=$(PWD) clean
|
||||
683
package/fish/fibocom_MHI/src/controllers/mhi_qcom.c
Normal file
683
package/fish/fibocom_MHI/src/controllers/mhi_qcom.c
Normal file
@ -0,0 +1,683 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/version.h>
|
||||
#include "../core/mhi.h"
|
||||
#include "mhi_qcom.h"
|
||||
|
||||
|
||||
#ifndef PCI_IRQ_MSI
|
||||
#define PCI_IRQ_MSI (1 << 1) /* Allow MSI interrupts */
|
||||
|
||||
#if (LINUX_VERSION_CODE <= KERNEL_VERSION( 3,10,108 ))
|
||||
int pci_enable_msi_range(struct pci_dev *dev, int minvec, int maxvec)
|
||||
{
|
||||
int nvec = maxvec;
|
||||
int rc;
|
||||
|
||||
if (maxvec < minvec)
|
||||
return -ERANGE;
|
||||
|
||||
do {
|
||||
rc = pci_enable_msi_block(dev, nvec);
|
||||
if (rc < 0) {
|
||||
return rc;
|
||||
} else if (rc > 0) {
|
||||
if (rc < minvec)
|
||||
return -ENOSPC;
|
||||
nvec = rc;
|
||||
}
|
||||
} while (rc);
|
||||
|
||||
return nvec;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int fibo_pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
|
||||
unsigned int max_vecs, unsigned int flags)
|
||||
{
|
||||
return pci_enable_msi_range(dev, min_vecs, max_vecs);
|
||||
}
|
||||
|
||||
static void fibo_pci_free_irq_vectors(struct pci_dev *dev)
|
||||
{
|
||||
pci_disable_msi(dev);
|
||||
}
|
||||
|
||||
static int fibo_pci_irq_vector(struct pci_dev *dev, unsigned int nr)
|
||||
{
|
||||
return dev->irq + nr;
|
||||
}
|
||||
#else
|
||||
static int fibo_pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
|
||||
unsigned int max_vecs, unsigned int flags)
|
||||
{
|
||||
return pci_alloc_irq_vectors(dev, min_vecs, max_vecs, flags);
|
||||
}
|
||||
|
||||
static void fibo_pci_free_irq_vectors(struct pci_dev *dev)
|
||||
{
|
||||
pci_free_irq_vectors(dev);
|
||||
}
|
||||
|
||||
static int fibo_pci_irq_vector(struct pci_dev *dev, unsigned int nr)
|
||||
{
|
||||
return pci_irq_vector(dev, nr);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static struct pci_device_id mhi_pcie_device_id[] = {
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0300)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0301)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0302)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0303)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0304)},//SDX24
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0305)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, 0x0306)}, //SDX55
|
||||
{PCI_DEVICE(0x2C7C, 0x0512)},
|
||||
{PCI_DEVICE(MHI_PCIE_VENDOR_ID, MHI_PCIE_DEBUG_ID)},
|
||||
{0},
|
||||
};
|
||||
|
||||
static struct pci_driver mhi_pcie_driver;
|
||||
|
||||
void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
struct pci_dev *pci_dev = mhi_dev->pci_dev;
|
||||
|
||||
fibo_pci_free_irq_vectors(pci_dev);
|
||||
iounmap(mhi_cntrl->regs);
|
||||
mhi_cntrl->regs = NULL;
|
||||
pci_clear_master(pci_dev);
|
||||
pci_release_region(pci_dev, mhi_dev->resn);
|
||||
pci_disable_device(pci_dev);
|
||||
}
|
||||
|
||||
static int mhi_init_pci_dev(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
struct pci_dev *pci_dev = mhi_dev->pci_dev;
|
||||
int ret;
|
||||
resource_size_t start, len;
|
||||
int i;
|
||||
|
||||
mhi_dev->resn = MHI_PCI_BAR_NUM;
|
||||
ret = pci_assign_resource(pci_dev, mhi_dev->resn);
|
||||
if (ret) {
|
||||
MHI_ERR("Error assign pci resources, ret:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = pci_enable_device(pci_dev);
|
||||
if (ret) {
|
||||
MHI_ERR("Error enabling device, ret:%d\n", ret);
|
||||
goto error_enable_device;
|
||||
}
|
||||
|
||||
ret = pci_request_region(pci_dev, mhi_dev->resn, "mhi");
|
||||
if (ret) {
|
||||
MHI_ERR("Error pci_request_region, ret:%d\n", ret);
|
||||
goto error_request_region;
|
||||
}
|
||||
|
||||
pci_set_master(pci_dev);
|
||||
|
||||
start = pci_resource_start(pci_dev, mhi_dev->resn);
|
||||
len = pci_resource_len(pci_dev, mhi_dev->resn);
|
||||
/*begin added by tony.du for mantis 0062018 on 2020-11-10*/
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 5,6,0 ))
|
||||
mhi_cntrl->regs = ioremap_nocache(start, len);
|
||||
#else
|
||||
mhi_cntrl->regs = ioremap(start, len);
|
||||
#endif
|
||||
/*end added by tony.du for mantis 0062018 on 2020-11-10*/
|
||||
MHI_LOG("mhi_cntrl->regs = %p\n", mhi_cntrl->regs);
|
||||
if (!mhi_cntrl->regs) {
|
||||
MHI_ERR("Error ioremap region\n");
|
||||
goto error_ioremap;
|
||||
}
|
||||
|
||||
ret = fibo_pci_alloc_irq_vectors(pci_dev, 1, mhi_cntrl->msi_required, PCI_IRQ_MSI);
|
||||
if (IS_ERR_VALUE((ulong)ret) || ret < mhi_cntrl->msi_required) {
|
||||
if (ret == -ENOSPC) {
|
||||
}
|
||||
//imx_4.1.15_2.0.0_ga & DELL_OPTIPLEX_7010 only alloc one msi interrupt for one pcie device
|
||||
if (ret != 1) {
|
||||
MHI_ERR("Failed to enable MSI, ret=%d, msi_required=%d\n", ret, mhi_cntrl->msi_required);
|
||||
goto error_req_msi;
|
||||
}
|
||||
}
|
||||
|
||||
mhi_cntrl->msi_allocated = ret;
|
||||
MHI_LOG("msi_required = %d, msi_allocated = %d, msi_irq = %u\n", mhi_cntrl->msi_required, mhi_cntrl->msi_allocated, pci_dev->irq);
|
||||
|
||||
for (i = 0; i < mhi_cntrl->msi_allocated; i++) {
|
||||
mhi_cntrl->irq[i] = fibo_pci_irq_vector(pci_dev, i);
|
||||
if (mhi_cntrl->irq[i] < 0) {
|
||||
ret = mhi_cntrl->irq[i];
|
||||
goto error_get_irq_vec;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error_get_irq_vec:
|
||||
fibo_pci_free_irq_vectors(pci_dev);
|
||||
|
||||
error_req_msi:
|
||||
iounmap(mhi_cntrl->regs);
|
||||
|
||||
error_ioremap:
|
||||
pci_clear_master(pci_dev);
|
||||
|
||||
error_request_region:
|
||||
pci_disable_device(pci_dev);
|
||||
|
||||
error_enable_device:
|
||||
pci_release_region(pci_dev, mhi_dev->resn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mhi_runtime_idle(struct device *dev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
|
||||
MHI_LOG("Entered returning -EBUSY\n");
|
||||
|
||||
/*
|
||||
* RPM framework during runtime resume always calls
|
||||
* rpm_idle to see if device ready to suspend.
|
||||
* If dev.power usage_count count is 0, rpm fw will call
|
||||
* rpm_idle cb to see if device is ready to suspend.
|
||||
* if cb return 0, or cb not defined the framework will
|
||||
* assume device driver is ready to suspend;
|
||||
* therefore, fw will schedule runtime suspend.
|
||||
* In MHI power management, MHI host shall go to
|
||||
* runtime suspend only after entering MHI State M2, even if
|
||||
* usage count is 0. Return -EBUSY to disable automatic suspend.
|
||||
*/
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
static int mhi_runtime_suspend(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
|
||||
MHI_LOG("Enter\n");
|
||||
|
||||
mutex_lock(&mhi_cntrl->pm_mutex);
|
||||
|
||||
ret = mhi_pm_suspend(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_LOG("Abort due to ret:%d\n", ret);
|
||||
goto exit_runtime_suspend;
|
||||
}
|
||||
|
||||
ret = mhi_arch_link_off(mhi_cntrl, true);
|
||||
if (ret)
|
||||
MHI_ERR("Failed to Turn off link ret:%d\n", ret);
|
||||
|
||||
exit_runtime_suspend:
|
||||
mutex_unlock(&mhi_cntrl->pm_mutex);
|
||||
MHI_LOG("Exited with ret:%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mhi_runtime_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
MHI_LOG("Enter\n");
|
||||
|
||||
mutex_lock(&mhi_cntrl->pm_mutex);
|
||||
|
||||
if (!mhi_dev->powered_on) {
|
||||
MHI_LOG("Not fully powered, return success\n");
|
||||
mutex_unlock(&mhi_cntrl->pm_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* turn on link */
|
||||
ret = mhi_arch_link_on(mhi_cntrl);
|
||||
if (ret)
|
||||
goto rpm_resume_exit;
|
||||
|
||||
/* enter M0 state */
|
||||
ret = mhi_pm_resume(mhi_cntrl);
|
||||
|
||||
rpm_resume_exit:
|
||||
mutex_unlock(&mhi_cntrl->pm_mutex);
|
||||
MHI_LOG("Exited with :%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mhi_system_resume(struct device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
|
||||
ret = mhi_runtime_resume(dev);
|
||||
if (ret) {
|
||||
MHI_ERR("Failed to resume link\n");
|
||||
} else {
|
||||
pm_runtime_set_active(dev);
|
||||
pm_runtime_enable(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int mhi_system_suspend(struct device *dev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = dev_get_drvdata(dev);
|
||||
|
||||
MHI_LOG("Entered\n");
|
||||
|
||||
/* if rpm status still active then force suspend */
|
||||
if (!pm_runtime_status_suspended(dev))
|
||||
return mhi_runtime_suspend(dev);
|
||||
|
||||
pm_runtime_set_suspended(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
MHI_LOG("Exit\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* checks if link is down */
|
||||
static int mhi_link_status(struct mhi_controller *mhi_cntrl, void *priv)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = priv;
|
||||
u16 dev_id;
|
||||
int ret;
|
||||
|
||||
/* try reading device id, if dev id don't match, link is down */
|
||||
ret = pci_read_config_word(mhi_dev->pci_dev, PCI_DEVICE_ID, &dev_id);
|
||||
|
||||
return (ret || dev_id != mhi_cntrl->dev_id) ? -EIO : 0;
|
||||
}
|
||||
|
||||
static int mhi_runtime_get(struct mhi_controller *mhi_cntrl, void *priv)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = priv;
|
||||
struct device *dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
return pm_runtime_get(dev);
|
||||
}
|
||||
|
||||
static void mhi_runtime_put(struct mhi_controller *mhi_cntrl, void *priv)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = priv;
|
||||
struct device *dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
pm_runtime_put_noidle(dev);
|
||||
}
|
||||
|
||||
static void mhi_status_cb(struct mhi_controller *mhi_cntrl,
|
||||
void *priv,
|
||||
enum MHI_CB reason)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = priv;
|
||||
struct device *dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
if (reason == MHI_CB_IDLE) {
|
||||
MHI_LOG("Schedule runtime suspend 1\n");
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_request_autosuspend(dev);
|
||||
}
|
||||
}
|
||||
|
||||
int mhi_debugfs_trigger_m0(void *data, u64 val)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = data;
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
MHI_LOG("Trigger M3 Exit\n");
|
||||
pm_runtime_get(&mhi_dev->pci_dev->dev);
|
||||
pm_runtime_put(&mhi_dev->pci_dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mhi_debugfs_trigger_m3(void *data, u64 val)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = data;
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
MHI_LOG("Trigger M3 Entry\n");
|
||||
pm_runtime_mark_last_busy(&mhi_dev->pci_dev->dev);
|
||||
pm_request_autosuspend(&mhi_dev->pci_dev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m0_fops, NULL,
|
||||
mhi_debugfs_trigger_m0, "%llu\n");
|
||||
|
||||
DEFINE_SIMPLE_ATTRIBUTE(debugfs_trigger_m3_fops, NULL,
|
||||
mhi_debugfs_trigger_m3, "%llu\n");
|
||||
|
||||
static int mhi_init_debugfs_trigger_go(void *data, u64 val)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = data;
|
||||
|
||||
MHI_LOG("Trigger power up sequence\n");
|
||||
|
||||
mhi_async_power_up(mhi_cntrl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DEFINE_SIMPLE_ATTRIBUTE(mhi_init_debugfs_trigger_go_fops, NULL,
|
||||
mhi_init_debugfs_trigger_go, "%llu\n");
|
||||
|
||||
|
||||
int mhi_init_debugfs_debug_show(struct seq_file *m, void *d)
|
||||
{
|
||||
seq_puts(m, "Enable debug mode to debug external soc\n");
|
||||
seq_puts(m,
|
||||
"Usage: echo 'devid,timeout,domain,smmu_cfg' > debug_mode\n");
|
||||
seq_puts(m, "No spaces between parameters\n");
|
||||
seq_puts(m, "\t1. devid : 0 or pci device id to register\n");
|
||||
seq_puts(m, "\t2. timeout: mhi cmd/state transition timeout\n");
|
||||
seq_puts(m, "\t3. domain: Rootcomplex\n");
|
||||
seq_puts(m, "\t4. smmu_cfg: smmu configuration mask:\n");
|
||||
seq_puts(m, "\t\t- BIT0: ATTACH\n");
|
||||
seq_puts(m, "\t\t- BIT1: S1 BYPASS\n");
|
||||
seq_puts(m, "\t\t-BIT2: FAST_MAP\n");
|
||||
seq_puts(m, "\t\t-BIT3: ATOMIC\n");
|
||||
seq_puts(m, "\t\t-BIT4: FORCE_COHERENT\n");
|
||||
seq_puts(m, "\t\t-BIT5: GEOMETRY\n");
|
||||
seq_puts(m, "\tAll timeout are in ms, enter 0 to keep default\n");
|
||||
seq_puts(m, "Examples inputs: '0x307,10000'\n");
|
||||
seq_puts(m, "\techo '0,10000,1'\n");
|
||||
seq_puts(m, "\techo '0x307,10000,0,0x3d'\n");
|
||||
seq_puts(m, "firmware image name will be changed to debug.mbn\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mhi_init_debugfs_debug_open(struct inode *node, struct file *file)
|
||||
{
|
||||
return single_open(file, mhi_init_debugfs_debug_show, NULL);
|
||||
}
|
||||
|
||||
static ssize_t mhi_init_debugfs_debug_write(struct file *fp,
|
||||
const char __user *ubuf,
|
||||
size_t count,
|
||||
loff_t *pos)
|
||||
{
|
||||
char *buf = kmalloc(count + 1, GFP_KERNEL);
|
||||
/* #,devid,timeout,domain,smmu-cfg */
|
||||
int args[5] = {0};
|
||||
static char const *dbg_fw = "debug.mbn";
|
||||
int ret;
|
||||
struct mhi_controller *mhi_cntrl = fp->f_inode->i_private;
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
struct pci_device_id *id;
|
||||
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = copy_from_user(buf, ubuf, count);
|
||||
if (ret)
|
||||
goto error_read;
|
||||
buf[count] = 0;
|
||||
get_options(buf, ARRAY_SIZE(args), args);
|
||||
kfree(buf);
|
||||
|
||||
/* override default parameters */
|
||||
mhi_cntrl->fw_image = dbg_fw;
|
||||
mhi_cntrl->edl_image = dbg_fw;
|
||||
|
||||
if (args[0] >= 2 && args[2])
|
||||
mhi_cntrl->timeout_ms = args[2];
|
||||
|
||||
if (args[0] >= 3 && args[3])
|
||||
mhi_cntrl->domain = args[3];
|
||||
|
||||
if (args[0] >= 4 && args[4])
|
||||
mhi_dev->smmu_cfg = args[4];
|
||||
|
||||
/* If it's a new device id register it */
|
||||
if (args[0] && args[1]) {
|
||||
/* find the debug_id and overwrite it */
|
||||
for (id = mhi_pcie_device_id; id->vendor; id++)
|
||||
if (id->device == MHI_PCIE_DEBUG_ID) {
|
||||
id->device = args[1];
|
||||
pci_unregister_driver(&mhi_pcie_driver);
|
||||
ret = pci_register_driver(&mhi_pcie_driver);
|
||||
}
|
||||
}
|
||||
|
||||
mhi_dev->debug_mode = true;
|
||||
debugfs_create_file("go", 0444, mhi_cntrl->parent, mhi_cntrl,
|
||||
&mhi_init_debugfs_trigger_go_fops);
|
||||
pr_info(
|
||||
"%s: ret:%d pcidev:0x%x smm_cfg:%u timeout:%u\n",
|
||||
__func__, ret, args[1], mhi_dev->smmu_cfg,
|
||||
mhi_cntrl->timeout_ms);
|
||||
return count;
|
||||
|
||||
error_read:
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations debugfs_debug_ops = {
|
||||
.open = mhi_init_debugfs_debug_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.write = mhi_init_debugfs_debug_write,
|
||||
};
|
||||
|
||||
static struct mhi_controller * mhi_platform_probe(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
struct mhi_dev *mhi_dev;
|
||||
u64 addr_win[2];
|
||||
int ret;
|
||||
|
||||
mhi_cntrl = mhi_alloc_controller(sizeof(*mhi_dev));
|
||||
if (!mhi_cntrl) {
|
||||
pr_err("mhi_alloc_controller fail\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->dev_id = pci_dev->device;
|
||||
mhi_cntrl->domain = pci_domain_nr(pci_dev->bus);
|
||||
mhi_cntrl->bus = pci_dev->bus->number;
|
||||
mhi_cntrl->slot = PCI_SLOT(pci_dev->devfn);
|
||||
mhi_dev->smmu_cfg = 0;
|
||||
|
||||
addr_win[0] = 0;
|
||||
addr_win[1] = 0xFFFFFFFFF; //16GB
|
||||
|
||||
mhi_cntrl->iova_start = addr_win[0];
|
||||
mhi_cntrl->iova_stop = addr_win[1];
|
||||
|
||||
mhi_dev->pci_dev = pci_dev;
|
||||
mhi_cntrl->pci_dev = pci_dev;
|
||||
|
||||
/* setup power management apis */
|
||||
mhi_cntrl->status_cb = mhi_status_cb;
|
||||
mhi_cntrl->runtime_get = mhi_runtime_get;
|
||||
mhi_cntrl->runtime_put = mhi_runtime_put;
|
||||
mhi_cntrl->link_status = mhi_link_status;
|
||||
|
||||
ret = mhi_arch_platform_init(mhi_dev);
|
||||
if (ret)
|
||||
goto error_probe;
|
||||
|
||||
ret = mhi_register_mhi_controller(mhi_cntrl);
|
||||
if (ret)
|
||||
goto error_register;
|
||||
|
||||
if (mhi_cntrl->parent)
|
||||
debugfs_create_file("debug_mode", 0444, mhi_cntrl->parent,
|
||||
mhi_cntrl, &debugfs_debug_ops);
|
||||
|
||||
return mhi_cntrl;
|
||||
|
||||
error_register:
|
||||
mhi_arch_platform_deinit(mhi_dev);
|
||||
|
||||
error_probe:
|
||||
mhi_free_controller(mhi_cntrl);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int mhi_pci_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *device_id)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = NULL;
|
||||
u32 domain = pci_domain_nr(pci_dev->bus);
|
||||
u32 bus = pci_dev->bus->number;
|
||||
u32 slot = PCI_SLOT(pci_dev->devfn);
|
||||
struct mhi_dev *mhi_dev;
|
||||
int ret;
|
||||
|
||||
pr_err("INFO:%s pci_dev->name = %s, domain=%d, bus=%d, slot=%d, vendor=%04X, device=%04X\n",
|
||||
__func__, dev_name(&pci_dev->dev), domain, bus, slot, pci_dev->vendor, pci_dev->device);
|
||||
|
||||
mhi_cntrl = mhi_platform_probe(pci_dev);
|
||||
if (!mhi_cntrl) {
|
||||
pr_err("mhi_platform_probe fail\n");
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
mhi_cntrl->dev_id = pci_dev->device;
|
||||
mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
mhi_dev->pci_dev = pci_dev;
|
||||
mhi_dev->powered_on = true;
|
||||
|
||||
ret = mhi_arch_pcie_init(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_ERR("Error mhi_arch_pcie_init, ret:%d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = mhi_arch_iommu_init(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_ERR("Error mhi_arch_iommu_init, ret:%d\n", ret);
|
||||
goto error_iommu_init;
|
||||
}
|
||||
|
||||
ret = mhi_init_pci_dev(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_ERR("Error mhi_init_pci_dev, ret:%d\n", ret);
|
||||
goto error_init_pci;
|
||||
}
|
||||
|
||||
/* start power up sequence if not in debug mode */
|
||||
if (!mhi_dev->debug_mode) {
|
||||
ret = mhi_async_power_up(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_ERR("Error mhi_async_power_up, ret:%d\n", ret);
|
||||
goto error_power_up;
|
||||
}
|
||||
}
|
||||
|
||||
if (mhi_cntrl->dentry) {
|
||||
debugfs_create_file("m0", 0444, mhi_cntrl->dentry, mhi_cntrl,
|
||||
&debugfs_trigger_m0_fops);
|
||||
debugfs_create_file("m3", 0444, mhi_cntrl->dentry, mhi_cntrl,
|
||||
&debugfs_trigger_m3_fops);
|
||||
}
|
||||
|
||||
dev_set_drvdata(&pci_dev->dev, mhi_cntrl);
|
||||
MHI_LOG("Return successful\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_power_up:
|
||||
mhi_deinit_pci_dev(mhi_cntrl);
|
||||
|
||||
error_init_pci:
|
||||
mhi_arch_iommu_deinit(mhi_cntrl);
|
||||
|
||||
error_iommu_init:
|
||||
mhi_arch_pcie_deinit(mhi_cntrl);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mhi_pci_remove(struct pci_dev *pci_dev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = (struct mhi_controller *)dev_get_drvdata(&pci_dev->dev);
|
||||
|
||||
if (mhi_cntrl && mhi_cntrl->pci_dev == pci_dev) {
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
MHI_LOG("%s\n", dev_name(&pci_dev->dev));
|
||||
if (!mhi_dev->debug_mode) {
|
||||
mhi_power_down(mhi_cntrl, 1);
|
||||
}
|
||||
mhi_deinit_pci_dev(mhi_cntrl);
|
||||
mhi_arch_iommu_deinit(mhi_cntrl);
|
||||
mhi_arch_pcie_deinit(mhi_cntrl);
|
||||
mhi_unregister_mhi_controller(mhi_cntrl);
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dev_pm_ops pm_ops = {
|
||||
SET_RUNTIME_PM_OPS(mhi_runtime_suspend,
|
||||
mhi_runtime_resume,
|
||||
mhi_runtime_idle)
|
||||
SET_SYSTEM_SLEEP_PM_OPS(mhi_system_suspend, mhi_system_resume)
|
||||
};
|
||||
|
||||
static struct pci_driver mhi_pcie_driver = {
|
||||
.name = "mhi",
|
||||
.id_table = mhi_pcie_device_id,
|
||||
.probe = mhi_pci_probe,
|
||||
.remove = mhi_pci_remove,
|
||||
.driver = {
|
||||
.pm = &pm_ops
|
||||
}
|
||||
};
|
||||
|
||||
int __init mhi_controller_qcom_init(void)
|
||||
{
|
||||
return pci_register_driver(&mhi_pcie_driver);
|
||||
};
|
||||
|
||||
void mhi_controller_qcom_exit(void)
|
||||
{
|
||||
pr_err("INFO:%s enter\n", __func__);
|
||||
pci_unregister_driver(&mhi_pcie_driver);
|
||||
pr_err("INFO:%s exit\n", __func__);
|
||||
}
|
||||
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom.h
Normal file
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
#ifndef _MHI_QCOM_
|
||||
#define _MHI_QCOM_
|
||||
|
||||
/* iova cfg bitmask */
|
||||
#define MHI_SMMU_ATTACH BIT(0)
|
||||
#define MHI_SMMU_S1_BYPASS BIT(1)
|
||||
#define MHI_SMMU_FAST BIT(2)
|
||||
#define MHI_SMMU_ATOMIC BIT(3)
|
||||
#define MHI_SMMU_FORCE_COHERENT BIT(4)
|
||||
|
||||
#define MHI_PCIE_VENDOR_ID (0x17cb)
|
||||
#define MHI_PCIE_DEBUG_ID (0xffff)
|
||||
#define MHI_RPM_SUSPEND_TMR_MS (3000)
|
||||
#define MHI_PCI_BAR_NUM (0)
|
||||
|
||||
struct mhi_dev {
|
||||
struct pci_dev *pci_dev;
|
||||
u32 smmu_cfg;
|
||||
int resn;
|
||||
void *arch_info;
|
||||
bool powered_on;
|
||||
bool debug_mode;
|
||||
};
|
||||
|
||||
void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_pci_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *device_id);
|
||||
|
||||
#if (LINUX_VERSION_CODE <= KERNEL_VERSION( 3,10,108 ))
|
||||
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
|
||||
{
|
||||
int rc = dma_set_mask(dev, mask);
|
||||
if (rc == 0)
|
||||
dma_set_coherent_mask(dev, mask);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
return dma_set_mask_and_coherent(mhi_cntrl->dev, DMA_BIT_MASK(64));
|
||||
}
|
||||
|
||||
static inline void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_platform_init(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_platform_deinit(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl,
|
||||
bool graceful)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _MHI_QCOM_ */
|
||||
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom_arm.h
Normal file
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom_arm.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
#ifndef _MHI_QCOM_
|
||||
#define _MHI_QCOM_
|
||||
|
||||
/* iova cfg bitmask */
|
||||
#define MHI_SMMU_ATTACH BIT(0)
|
||||
#define MHI_SMMU_S1_BYPASS BIT(1)
|
||||
#define MHI_SMMU_FAST BIT(2)
|
||||
#define MHI_SMMU_ATOMIC BIT(3)
|
||||
#define MHI_SMMU_FORCE_COHERENT BIT(4)
|
||||
|
||||
#define MHI_PCIE_VENDOR_ID (0x17cb)
|
||||
#define MHI_PCIE_DEBUG_ID (0xffff)
|
||||
#define MHI_RPM_SUSPEND_TMR_MS (3000)
|
||||
#define MHI_PCI_BAR_NUM (0)
|
||||
|
||||
struct mhi_dev {
|
||||
struct pci_dev *pci_dev;
|
||||
u32 smmu_cfg;
|
||||
int resn;
|
||||
void *arch_info;
|
||||
bool powered_on;
|
||||
bool debug_mode;
|
||||
};
|
||||
|
||||
void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_pci_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *device_id);
|
||||
|
||||
#if (LINUX_VERSION_CODE <= KERNEL_VERSION( 3,10,108 ))
|
||||
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
|
||||
{
|
||||
int rc = dma_set_mask(dev, mask);
|
||||
if (rc == 0)
|
||||
dma_set_coherent_mask(dev, mask);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
return dma_set_mask_and_coherent(mhi_cntrl->dev, DMA_BIT_MASK(64));
|
||||
}
|
||||
|
||||
static inline void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_platform_init(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_platform_deinit(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl,
|
||||
bool graceful)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _MHI_QCOM_ */
|
||||
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom_x86.h
Normal file
92
package/fish/fibocom_MHI/src/controllers/mhi_qcom_x86.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
#ifndef _MHI_QCOM_
|
||||
#define _MHI_QCOM_
|
||||
|
||||
/* iova cfg bitmask */
|
||||
#define MHI_SMMU_ATTACH BIT(0)
|
||||
#define MHI_SMMU_S1_BYPASS BIT(1)
|
||||
#define MHI_SMMU_FAST BIT(2)
|
||||
#define MHI_SMMU_ATOMIC BIT(3)
|
||||
#define MHI_SMMU_FORCE_COHERENT BIT(4)
|
||||
|
||||
#define MHI_PCIE_VENDOR_ID (0x17cb)
|
||||
#define MHI_PCIE_DEBUG_ID (0xffff)
|
||||
#define MHI_RPM_SUSPEND_TMR_MS (3000)
|
||||
#define MHI_PCI_BAR_NUM (0)
|
||||
|
||||
struct mhi_dev {
|
||||
struct pci_dev *pci_dev;
|
||||
u32 smmu_cfg;
|
||||
int resn;
|
||||
void *arch_info;
|
||||
bool powered_on;
|
||||
bool debug_mode;
|
||||
};
|
||||
|
||||
void mhi_deinit_pci_dev(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_pci_probe(struct pci_dev *pci_dev,
|
||||
const struct pci_device_id *device_id);
|
||||
|
||||
#if (LINUX_VERSION_CODE <= KERNEL_VERSION( 3,10,108 ))
|
||||
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
|
||||
{
|
||||
int rc = dma_set_mask(dev, mask);
|
||||
if (rc == 0)
|
||||
dma_set_coherent_mask(dev, mask);
|
||||
return rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int mhi_arch_iommu_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
struct mhi_dev *mhi_dev = mhi_controller_get_devdata(mhi_cntrl);
|
||||
|
||||
mhi_cntrl->dev = &mhi_dev->pci_dev->dev;
|
||||
|
||||
return dma_set_mask_and_coherent(mhi_cntrl->dev, DMA_BIT_MASK(32));
|
||||
}
|
||||
|
||||
static inline void mhi_arch_iommu_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_pcie_init(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_pcie_deinit(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_platform_init(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void mhi_arch_platform_deinit(struct mhi_dev *mhi_dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_off(struct mhi_controller *mhi_cntrl,
|
||||
bool graceful)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int mhi_arch_link_on(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* _MHI_QCOM_ */
|
||||
891
package/fish/fibocom_MHI/src/core/mhi.h
Normal file
891
package/fish/fibocom_MHI/src/core/mhi.h
Normal file
@ -0,0 +1,891 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
#ifndef _MHI_H_
|
||||
#define _MHI_H_
|
||||
|
||||
#include <linux/miscdevice.h>
|
||||
|
||||
typedef u64 uint64;
|
||||
typedef u32 uint32;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
MHI_CLIENT_LOOPBACK_OUT = 0,
|
||||
MHI_CLIENT_LOOPBACK_IN = 1,
|
||||
MHI_CLIENT_SAHARA_OUT = 2,
|
||||
MHI_CLIENT_SAHARA_IN = 3,
|
||||
MHI_CLIENT_DIAG_OUT = 4,
|
||||
MHI_CLIENT_DIAG_IN = 5,
|
||||
MHI_CLIENT_SSR_OUT = 6,
|
||||
MHI_CLIENT_SSR_IN = 7,
|
||||
MHI_CLIENT_QDSS_OUT = 8,
|
||||
MHI_CLIENT_QDSS_IN = 9,
|
||||
MHI_CLIENT_EFS_OUT = 10,
|
||||
MHI_CLIENT_EFS_IN = 11,
|
||||
MHI_CLIENT_MBIM_OUT = 12,
|
||||
MHI_CLIENT_MBIM_IN = 13,
|
||||
MHI_CLIENT_QMI_OUT = 14,
|
||||
MHI_CLIENT_QMI_IN = 15,
|
||||
MHI_CLIENT_QMI_2_OUT = 16,
|
||||
MHI_CLIENT_QMI_2_IN = 17,
|
||||
MHI_CLIENT_IP_CTRL_1_OUT = 18,
|
||||
MHI_CLIENT_IP_CTRL_1_IN = 19,
|
||||
MHI_CLIENT_IPCR_OUT = 20,
|
||||
MHI_CLIENT_IPCR_IN = 21,
|
||||
MHI_CLIENT_TEST_FW_OUT = 22,
|
||||
MHI_CLIENT_TEST_FW_IN = 23,
|
||||
MHI_CLIENT_RESERVED_0 = 24,
|
||||
MHI_CLIENT_BOOT_LOG_IN = 25,
|
||||
MHI_CLIENT_DCI_OUT = 26,
|
||||
MHI_CLIENT_DCI_IN = 27,
|
||||
MHI_CLIENT_QBI_OUT = 28,
|
||||
MHI_CLIENT_QBI_IN = 29,
|
||||
MHI_CLIENT_RESERVED_1_LOWER = 30,
|
||||
MHI_CLIENT_RESERVED_1_UPPER = 31,
|
||||
MHI_CLIENT_DUN_OUT = 32,
|
||||
MHI_CLIENT_DUN_IN = 33,
|
||||
MHI_CLIENT_EDL_OUT = 34,
|
||||
MHI_CLIENT_EDL_IN = 35,
|
||||
MHI_CLIENT_ADB_FB_OUT = 36,
|
||||
MHI_CLIENT_ADB_FB_IN = 37,
|
||||
MHI_CLIENT_RESERVED_2_LOWER = 38,
|
||||
MHI_CLIENT_RESERVED_2_UPPER = 41,
|
||||
MHI_CLIENT_CSVT_OUT = 42,
|
||||
MHI_CLIENT_CSVT_IN = 43,
|
||||
MHI_CLIENT_SMCT_OUT = 44,
|
||||
MHI_CLIENT_SMCT_IN = 45,
|
||||
MHI_CLIENT_IP_SW_0_OUT = 46,
|
||||
MHI_CLIENT_IP_SW_0_IN = 47,
|
||||
MHI_CLIENT_IP_SW_1_OUT = 48,
|
||||
MHI_CLIENT_IP_SW_1_IN = 49,
|
||||
MHI_CLIENT_GNSS_OUT = 50,
|
||||
MHI_CLIENT_GNSS_IN = 51,
|
||||
MHI_CLIENT_AUDIO_OUT = 52,
|
||||
MHI_CLIENT_AUDIO_IN = 53,
|
||||
MHI_CLIENT_RESERVED_3_LOWER = 54,
|
||||
MHI_CLIENT_RESERVED_3_UPPER = 59,
|
||||
MHI_CLIENT_TEST_0_OUT = 60,
|
||||
MHI_CLIENT_TEST_0_IN = 61,
|
||||
MHI_CLIENT_TEST_1_OUT = 62,
|
||||
MHI_CLIENT_TEST_1_IN = 63,
|
||||
MHI_CLIENT_TEST_2_OUT = 64,
|
||||
MHI_CLIENT_TEST_2_IN = 65,
|
||||
MHI_CLIENT_TEST_3_OUT = 66,
|
||||
MHI_CLIENT_TEST_3_IN = 67,
|
||||
MHI_CLIENT_RESERVED_4_LOWER = 68,
|
||||
MHI_CLIENT_RESERVED_4_UPPER = 91,
|
||||
MHI_CLIENT_OEM_0_OUT = 92,
|
||||
MHI_CLIENT_OEM_0_IN = 93,
|
||||
MHI_CLIENT_OEM_1_OUT = 94,
|
||||
MHI_CLIENT_OEM_1_IN = 95,
|
||||
MHI_CLIENT_OEM_2_OUT = 96,
|
||||
MHI_CLIENT_OEM_2_IN = 97,
|
||||
MHI_CLIENT_OEM_3_OUT = 98,
|
||||
MHI_CLIENT_OEM_3_IN = 99,
|
||||
MHI_CLIENT_IP_HW_0_OUT = 100,
|
||||
MHI_CLIENT_IP_HW_0_IN = 101,
|
||||
MHI_CLIENT_ADPL = 102,
|
||||
MHI_CLIENT_RESERVED_5_LOWER = 103,
|
||||
MHI_CLIENT_RESERVED_5_UPPER = 127,
|
||||
MHI_MAX_CHANNELS = 128
|
||||
}MHI_CLIENT_CHANNEL_TYPE;
|
||||
|
||||
#define MHI_VERSION 0x01000000
|
||||
#define MHIREGLEN_VALUE 0x100 /* **** WRONG VALUE *** */
|
||||
#define MHI_MSI_INDEX 1
|
||||
#define MAX_NUM_MHI_DEVICES 1
|
||||
#define NUM_MHI_XFER_RINGS 128
|
||||
#define NUM_MHI_EVT_RINGS 3
|
||||
#define PRIMARY_EVENT_RING 0
|
||||
#define IPA_OUT_EVENT_RING 1
|
||||
#define IPA_IN_EVENT_RING 2
|
||||
#define NUM_MHI_XFER_RING_ELEMENTS 16
|
||||
#define NUM_MHI_EVT_RING_ELEMENTS 256
|
||||
#define NUM_MHI_IPA_OUT_EVT_RING_ELEMENTS 2048
|
||||
#define NUM_MHI_IPA_IN_EVT_RING_ELEMENTS 1024
|
||||
#define NUM_MHI_IPA_IN_RING_ELEMENTS 256
|
||||
#define NUM_MHI_IPA_OUT_RING_ELEMENTS 256
|
||||
#define NUM_MHI_DIAG_IN_RING_ELEMENTS 128
|
||||
#define NUM_MHI_CHAN_RING_ELEMENTS 8
|
||||
#define MHI_EVT_CMD_QUEUE_SIZE 160
|
||||
#define MHI_EVT_STATE_QUEUE_SIZE 128
|
||||
#define MHI_EVT_XFER_QUEUE_SIZE 1024
|
||||
#define MHI_ALIGN_4BYTE_OFFSET 0x3
|
||||
#define MHI_ALIGN_4K_OFFSET 0xFFF
|
||||
#define MAX_TRB_DATA_SIZE 0xFFFF
|
||||
#define RESERVED_VALUE_64 0xFFFFFFFFFFFFFFFF
|
||||
#define RESERVED_VALUE 0xFFFFFFFF
|
||||
#define PCIE_LINK_DOWN 0xFFFFFFFF
|
||||
#define SECONDS 1000
|
||||
#define MINUTES 60000
|
||||
|
||||
#define MHI_FILE_MHI 0x4D4849
|
||||
#define MHI_FILE_INIT 0x494E4954
|
||||
#define MHI_FILE_MSI 0x4D5349
|
||||
#define MHI_FILE_OS 0x4F53
|
||||
#define MHI_FILE_SM 0x534D
|
||||
#define MHI_FILE_THREADS 0x54485245
|
||||
#define MHI_FILE_TRANSFER 0x5452414E
|
||||
#define MHI_FILE_UTILS 0x5554494C
|
||||
|
||||
|
||||
#define MHI_ER_PRIORITY_HIGH 0
|
||||
#define MHI_ER_PRIORITY_MEDIUM 1
|
||||
#define MHI_ER_PRIORITY_SPECIAL 2
|
||||
|
||||
#undef FALSE
|
||||
#undef TRUE
|
||||
#define FALSE 0
|
||||
#define TRUE 1
|
||||
|
||||
typedef struct MHI_DEV_CTXT MHI_DEV_CTXT;
|
||||
typedef struct PCI_CORE_INFO PCI_CORE_INFO;
|
||||
typedef struct PCIE_DEV_INFO PCIE_DEV_INFO;
|
||||
|
||||
/* Memory Segment Properties */
|
||||
typedef struct _MHI_MEM_PROPS
|
||||
{
|
||||
uint64 VirtAligned;
|
||||
uint64 VirtUnaligned;
|
||||
uint64 PhysAligned;
|
||||
uint64 PhysUnaligned;
|
||||
uint64 Size;
|
||||
void *Handle;
|
||||
}MHI_MEM_PROPS, *PMHI_MEM_PROPS;
|
||||
|
||||
/* Device Power State Type */
|
||||
typedef enum
|
||||
{
|
||||
POWER_DEVICE_INVALID = 0,
|
||||
POWER_DEVICE_D0 = 1,
|
||||
POWER_DEVICE_D1 = 2,
|
||||
POWER_DEVICE_D2 = 3,
|
||||
POWER_DEVICE_D3 = 4,
|
||||
POWER_DEVICE_D3FINAL = 5, // System shutting down
|
||||
POWER_DEVICE_HIBARNATION = 6, // Entering system state S4
|
||||
POWER_DEVICE_MAX = 7
|
||||
}PWR_STATE_TYPE;
|
||||
|
||||
/* Channel State */
|
||||
typedef enum
|
||||
{
|
||||
CHAN_STATE_DISABLED = 0,
|
||||
CHAN_STATE_ENABLED = 1,
|
||||
CHAN_STATE_RUNNING = 2,
|
||||
CHAN_STATE_SUSPENDED = 3,
|
||||
CHAN_STATE_STOPPED = 4,
|
||||
CHAN_STATE_ERROR = 5,
|
||||
|
||||
CHAN_STATE_OTHER = RESERVED_VALUE
|
||||
}CHAN_STATE_TYPE;
|
||||
|
||||
/* Channel Type */
|
||||
typedef enum
|
||||
{
|
||||
INVALID_CHAN = 0,
|
||||
OUTBOUND_CHAN = 1,
|
||||
INBOUND_CHAN = 2,
|
||||
|
||||
OTHER_CHAN = RESERVED_VALUE
|
||||
}CHAN_TYPE;
|
||||
|
||||
/* Ring Type */
|
||||
typedef enum
|
||||
{
|
||||
CMD_RING = 0,
|
||||
XFER_RING = 1,
|
||||
EVT_RING = 2,
|
||||
}MHI_RING_TYPE;
|
||||
|
||||
/* Event Ring */
|
||||
typedef enum
|
||||
{
|
||||
EVT_RING_INVALID = 0x0,
|
||||
EVT_RING_VALID = 0x1,
|
||||
EVT_RING_RESERVED = RESERVED_VALUE
|
||||
}MHI_EVENT_RING_TYPE;
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
||||
/* MHI Ring Context */
|
||||
typedef /*_ALIGN(1)*/ struct _MHI_RING_CTXT_TYPE
|
||||
{
|
||||
uint32 Info;
|
||||
uint32 Type;
|
||||
uint32 Index;
|
||||
uint64 Base;
|
||||
uint64 Length;
|
||||
volatile uint64 RP;
|
||||
uint64 WP;
|
||||
}MHI_RING_CTXT_TYPE, *PMHI_RING_CTXT_TYPE;
|
||||
|
||||
/* MHI Ring Element */
|
||||
typedef /*_ALIGN(1)*/ struct _MHI_ELEMENT_TYPE
|
||||
{
|
||||
uint64 Ptr;
|
||||
uint32 Status;
|
||||
uint32 Control;
|
||||
}MHI_ELEMENT_TYPE, *PMHI_ELEMENT_TYPE;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* Command Ring Element Type */
|
||||
typedef enum
|
||||
{
|
||||
CMD_NONE = 0,
|
||||
CMD_NOOP = 1,
|
||||
CMD_RESET_CHAN = 16,
|
||||
CMD_STOP_CHAN = 17,
|
||||
CMD_START_CHAN = 18,
|
||||
CMD_CANCEL_CHAN_XFERS = 21
|
||||
}MHI_CMD_TYPE;
|
||||
|
||||
/* Event Ring Element Type */
|
||||
typedef enum
|
||||
{
|
||||
STATE_CHANGE_EVT = 32,
|
||||
CMD_COMPLETION_EVT = 33,
|
||||
XFER_COMPLETION_EVT = 34,
|
||||
EE_STATE_CHANGE_EVT = 64
|
||||
} MHI_EVT_TYPE;
|
||||
|
||||
/* Ring Status Type */
|
||||
typedef enum
|
||||
{
|
||||
RING_EMPTY = 0,
|
||||
RING_FULL = 1,
|
||||
RING_QUEUED = 2,
|
||||
} MHI_RING_STATUS_TYPE;
|
||||
|
||||
/* XFER Ring Element Type */
|
||||
#define XFER_RING_ELEMENT_TYPE 2
|
||||
|
||||
/* Event Ring Completion Status */
|
||||
typedef enum
|
||||
{
|
||||
EVT_COMPLETION_INVALID = 0,
|
||||
EVT_COMPLETION_SUCCESS = 1,
|
||||
EVT_COMPLETION_EOT = 2,
|
||||
EVT_COMPLETION_OVERFLOW = 3,
|
||||
EVT_COMPLETION_EOB = 4,
|
||||
EVT_COMPLETION_OOB = 5, /* Out-Of-Buffer */
|
||||
EVT_COMPLETION_DB_MODE = 6,
|
||||
EVT_COMPLETION_UNDEFINED = 16,
|
||||
EVT_COMPLETION_MALFORMED = 17,
|
||||
|
||||
EVT_COMPLETION_OTHER = RESERVED_VALUE
|
||||
}EVT_COMPLETION_STATUS_TYPE;
|
||||
|
||||
/* *********************************************************************************************** */
|
||||
/* Macros */
|
||||
/* *********************************************************************************************** */
|
||||
#define ADVANCE_RING_PTR(RingCtxt, Ptr, Size) \
|
||||
*Ptr = ((*Ptr - RingCtxt->Base)/sizeof(MHI_ELEMENT_TYPE) == (Size - 1))? \
|
||||
RingCtxt->Base: (*Ptr + sizeof(MHI_ELEMENT_TYPE))
|
||||
|
||||
#define GET_VIRT_ADDR(MhiCtxt, PhysAddr) \
|
||||
((MhiCtxt)->CtrlSegProps.VirtAligned + ((PhysAddr) - (MhiCtxt)->CtrlSegProps.PhysAligned)) \
|
||||
|
||||
#define GET_PHYS_ADDR(MhiCtxt, VirtAddr) \
|
||||
((MhiCtxt)->CtrlSegProps.PhysAligned + ((VirtAddr) - (MhiCtxt)->CtrlSegProps.VirtAligned)) \
|
||||
|
||||
#define GET_RING_ELEMENT_INDEX(RingBase, Element) \
|
||||
(((Element) - (RingBase))/sizeof(MHI_ELEMENT_TYPE))
|
||||
|
||||
#define VALID_RING_PTR(Ring, Ptr) \
|
||||
(((Ptr) >= (Ring)->Base) && \
|
||||
((Ptr) <= ((Ring)->Base + (Ring)->Length - sizeof(MHI_ELEMENT_TYPE))))
|
||||
|
||||
#define CHAN_INBOUND(_x) ((_x)%2)
|
||||
|
||||
#define CHAN_SBL(_x) (((_x) == MHI_CLIENT_SAHARA_OUT) || \
|
||||
((_x) == MHI_CLIENT_SAHARA_IN) || \
|
||||
((_x) == MHI_CLIENT_BOOT_LOG_IN))
|
||||
|
||||
#define CHAN_EDL(_x) (((_x) == MHI_CLIENT_EDL_OUT) || \
|
||||
((_x) == MHI_CLIENT_EDL_IN))
|
||||
|
||||
#define RESERVED_CHAN(_x) (((_x) == MHI_CLIENT_RESERVED_0) || \
|
||||
((_x) >= MHI_CLIENT_RESERVED_1_LOWER && (_x) <= MHI_CLIENT_RESERVED_1_UPPER) || \
|
||||
((_x) >= MHI_CLIENT_RESERVED_2_LOWER && (_x) <= MHI_CLIENT_RESERVED_2_UPPER) || \
|
||||
((_x) >= MHI_CLIENT_RESERVED_3_LOWER && (_x) <= MHI_CLIENT_RESERVED_3_UPPER) || \
|
||||
((_x) >= MHI_CLIENT_RESERVED_4_LOWER && (_x) <= MHI_CLIENT_RESERVED_4_UPPER) || \
|
||||
((_x) >= MHI_CLIENT_RESERVED_5_LOWER))
|
||||
|
||||
#define VALID_CHAN(_x) ((((_x) >= 0) && ((_x) < MHI_MAX_CHANNELS)))
|
||||
|
||||
#define MHI_HW_CHAN(_x) ((_x) == MHI_CLIENT_IP_HW_0_OUT || \
|
||||
(_x) == MHI_CLIENT_IP_HW_0_IN || \
|
||||
(_x) == MHI_CLIENT_ADPL)
|
||||
|
||||
#define MIN(_x,_y) ((_x) < (_y) ? (_x): (_y))
|
||||
|
||||
struct mhi_chan;
|
||||
struct mhi_event;
|
||||
struct mhi_ctxt;
|
||||
struct mhi_cmd;
|
||||
struct image_info;
|
||||
struct bhi_vec_entry;
|
||||
struct mhi_cntrl_data;
|
||||
|
||||
/**
|
||||
* enum MHI_CB - MHI callback
|
||||
* @MHI_CB_IDLE: MHI entered idle state
|
||||
* @MHI_CB_PENDING_DATA: New data available for client to process
|
||||
* @MHI_CB_LPM_ENTER: MHI host entered low power mode
|
||||
* @MHI_CB_LPM_EXIT: MHI host about to exit low power mode
|
||||
* @MHI_CB_EE_RDDM: MHI device entered RDDM execution enviornment
|
||||
*/
|
||||
enum MHI_CB {
|
||||
MHI_CB_IDLE,
|
||||
MHI_CB_PENDING_DATA,
|
||||
MHI_CB_LPM_ENTER,
|
||||
MHI_CB_LPM_EXIT,
|
||||
MHI_CB_EE_RDDM,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum MHI_DEBUG_LEVL - various debugging level
|
||||
*/
|
||||
enum MHI_DEBUG_LEVEL {
|
||||
MHI_MSG_LVL_VERBOSE,
|
||||
MHI_MSG_LVL_INFO,
|
||||
MHI_MSG_LVL_ERROR,
|
||||
MHI_MSG_LVL_CRITICAL,
|
||||
MHI_MSG_LVL_MASK_ALL,
|
||||
};
|
||||
|
||||
/**
|
||||
* enum MHI_FLAGS - Transfer flags
|
||||
* @MHI_EOB: End of buffer for bulk transfer
|
||||
* @MHI_EOT: End of transfer
|
||||
* @MHI_CHAIN: Linked transfer
|
||||
*/
|
||||
enum MHI_FLAGS {
|
||||
MHI_EOB,
|
||||
MHI_EOT,
|
||||
MHI_CHAIN,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct image_info - firmware and rddm table table
|
||||
* @mhi_buf - Contain device firmware and rddm table
|
||||
* @entries - # of entries in table
|
||||
*/
|
||||
struct image_info {
|
||||
struct mhi_buf *mhi_buf;
|
||||
struct bhi_vec_entry *bhi_vec;
|
||||
u32 entries;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mhi_controller - Master controller structure for external modem
|
||||
* @dev: Device associated with this controller
|
||||
* @of_node: DT that has MHI configuration information
|
||||
* @regs: Points to base of MHI MMIO register space
|
||||
* @bhi: Points to base of MHI BHI register space
|
||||
* @wake_db: MHI WAKE doorbell register address
|
||||
* @dev_id: PCIe device id of the external device
|
||||
* @domain: PCIe domain the device connected to
|
||||
* @bus: PCIe bus the device assigned to
|
||||
* @slot: PCIe slot for the modem
|
||||
* @iova_start: IOMMU starting address for data
|
||||
* @iova_stop: IOMMU stop address for data
|
||||
* @fw_image: Firmware image name for normal booting
|
||||
* @edl_image: Firmware image name for emergency download mode
|
||||
* @fbc_download: MHI host needs to do complete image transfer
|
||||
* @rddm_size: RAM dump size that host should allocate for debugging purpose
|
||||
* @sbl_size: SBL image size
|
||||
* @seg_len: BHIe vector size
|
||||
* @fbc_image: Points to firmware image buffer
|
||||
* @rddm_image: Points to RAM dump buffer
|
||||
* @max_chan: Maximum number of channels controller support
|
||||
* @mhi_chan: Points to channel configuration table
|
||||
* @lpm_chans: List of channels that require LPM notifications
|
||||
* @total_ev_rings: Total # of event rings allocated
|
||||
* @hw_ev_rings: Number of hardware event rings
|
||||
* @sw_ev_rings: Number of software event rings
|
||||
* @msi_required: Number of msi required to operate
|
||||
* @msi_allocated: Number of msi allocated by bus master
|
||||
* @irq: base irq # to request
|
||||
* @mhi_event: MHI event ring configurations table
|
||||
* @mhi_cmd: MHI command ring configurations table
|
||||
* @mhi_ctxt: MHI device context, shared memory between host and device
|
||||
* @timeout_ms: Timeout in ms for state transitions
|
||||
* @pm_state: Power management state
|
||||
* @ee: MHI device execution environment
|
||||
* @dev_state: MHI STATE
|
||||
* @status_cb: CB function to notify various power states to but master
|
||||
* @link_status: Query link status in case of abnormal value read from device
|
||||
* @runtime_get: Async runtime resume function
|
||||
* @runtimet_put: Release votes
|
||||
* @priv_data: Points to bus master's private data
|
||||
*/
|
||||
struct mhi_controller {
|
||||
struct list_head node;
|
||||
|
||||
/* device node for iommu ops */
|
||||
struct device *dev;
|
||||
struct pci_dev *pci_dev;
|
||||
|
||||
/* mmio base */
|
||||
void __iomem *regs;
|
||||
void __iomem *bhi;
|
||||
void __iomem *wake_db;
|
||||
|
||||
/* device topology */
|
||||
u32 dev_id;
|
||||
u32 domain;
|
||||
u32 bus;
|
||||
u32 slot;
|
||||
|
||||
/* addressing window */
|
||||
dma_addr_t iova_start;
|
||||
dma_addr_t iova_stop;
|
||||
|
||||
/* fw images */
|
||||
const char *fw_image;
|
||||
const char *edl_image;
|
||||
|
||||
/* mhi host manages downloading entire fbc images */
|
||||
bool fbc_download;
|
||||
size_t rddm_size;
|
||||
size_t sbl_size;
|
||||
size_t seg_len;
|
||||
u32 session_id;
|
||||
u32 sequence_id;
|
||||
struct image_info *fbc_image;
|
||||
struct image_info *rddm_image;
|
||||
|
||||
/* physical channel config data */
|
||||
u32 max_chan;
|
||||
struct mhi_chan *mhi_chan;
|
||||
struct list_head lpm_chans; /* these chan require lpm notification */
|
||||
|
||||
/* physical event config data */
|
||||
u32 total_ev_rings;
|
||||
u32 hw_ev_rings;
|
||||
u32 sw_ev_rings;
|
||||
u32 msi_required;
|
||||
u32 msi_allocated;
|
||||
int irq[8]; /* interrupt table */
|
||||
struct mhi_event *mhi_event;
|
||||
|
||||
/* cmd rings */
|
||||
struct mhi_cmd *mhi_cmd;
|
||||
|
||||
/* mhi context (shared with device) */
|
||||
struct mhi_ctxt *mhi_ctxt;
|
||||
|
||||
u32 timeout_ms;
|
||||
|
||||
/* caller should grab pm_mutex for suspend/resume operations */
|
||||
struct mutex pm_mutex;
|
||||
bool pre_init;
|
||||
rwlock_t pm_lock;
|
||||
u32 pm_state;
|
||||
u32 ee;
|
||||
u32 dev_state;
|
||||
bool wake_set;
|
||||
atomic_t dev_wake;
|
||||
atomic_t alloc_size;
|
||||
struct list_head transition_list;
|
||||
spinlock_t transition_lock;
|
||||
spinlock_t wlock;
|
||||
|
||||
/* debug counters */
|
||||
u32 M0, M1, M2, M3;
|
||||
|
||||
/* worker for different state transitions */
|
||||
struct work_struct st_worker;
|
||||
struct work_struct fw_worker;
|
||||
struct work_struct m1_worker;
|
||||
struct work_struct syserr_worker;
|
||||
wait_queue_head_t state_event;
|
||||
|
||||
/* shadow functions */
|
||||
void (*status_cb)(struct mhi_controller *mhi_cntrl, void *piv,
|
||||
enum MHI_CB reason);
|
||||
int (*link_status)(struct mhi_controller *mhi_cntrl, void *priv);
|
||||
void (*wake_get)(struct mhi_controller *mhi_cntrl, bool override);
|
||||
void (*wake_put)(struct mhi_controller *mhi_cntrl, bool override);
|
||||
int (*runtime_get)(struct mhi_controller *mhi_cntrl, void *priv);
|
||||
void (*runtime_put)(struct mhi_controller *mhi_cntrl, void *priv);
|
||||
|
||||
/* channel to control DTR messaging */
|
||||
struct mhi_device *dtr_dev;
|
||||
|
||||
/* kernel log level */
|
||||
enum MHI_DEBUG_LEVEL klog_lvl;
|
||||
|
||||
/* private log level controller driver to set */
|
||||
enum MHI_DEBUG_LEVEL log_lvl;
|
||||
|
||||
/* controller specific data */
|
||||
void *priv_data;
|
||||
void *log_buf;
|
||||
struct dentry *dentry;
|
||||
struct dentry *parent;
|
||||
struct mhi_cntrl_data *data;
|
||||
|
||||
struct miscdevice miscdev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mhi_device - mhi device structure associated bind to channel
|
||||
* @dev: Device associated with the channels
|
||||
* @mtu: Maximum # of bytes controller support
|
||||
* @ul_chan_id: MHI channel id for UL transfer
|
||||
* @dl_chan_id: MHI channel id for DL transfer
|
||||
* @priv: Driver private data
|
||||
*/
|
||||
struct mhi_device {
|
||||
struct device dev;
|
||||
u32 dev_id;
|
||||
u32 domain;
|
||||
u32 bus;
|
||||
u32 slot;
|
||||
size_t mtu;
|
||||
int ul_chan_id;
|
||||
int dl_chan_id;
|
||||
int ul_event_id;
|
||||
int dl_event_id;
|
||||
const struct mhi_device_id *id;
|
||||
const char *chan_name;
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
struct mhi_chan *ul_chan;
|
||||
struct mhi_chan *dl_chan;
|
||||
atomic_t dev_wake;
|
||||
void *priv_data;
|
||||
int (*ul_xfer)(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS flags);
|
||||
int (*dl_xfer)(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS flags);
|
||||
void (*status_cb)(struct mhi_device *mhi_dev, enum MHI_CB reason);
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mhi_result - Completed buffer information
|
||||
* @buf_addr: Address of data buffer
|
||||
* @dir: Channel direction
|
||||
* @bytes_xfer: # of bytes transferred
|
||||
* @transaction_status: Status of last trasnferred
|
||||
*/
|
||||
struct mhi_result {
|
||||
void *buf_addr;
|
||||
enum dma_data_direction dir;
|
||||
size_t bytes_xferd;
|
||||
int transaction_status;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mhi_buf - Describes the buffer
|
||||
* @buf: cpu address for the buffer
|
||||
* @phys_addr: physical address of the buffer
|
||||
* @dma_addr: iommu address for the buffer
|
||||
* @len: # of bytes
|
||||
* @name: Buffer label, for offload channel configurations name must be:
|
||||
* ECA - Event context array data
|
||||
* CCA - Channel context array data
|
||||
*/
|
||||
struct mhi_buf {
|
||||
void *buf;
|
||||
phys_addr_t phys_addr;
|
||||
dma_addr_t dma_addr;
|
||||
size_t len;
|
||||
const char *name; /* ECA, CCA */
|
||||
};
|
||||
|
||||
/**
|
||||
* struct mhi_driver - mhi driver information
|
||||
* @id_table: NULL terminated channel ID names
|
||||
* @ul_xfer_cb: UL data transfer callback
|
||||
* @dl_xfer_cb: DL data transfer callback
|
||||
* @status_cb: Asynchronous status callback
|
||||
*/
|
||||
struct mhi_driver {
|
||||
const struct mhi_device_id *id_table;
|
||||
int (*probe)(struct mhi_device *mhi_dev,
|
||||
const struct mhi_device_id *id);
|
||||
void (*remove)(struct mhi_device *mhi_dev);
|
||||
void (*ul_xfer_cb)(struct mhi_device *mhi_dev,
|
||||
struct mhi_result *result);
|
||||
void (*dl_xfer_cb)(struct mhi_device *mhi_dev,
|
||||
struct mhi_result *result);
|
||||
void (*status_cb)(struct mhi_device *mhi_dev, enum MHI_CB mhi_cb);
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
#define to_mhi_driver(drv) container_of(drv, struct mhi_driver, driver)
|
||||
#define to_mhi_device(dev) container_of(dev, struct mhi_device, dev)
|
||||
|
||||
static inline void mhi_device_set_devdata(struct mhi_device *mhi_dev,
|
||||
void *priv)
|
||||
{
|
||||
mhi_dev->priv_data = priv;
|
||||
}
|
||||
|
||||
static inline void *mhi_device_get_devdata(struct mhi_device *mhi_dev)
|
||||
{
|
||||
return mhi_dev->priv_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* mhi_queue_transfer - Queue a buffer to hardware
|
||||
* All transfers are asyncronous transfers
|
||||
* @mhi_dev: Device associated with the channels
|
||||
* @dir: Data direction
|
||||
* @buf: Data buffer (skb for hardware channels)
|
||||
* @len: Size in bytes
|
||||
* @mflags: Interrupt flags for the device
|
||||
*/
|
||||
static inline int mhi_queue_transfer(struct mhi_device *mhi_dev,
|
||||
enum dma_data_direction dir,
|
||||
void *buf,
|
||||
size_t len,
|
||||
enum MHI_FLAGS mflags)
|
||||
{
|
||||
if (dir == DMA_TO_DEVICE)
|
||||
return mhi_dev->ul_xfer(mhi_dev, mhi_dev->ul_chan, buf, len,
|
||||
mflags);
|
||||
else
|
||||
return mhi_dev->dl_xfer(mhi_dev, mhi_dev->dl_chan, buf, len,
|
||||
mflags);
|
||||
}
|
||||
|
||||
static inline void *mhi_controller_get_devdata(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
return mhi_cntrl->priv_data;
|
||||
}
|
||||
|
||||
static inline void mhi_free_controller(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
kfree(mhi_cntrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* mhi_driver_register - Register driver with MHI framework
|
||||
* @mhi_drv: mhi_driver structure
|
||||
*/
|
||||
int mhi_driver_register(struct mhi_driver *mhi_drv);
|
||||
|
||||
/**
|
||||
* mhi_driver_unregister - Unregister a driver for mhi_devices
|
||||
* @mhi_drv: mhi_driver structure
|
||||
*/
|
||||
void mhi_driver_unregister(struct mhi_driver *mhi_drv);
|
||||
|
||||
/**
|
||||
* mhi_device_configure - configure ECA or CCA context
|
||||
* For offload channels that client manage, call this
|
||||
* function to configure channel context or event context
|
||||
* array associated with the channel
|
||||
* @mhi_div: Device associated with the channels
|
||||
* @dir: Direction of the channel
|
||||
* @mhi_buf: Configuration data
|
||||
* @elements: # of configuration elements
|
||||
*/
|
||||
int mhi_device_configure(struct mhi_device *mhi_div,
|
||||
enum dma_data_direction dir,
|
||||
struct mhi_buf *mhi_buf,
|
||||
int elements);
|
||||
|
||||
/**
|
||||
* mhi_device_get - disable all low power modes
|
||||
* Only disables lpm, does not immediately exit low power mode
|
||||
* if controller already in a low power mode
|
||||
* @mhi_dev: Device associated with the channels
|
||||
*/
|
||||
void mhi_device_get(struct mhi_device *mhi_dev);
|
||||
|
||||
/**
|
||||
* mhi_device_get_sync - disable all low power modes
|
||||
* Synchronously disable all low power, exit low power mode if
|
||||
* controller already in a low power state
|
||||
* @mhi_dev: Device associated with the channels
|
||||
*/
|
||||
int mhi_device_get_sync(struct mhi_device *mhi_dev);
|
||||
|
||||
/**
|
||||
* mhi_device_put - re-enable low power modes
|
||||
* @mhi_dev: Device associated with the channels
|
||||
*/
|
||||
void mhi_device_put(struct mhi_device *mhi_dev);
|
||||
|
||||
/**
|
||||
* mhi_prepare_for_transfer - setup channel for data transfer
|
||||
* Moves both UL and DL channel from RESET to START state
|
||||
* @mhi_dev: Device associated with the channels
|
||||
*/
|
||||
int mhi_prepare_for_transfer(struct mhi_device *mhi_dev);
|
||||
|
||||
/**
|
||||
* mhi_unprepare_from_transfer -unprepare the channels
|
||||
* Moves both UL and DL channels to RESET state
|
||||
* @mhi_dev: Device associated with the channels
|
||||
*/
|
||||
void mhi_unprepare_from_transfer(struct mhi_device *mhi_dev);
|
||||
|
||||
/**
|
||||
* mhi_get_no_free_descriptors - Get transfer ring length
|
||||
* Get # of TD available to queue buffers
|
||||
* @mhi_dev: Device associated with the channels
|
||||
* @dir: Direction of the channel
|
||||
*/
|
||||
int mhi_get_no_free_descriptors(struct mhi_device *mhi_dev,
|
||||
enum dma_data_direction dir);
|
||||
|
||||
/**
|
||||
* mhi_poll - poll for any available data to consume
|
||||
* This is only applicable for DL direction
|
||||
* @mhi_dev: Device associated with the channels
|
||||
* @budget: In descriptors to service before returning
|
||||
*/
|
||||
int mhi_poll(struct mhi_device *mhi_dev, u32 budget);
|
||||
|
||||
/**
|
||||
* mhi_ioctl - user space IOCTL support for MHI channels
|
||||
* Native support for setting TIOCM
|
||||
* @mhi_dev: Device associated with the channels
|
||||
* @cmd: IOCTL cmd
|
||||
* @arg: Optional parameter, iotcl cmd specific
|
||||
*/
|
||||
long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg);
|
||||
|
||||
/**
|
||||
* mhi_alloc_controller - Allocate mhi_controller structure
|
||||
* Allocate controller structure and additional data for controller
|
||||
* private data. You may get the private data pointer by calling
|
||||
* mhi_controller_get_devdata
|
||||
* @size: # of additional bytes to allocate
|
||||
*/
|
||||
struct mhi_controller *mhi_alloc_controller(size_t size);
|
||||
|
||||
/**
|
||||
* mhi_register_mhi_controller - Register MHI controller
|
||||
* Registers MHI controller with MHI bus framework. DT must be supported
|
||||
* @mhi_cntrl: MHI controller to register
|
||||
*/
|
||||
int mhi_register_mhi_controller(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
void mhi_unregister_mhi_controller(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_bdf_to_controller - Look up a registered controller
|
||||
* Search for controller based on device identification
|
||||
* @domain: RC domain of the device
|
||||
* @bus: Bus device connected to
|
||||
* @slot: Slot device assigned to
|
||||
* @dev_id: Device Identification
|
||||
*/
|
||||
struct mhi_controller *mhi_bdf_to_controller(u32 domain, u32 bus, u32 slot,
|
||||
u32 dev_id);
|
||||
|
||||
/**
|
||||
* mhi_prepare_for_power_up - Do pre-initialization before power up
|
||||
* This is optional, call this before power up if controller do not
|
||||
* want bus framework to automatically free any allocated memory during shutdown
|
||||
* process.
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
int mhi_prepare_for_power_up(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_async_power_up - Starts MHI power up sequence
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
int mhi_async_power_up(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_sync_power_up(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_power_down - Start MHI power down sequence
|
||||
* @mhi_cntrl: MHI controller
|
||||
* @graceful: link is still accessible, do a graceful shutdown process otherwise
|
||||
* we will shutdown host w/o putting device into RESET state
|
||||
*/
|
||||
void mhi_power_down(struct mhi_controller *mhi_cntrl, bool graceful);
|
||||
|
||||
/**
|
||||
* mhi_unprepare_after_powre_down - free any allocated memory for power up
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
void mhi_unprepare_after_power_down(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_pm_suspend - Move MHI into a suspended state
|
||||
* Transition to MHI state M3 state from M0||M1||M2 state
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
int mhi_pm_suspend(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_pm_resume - Resume MHI from suspended state
|
||||
* Transition to MHI state M0 state from M3 state
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
int mhi_pm_resume(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/**
|
||||
* mhi_download_rddm_img - Download ramdump image from device for
|
||||
* debugging purpose.
|
||||
* @mhi_cntrl: MHI controller
|
||||
* @in_panic: If we trying to capture image while in kernel panic
|
||||
*/
|
||||
int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic);
|
||||
|
||||
/**
|
||||
* mhi_force_rddm_mode - Force external device into rddm mode
|
||||
* to collect device ramdump. This is useful if host driver assert
|
||||
* and we need to see device state as well.
|
||||
* @mhi_cntrl: MHI controller
|
||||
*/
|
||||
int mhi_force_rddm_mode(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
int mhi_cntrl_register_miscdev(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_cntrl_deregister_miscdev(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
extern int mhi_debug_mask;
|
||||
|
||||
#define MHI_VERB(fmt, ...) do { \
|
||||
if (mhi_cntrl->klog_lvl <= MHI_MSG_LVL_VERBOSE) \
|
||||
pr_err("VERBOSE:[D][%s] " fmt, __func__, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define MHI_LOG(fmt, ...) do { \
|
||||
if (mhi_cntrl->klog_lvl <= MHI_MSG_LVL_INFO) \
|
||||
pr_err("INFO:[I][%s] " fmt, __func__, ##__VA_ARGS__);\
|
||||
} while (0)
|
||||
|
||||
#define MHI_ERR(fmt, ...) do { \
|
||||
if (mhi_cntrl->klog_lvl <= MHI_MSG_LVL_ERROR) \
|
||||
pr_err("[E][%s] " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define MHI_CRITICAL(fmt, ...) do { \
|
||||
if (mhi_cntrl->klog_lvl <= MHI_MSG_LVL_CRITICAL) \
|
||||
pr_err("ALERT:[C][%s] " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#ifndef MHI_NAME_SIZE
|
||||
#define MHI_NAME_SIZE 32
|
||||
/**
|
||||
* * struct mhi_device_id - MHI device identification
|
||||
* * @chan: MHI channel name
|
||||
* * @driver_data: driver data;
|
||||
* */
|
||||
struct mhi_device_id {
|
||||
const char chan[MHI_NAME_SIZE];
|
||||
unsigned long driver_data;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* _MHI_H_ */
|
||||
878
package/fish/fibocom_MHI/src/core/mhi_boot.c
Normal file
878
package/fish/fibocom_MHI/src/core/mhi_boot.c
Normal file
@ -0,0 +1,878 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/firmware.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include "mhi.h"
|
||||
#include "mhi_internal.h"
|
||||
|
||||
#define IOCTL_BHI_GETDEVINFO 0x8BE0 + 1
|
||||
#define IOCTL_BHI_WRITEIMAGE 0x8BE0 + 2
|
||||
|
||||
/* Software defines */
|
||||
/* BHI Version */
|
||||
#define BHI_MAJOR_VERSION 0x1
|
||||
#define BHI_MINOR_VERSION 0x1
|
||||
|
||||
#define MSMHWID_NUMDWORDS 6 /* Number of dwords that make the MSMHWID */
|
||||
#define OEMPKHASH_NUMDWORDS 48 /* Number of dwords that make the OEM PK HASH */
|
||||
|
||||
#define IsPBLExecEnv(ExecEnv) ((ExecEnv == MHI_EE_PBL) || (ExecEnv == MHI_EE_EDL) )
|
||||
|
||||
typedef u32 ULONG;
|
||||
|
||||
typedef struct _bhi_info_type
|
||||
{
|
||||
ULONG bhi_ver_minor;
|
||||
ULONG bhi_ver_major;
|
||||
ULONG bhi_image_address_low;
|
||||
ULONG bhi_image_address_high;
|
||||
ULONG bhi_image_size;
|
||||
ULONG bhi_rsvd1;
|
||||
ULONG bhi_imgtxdb;
|
||||
ULONG bhi_rsvd2;
|
||||
ULONG bhi_msivec;
|
||||
ULONG bhi_rsvd3;
|
||||
ULONG bhi_ee;
|
||||
ULONG bhi_status;
|
||||
ULONG bhi_errorcode;
|
||||
ULONG bhi_errdbg1;
|
||||
ULONG bhi_errdbg2;
|
||||
ULONG bhi_errdbg3;
|
||||
ULONG bhi_sernum;
|
||||
ULONG bhi_sblantirollbackver;
|
||||
ULONG bhi_numsegs;
|
||||
ULONG bhi_msmhwid[6];
|
||||
ULONG bhi_oempkhash[48];
|
||||
ULONG bhi_rsvd5;
|
||||
}BHI_INFO_TYPE, *PBHI_INFO_TYPE;
|
||||
|
||||
#if 0
|
||||
static void PrintBhiInfo(BHI_INFO_TYPE *bhi_info)
|
||||
{
|
||||
ULONG index;
|
||||
|
||||
printk("BHI Device Info...\n");
|
||||
printk("BHI Version = { Major = 0x%X Minor = 0x%X}\n", bhi_info->bhi_ver_major, bhi_info->bhi_ver_minor);
|
||||
printk("BHI Execution Environment = 0x%X\n", bhi_info->bhi_ee);
|
||||
printk("BHI Status = 0x%X\n", bhi_info->bhi_status);
|
||||
printk("BHI Error code = 0x%X { Dbg1 = 0x%X Dbg2 = 0x%X Dbg3 = 0x%X }\n", bhi_info->bhi_errorcode, bhi_info->bhi_errdbg1, bhi_info->bhi_errdbg2, bhi_info->bhi_errdbg3);
|
||||
printk("BHI Serial Number = 0x%X\n", bhi_info->bhi_sernum);
|
||||
printk("BHI SBL Anti-Rollback Ver = 0x%X\n", bhi_info->bhi_sblantirollbackver);
|
||||
printk("BHI Number of Segments = 0x%X\n", bhi_info->bhi_numsegs);
|
||||
printk("BHI MSM HW-Id = ");
|
||||
for (index = 0; index < 6; index++)
|
||||
{
|
||||
printk("0x%X ", bhi_info->bhi_msmhwid[index]);
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
printk("BHI OEM PK Hash = \n");
|
||||
for (index = 0; index < 24; index++)
|
||||
{
|
||||
printk("0x%X ", bhi_info->bhi_oempkhash[index]);
|
||||
}
|
||||
printk("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
static u32 bhi_read_reg(struct mhi_controller *mhi_cntrl, u32 offset)
|
||||
{
|
||||
u32 out = 0;
|
||||
int ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->bhi, offset, &out);
|
||||
|
||||
return (ret) ? 0 : out;
|
||||
}
|
||||
|
||||
static int BhiRead(struct mhi_controller *mhi_cntrl, BHI_INFO_TYPE *bhi_info)
|
||||
{
|
||||
ULONG index;
|
||||
|
||||
memset(bhi_info, 0x00, sizeof(BHI_INFO_TYPE));
|
||||
|
||||
/* bhi_ver */
|
||||
bhi_info->bhi_ver_minor = bhi_read_reg(mhi_cntrl, BHI_BHIVERSION_MINOR);
|
||||
bhi_info->bhi_ver_major = bhi_read_reg(mhi_cntrl, BHI_BHIVERSION_MINOR);
|
||||
bhi_info->bhi_image_address_low = bhi_read_reg(mhi_cntrl, BHI_IMGADDR_LOW);
|
||||
bhi_info->bhi_image_address_high = bhi_read_reg(mhi_cntrl, BHI_IMGADDR_HIGH);
|
||||
bhi_info->bhi_image_size = bhi_read_reg(mhi_cntrl, BHI_IMGSIZE);
|
||||
bhi_info->bhi_rsvd1 = bhi_read_reg(mhi_cntrl, BHI_RSVD1);
|
||||
bhi_info->bhi_imgtxdb = bhi_read_reg(mhi_cntrl, BHI_IMGTXDB);
|
||||
bhi_info->bhi_rsvd2 = bhi_read_reg(mhi_cntrl, BHI_RSVD2);
|
||||
bhi_info->bhi_msivec = bhi_read_reg(mhi_cntrl, BHI_INTVEC);
|
||||
bhi_info->bhi_rsvd3 = bhi_read_reg(mhi_cntrl, BHI_RSVD3);
|
||||
bhi_info->bhi_ee = bhi_read_reg(mhi_cntrl, BHI_EXECENV);
|
||||
bhi_info->bhi_status = bhi_read_reg(mhi_cntrl, BHI_STATUS);
|
||||
bhi_info->bhi_errorcode = bhi_read_reg(mhi_cntrl, BHI_ERRCODE);
|
||||
bhi_info->bhi_errdbg1 = bhi_read_reg(mhi_cntrl, BHI_ERRDBG1);
|
||||
bhi_info->bhi_errdbg2 = bhi_read_reg(mhi_cntrl, BHI_ERRDBG2);
|
||||
bhi_info->bhi_errdbg3 = bhi_read_reg(mhi_cntrl, BHI_ERRDBG3);
|
||||
bhi_info->bhi_sernum = bhi_read_reg(mhi_cntrl, BHI_SERIALNUM);
|
||||
bhi_info->bhi_sblantirollbackver = bhi_read_reg(mhi_cntrl, BHI_SBLANTIROLLVER);
|
||||
bhi_info->bhi_numsegs = bhi_read_reg(mhi_cntrl, BHI_NUMSEG);
|
||||
for (index = 0; index < MSMHWID_NUMDWORDS; index++)
|
||||
{
|
||||
bhi_info->bhi_msmhwid[index] = bhi_read_reg(mhi_cntrl, BHI_MSMHWID(index));
|
||||
}
|
||||
for (index = 0; index < OEMPKHASH_NUMDWORDS; index++)
|
||||
{
|
||||
bhi_info->bhi_oempkhash[index] = bhi_read_reg(mhi_cntrl, BHI_OEMPKHASH(index));
|
||||
}
|
||||
bhi_info->bhi_rsvd5 = bhi_read_reg(mhi_cntrl, BHI_RSVD5);
|
||||
//PrintBhiInfo(bhi_info);
|
||||
/* Check the Execution Environment */
|
||||
if (!IsPBLExecEnv(bhi_info->bhi_ee))
|
||||
{
|
||||
printk("E - EE: 0x%X Expected PBL/EDL\n", bhi_info->bhi_ee);
|
||||
}
|
||||
|
||||
/* Return the number of bytes read */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* setup rddm vector table for rddm transfer */
|
||||
static void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *img_info)
|
||||
{
|
||||
struct mhi_buf *mhi_buf = img_info->mhi_buf;
|
||||
struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < img_info->entries - 1; i++, mhi_buf++, bhi_vec++) {
|
||||
MHI_VERB("Setting vector:%pad size:%zu\n",
|
||||
&mhi_buf->dma_addr, mhi_buf->len);
|
||||
bhi_vec->dma_addr = mhi_buf->dma_addr;
|
||||
bhi_vec->size = mhi_buf->len;
|
||||
}
|
||||
}
|
||||
|
||||
/* collect rddm during kernel panic */
|
||||
static int __mhi_download_rddm_in_panic(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
int ret;
|
||||
struct mhi_buf *mhi_buf;
|
||||
u32 sequence_id;
|
||||
u32 rx_status;
|
||||
enum MHI_EE ee;
|
||||
struct image_info *rddm_image = mhi_cntrl->rddm_image;
|
||||
const u32 delayus = 100;
|
||||
u32 retry = (mhi_cntrl->timeout_ms * 1000) / delayus;
|
||||
void __iomem *base = mhi_cntrl->bhi;
|
||||
|
||||
MHI_LOG("Entered with pm_state:%s dev_state:%s ee:%s\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
TO_MHI_STATE_STR(mhi_cntrl->dev_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
|
||||
/*
|
||||
* This should only be executing during a kernel panic, we expect all
|
||||
* other cores to shutdown while we're collecting rddm buffer. After
|
||||
* returning from this function, we expect device to reset.
|
||||
*
|
||||
* Normaly, we would read/write pm_state only after grabbing
|
||||
* pm_lock, since we're in a panic, skipping it.
|
||||
*/
|
||||
|
||||
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state))
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* There is no gurantee this state change would take effect since
|
||||
* we're setting it w/o grabbing pmlock, it's best effort
|
||||
*/
|
||||
mhi_cntrl->pm_state = MHI_PM_LD_ERR_FATAL_DETECT;
|
||||
/* update should take the effect immediately */
|
||||
smp_wmb();
|
||||
|
||||
/* setup the RX vector table */
|
||||
mhi_rddm_prepare(mhi_cntrl, rddm_image);
|
||||
mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1];
|
||||
|
||||
MHI_LOG("Starting BHIe programming for RDDM\n");
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS,
|
||||
upper_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS,
|
||||
lower_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len);
|
||||
sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK;
|
||||
|
||||
if (unlikely(!sequence_id))
|
||||
sequence_id = 1;
|
||||
|
||||
|
||||
mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS,
|
||||
BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT,
|
||||
sequence_id);
|
||||
|
||||
MHI_LOG("Trigger device into RDDM mode\n");
|
||||
mhi_set_mhi_state(mhi_cntrl, MHI_STATE_SYS_ERR);
|
||||
|
||||
MHI_LOG("Waiting for image download completion\n");
|
||||
while (retry--) {
|
||||
ret = mhi_read_reg_field(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS,
|
||||
BHIE_RXVECSTATUS_STATUS_BMSK,
|
||||
BHIE_RXVECSTATUS_STATUS_SHFT,
|
||||
&rx_status);
|
||||
if (ret)
|
||||
return -EIO;
|
||||
|
||||
if (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) {
|
||||
MHI_LOG("RDDM successfully collected\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
udelay(delayus);
|
||||
}
|
||||
|
||||
ee = mhi_get_exec_env(mhi_cntrl);
|
||||
ret = mhi_read_reg(mhi_cntrl, base, BHIE_RXVECSTATUS_OFFS, &rx_status);
|
||||
|
||||
MHI_ERR("Did not complete RDDM transfer\n");
|
||||
MHI_ERR("Current EE:%s\n", TO_MHI_EXEC_STR(ee));
|
||||
MHI_ERR("RXVEC_STATUS:0x%x, ret:%d\n", rx_status, ret);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* download ramdump image from device */
|
||||
int mhi_download_rddm_img(struct mhi_controller *mhi_cntrl, bool in_panic)
|
||||
{
|
||||
void __iomem *base = mhi_cntrl->bhi;
|
||||
rwlock_t *pm_lock = &mhi_cntrl->pm_lock;
|
||||
struct image_info *rddm_image = mhi_cntrl->rddm_image;
|
||||
struct mhi_buf *mhi_buf;
|
||||
int ret;
|
||||
u32 rx_status;
|
||||
u32 sequence_id;
|
||||
|
||||
if (!rddm_image)
|
||||
return -ENOMEM;
|
||||
|
||||
if (in_panic)
|
||||
return __mhi_download_rddm_in_panic(mhi_cntrl);
|
||||
|
||||
MHI_LOG("Waiting for device to enter RDDM state from EE:%s\n",
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_cntrl->ee == MHI_EE_RDDM ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
MHI_ERR("MHI is not in valid state, pm_state:%s ee:%s\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
mhi_rddm_prepare(mhi_cntrl, mhi_cntrl->rddm_image);
|
||||
|
||||
/* vector table is the last entry */
|
||||
mhi_buf = &rddm_image->mhi_buf[rddm_image->entries - 1];
|
||||
|
||||
read_lock_bh(pm_lock);
|
||||
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
|
||||
read_unlock_bh(pm_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
MHI_LOG("Starting BHIe Programming for RDDM\n");
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_HIGH_OFFS,
|
||||
upper_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECADDR_LOW_OFFS,
|
||||
lower_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_RXVECSIZE_OFFS, mhi_buf->len);
|
||||
|
||||
sequence_id = prandom_u32() & BHIE_RXVECSTATUS_SEQNUM_BMSK;
|
||||
mhi_write_reg_field(mhi_cntrl, base, BHIE_RXVECDB_OFFS,
|
||||
BHIE_RXVECDB_SEQNUM_BMSK, BHIE_RXVECDB_SEQNUM_SHFT,
|
||||
sequence_id);
|
||||
read_unlock_bh(pm_lock);
|
||||
|
||||
MHI_LOG("Upper:0x%x Lower:0x%x len:0x%zx sequence:%u\n",
|
||||
upper_32_bits(mhi_buf->dma_addr),
|
||||
lower_32_bits(mhi_buf->dma_addr),
|
||||
mhi_buf->len, sequence_id);
|
||||
MHI_LOG("Waiting for image download completion\n");
|
||||
|
||||
/* waiting for image download completion */
|
||||
wait_event_timeout(mhi_cntrl->state_event,
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) ||
|
||||
mhi_read_reg_field(mhi_cntrl, base,
|
||||
BHIE_RXVECSTATUS_OFFS,
|
||||
BHIE_RXVECSTATUS_STATUS_BMSK,
|
||||
BHIE_RXVECSTATUS_STATUS_SHFT,
|
||||
&rx_status) || rx_status,
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
|
||||
return -EIO;
|
||||
|
||||
return (rx_status == BHIE_RXVECSTATUS_STATUS_XFER_COMPL) ? 0 : -EIO;
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_download_rddm_img);
|
||||
|
||||
static int mhi_fw_load_amss(struct mhi_controller *mhi_cntrl,
|
||||
const struct mhi_buf *mhi_buf)
|
||||
{
|
||||
void __iomem *base = mhi_cntrl->bhi;
|
||||
rwlock_t *pm_lock = &mhi_cntrl->pm_lock;
|
||||
u32 tx_status;
|
||||
|
||||
read_lock_bh(pm_lock);
|
||||
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
|
||||
read_unlock_bh(pm_lock);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
MHI_LOG("Starting BHIe Programming\n");
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_TXVECADDR_HIGH_OFFS,
|
||||
upper_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_TXVECADDR_LOW_OFFS,
|
||||
lower_32_bits(mhi_buf->dma_addr));
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHIE_TXVECSIZE_OFFS, mhi_buf->len);
|
||||
|
||||
mhi_cntrl->sequence_id = prandom_u32() & BHIE_TXVECSTATUS_SEQNUM_BMSK;
|
||||
mhi_write_reg_field(mhi_cntrl, base, BHIE_TXVECDB_OFFS,
|
||||
BHIE_TXVECDB_SEQNUM_BMSK, BHIE_TXVECDB_SEQNUM_SHFT,
|
||||
mhi_cntrl->sequence_id);
|
||||
read_unlock_bh(pm_lock);
|
||||
|
||||
MHI_LOG("Upper:0x%x Lower:0x%x len:0x%zx sequence:%u\n",
|
||||
upper_32_bits(mhi_buf->dma_addr),
|
||||
lower_32_bits(mhi_buf->dma_addr),
|
||||
mhi_buf->len, mhi_cntrl->sequence_id);
|
||||
MHI_LOG("Waiting for image transfer completion\n");
|
||||
|
||||
/* waiting for image download completion */
|
||||
wait_event_timeout(mhi_cntrl->state_event,
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) ||
|
||||
mhi_read_reg_field(mhi_cntrl, base,
|
||||
BHIE_TXVECSTATUS_OFFS,
|
||||
BHIE_TXVECSTATUS_STATUS_BMSK,
|
||||
BHIE_TXVECSTATUS_STATUS_SHFT,
|
||||
&tx_status) || tx_status,
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
|
||||
return -EIO;
|
||||
|
||||
return (tx_status == BHIE_TXVECSTATUS_STATUS_XFER_COMPL) ? 0 : -EIO;
|
||||
}
|
||||
|
||||
static int mhi_fw_load_sbl(struct mhi_controller *mhi_cntrl,
|
||||
void *buf,
|
||||
size_t size)
|
||||
{
|
||||
u32 tx_status, val;
|
||||
int i, ret;
|
||||
void __iomem *base = mhi_cntrl->bhi;
|
||||
rwlock_t *pm_lock = &mhi_cntrl->pm_lock;
|
||||
dma_addr_t phys = dma_map_single(mhi_cntrl->dev, buf, size,
|
||||
DMA_TO_DEVICE);
|
||||
struct {
|
||||
char *name;
|
||||
u32 offset;
|
||||
} error_reg[] = {
|
||||
{ "ERROR_CODE", BHI_ERRCODE },
|
||||
{ "ERROR_DBG1", BHI_ERRDBG1 },
|
||||
{ "ERROR_DBG2", BHI_ERRDBG2 },
|
||||
{ "ERROR_DBG3", BHI_ERRDBG3 },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
if (dma_mapping_error(mhi_cntrl->dev, phys))
|
||||
return -ENOMEM;
|
||||
|
||||
MHI_LOG("Starting BHI programming\n");
|
||||
|
||||
/* program start sbl download via bhi protocol */
|
||||
read_lock_bh(pm_lock);
|
||||
if (!MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
|
||||
read_unlock_bh(pm_lock);
|
||||
goto invalid_pm_state;
|
||||
}
|
||||
|
||||
mhi_write_reg(mhi_cntrl, base, BHI_STATUS, 0);
|
||||
mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_HIGH, upper_32_bits(phys));
|
||||
mhi_write_reg(mhi_cntrl, base, BHI_IMGADDR_LOW, lower_32_bits(phys));
|
||||
mhi_write_reg(mhi_cntrl, base, BHI_IMGSIZE, size);
|
||||
mhi_cntrl->session_id = prandom_u32() & BHI_TXDB_SEQNUM_BMSK;
|
||||
mhi_write_reg(mhi_cntrl, base, BHI_IMGTXDB, mhi_cntrl->session_id);
|
||||
read_unlock_bh(pm_lock);
|
||||
|
||||
MHI_LOG("Waiting for image transfer completion\n");
|
||||
|
||||
/* waiting for image download completion */
|
||||
wait_event_timeout(mhi_cntrl->state_event,
|
||||
/*MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state) ||*/
|
||||
mhi_read_reg_field(mhi_cntrl, base, BHI_STATUS,
|
||||
BHI_STATUS_MASK, BHI_STATUS_SHIFT,
|
||||
&tx_status) || tx_status,
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
#if 0
|
||||
if (MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state))
|
||||
goto invalid_pm_state;
|
||||
#endif
|
||||
|
||||
MHI_LOG("image transfer status:%d\n", tx_status);
|
||||
|
||||
if (tx_status == BHI_STATUS_ERROR) {
|
||||
MHI_ERR("Image transfer failed\n");
|
||||
read_lock_bh(pm_lock);
|
||||
if (MHI_REG_ACCESS_VALID(mhi_cntrl->pm_state)) {
|
||||
for (i = 0; error_reg[i].name; i++) {
|
||||
ret = mhi_read_reg(mhi_cntrl, base,
|
||||
error_reg[i].offset, &val);
|
||||
if (ret)
|
||||
break;
|
||||
MHI_ERR("reg:%s value:0x%x\n",
|
||||
error_reg[i].name, val);
|
||||
}
|
||||
}
|
||||
read_unlock_bh(pm_lock);
|
||||
goto invalid_pm_state;
|
||||
}
|
||||
|
||||
dma_unmap_single(mhi_cntrl->dev, phys, size, DMA_TO_DEVICE);
|
||||
|
||||
return (tx_status == BHI_STATUS_SUCCESS) ? 0 : -ETIMEDOUT;
|
||||
|
||||
invalid_pm_state:
|
||||
dma_unmap_single(mhi_cntrl->dev, phys, size, DMA_TO_DEVICE);
|
||||
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *image_info)
|
||||
{
|
||||
int i;
|
||||
struct mhi_buf *mhi_buf = image_info->mhi_buf;
|
||||
|
||||
for (i = 0; i < image_info->entries; i++, mhi_buf++)
|
||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
||||
mhi_buf->dma_addr);
|
||||
|
||||
kfree(image_info->mhi_buf);
|
||||
kfree(image_info);
|
||||
}
|
||||
|
||||
int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info **image_info,
|
||||
size_t alloc_size)
|
||||
{
|
||||
size_t seg_size = mhi_cntrl->seg_len;
|
||||
/* requier additional entry for vec table */
|
||||
int segments = DIV_ROUND_UP(alloc_size, seg_size) + 1;
|
||||
int i;
|
||||
struct image_info *img_info;
|
||||
struct mhi_buf *mhi_buf;
|
||||
|
||||
MHI_LOG("Allocating bytes:%zu seg_size:%zu total_seg:%u\n",
|
||||
alloc_size, seg_size, segments);
|
||||
|
||||
img_info = kzalloc(sizeof(*img_info), GFP_KERNEL);
|
||||
if (!img_info)
|
||||
return -ENOMEM;
|
||||
|
||||
/* allocate memory for entries */
|
||||
img_info->mhi_buf = kcalloc(segments, sizeof(*img_info->mhi_buf),
|
||||
GFP_KERNEL);
|
||||
if (!img_info->mhi_buf)
|
||||
goto error_alloc_mhi_buf;
|
||||
|
||||
/* allocate and populate vector table */
|
||||
mhi_buf = img_info->mhi_buf;
|
||||
for (i = 0; i < segments; i++, mhi_buf++) {
|
||||
size_t vec_size = seg_size;
|
||||
|
||||
/* last entry is for vector table */
|
||||
if (i == segments - 1)
|
||||
vec_size = sizeof(struct __packed bhi_vec_entry) * i;
|
||||
|
||||
mhi_buf->len = vec_size;
|
||||
mhi_buf->buf = mhi_alloc_coherent(mhi_cntrl, vec_size,
|
||||
&mhi_buf->dma_addr, GFP_KERNEL);
|
||||
if (!mhi_buf->buf)
|
||||
goto error_alloc_segment;
|
||||
|
||||
MHI_LOG("Entry:%d Address:0x%llx size:%zd\n", i,
|
||||
(u64)mhi_buf->dma_addr, mhi_buf->len);
|
||||
}
|
||||
|
||||
img_info->bhi_vec = img_info->mhi_buf[segments - 1].buf;
|
||||
img_info->entries = segments;
|
||||
*image_info = img_info;
|
||||
|
||||
MHI_LOG("Successfully allocated bhi vec table\n");
|
||||
|
||||
return 0;
|
||||
|
||||
error_alloc_segment:
|
||||
for (--i, --mhi_buf; i >= 0; i--, mhi_buf--)
|
||||
mhi_free_coherent(mhi_cntrl, mhi_buf->len, mhi_buf->buf,
|
||||
mhi_buf->dma_addr);
|
||||
|
||||
error_alloc_mhi_buf:
|
||||
kfree(img_info);
|
||||
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void mhi_firmware_copy(struct mhi_controller *mhi_cntrl,
|
||||
const struct firmware *firmware,
|
||||
struct image_info *img_info)
|
||||
{
|
||||
size_t remainder = firmware->size;
|
||||
size_t to_cpy;
|
||||
const u8 *buf = firmware->data;
|
||||
int i = 0;
|
||||
struct mhi_buf *mhi_buf = img_info->mhi_buf;
|
||||
struct bhi_vec_entry *bhi_vec = img_info->bhi_vec;
|
||||
|
||||
while (remainder) {
|
||||
MHI_ASSERT(i >= img_info->entries, "malformed vector table");
|
||||
|
||||
to_cpy = min(remainder, mhi_buf->len);
|
||||
memcpy(mhi_buf->buf, buf, to_cpy);
|
||||
bhi_vec->dma_addr = mhi_buf->dma_addr;
|
||||
bhi_vec->size = to_cpy;
|
||||
|
||||
MHI_VERB("Setting Vector:0x%llx size: %llu\n",
|
||||
bhi_vec->dma_addr, bhi_vec->size);
|
||||
buf += to_cpy;
|
||||
remainder -= to_cpy;
|
||||
i++;
|
||||
bhi_vec++;
|
||||
mhi_buf++;
|
||||
}
|
||||
}
|
||||
|
||||
void mhi_fw_load_worker(struct work_struct *work)
|
||||
{
|
||||
int ret;
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
const char *fw_name;
|
||||
const struct firmware *firmware;
|
||||
struct image_info *image_info;
|
||||
void *buf;
|
||||
size_t size;
|
||||
|
||||
mhi_cntrl = container_of(work, struct mhi_controller, fw_worker);
|
||||
|
||||
MHI_LOG("Waiting for device to enter PBL from EE:%s\n",
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
MHI_IN_PBL(mhi_cntrl->ee) ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
MHI_ERR("MHI is not in valid state\n");
|
||||
return;
|
||||
}
|
||||
|
||||
MHI_LOG("Device current EE:%s\n", TO_MHI_EXEC_STR(mhi_cntrl->ee));
|
||||
|
||||
/* if device in pthru, we do not have to load firmware */
|
||||
if (mhi_cntrl->ee == MHI_EE_PT)
|
||||
return;
|
||||
|
||||
fw_name = (mhi_cntrl->ee == MHI_EE_EDL) ?
|
||||
mhi_cntrl->edl_image : mhi_cntrl->fw_image;
|
||||
|
||||
if (!fw_name || (mhi_cntrl->fbc_download && (!mhi_cntrl->sbl_size ||
|
||||
!mhi_cntrl->seg_len))) {
|
||||
MHI_ERR("No firmware image defined or !sbl_size || !seg_len\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ret = request_firmware(&firmware, fw_name, mhi_cntrl->dev);
|
||||
if (ret) {
|
||||
MHI_ERR("Error loading firmware, ret:%d\n", ret);
|
||||
return;
|
||||
}
|
||||
|
||||
size = (mhi_cntrl->fbc_download) ? mhi_cntrl->sbl_size : firmware->size;
|
||||
|
||||
/* the sbl size provided is maximum size, not necessarily image size */
|
||||
if (size > firmware->size)
|
||||
size = firmware->size;
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (!buf) {
|
||||
MHI_ERR("Could not allocate memory for image\n");
|
||||
release_firmware(firmware);
|
||||
return;
|
||||
}
|
||||
|
||||
/* load sbl image */
|
||||
memcpy(buf, firmware->data, size);
|
||||
ret = mhi_fw_load_sbl(mhi_cntrl, buf, size);
|
||||
kfree(buf);
|
||||
|
||||
if (!mhi_cntrl->fbc_download || ret || mhi_cntrl->ee == MHI_EE_EDL)
|
||||
release_firmware(firmware);
|
||||
|
||||
/* error or in edl, we're done */
|
||||
if (ret || mhi_cntrl->ee == MHI_EE_EDL)
|
||||
return;
|
||||
|
||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||
mhi_cntrl->dev_state = MHI_STATE_RESET;
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
|
||||
/*
|
||||
* if we're doing fbc, populate vector tables while
|
||||
* device transitioning into MHI READY state
|
||||
*/
|
||||
if (mhi_cntrl->fbc_download) {
|
||||
ret = mhi_alloc_bhie_table(mhi_cntrl, &mhi_cntrl->fbc_image,
|
||||
firmware->size);
|
||||
if (ret) {
|
||||
MHI_ERR("Error alloc size of %zu\n", firmware->size);
|
||||
goto error_alloc_fw_table;
|
||||
}
|
||||
|
||||
MHI_LOG("Copying firmware image into vector table\n");
|
||||
|
||||
/* load the firmware into BHIE vec table */
|
||||
mhi_firmware_copy(mhi_cntrl, firmware, mhi_cntrl->fbc_image);
|
||||
}
|
||||
|
||||
/* transitioning into MHI RESET->READY state */
|
||||
ret = mhi_ready_state_transition(mhi_cntrl);
|
||||
|
||||
MHI_LOG("To Reset->Ready PM_STATE:%s MHI_STATE:%s EE:%s, ret:%d\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
TO_MHI_STATE_STR(mhi_cntrl->dev_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee), ret);
|
||||
|
||||
if (!mhi_cntrl->fbc_download)
|
||||
return;
|
||||
|
||||
if (ret) {
|
||||
MHI_ERR("Did not transition to READY state\n");
|
||||
goto error_read;
|
||||
}
|
||||
|
||||
/* wait for BHIE event */
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_cntrl->ee == MHI_EE_BHIE ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
MHI_ERR("MHI did not enter BHIE\n");
|
||||
goto error_read;
|
||||
}
|
||||
|
||||
/* start full firmware image download */
|
||||
image_info = mhi_cntrl->fbc_image;
|
||||
ret = mhi_fw_load_amss(mhi_cntrl,
|
||||
/* last entry is vec table */
|
||||
&image_info->mhi_buf[image_info->entries - 1]);
|
||||
|
||||
MHI_LOG("amss fw_load, ret:%d\n", ret);
|
||||
|
||||
release_firmware(firmware);
|
||||
|
||||
return;
|
||||
|
||||
error_read:
|
||||
mhi_free_bhie_table(mhi_cntrl, mhi_cntrl->fbc_image);
|
||||
mhi_cntrl->fbc_image = NULL;
|
||||
|
||||
error_alloc_fw_table:
|
||||
release_firmware(firmware);
|
||||
}
|
||||
|
||||
int BhiWrite(struct mhi_controller *mhi_cntrl, void *buf, size_t size)
|
||||
{
|
||||
int ret;
|
||||
|
||||
MHI_LOG("Device current EE:%s,%d M:%s\n",
|
||||
TO_MHI_EXEC_STR(mhi_get_exec_env(mhi_cntrl)),
|
||||
mhi_cntrl->ee,
|
||||
TO_MHI_STATE_STR(mhi_get_m_state(mhi_cntrl)));
|
||||
|
||||
mhi_cntrl->ee = mhi_get_exec_env(mhi_cntrl);
|
||||
|
||||
if (!MHI_IN_PBL(mhi_cntrl->ee)/* || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)*/) {
|
||||
MHI_ERR("MHI is not in valid BHI state:%d\n", mhi_cntrl->ee);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (mhi_cntrl->ee != MHI_EE_EDL)
|
||||
return 0;
|
||||
|
||||
ret = mhi_fw_load_sbl(mhi_cntrl, buf, size);
|
||||
|
||||
if (ret) {
|
||||
MHI_ERR("ret = %d, ee=%d\n", ret, mhi_cntrl->ee);
|
||||
goto error_state;
|
||||
}
|
||||
|
||||
write_lock_irq(&mhi_cntrl->pm_lock);
|
||||
mhi_cntrl->dev_state = MHI_STATE_RESET;
|
||||
write_unlock_irq(&mhi_cntrl->pm_lock);
|
||||
|
||||
/* transitioning into MHI RESET->READY state */
|
||||
ret = mhi_ready_state_transition(mhi_cntrl);
|
||||
if (ret) {
|
||||
MHI_ERR("Did not transition to READY state\n");
|
||||
goto error_state;
|
||||
}
|
||||
|
||||
MHI_LOG("To Reset->Ready PM_STATE:%s MHI_STATE:%s EE:%s, ret:%d\n",
|
||||
to_mhi_pm_state_str(mhi_cntrl->pm_state),
|
||||
TO_MHI_STATE_STR(mhi_cntrl->dev_state),
|
||||
TO_MHI_EXEC_STR(mhi_cntrl->ee), ret);
|
||||
|
||||
/* wait for BHIE event */
|
||||
ret = wait_event_timeout(mhi_cntrl->state_event,
|
||||
mhi_cntrl->ee == MHI_EE_FP ||
|
||||
MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state),
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
if (!ret || MHI_PM_IN_ERROR_STATE(mhi_cntrl->pm_state)) {
|
||||
MHI_ERR("MHI did not enter Flash Programmer Environment\n");
|
||||
goto error_state;
|
||||
}
|
||||
|
||||
MHI_LOG("MHI enter Flash Programmer Environment\n");
|
||||
return 0;
|
||||
|
||||
error_state:
|
||||
MHI_LOG("Device current EE:%s, M:%s\n",
|
||||
TO_MHI_EXEC_STR(mhi_get_exec_env(mhi_cntrl)),
|
||||
TO_MHI_STATE_STR(mhi_get_m_state(mhi_cntrl)));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mhi_cntrl_open(struct inode *inode, struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mhi_cntrl_release(struct inode *inode, struct file *f)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long mhi_cntrl_ioctl(struct file *f, unsigned int cmd, unsigned long __arg)
|
||||
{
|
||||
long ret = -EINVAL;
|
||||
void *ubuf = (void *)__arg;
|
||||
struct miscdevice *c = (struct miscdevice *)f->private_data;
|
||||
struct mhi_controller *mhi_cntrl = container_of(c, struct mhi_controller, miscdev);
|
||||
|
||||
switch (cmd) {
|
||||
case IOCTL_BHI_GETDEVINFO:
|
||||
{
|
||||
BHI_INFO_TYPE bhi_info;
|
||||
ret = BhiRead(mhi_cntrl, &bhi_info);
|
||||
if (ret) {
|
||||
MHI_ERR("IOCTL_BHI_GETDEVINFO BhiRead error, ret = %ld\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = copy_to_user(ubuf, &bhi_info, sizeof(bhi_info));
|
||||
if (ret) {
|
||||
MHI_ERR("IOCTL_BHI_GETDEVINFO copy error, ret = %ld\n", ret);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IOCTL_BHI_WRITEIMAGE:
|
||||
{
|
||||
void *buf;
|
||||
size_t size;
|
||||
|
||||
ret = copy_from_user(&size, ubuf, sizeof(size));
|
||||
if (ret) {
|
||||
MHI_ERR("IOCTL_BHI_WRITEIMAGE copy size error, ret = %ld\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
buf = kmalloc(size, GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = copy_from_user(buf, ubuf+sizeof(size), size);
|
||||
if (ret) {
|
||||
MHI_ERR("IOCTL_BHI_WRITEIMAGE copy buf error, ret = %ld\n", ret);
|
||||
kfree(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = BhiWrite(mhi_cntrl, buf, size);
|
||||
if (ret) {
|
||||
MHI_ERR("IOCTL_BHI_WRITEIMAGE BhiWrite error, ret = %ld\n", ret);
|
||||
}
|
||||
kfree(buf);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations mhi_cntrl_fops = {
|
||||
.unlocked_ioctl = mhi_cntrl_ioctl,
|
||||
.open = mhi_cntrl_open,
|
||||
.release = mhi_cntrl_release,
|
||||
};
|
||||
|
||||
int mhi_cntrl_register_miscdev(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
mhi_cntrl->miscdev.minor = MISC_DYNAMIC_MINOR;
|
||||
mhi_cntrl->miscdev.name = "mhi_BHI";
|
||||
mhi_cntrl->miscdev.fops = &mhi_cntrl_fops;
|
||||
|
||||
return misc_register(&mhi_cntrl->miscdev);
|
||||
}
|
||||
|
||||
void mhi_cntrl_deregister_miscdev(struct mhi_controller *mhi_cntrl)
|
||||
{
|
||||
misc_deregister(&mhi_cntrl->miscdev);
|
||||
}
|
||||
362
package/fish/fibocom_MHI/src/core/mhi_common.h
Normal file
362
package/fish/fibocom_MHI/src/core/mhi_common.h
Normal file
@ -0,0 +1,362 @@
|
||||
#ifndef __MHI_COMMON_H
|
||||
#define __MHI_COMMON_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* MHI control data structures alloted by the host, including
|
||||
* channel context array, event context array, command context and rings */
|
||||
|
||||
/* Channel context state */
|
||||
enum mhi_dev_ch_ctx_state {
|
||||
MHI_DEV_CH_STATE_DISABLED,
|
||||
MHI_DEV_CH_STATE_ENABLED,
|
||||
MHI_DEV_CH_STATE_RUNNING,
|
||||
MHI_DEV_CH_STATE_SUSPENDED,
|
||||
MHI_DEV_CH_STATE_STOP,
|
||||
MHI_DEV_CH_STATE_ERROR,
|
||||
MHI_DEV_CH_STATE_RESERVED,
|
||||
MHI_DEV_CH_STATE_32BIT = 0x7FFFFFFF
|
||||
};
|
||||
|
||||
/* Channel type */
|
||||
enum mhi_dev_ch_ctx_type {
|
||||
MHI_DEV_CH_TYPE_NONE,
|
||||
MHI_DEV_CH_TYPE_OUTBOUND_CHANNEL,
|
||||
MHI_DEV_CH_TYPE_INBOUND_CHANNEL,
|
||||
MHI_DEV_CH_RESERVED
|
||||
};
|
||||
|
||||
/* Channel context type */
|
||||
struct mhi_dev_ch_ctx {
|
||||
enum mhi_dev_ch_ctx_state ch_state;
|
||||
enum mhi_dev_ch_ctx_type ch_type;
|
||||
uint32_t err_indx;
|
||||
uint64_t rbase;
|
||||
uint64_t rlen;
|
||||
uint64_t rp;
|
||||
uint64_t wp;
|
||||
} __packed;
|
||||
|
||||
enum mhi_dev_ring_element_type_id {
|
||||
MHI_DEV_RING_EL_INVALID = 0,
|
||||
MHI_DEV_RING_EL_NOOP = 1,
|
||||
MHI_DEV_RING_EL_TRANSFER = 2,
|
||||
MHI_DEV_RING_EL_RESET = 16,
|
||||
MHI_DEV_RING_EL_STOP = 17,
|
||||
MHI_DEV_RING_EL_START = 18,
|
||||
MHI_DEV_RING_EL_MHI_STATE_CHG = 32,
|
||||
MHI_DEV_RING_EL_CMD_COMPLETION_EVT = 33,
|
||||
MHI_DEV_RING_EL_TRANSFER_COMPLETION_EVENT = 34,
|
||||
MHI_DEV_RING_EL_EE_STATE_CHANGE_NOTIFY = 64,
|
||||
MHI_DEV_RING_EL_UNDEF
|
||||
};
|
||||
|
||||
enum mhi_dev_ring_state {
|
||||
RING_STATE_UINT = 0,
|
||||
RING_STATE_IDLE,
|
||||
RING_STATE_PENDING,
|
||||
};
|
||||
|
||||
enum mhi_dev_ring_type {
|
||||
RING_TYPE_CMD = 0,
|
||||
RING_TYPE_ER,
|
||||
RING_TYPE_CH,
|
||||
RING_TYPE_INVAL
|
||||
};
|
||||
|
||||
/* Event context interrupt moderation */
|
||||
enum mhi_dev_evt_ctx_int_mod_timer {
|
||||
MHI_DEV_EVT_INT_MODERATION_DISABLED
|
||||
};
|
||||
|
||||
/* Event ring type */
|
||||
enum mhi_dev_evt_ctx_event_ring_type {
|
||||
MHI_DEV_EVT_TYPE_DEFAULT,
|
||||
MHI_DEV_EVT_TYPE_VALID,
|
||||
MHI_DEV_EVT_RESERVED
|
||||
};
|
||||
|
||||
/* Event ring context type */
|
||||
struct mhi_dev_ev_ctx {
|
||||
uint32_t res1:16;
|
||||
enum mhi_dev_evt_ctx_int_mod_timer intmodt:16;
|
||||
enum mhi_dev_evt_ctx_event_ring_type ertype;
|
||||
uint32_t msivec;
|
||||
uint64_t rbase;
|
||||
uint64_t rlen;
|
||||
uint64_t rp;
|
||||
uint64_t wp;
|
||||
} __packed;
|
||||
|
||||
/* Command context */
|
||||
struct mhi_dev_cmd_ctx {
|
||||
uint32_t res1;
|
||||
uint32_t res2;
|
||||
uint32_t res3;
|
||||
uint64_t rbase;
|
||||
uint64_t rlen;
|
||||
uint64_t rp;
|
||||
uint64_t wp;
|
||||
} __packed;
|
||||
|
||||
/* generic context */
|
||||
struct mhi_dev_gen_ctx {
|
||||
uint32_t res1;
|
||||
uint32_t res2;
|
||||
uint32_t res3;
|
||||
uint64_t rbase;
|
||||
uint64_t rlen;
|
||||
uint64_t rp;
|
||||
uint64_t wp;
|
||||
} __packed;
|
||||
|
||||
/* Transfer ring element */
|
||||
struct mhi_dev_transfer_ring_element {
|
||||
uint64_t data_buf_ptr;
|
||||
uint32_t len:16;
|
||||
uint32_t res1:16;
|
||||
uint32_t chain:1;
|
||||
uint32_t res2:7;
|
||||
uint32_t ieob:1;
|
||||
uint32_t ieot:1;
|
||||
uint32_t bei:1;
|
||||
uint32_t res3:5;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t res4:8;
|
||||
} __packed;
|
||||
|
||||
/* Command ring element */
|
||||
/* Command ring No op command */
|
||||
struct mhi_dev_cmd_ring_op {
|
||||
uint64_t res1;
|
||||
uint32_t res2;
|
||||
uint32_t res3:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
/* Command ring reset channel command */
|
||||
struct mhi_dev_cmd_ring_reset_channel_cmd {
|
||||
uint64_t res1;
|
||||
uint32_t res2;
|
||||
uint32_t res3:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
/* Command ring stop channel command */
|
||||
struct mhi_dev_cmd_ring_stop_channel_cmd {
|
||||
uint64_t res1;
|
||||
uint32_t res2;
|
||||
uint32_t res3:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
/* Command ring start channel command */
|
||||
struct mhi_dev_cmd_ring_start_channel_cmd {
|
||||
uint64_t res1;
|
||||
uint32_t seqnum;
|
||||
uint32_t reliable:1;
|
||||
uint32_t res2:15;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
enum mhi_dev_cmd_completion_code {
|
||||
MHI_CMD_COMPL_CODE_INVALID = 0,
|
||||
MHI_CMD_COMPL_CODE_SUCCESS = 1,
|
||||
MHI_CMD_COMPL_CODE_EOT = 2,
|
||||
MHI_CMD_COMPL_CODE_OVERFLOW = 3,
|
||||
MHI_CMD_COMPL_CODE_EOB = 4,
|
||||
MHI_CMD_COMPL_CODE_UNDEFINED = 16,
|
||||
MHI_CMD_COMPL_CODE_RING_EL = 17,
|
||||
MHI_CMD_COMPL_CODE_RES
|
||||
};
|
||||
|
||||
/* Event ring elements */
|
||||
/* Transfer completion event */
|
||||
struct mhi_dev_event_ring_transfer_completion {
|
||||
uint64_t ptr;
|
||||
uint32_t len:16;
|
||||
uint32_t res1:8;
|
||||
enum mhi_dev_cmd_completion_code code:8;
|
||||
uint32_t res2:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
/* Command completion event */
|
||||
struct mhi_dev_event_ring_cmd_completion {
|
||||
uint64_t ptr;
|
||||
uint32_t res1:24;
|
||||
enum mhi_dev_cmd_completion_code code:8;
|
||||
uint32_t res2:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t res3:8;
|
||||
} __packed;
|
||||
|
||||
enum mhi_dev_state {
|
||||
MHI_DEV_RESET_STATE = 0,
|
||||
MHI_DEV_READY_STATE,
|
||||
MHI_DEV_M0_STATE,
|
||||
MHI_DEV_M1_STATE,
|
||||
MHI_DEV_M2_STATE,
|
||||
MHI_DEV_M3_STATE,
|
||||
MHI_DEV_MAX_STATE,
|
||||
MHI_DEV_SYSERR_STATE = 0xff
|
||||
};
|
||||
|
||||
/* MHI state change event */
|
||||
struct mhi_dev_event_ring_state_change {
|
||||
uint64_t ptr;
|
||||
uint32_t res1:24;
|
||||
enum mhi_dev_state mhistate:8;
|
||||
uint32_t res2:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t res3:8;
|
||||
} __packed;
|
||||
|
||||
enum mhi_dev_execenv {
|
||||
MHI_DEV_SBL_EE = 1,
|
||||
MHI_DEV_AMSS_EE = 2,
|
||||
MHI_DEV_UNRESERVED
|
||||
};
|
||||
|
||||
/* EE state change event */
|
||||
struct mhi_dev_event_ring_ee_state_change {
|
||||
uint64_t ptr;
|
||||
uint32_t res1:24;
|
||||
enum mhi_dev_execenv execenv:8;
|
||||
uint32_t res2:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t res3:8;
|
||||
} __packed;
|
||||
|
||||
/* Generic cmd to parse common details like type and channel id */
|
||||
struct mhi_dev_ring_generic {
|
||||
uint64_t ptr;
|
||||
uint32_t res1:24;
|
||||
enum mhi_dev_state mhistate:8;
|
||||
uint32_t res2:16;
|
||||
enum mhi_dev_ring_element_type_id type:8;
|
||||
uint32_t chid:8;
|
||||
} __packed;
|
||||
|
||||
struct mhi_config {
|
||||
uint32_t mhi_reg_len;
|
||||
uint32_t version;
|
||||
uint32_t event_rings;
|
||||
uint32_t channels;
|
||||
uint32_t chdb_offset;
|
||||
uint32_t erdb_offset;
|
||||
};
|
||||
|
||||
#define NUM_CHANNELS 128
|
||||
#define HW_CHANNEL_BASE 100
|
||||
#define HW_CHANNEL_END 107
|
||||
#define MHI_ENV_VALUE 2
|
||||
#define MHI_MASK_ROWS_CH_EV_DB 4
|
||||
#define TRB_MAX_DATA_SIZE 8192
|
||||
#define MHI_CTRL_STATE 25
|
||||
#define IPA_DMA_SYNC 1
|
||||
#define IPA_DMA_ASYNC 0
|
||||
|
||||
/*maximum trasnfer completion events buffer*/
|
||||
#define MAX_TR_EVENTS 50
|
||||
/*maximum event requests */
|
||||
#define MHI_MAX_EVT_REQ 50
|
||||
|
||||
/* Possible ring element types */
|
||||
union mhi_dev_ring_element_type {
|
||||
struct mhi_dev_cmd_ring_op cmd_no_op;
|
||||
struct mhi_dev_cmd_ring_reset_channel_cmd cmd_reset;
|
||||
struct mhi_dev_cmd_ring_stop_channel_cmd cmd_stop;
|
||||
struct mhi_dev_cmd_ring_start_channel_cmd cmd_start;
|
||||
struct mhi_dev_transfer_ring_element tre;
|
||||
struct mhi_dev_event_ring_transfer_completion evt_tr_comp;
|
||||
struct mhi_dev_event_ring_cmd_completion evt_cmd_comp;
|
||||
struct mhi_dev_event_ring_state_change evt_state_change;
|
||||
struct mhi_dev_event_ring_ee_state_change evt_ee_state;
|
||||
struct mhi_dev_ring_generic generic;
|
||||
};
|
||||
|
||||
/* Transfer ring element type */
|
||||
union mhi_dev_ring_ctx {
|
||||
struct mhi_dev_cmd_ctx cmd;
|
||||
struct mhi_dev_ev_ctx ev;
|
||||
struct mhi_dev_ch_ctx ch;
|
||||
struct mhi_dev_gen_ctx generic;
|
||||
};
|
||||
|
||||
/* MHI host Control and data address region */
|
||||
struct mhi_host_addr {
|
||||
uint32_t ctrl_base_lsb;
|
||||
uint32_t ctrl_base_msb;
|
||||
uint32_t ctrl_limit_lsb;
|
||||
uint32_t ctrl_limit_msb;
|
||||
uint32_t data_base_lsb;
|
||||
uint32_t data_base_msb;
|
||||
uint32_t data_limit_lsb;
|
||||
uint32_t data_limit_msb;
|
||||
};
|
||||
|
||||
/* MHI physical and virtual address region */
|
||||
struct mhi_meminfo {
|
||||
struct device *dev;
|
||||
uintptr_t pa_aligned;
|
||||
uintptr_t pa_unaligned;
|
||||
uintptr_t va_aligned;
|
||||
uintptr_t va_unaligned;
|
||||
uintptr_t size;
|
||||
};
|
||||
|
||||
struct mhi_addr {
|
||||
uint64_t host_pa;
|
||||
uintptr_t device_pa;
|
||||
uintptr_t device_va;
|
||||
size_t size;
|
||||
dma_addr_t phy_addr;
|
||||
void *virt_addr;
|
||||
bool use_ipa_dma;
|
||||
};
|
||||
|
||||
struct mhi_interrupt_state {
|
||||
uint32_t mask;
|
||||
uint32_t status;
|
||||
};
|
||||
|
||||
enum mhi_dev_channel_state {
|
||||
MHI_DEV_CH_UNINT,
|
||||
MHI_DEV_CH_STARTED,
|
||||
MHI_DEV_CH_PENDING_START,
|
||||
MHI_DEV_CH_PENDING_STOP,
|
||||
MHI_DEV_CH_STOPPED,
|
||||
MHI_DEV_CH_CLOSED,
|
||||
};
|
||||
|
||||
enum mhi_dev_ch_operation {
|
||||
MHI_DEV_OPEN_CH,
|
||||
MHI_DEV_CLOSE_CH,
|
||||
MHI_DEV_READ_CH,
|
||||
MHI_DEV_READ_WR,
|
||||
MHI_DEV_POLL,
|
||||
};
|
||||
|
||||
enum mhi_ctrl_info {
|
||||
MHI_STATE_CONFIGURED = 0,
|
||||
MHI_STATE_CONNECTED = 1,
|
||||
MHI_STATE_DISCONNECTED = 2,
|
||||
MHI_STATE_INVAL,
|
||||
};
|
||||
|
||||
enum mhi_dev_tr_compl_evt_type {
|
||||
SEND_EVENT_BUFFER,
|
||||
SEND_EVENT_RD_OFFSET,
|
||||
};
|
||||
|
||||
enum mhi_dev_transfer_type {
|
||||
MHI_DEV_DMA_SYNC,
|
||||
MHI_DEV_DMA_ASYNC,
|
||||
};
|
||||
#endif /* _MHI_COMMON_H_ */
|
||||
181
package/fish/fibocom_MHI/src/core/mhi_dtr.c
Normal file
181
package/fish/fibocom_MHI/src/core/mhi_dtr.c
Normal file
@ -0,0 +1,181 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/termios.h>
|
||||
#include <linux/wait.h>
|
||||
#include "mhi.h"
|
||||
#include "mhi_internal.h"
|
||||
|
||||
struct __packed dtr_ctrl_msg {
|
||||
u32 preamble;
|
||||
u32 msg_id;
|
||||
u32 dest_id;
|
||||
u32 size;
|
||||
u32 msg;
|
||||
};
|
||||
|
||||
#define CTRL_MAGIC (0x4C525443)
|
||||
#define CTRL_MSG_DTR BIT(0)
|
||||
#define CTRL_MSG_ID (0x10)
|
||||
|
||||
static int mhi_dtr_tiocmset(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan,
|
||||
u32 tiocm)
|
||||
{
|
||||
struct dtr_ctrl_msg *dtr_msg = NULL;
|
||||
struct mhi_chan *dtr_chan = mhi_cntrl->dtr_dev->ul_chan;
|
||||
int ret = 0;
|
||||
|
||||
tiocm &= TIOCM_DTR;
|
||||
if (mhi_chan->tiocm == tiocm)
|
||||
return 0;
|
||||
|
||||
mutex_lock(&dtr_chan->mutex);
|
||||
|
||||
dtr_msg = kzalloc(sizeof(*dtr_msg), GFP_KERNEL);
|
||||
if (!dtr_msg) {
|
||||
ret = -ENOMEM;
|
||||
goto tiocm_exit;
|
||||
}
|
||||
|
||||
dtr_msg->preamble = CTRL_MAGIC;
|
||||
dtr_msg->msg_id = CTRL_MSG_ID;
|
||||
dtr_msg->dest_id = mhi_chan->chan;
|
||||
dtr_msg->size = sizeof(u32);
|
||||
if (tiocm & TIOCM_DTR)
|
||||
dtr_msg->msg |= CTRL_MSG_DTR;
|
||||
|
||||
reinit_completion(&dtr_chan->completion);
|
||||
ret = mhi_queue_transfer(mhi_cntrl->dtr_dev, DMA_TO_DEVICE, dtr_msg,
|
||||
sizeof(*dtr_msg), MHI_EOT);
|
||||
if (ret)
|
||||
goto tiocm_exit;
|
||||
|
||||
ret = wait_for_completion_timeout(&dtr_chan->completion,
|
||||
msecs_to_jiffies(mhi_cntrl->timeout_ms));
|
||||
|
||||
if (!ret) {
|
||||
MHI_ERR("Failed to receive transfer callback\n");
|
||||
ret = -EIO;
|
||||
goto tiocm_exit;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
mhi_chan->tiocm = tiocm;
|
||||
|
||||
tiocm_exit:
|
||||
kfree(dtr_msg);
|
||||
mutex_unlock(&dtr_chan->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
long mhi_ioctl(struct mhi_device *mhi_dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *mhi_chan = mhi_dev->ul_chan;
|
||||
int ret;
|
||||
|
||||
/* ioctl not supported by this controller */
|
||||
if (!mhi_cntrl->dtr_dev)
|
||||
return -EIO;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCMGET:
|
||||
return mhi_chan->tiocm;
|
||||
case TIOCMSET:
|
||||
{
|
||||
u32 tiocm;
|
||||
|
||||
ret = get_user(tiocm, (u32 *)arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return mhi_dtr_tiocmset(mhi_cntrl, mhi_chan, tiocm);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(mhi_ioctl);
|
||||
|
||||
static void mhi_dtr_xfer_cb(struct mhi_device *mhi_dev,
|
||||
struct mhi_result *mhi_result)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
struct mhi_chan *dtr_chan = mhi_cntrl->dtr_dev->ul_chan;
|
||||
|
||||
MHI_VERB("Received with status:%d\n", mhi_result->transaction_status);
|
||||
if (!mhi_result->transaction_status)
|
||||
complete(&dtr_chan->completion);
|
||||
}
|
||||
|
||||
static void mhi_dtr_remove(struct mhi_device *mhi_dev)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
|
||||
mhi_cntrl->dtr_dev = NULL;
|
||||
}
|
||||
|
||||
static int mhi_dtr_probe(struct mhi_device *mhi_dev,
|
||||
const struct mhi_device_id *id)
|
||||
{
|
||||
struct mhi_controller *mhi_cntrl = mhi_dev->mhi_cntrl;
|
||||
int ret;
|
||||
|
||||
MHI_LOG("Enter for DTR control channel\n");
|
||||
|
||||
ret = mhi_prepare_for_transfer(mhi_dev);
|
||||
if (!ret)
|
||||
mhi_cntrl->dtr_dev = mhi_dev;
|
||||
|
||||
MHI_LOG("Exit with ret:%d\n", ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct mhi_device_id mhi_dtr_table[] = {
|
||||
{ .chan = "IP_CTRL" },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct mhi_driver mhi_dtr_driver = {
|
||||
.id_table = mhi_dtr_table,
|
||||
.remove = mhi_dtr_remove,
|
||||
.probe = mhi_dtr_probe,
|
||||
.ul_xfer_cb = mhi_dtr_xfer_cb,
|
||||
.dl_xfer_cb = mhi_dtr_xfer_cb,
|
||||
.driver = {
|
||||
.name = "MHI_DTR",
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
int __init mhi_dtr_init(void)
|
||||
{
|
||||
return mhi_driver_register(&mhi_dtr_driver);
|
||||
}
|
||||
|
||||
void mhi_dtr_exit(void) {
|
||||
mhi_driver_unregister(&mhi_dtr_driver);
|
||||
}
|
||||
1442
package/fish/fibocom_MHI/src/core/mhi_init.c
Normal file
1442
package/fish/fibocom_MHI/src/core/mhi_init.c
Normal file
File diff suppressed because it is too large
Load Diff
800
package/fish/fibocom_MHI/src/core/mhi_internal.h
Normal file
800
package/fish/fibocom_MHI/src/core/mhi_internal.h
Normal file
@ -0,0 +1,800 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#ifndef _MHI_INT_H
|
||||
#define _MHI_INT_H
|
||||
|
||||
#include <linux/version.h>
|
||||
#ifndef writel_relaxed
|
||||
#define writel_relaxed writel
|
||||
#endif
|
||||
|
||||
#ifndef U32_MAX
|
||||
#define U32_MAX ((u32)~0U)
|
||||
#endif
|
||||
|
||||
#if (LINUX_VERSION_CODE <= KERNEL_VERSION( 3,10,108 ))
|
||||
static inline void reinit_completion(struct completion *x)
|
||||
{
|
||||
x->done = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
extern struct bus_type mhi_bus_type;
|
||||
|
||||
/* MHI mmio register mapping */
|
||||
#define PCI_INVALID_READ(val) (val == U32_MAX)
|
||||
|
||||
#define MHIREGLEN (0x0)
|
||||
#define MHIREGLEN_MHIREGLEN_MASK (0xFFFFFFFF)
|
||||
#define MHIREGLEN_MHIREGLEN_SHIFT (0)
|
||||
|
||||
#define MHIVER (0x8)
|
||||
#define MHIVER_MHIVER_MASK (0xFFFFFFFF)
|
||||
#define MHIVER_MHIVER_SHIFT (0)
|
||||
|
||||
#define MHICFG (0x10)
|
||||
#define MHICFG_NHWER_MASK (0xFF000000)
|
||||
#define MHICFG_NHWER_SHIFT (24)
|
||||
#define MHICFG_NER_MASK (0xFF0000)
|
||||
#define MHICFG_NER_SHIFT (16)
|
||||
#define MHICFG_NHWCH_MASK (0xFF00)
|
||||
#define MHICFG_NHWCH_SHIFT (8)
|
||||
#define MHICFG_NCH_MASK (0xFF)
|
||||
#define MHICFG_NCH_SHIFT (0)
|
||||
|
||||
#define CHDBOFF (0x18)
|
||||
#define CHDBOFF_CHDBOFF_MASK (0xFFFFFFFF)
|
||||
#define CHDBOFF_CHDBOFF_SHIFT (0)
|
||||
|
||||
#define ERDBOFF (0x20)
|
||||
#define ERDBOFF_ERDBOFF_MASK (0xFFFFFFFF)
|
||||
#define ERDBOFF_ERDBOFF_SHIFT (0)
|
||||
|
||||
#define BHIOFF (0x28)
|
||||
#define BHIOFF_BHIOFF_MASK (0xFFFFFFFF)
|
||||
#define BHIOFF_BHIOFF_SHIFT (0)
|
||||
|
||||
#define DEBUGOFF (0x30)
|
||||
#define DEBUGOFF_DEBUGOFF_MASK (0xFFFFFFFF)
|
||||
#define DEBUGOFF_DEBUGOFF_SHIFT (0)
|
||||
|
||||
#define MHICTRL (0x38)
|
||||
#define MHICTRL_MHISTATE_MASK (0x0000FF00)
|
||||
#define MHICTRL_MHISTATE_SHIFT (8)
|
||||
#define MHICTRL_RESET_MASK (0x2)
|
||||
#define MHICTRL_RESET_SHIFT (1)
|
||||
|
||||
#define MHISTATUS (0x48)
|
||||
#define MHISTATUS_MHISTATE_MASK (0x0000FF00)
|
||||
#define MHISTATUS_MHISTATE_SHIFT (8)
|
||||
#define MHISTATUS_SYSERR_MASK (0x4)
|
||||
#define MHISTATUS_SYSERR_SHIFT (2)
|
||||
#define MHISTATUS_READY_MASK (0x1)
|
||||
#define MHISTATUS_READY_SHIFT (0)
|
||||
|
||||
#define CCABAP_LOWER (0x58)
|
||||
#define CCABAP_LOWER_CCABAP_LOWER_MASK (0xFFFFFFFF)
|
||||
#define CCABAP_LOWER_CCABAP_LOWER_SHIFT (0)
|
||||
|
||||
#define CCABAP_HIGHER (0x5C)
|
||||
#define CCABAP_HIGHER_CCABAP_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define CCABAP_HIGHER_CCABAP_HIGHER_SHIFT (0)
|
||||
|
||||
#define ECABAP_LOWER (0x60)
|
||||
#define ECABAP_LOWER_ECABAP_LOWER_MASK (0xFFFFFFFF)
|
||||
#define ECABAP_LOWER_ECABAP_LOWER_SHIFT (0)
|
||||
|
||||
#define ECABAP_HIGHER (0x64)
|
||||
#define ECABAP_HIGHER_ECABAP_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define ECABAP_HIGHER_ECABAP_HIGHER_SHIFT (0)
|
||||
|
||||
#define CRCBAP_LOWER (0x68)
|
||||
#define CRCBAP_LOWER_CRCBAP_LOWER_MASK (0xFFFFFFFF)
|
||||
#define CRCBAP_LOWER_CRCBAP_LOWER_SHIFT (0)
|
||||
|
||||
#define CRCBAP_HIGHER (0x6C)
|
||||
#define CRCBAP_HIGHER_CRCBAP_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define CRCBAP_HIGHER_CRCBAP_HIGHER_SHIFT (0)
|
||||
|
||||
#define CRDB_LOWER (0x70)
|
||||
#define CRDB_LOWER_CRDB_LOWER_MASK (0xFFFFFFFF)
|
||||
#define CRDB_LOWER_CRDB_LOWER_SHIFT (0)
|
||||
|
||||
#define CRDB_HIGHER (0x74)
|
||||
#define CRDB_HIGHER_CRDB_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define CRDB_HIGHER_CRDB_HIGHER_SHIFT (0)
|
||||
|
||||
#define MHICTRLBASE_LOWER (0x80)
|
||||
#define MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_MASK (0xFFFFFFFF)
|
||||
#define MHICTRLBASE_LOWER_MHICTRLBASE_LOWER_SHIFT (0)
|
||||
|
||||
#define MHICTRLBASE_HIGHER (0x84)
|
||||
#define MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define MHICTRLBASE_HIGHER_MHICTRLBASE_HIGHER_SHIFT (0)
|
||||
|
||||
#define MHICTRLLIMIT_LOWER (0x88)
|
||||
#define MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_MASK (0xFFFFFFFF)
|
||||
#define MHICTRLLIMIT_LOWER_MHICTRLLIMIT_LOWER_SHIFT (0)
|
||||
|
||||
#define MHICTRLLIMIT_HIGHER (0x8C)
|
||||
#define MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define MHICTRLLIMIT_HIGHER_MHICTRLLIMIT_HIGHER_SHIFT (0)
|
||||
|
||||
#define MHIDATABASE_LOWER (0x98)
|
||||
#define MHIDATABASE_LOWER_MHIDATABASE_LOWER_MASK (0xFFFFFFFF)
|
||||
#define MHIDATABASE_LOWER_MHIDATABASE_LOWER_SHIFT (0)
|
||||
|
||||
#define MHIDATABASE_HIGHER (0x9C)
|
||||
#define MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define MHIDATABASE_HIGHER_MHIDATABASE_HIGHER_SHIFT (0)
|
||||
|
||||
#define MHIDATALIMIT_LOWER (0xA0)
|
||||
#define MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_MASK (0xFFFFFFFF)
|
||||
#define MHIDATALIMIT_LOWER_MHIDATALIMIT_LOWER_SHIFT (0)
|
||||
|
||||
#define MHIDATALIMIT_HIGHER (0xA4)
|
||||
#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_MASK (0xFFFFFFFF)
|
||||
#define MHIDATALIMIT_HIGHER_MHIDATALIMIT_HIGHER_SHIFT (0)
|
||||
|
||||
/* MHI BHI offfsets */
|
||||
#define BHI_BHIVERSION_MINOR (0x00)
|
||||
#define BHI_BHIVERSION_MAJOR (0x04)
|
||||
#define BHI_IMGADDR_LOW (0x08)
|
||||
#define BHI_IMGADDR_HIGH (0x0C)
|
||||
#define BHI_IMGSIZE (0x10)
|
||||
#define BHI_RSVD1 (0x14)
|
||||
#define BHI_IMGTXDB (0x18)
|
||||
#define BHI_TXDB_SEQNUM_BMSK (0x3FFFFFFF)
|
||||
#define BHI_TXDB_SEQNUM_SHFT (0)
|
||||
#define BHI_RSVD2 (0x1C)
|
||||
#define BHI_INTVEC (0x20)
|
||||
#define BHI_RSVD3 (0x24)
|
||||
#define BHI_EXECENV (0x28)
|
||||
#define BHI_STATUS (0x2C)
|
||||
#define BHI_ERRCODE (0x30)
|
||||
#define BHI_ERRDBG1 (0x34)
|
||||
#define BHI_ERRDBG2 (0x38)
|
||||
#define BHI_ERRDBG3 (0x3C)
|
||||
#define BHI_SERIALNUM ( 0x40 )
|
||||
#define BHI_SERIALNU (0x40)
|
||||
#define BHI_SBLANTIROLLVER (0x44)
|
||||
#define BHI_NUMSEG (0x48)
|
||||
#define BHI_MSMHWID(n) (0x4C + (0x4 * n))
|
||||
#define BHI_OEMPKHASH(n) (0x64 + (0x4 * n))
|
||||
#define BHI_RSVD5 (0xC4)
|
||||
#define BHI_STATUS_MASK (0xC0000000)
|
||||
#define BHI_STATUS_SHIFT (30)
|
||||
#define BHI_STATUS_ERROR (3)
|
||||
#define BHI_STATUS_SUCCESS (2)
|
||||
#define BHI_STATUS_RESET (0)
|
||||
|
||||
/* MHI BHIE offsets */
|
||||
#define BHIE_OFFSET (0x0124) /* BHIE register space offset from BHI base */
|
||||
#define BHIE_MSMSOCID_OFFS (BHIE_OFFSET + 0x0000)
|
||||
#define BHIE_TXVECADDR_LOW_OFFS (BHIE_OFFSET + 0x002C)
|
||||
#define BHIE_TXVECADDR_HIGH_OFFS (BHIE_OFFSET + 0x0030)
|
||||
#define BHIE_TXVECSIZE_OFFS (BHIE_OFFSET + 0x0034)
|
||||
#define BHIE_TXVECDB_OFFS (BHIE_OFFSET + 0x003C)
|
||||
#define BHIE_TXVECDB_SEQNUM_BMSK (0x3FFFFFFF)
|
||||
#define BHIE_TXVECDB_SEQNUM_SHFT (0)
|
||||
#define BHIE_TXVECSTATUS_OFFS (BHIE_OFFSET + 0x0044)
|
||||
#define BHIE_TXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF)
|
||||
#define BHIE_TXVECSTATUS_SEQNUM_SHFT (0)
|
||||
#define BHIE_TXVECSTATUS_STATUS_BMSK (0xC0000000)
|
||||
#define BHIE_TXVECSTATUS_STATUS_SHFT (30)
|
||||
#define BHIE_TXVECSTATUS_STATUS_RESET (0x00)
|
||||
#define BHIE_TXVECSTATUS_STATUS_XFER_COMPL (0x02)
|
||||
#define BHIE_TXVECSTATUS_STATUS_ERROR (0x03)
|
||||
#define BHIE_RXVECADDR_LOW_OFFS (BHIE_OFFSET + 0x0060)
|
||||
#define BHIE_RXVECADDR_HIGH_OFFS (BHIE_OFFSET + 0x0064)
|
||||
#define BHIE_RXVECSIZE_OFFS (BHIE_OFFSET + 0x0068)
|
||||
#define BHIE_RXVECDB_OFFS (BHIE_OFFSET + 0x0070)
|
||||
#define BHIE_RXVECDB_SEQNUM_BMSK (0x3FFFFFFF)
|
||||
#define BHIE_RXVECDB_SEQNUM_SHFT (0)
|
||||
#define BHIE_RXVECSTATUS_OFFS (BHIE_OFFSET + 0x0078)
|
||||
#define BHIE_RXVECSTATUS_SEQNUM_BMSK (0x3FFFFFFF)
|
||||
#define BHIE_RXVECSTATUS_SEQNUM_SHFT (0)
|
||||
#define BHIE_RXVECSTATUS_STATUS_BMSK (0xC0000000)
|
||||
#define BHIE_RXVECSTATUS_STATUS_SHFT (30)
|
||||
#define BHIE_RXVECSTATUS_STATUS_RESET (0x00)
|
||||
#define BHIE_RXVECSTATUS_STATUS_XFER_COMPL (0x02)
|
||||
#define BHIE_RXVECSTATUS_STATUS_ERROR (0x03)
|
||||
|
||||
struct __packed mhi_event_ctxt {
|
||||
u32 reserved : 8;
|
||||
u32 intmodc : 8;
|
||||
u32 intmodt : 16;
|
||||
u32 ertype;
|
||||
u32 msivec;
|
||||
u64 rbase;
|
||||
u64 rlen;
|
||||
u64 rp;
|
||||
u64 wp;
|
||||
};
|
||||
|
||||
struct __packed mhi_chan_ctxt {
|
||||
u32 chstate : 8;
|
||||
u32 brstmode : 2;
|
||||
u32 pollcfg : 6;
|
||||
u32 reserved : 16;
|
||||
u32 chtype;
|
||||
u32 erindex;
|
||||
u64 rbase;
|
||||
u64 rlen;
|
||||
u64 rp;
|
||||
u64 wp;
|
||||
};
|
||||
|
||||
struct __packed mhi_cmd_ctxt {
|
||||
u32 reserved0;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u64 rbase;
|
||||
u64 rlen;
|
||||
u64 rp;
|
||||
u64 wp;
|
||||
};
|
||||
|
||||
struct __packed mhi_tre {
|
||||
u64 ptr;
|
||||
u32 dword[2];
|
||||
};
|
||||
|
||||
struct __packed bhi_vec_entry {
|
||||
u64 dma_addr;
|
||||
u64 size;
|
||||
};
|
||||
|
||||
/* no operation command */
|
||||
#define MHI_TRE_CMD_NOOP_PTR cpu_to_le64(0)
|
||||
#define MHI_TRE_CMD_NOOP_DWORD0 cpu_to_le32(0)
|
||||
#define MHI_TRE_CMD_NOOP_DWORD1 cpu_to_le32(1 << 16)
|
||||
|
||||
/* channel reset command */
|
||||
#define MHI_TRE_CMD_RESET_PTR cpu_to_le64(0)
|
||||
#define MHI_TRE_CMD_RESET_DWORD0 cpu_to_le32(0)
|
||||
#define MHI_TRE_CMD_RESET_DWORD1(chid) cpu_to_le32((chid << 24) | (16 << 16))
|
||||
|
||||
/* channel stop command */
|
||||
#define MHI_TRE_CMD_STOP_PTR cpu_to_le64(0)
|
||||
#define MHI_TRE_CMD_STOP_DWORD0 cpu_to_le32(0)
|
||||
#define MHI_TRE_CMD_STOP_DWORD1(chid) cpu_to_le32((chid << 24) | (17 << 16))
|
||||
|
||||
/* channel start command */
|
||||
#define MHI_TRE_CMD_START_PTR cpu_to_le64(0)
|
||||
#define MHI_TRE_CMD_START_DWORD0 cpu_to_le32(0)
|
||||
#define MHI_TRE_CMD_START_DWORD1(chid) cpu_to_le32((chid << 24) | (18 << 16))
|
||||
|
||||
#define MHI_TRE_GET_CMD_CHID(tre) ((le32_to_cpu((tre)->dword[1]) >> 24) & 0xFF)
|
||||
|
||||
/* event descriptor macros */
|
||||
//#define MHI_TRE_EV_PTR(ptr) (ptr)
|
||||
//#define MHI_TRE_EV_DWORD0(code, len) ((code << 24) | len)
|
||||
#define MHI_TRE_EV_DWORD1(chid, type) cpu_to_le32((chid << 24) | (type << 16))
|
||||
#define MHI_TRE_GET_EV_PTR(tre) le64_to_cpu((tre)->ptr)
|
||||
#define MHI_TRE_GET_EV_CODE(tre) ((le32_to_cpu((tre)->dword[0]) >> 24) & 0xFF)
|
||||
#define MHI_TRE_GET_EV_LEN(tre) (le32_to_cpu((tre)->dword[0]) & 0xFFFF)
|
||||
#define MHI_TRE_GET_EV_CHID(tre) ((le32_to_cpu((tre)->dword[1]) >> 24) & 0xFF)
|
||||
#define MHI_TRE_GET_EV_TYPE(tre) ((le32_to_cpu((tre)->dword[1]) >> 16) & 0xFF)
|
||||
#define MHI_TRE_GET_EV_STATE(tre) ((le32_to_cpu((tre)->dword[0]) >> 24) & 0xFF)
|
||||
#define MHI_TRE_GET_EV_EXECENV(tre) ((le32_to_cpu((tre)->dword[0]) >> 24) & 0xFF)
|
||||
|
||||
|
||||
/* transfer descriptor macros */
|
||||
#define MHI_TRE_DATA_PTR(ptr) cpu_to_le64(ptr)
|
||||
#define MHI_TRE_DATA_DWORD0(len) cpu_to_le32(len & MHI_MAX_MTU)
|
||||
#define MHI_TRE_DATA_DWORD1(bei, ieot, ieob, chain) cpu_to_le32((2 << 16) | (bei << 10) \
|
||||
| (ieot << 9) | (ieob << 8) | chain)
|
||||
|
||||
enum MHI_CMD {
|
||||
MHI_CMD_NOOP = 0x0,
|
||||
MHI_CMD_RESET_CHAN = 0x1,
|
||||
MHI_CMD_STOP_CHAN = 0x2,
|
||||
MHI_CMD_START_CHAN = 0x3,
|
||||
MHI_CMD_RESUME_CHAN = 0x4,
|
||||
};
|
||||
|
||||
enum MHI_PKT_TYPE {
|
||||
MHI_PKT_TYPE_INVALID = 0x0,
|
||||
MHI_PKT_TYPE_NOOP_CMD = 0x1,
|
||||
MHI_PKT_TYPE_TRANSFER = 0x2,
|
||||
MHI_PKT_TYPE_RESET_CHAN_CMD = 0x10,
|
||||
MHI_PKT_TYPE_STOP_CHAN_CMD = 0x11,
|
||||
MHI_PKT_TYPE_START_CHAN_CMD = 0x12,
|
||||
MHI_PKT_TYPE_STATE_CHANGE_EVENT = 0x20,
|
||||
MHI_PKT_TYPE_CMD_COMPLETION_EVENT = 0x21,
|
||||
MHI_PKT_TYPE_TX_EVENT = 0x22,
|
||||
MHI_PKT_TYPE_EE_EVENT = 0x40,
|
||||
MHI_PKT_TYPE_STALE_EVENT, /* internal event */
|
||||
};
|
||||
|
||||
/* MHI transfer completion events */
|
||||
enum MHI_EV_CCS {
|
||||
MHI_EV_CC_INVALID = 0x0,
|
||||
MHI_EV_CC_SUCCESS = 0x1,
|
||||
MHI_EV_CC_EOT = 0x2,
|
||||
MHI_EV_CC_OVERFLOW = 0x3,
|
||||
MHI_EV_CC_EOB = 0x4,
|
||||
MHI_EV_CC_OOB = 0x5,
|
||||
MHI_EV_CC_DB_MODE = 0x6,
|
||||
MHI_EV_CC_UNDEFINED_ERR = 0x10,
|
||||
MHI_EV_CC_BAD_TRE = 0x11,
|
||||
};
|
||||
|
||||
enum MHI_CH_STATE {
|
||||
MHI_CH_STATE_DISABLED = 0x0,
|
||||
MHI_CH_STATE_ENABLED = 0x1,
|
||||
MHI_CH_STATE_RUNNING = 0x2,
|
||||
MHI_CH_STATE_SUSPENDED = 0x3,
|
||||
MHI_CH_STATE_STOP = 0x4,
|
||||
MHI_CH_STATE_ERROR = 0x5,
|
||||
};
|
||||
|
||||
enum MHI_CH_CFG {
|
||||
MHI_CH_CFG_CHAN_ID = 0,
|
||||
MHI_CH_CFG_ELEMENTS = 1,
|
||||
MHI_CH_CFG_ER_INDEX = 2,
|
||||
MHI_CH_CFG_DIRECTION = 3,
|
||||
MHI_CH_CFG_BRSTMODE = 4,
|
||||
MHI_CH_CFG_POLLCFG = 5,
|
||||
MHI_CH_CFG_EE = 6,
|
||||
MHI_CH_CFG_XFER_TYPE = 7,
|
||||
MHI_CH_CFG_BITCFG = 8,
|
||||
MHI_CH_CFG_MAX
|
||||
};
|
||||
|
||||
#define MHI_CH_CFG_BIT_LPM_NOTIFY BIT(0) /* require LPM notification */
|
||||
#define MHI_CH_CFG_BIT_OFFLOAD_CH BIT(1) /* satellite mhi devices */
|
||||
#define MHI_CH_CFG_BIT_DBMODE_RESET_CH BIT(2) /* require db mode to reset */
|
||||
#define MHI_CH_CFG_BIT_PRE_ALLOC BIT(3) /* host allocate buffers for DL */
|
||||
|
||||
enum MHI_EV_CFG {
|
||||
MHI_EV_CFG_ELEMENTS = 0,
|
||||
MHI_EV_CFG_INTMOD = 1,
|
||||
MHI_EV_CFG_MSI = 2,
|
||||
MHI_EV_CFG_CHAN = 3,
|
||||
MHI_EV_CFG_PRIORITY = 4,
|
||||
MHI_EV_CFG_BRSTMODE = 5,
|
||||
MHI_EV_CFG_BITCFG = 6,
|
||||
MHI_EV_CFG_MAX
|
||||
};
|
||||
|
||||
#define MHI_EV_CFG_BIT_HW_EV BIT(0) /* hw event ring */
|
||||
#define MHI_EV_CFG_BIT_CL_MANAGE BIT(1) /* client manages the event ring */
|
||||
#define MHI_EV_CFG_BIT_OFFLOAD_EV BIT(2) /* satellite driver manges it */
|
||||
#define MHI_EV_CFG_BIT_CTRL_EV BIT(3) /* ctrl event ring */
|
||||
|
||||
enum MHI_BRSTMODE {
|
||||
MHI_BRSTMODE_DISABLE = 0x2,
|
||||
MHI_BRSTMODE_ENABLE = 0x3,
|
||||
};
|
||||
|
||||
#define MHI_INVALID_BRSTMODE(mode) (mode != MHI_BRSTMODE_DISABLE && \
|
||||
mode != MHI_BRSTMODE_ENABLE)
|
||||
|
||||
enum MHI_EE {
|
||||
MHI_EE_PBL = 0x0, /* Primary Boot Loader */
|
||||
MHI_EE_SBL = 0x1, /* Secondary Boot Loader */
|
||||
MHI_EE_AMSS = 0x2, /* AMSS Firmware */
|
||||
MHI_EE_RDDM = 0x3, /* WIFI Ram Dump Debug Module */
|
||||
MHI_EE_WFW = 0x4, /* WIFI (WLAN) Firmware */
|
||||
MHI_EE_PT = 0x5, /* PassThrough, Non PCIe BOOT (PCIe is BIOS locked, not used for boot */
|
||||
MHI_EE_EDL = 0x6, /* PCIe enabled in PBL for emergency download (Non PCIe BOOT) */
|
||||
MHI_EE_FP = 0x7, /* FlashProg, Flash Programmer Environment */
|
||||
MHI_EE_BHIE = MHI_EE_FP,
|
||||
MHI_EE_UEFI = 0x8, /* UEFI */
|
||||
|
||||
MHI_EE_DISABLE_TRANSITION = 0x9,
|
||||
MHI_EE_MAX
|
||||
};
|
||||
|
||||
extern const char * const mhi_ee_str[MHI_EE_MAX];
|
||||
#define TO_MHI_EXEC_STR(ee) (((ee) >= MHI_EE_MAX) ? \
|
||||
"INVALID_EE" : mhi_ee_str[ee])
|
||||
|
||||
#define MHI_IN_PBL(ee) (ee == MHI_EE_PBL || ee == MHI_EE_PT || ee == MHI_EE_EDL)
|
||||
|
||||
enum MHI_ST_TRANSITION {
|
||||
MHI_ST_TRANSITION_PBL,
|
||||
MHI_ST_TRANSITION_READY,
|
||||
MHI_ST_TRANSITION_SBL,
|
||||
MHI_ST_TRANSITION_AMSS,
|
||||
MHI_ST_TRANSITION_FP,
|
||||
MHI_ST_TRANSITION_BHIE = MHI_ST_TRANSITION_FP,
|
||||
MHI_ST_TRANSITION_MAX,
|
||||
};
|
||||
|
||||
extern const char * const mhi_state_tran_str[MHI_ST_TRANSITION_MAX];
|
||||
#define TO_MHI_STATE_TRANS_STR(state) (((state) >= MHI_ST_TRANSITION_MAX) ? \
|
||||
"INVALID_STATE" : mhi_state_tran_str[state])
|
||||
|
||||
enum MHI_STATE {
|
||||
MHI_STATE_RESET = 0x0,
|
||||
MHI_STATE_READY = 0x1,
|
||||
MHI_STATE_M0 = 0x2,
|
||||
MHI_STATE_M1 = 0x3,
|
||||
MHI_STATE_M2 = 0x4,
|
||||
MHI_STATE_M3 = 0x5,
|
||||
MHI_STATE_D3 = 0x6,
|
||||
MHI_STATE_BHI = 0x7,
|
||||
MHI_STATE_SYS_ERR = 0xFF,
|
||||
MHI_STATE_MAX,
|
||||
};
|
||||
|
||||
extern const char * const mhi_state_str[MHI_STATE_MAX];
|
||||
#define TO_MHI_STATE_STR(state) ((state >= MHI_STATE_MAX || \
|
||||
!mhi_state_str[state]) ? \
|
||||
"INVALID_STATE" : mhi_state_str[state])
|
||||
|
||||
/* internal power states */
|
||||
enum MHI_PM_STATE {
|
||||
MHI_PM_DISABLE = BIT(0), /* MHI is not enabled */
|
||||
MHI_PM_POR = BIT(1), /* reset state */
|
||||
MHI_PM_M0 = BIT(2),
|
||||
MHI_PM_M1 = BIT(3),
|
||||
MHI_PM_M1_M2_TRANSITION = BIT(4), /* register access not allowed */
|
||||
MHI_PM_M2 = BIT(5),
|
||||
MHI_PM_M3_ENTER = BIT(6),
|
||||
MHI_PM_M3 = BIT(7),
|
||||
MHI_PM_M3_EXIT = BIT(8),
|
||||
MHI_PM_FW_DL_ERR = BIT(9), /* firmware download failure state */
|
||||
MHI_PM_SYS_ERR_DETECT = BIT(10),
|
||||
MHI_PM_SYS_ERR_PROCESS = BIT(11),
|
||||
MHI_PM_SHUTDOWN_PROCESS = BIT(12),
|
||||
MHI_PM_LD_ERR_FATAL_DETECT = BIT(13), /* link not accessible */
|
||||
};
|
||||
|
||||
#define MHI_REG_ACCESS_VALID(pm_state) ((pm_state & (MHI_PM_POR | MHI_PM_M0 | \
|
||||
MHI_PM_M1 | MHI_PM_M2 | MHI_PM_M3_ENTER | MHI_PM_M3_EXIT | \
|
||||
MHI_PM_SYS_ERR_DETECT | MHI_PM_SYS_ERR_PROCESS | \
|
||||
MHI_PM_SHUTDOWN_PROCESS | MHI_PM_FW_DL_ERR)))
|
||||
#define MHI_PM_IN_ERROR_STATE(pm_state) (pm_state >= MHI_PM_FW_DL_ERR)
|
||||
#define MHI_PM_IN_FATAL_STATE(pm_state) (pm_state == MHI_PM_LD_ERR_FATAL_DETECT)
|
||||
#define MHI_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | MHI_PM_M1))
|
||||
#define MHI_WAKE_DB_ACCESS_VALID(pm_state) (pm_state & (MHI_PM_M0 | \
|
||||
MHI_PM_M1 | MHI_PM_M2))
|
||||
#define MHI_EVENT_ACCESS_INVALID(pm_state) (pm_state == MHI_PM_DISABLE || \
|
||||
MHI_PM_IN_ERROR_STATE(pm_state))
|
||||
#define MHI_PM_IN_SUSPEND_STATE(pm_state) (pm_state & \
|
||||
(MHI_PM_M3_ENTER | MHI_PM_M3))
|
||||
|
||||
/* accepted buffer type for the channel */
|
||||
enum MHI_XFER_TYPE {
|
||||
MHI_XFER_BUFFER,
|
||||
MHI_XFER_SKB,
|
||||
MHI_XFER_SCLIST,
|
||||
MHI_XFER_NOP, /* CPU offload channel, host does not accept transfer */
|
||||
};
|
||||
|
||||
#define NR_OF_CMD_RINGS (1)
|
||||
#define CMD_EL_PER_RING (128)
|
||||
#define PRIMARY_CMD_RING (0)
|
||||
#define MHI_DEV_WAKE_DB (127)
|
||||
#define MHI_M2_DEBOUNCE_TMR_US (10000)
|
||||
#define MHI_MAX_MTU (0xffff)
|
||||
|
||||
enum MHI_ER_TYPE {
|
||||
MHI_ER_TYPE_INVALID = 0x0,
|
||||
MHI_ER_TYPE_VALID = 0x1,
|
||||
};
|
||||
|
||||
struct db_cfg {
|
||||
bool reset_req;
|
||||
bool db_mode;
|
||||
u32 pollcfg;
|
||||
enum MHI_BRSTMODE brstmode;
|
||||
dma_addr_t db_val;
|
||||
void (*process_db)(struct mhi_controller *mhi_cntrl,
|
||||
struct db_cfg *db_cfg, void __iomem *io_addr,
|
||||
dma_addr_t db_val);
|
||||
};
|
||||
|
||||
struct mhi_pm_transitions {
|
||||
enum MHI_PM_STATE from_state;
|
||||
u32 to_states;
|
||||
};
|
||||
|
||||
struct state_transition {
|
||||
struct list_head node;
|
||||
enum MHI_ST_TRANSITION state;
|
||||
};
|
||||
|
||||
/* Control Segment */
|
||||
struct mhi_ctrl_seg
|
||||
{
|
||||
struct __packed mhi_tre hw_in_chan_ring[NUM_MHI_IPA_IN_RING_ELEMENTS] __aligned(NUM_MHI_IPA_IN_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre hw_out_chan_ring[NUM_MHI_IPA_OUT_RING_ELEMENTS] __aligned(NUM_MHI_IPA_OUT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre diag_in_chan_ring[NUM_MHI_IPA_OUT_RING_ELEMENTS] __aligned(NUM_MHI_IPA_OUT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre chan_ring[NUM_MHI_CHAN_RING_ELEMENTS*2*12] __aligned(NUM_MHI_CHAN_RING_ELEMENTS*16);
|
||||
//struct __packed mhi_tre event_ring[NUM_MHI_EVT_RINGS][NUM_MHI_EVT_RING_ELEMENTS] __aligned(NUM_MHI_EVT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre event_ring_0[NUM_MHI_EVT_RING_ELEMENTS] __aligned(NUM_MHI_EVT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre event_ring_1[NUM_MHI_IPA_OUT_EVT_RING_ELEMENTS] __aligned(NUM_MHI_IPA_OUT_EVT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre event_ring_2[NUM_MHI_IPA_IN_EVT_RING_ELEMENTS] __aligned(NUM_MHI_IPA_IN_EVT_RING_ELEMENTS*16);
|
||||
struct __packed mhi_tre cmd_ring[NR_OF_CMD_RINGS][CMD_EL_PER_RING] __aligned(CMD_EL_PER_RING*16);
|
||||
|
||||
struct mhi_chan_ctxt chan_ctxt[NUM_MHI_XFER_RINGS] __aligned(128);
|
||||
struct mhi_event_ctxt er_ctxt[NUM_MHI_EVT_RINGS] __aligned(128);
|
||||
struct mhi_cmd_ctxt cmd_ctxt[NR_OF_CMD_RINGS] __aligned(128);
|
||||
} __aligned(4096);
|
||||
|
||||
struct mhi_ctxt {
|
||||
struct mhi_event_ctxt *er_ctxt;
|
||||
struct mhi_chan_ctxt *chan_ctxt;
|
||||
struct mhi_cmd_ctxt *cmd_ctxt;
|
||||
dma_addr_t er_ctxt_addr;
|
||||
dma_addr_t chan_ctxt_addr;
|
||||
dma_addr_t cmd_ctxt_addr;
|
||||
struct mhi_ctrl_seg *ctrl_seg;
|
||||
dma_addr_t ctrl_seg_addr;
|
||||
};
|
||||
|
||||
struct mhi_ring {
|
||||
dma_addr_t dma_handle;
|
||||
dma_addr_t iommu_base;
|
||||
u64 *ctxt_wp; /* point to ctxt wp */
|
||||
void *pre_aligned;
|
||||
void *base;
|
||||
void *rp;
|
||||
void *wp;
|
||||
size_t el_size;
|
||||
size_t len;
|
||||
size_t elements;
|
||||
size_t alloc_size;
|
||||
void __iomem *db_addr;
|
||||
};
|
||||
|
||||
struct mhi_cmd {
|
||||
struct mhi_ring ring;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
struct mhi_buf_info {
|
||||
dma_addr_t p_addr;
|
||||
void *v_addr;
|
||||
void *wp;
|
||||
size_t len;
|
||||
void *cb_buf;
|
||||
enum dma_data_direction dir;
|
||||
};
|
||||
|
||||
struct mhi_event {
|
||||
u32 er_index;
|
||||
u32 intmod;
|
||||
u32 msi;
|
||||
int chan; /* this event ring is dedicated to a channel */
|
||||
u32 priority;
|
||||
struct mhi_ring ring;
|
||||
struct db_cfg db_cfg;
|
||||
bool hw_ring;
|
||||
bool cl_manage;
|
||||
bool offload_ev; /* managed by a device driver */
|
||||
bool ctrl_ev;
|
||||
spinlock_t lock;
|
||||
struct mhi_chan *mhi_chan; /* dedicated to channel */
|
||||
struct tasklet_struct task;
|
||||
struct mhi_controller *mhi_cntrl;
|
||||
};
|
||||
|
||||
struct mhi_chan {
|
||||
u32 chan;
|
||||
u32 ring;
|
||||
const char *name;
|
||||
/*
|
||||
* important, when consuming increment tre_ring first, when releasing
|
||||
* decrement buf_ring first. If tre_ring has space, buf_ring
|
||||
* guranteed to have space so we do not need to check both rings.
|
||||
*/
|
||||
struct mhi_ring buf_ring;
|
||||
struct mhi_ring tre_ring;
|
||||
u32 er_index;
|
||||
u32 intmod;
|
||||
u32 tiocm;
|
||||
u32 full;
|
||||
enum dma_data_direction dir;
|
||||
struct db_cfg db_cfg;
|
||||
enum MHI_EE ee;
|
||||
enum MHI_XFER_TYPE xfer_type;
|
||||
enum MHI_CH_STATE ch_state;
|
||||
enum MHI_EV_CCS ccs;
|
||||
bool lpm_notify;
|
||||
bool configured;
|
||||
bool offload_ch;
|
||||
bool pre_alloc;
|
||||
/* functions that generate the transfer ring elements */
|
||||
int (*gen_tre)(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan, void *buf, void *cb,
|
||||
size_t len, enum MHI_FLAGS flags);
|
||||
int (*queue_xfer)(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS flags);
|
||||
/* xfer call back */
|
||||
struct mhi_device *mhi_dev;
|
||||
void (*xfer_cb)(struct mhi_device *mhi_dev, struct mhi_result *res);
|
||||
struct mutex mutex;
|
||||
struct completion completion;
|
||||
rwlock_t lock;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct mhi_bus {
|
||||
struct list_head controller_list;
|
||||
struct mutex lock;
|
||||
struct dentry *dentry;
|
||||
};
|
||||
|
||||
struct mhi_cntrl_data {
|
||||
struct mhi_ctxt mhi_ctxt;
|
||||
struct mhi_cmd mhi_cmd[NR_OF_CMD_RINGS];
|
||||
struct mhi_event mhi_event[NUM_MHI_EVT_RINGS];
|
||||
struct mhi_chan mhi_chan[MHI_MAX_CHANNELS];
|
||||
};
|
||||
|
||||
/* default MHI timeout */
|
||||
#define MHI_TIMEOUT_MS (3000)
|
||||
extern struct mhi_bus mhi_bus;
|
||||
|
||||
/* debug fs related functions */
|
||||
int mhi_debugfs_mhi_chan_show(struct seq_file *m, void *d);
|
||||
int mhi_debugfs_mhi_event_show(struct seq_file *m, void *d);
|
||||
int mhi_debugfs_mhi_states_show(struct seq_file *m, void *d);
|
||||
int mhi_debugfs_trigger_reset(void *data, u64 val);
|
||||
|
||||
void mhi_deinit_debugfs(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_init_debugfs(struct mhi_controller *mhi_cntrl);
|
||||
|
||||
/* power management apis */
|
||||
enum MHI_PM_STATE __must_check mhi_tryset_pm_state(
|
||||
struct mhi_controller *mhi_cntrl,
|
||||
enum MHI_PM_STATE state);
|
||||
const char *to_mhi_pm_state_str(enum MHI_PM_STATE state);
|
||||
void mhi_reset_chan(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
enum MHI_EE mhi_get_exec_env(struct mhi_controller *mhi_cntrl);
|
||||
enum MHI_STATE mhi_get_m_state(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_queue_state_transition(struct mhi_controller *mhi_cntrl,
|
||||
enum MHI_ST_TRANSITION state);
|
||||
void mhi_pm_st_worker(struct work_struct *work);
|
||||
void mhi_fw_load_worker(struct work_struct *work);
|
||||
void mhi_pm_m1_worker(struct work_struct *work);
|
||||
void mhi_pm_sys_err_worker(struct work_struct *work);
|
||||
int mhi_ready_state_transition(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_ctrl_ev_task(unsigned long data);
|
||||
int mhi_pm_m0_transition(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_pm_m1_transition(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_pm_m3_transition(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_notify(struct mhi_device *mhi_dev, enum MHI_CB cb_reason);
|
||||
|
||||
/* queue transfer buffer */
|
||||
int mhi_gen_tre(struct mhi_controller *mhi_cntrl, struct mhi_chan *mhi_chan,
|
||||
void *buf, void *cb, size_t buf_len, enum MHI_FLAGS flags);
|
||||
int mhi_queue_buf(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS mflags);
|
||||
int mhi_queue_skb(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS mflags);
|
||||
int mhi_queue_sclist(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS mflags);
|
||||
int mhi_queue_nop(struct mhi_device *mhi_dev, struct mhi_chan *mhi_chan,
|
||||
void *buf, size_t len, enum MHI_FLAGS mflags);
|
||||
|
||||
|
||||
/* register access methods */
|
||||
void mhi_db_brstmode(struct mhi_controller *mhi_cntrl, struct db_cfg *db_cfg,
|
||||
void __iomem *db_addr, dma_addr_t wp);
|
||||
void mhi_db_brstmode_disable(struct mhi_controller *mhi_cntrl,
|
||||
struct db_cfg *db_mode, void __iomem *db_addr,
|
||||
dma_addr_t wp);
|
||||
int __must_check mhi_read_reg(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *base, u32 offset, u32 *out);
|
||||
int __must_check mhi_read_reg_field(struct mhi_controller *mhi_cntrl,
|
||||
void __iomem *base, u32 offset, u32 mask,
|
||||
u32 shift, u32 *out);
|
||||
void mhi_write_reg(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
u32 offset, u32 val);
|
||||
void mhi_write_reg_field(struct mhi_controller *mhi_cntrl, void __iomem *base,
|
||||
u32 offset, u32 mask, u32 shift, u32 val);
|
||||
void mhi_ring_er_db(struct mhi_event *mhi_event);
|
||||
void mhi_write_db(struct mhi_controller *mhi_cntrl, void __iomem *db_addr,
|
||||
dma_addr_t wp);
|
||||
void mhi_ring_cmd_db(struct mhi_controller *mhi_cntrl, struct mhi_cmd *mhi_cmd);
|
||||
void mhi_ring_chan_db(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
void mhi_set_mhi_state(struct mhi_controller *mhi_cntrl, enum MHI_STATE state);
|
||||
|
||||
/* memory allocation methods */
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION( 5,3,0 ))
|
||||
static inline void *dma_zalloc_coherent(struct device *dev, size_t size,
|
||||
dma_addr_t *dma_handle, gfp_t flag)
|
||||
{
|
||||
void *ret = dma_alloc_coherent(dev, size, dma_handle,
|
||||
flag | __GFP_ZERO);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void *mhi_alloc_coherent(struct mhi_controller *mhi_cntrl,
|
||||
size_t size,
|
||||
dma_addr_t *dma_handle,
|
||||
gfp_t gfp)
|
||||
{
|
||||
void *buf = dma_zalloc_coherent(mhi_cntrl->dev, size, dma_handle, gfp);
|
||||
|
||||
MHI_LOG("size = %zd, dma_handle = %llx\n", size, (u64)*dma_handle);
|
||||
if (buf) {
|
||||
//if (*dma_handle < mhi_cntrl->iova_start || 0 == mhi_cntrl->iova_start)
|
||||
// mhi_cntrl->iova_start = (*dma_handle)&0xFFF0000000;
|
||||
//if ((*dma_handle + size) > mhi_cntrl->iova_stop || 0 == mhi_cntrl->iova_stop)
|
||||
// mhi_cntrl->iova_stop = ((*dma_handle + size)+0x0FFFFFFF)&0xFFF0000000;
|
||||
}
|
||||
if (buf)
|
||||
atomic_add(size, &mhi_cntrl->alloc_size);
|
||||
|
||||
return buf;
|
||||
}
|
||||
static inline void mhi_free_coherent(struct mhi_controller *mhi_cntrl,
|
||||
size_t size,
|
||||
void *vaddr,
|
||||
dma_addr_t dma_handle)
|
||||
{
|
||||
atomic_sub(size, &mhi_cntrl->alloc_size);
|
||||
dma_free_coherent(mhi_cntrl->dev, size, vaddr, dma_handle);
|
||||
}
|
||||
struct mhi_device *mhi_alloc_device(struct mhi_controller *mhi_cntrl);
|
||||
static inline void mhi_dealloc_device(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_device *mhi_dev)
|
||||
{
|
||||
kfree(mhi_dev);
|
||||
}
|
||||
int mhi_destroy_device(struct device *dev, void *data);
|
||||
void mhi_create_devices(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_alloc_bhie_table(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info **image_info, size_t alloc_size);
|
||||
void mhi_free_bhie_table(struct mhi_controller *mhi_cntrl,
|
||||
struct image_info *image_info);
|
||||
|
||||
/* initialization methods */
|
||||
int mhi_init_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
void mhi_deinit_chan_ctxt(struct mhi_controller *mhi_cntrl,
|
||||
struct mhi_chan *mhi_chan);
|
||||
int mhi_init_mmio(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_init_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_dev_ctxt(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_init_irq_setup(struct mhi_controller *mhi_cntrl);
|
||||
void mhi_deinit_free_irq(struct mhi_controller *mhi_cntrl);
|
||||
int mhi_dtr_init(void);
|
||||
|
||||
/* isr handlers */
|
||||
irqreturn_t mhi_msi_handlr(int irq_number, void *dev);
|
||||
irqreturn_t mhi_intvec_threaded_handlr(int irq_number, void *dev);
|
||||
irqreturn_t mhi_intvec_handlr(int irq_number, void *dev);
|
||||
void mhi_ev_task(unsigned long data);
|
||||
|
||||
#ifdef CONFIG_MHI_DEBUG
|
||||
|
||||
#define MHI_ASSERT(cond, msg) do { \
|
||||
if (cond) \
|
||||
panic(msg); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define MHI_ASSERT(cond, msg) do { \
|
||||
if (cond) { \
|
||||
MHI_ERR(msg); \
|
||||
WARN_ON(cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* _MHI_INT_H */
|
||||
1612
package/fish/fibocom_MHI/src/core/mhi_main.c
Normal file
1612
package/fish/fibocom_MHI/src/core/mhi_main.c
Normal file
File diff suppressed because it is too large
Load Diff
1271
package/fish/fibocom_MHI/src/core/mhi_pm.c
Normal file
1271
package/fish/fibocom_MHI/src/core/mhi_pm.c
Normal file
File diff suppressed because it is too large
Load Diff
1313
package/fish/fibocom_MHI/src/devices/mhi_netdev.c
Normal file
1313
package/fish/fibocom_MHI/src/devices/mhi_netdev.c
Normal file
File diff suppressed because it is too large
Load Diff
18
package/fish/fibocom_MHI/src/devices/mhi_netdev.h
Normal file
18
package/fish/fibocom_MHI/src/devices/mhi_netdev.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef _FIBO_MHI_NETDEV_H
|
||||
#define _FIBO_MHI_NETDEV_H
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION( 4,15,0 ))
|
||||
static inline void *fibo_skb_put_data(struct sk_buff *skb, const void *data,
|
||||
unsigned int len)
|
||||
{
|
||||
void *tmp = skb_put(skb, len);
|
||||
|
||||
memcpy(tmp,data, len);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
785
package/fish/fibocom_MHI/src/devices/mhi_uci.c
Normal file
785
package/fish/fibocom_MHI/src/devices/mhi_uci.c
Normal file
@ -0,0 +1,785 @@
|
||||
/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 and
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program 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.
|
||||
*/
|
||||
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/dma-direction.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/tty.h>
|
||||
#include "../core/mhi.h"
|
||||
|
||||
#define DEVICE_NAME "mhi"
|
||||
#define MHI_UCI_DRIVER_NAME "mhi_uci"
|
||||
|
||||
struct uci_chan {
|
||||
wait_queue_head_t wq;
|
||||
spinlock_t lock;
|
||||
struct list_head pending; /* user space waiting to read */
|
||||
struct uci_buf *cur_buf; /* current buffer user space reading */
|
||||
size_t rx_size;
|
||||
};
|
||||
|
||||
struct uci_buf {
|
||||
void *data;
|
||||
size_t len;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct uci_dev {
|
||||
struct list_head node;
|
||||
dev_t devt;
|
||||
struct device *dev;
|
||||
struct mhi_device *mhi_dev;
|
||||
const char *chan;
|
||||
struct mutex mutex; /* sync open and close */
|
||||
struct uci_chan ul_chan;
|
||||
struct uci_chan dl_chan;
|
||||
size_t mtu;
|
||||
int ref_count;
|
||||
bool enabled;
|
||||
bool disconnect;
|
||||
struct ktermios termios;
|
||||
int sigs;
|
||||
};
|
||||
|
||||
struct mhi_uci_drv {
|
||||
struct list_head head;
|
||||
struct mutex lock;
|
||||
struct class *class;
|
||||
int major;
|
||||
dev_t dev_t;
|
||||
};
|
||||
|
||||
enum MHI_DEBUG_LEVEL msg_lvl = MHI_MSG_LVL_ERROR;
|
||||
|
||||
typedef struct _QCQMI_HDR {
|
||||
u8 IFType;
|
||||
u16 Length;
|
||||
u8 CtlFlags; // reserved
|
||||
u8 QMIType;
|
||||
u8 ClientId;
|
||||
} __attribute__ ((packed)) *PQCQMI_HDR;
|
||||
|
||||
#define MSG_VERB(fmt, ...) do { \
|
||||
if (msg_lvl <= MHI_MSG_LVL_VERBOSE) \
|
||||
pr_err("[D][%s] " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define MSG_LOG(fmt, ...) do { \
|
||||
if (msg_lvl <= MHI_MSG_LVL_INFO) \
|
||||
pr_err("[I][%s] " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define MSG_ERR(fmt, ...) do { \
|
||||
if (msg_lvl <= MHI_MSG_LVL_ERROR) \
|
||||
pr_err("[E][%s] " fmt, __func__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define MAX_UCI_DEVICES (64)
|
||||
#define QUEC_MHI_UCI_ALWAYS_OPEN //by now, sdx20 can not handle "start-reset-start" operation, so the simply solution is keep start state
|
||||
|
||||
static DECLARE_BITMAP(uci_minors, MAX_UCI_DEVICES);
|
||||
static struct mhi_uci_drv mhi_uci_drv;
|
||||
|
||||
static int mhi_queue_inbound(struct uci_dev *uci_dev)
|
||||
{
|
||||
struct mhi_device *mhi_dev = uci_dev->mhi_dev;
|
||||
int nr_trbs = mhi_get_no_free_descriptors(mhi_dev, DMA_FROM_DEVICE);
|
||||
size_t mtu = uci_dev->mtu;
|
||||
void *buf;
|
||||
struct uci_buf *uci_buf;
|
||||
int ret = -EIO, i;
|
||||
|
||||
for (i = 0; i < nr_trbs; i++) {
|
||||
buf = kmalloc(mtu + sizeof(*uci_buf), GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
uci_buf = buf + mtu;
|
||||
uci_buf->data = buf;
|
||||
|
||||
MSG_VERB("Allocated buf %d of %d size %zd\n", i, nr_trbs, mtu);
|
||||
|
||||
ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE, buf, mtu,
|
||||
MHI_EOT);
|
||||
if (ret) {
|
||||
kfree(buf);
|
||||
MSG_ERR("Failed to queue buffer %d\n", i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long mhi_uci_ioctl(struct file *file,
|
||||
unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct uci_dev *uci_dev = file->private_data;
|
||||
struct mhi_device *mhi_dev = uci_dev->mhi_dev;
|
||||
long ret = -ERESTARTSYS;
|
||||
|
||||
mutex_lock(&uci_dev->mutex);
|
||||
if (uci_dev->enabled) {
|
||||
switch (cmd) {
|
||||
case TCGETS:
|
||||
#ifndef TCGETS2
|
||||
ret = kernel_termios_to_user_termios((struct termios __user *)arg, &uci_dev->termios);
|
||||
#else
|
||||
ret = kernel_termios_to_user_termios_1((struct termios __user *)arg, &uci_dev->termios);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TCSETSF:
|
||||
case TCSETS:
|
||||
#ifndef TCGETS2
|
||||
ret = user_termios_to_kernel_termios(&uci_dev->termios, (struct termios __user *)arg);
|
||||
#else
|
||||
ret = user_termios_to_kernel_termios_1(&uci_dev->termios, (struct termios __user *)arg);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case TIOCMSET:
|
||||
case TIOCMBIS:
|
||||
case TIOCMBIC:
|
||||
{
|
||||
uint32_t val;
|
||||
|
||||
ret = get_user(val, (uint32_t *)arg);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
switch (cmd) {
|
||||
case TIOCMBIS:
|
||||
uci_dev->sigs |= val;
|
||||
break;
|
||||
case TIOCMBIC:
|
||||
uci_dev->sigs &= ~val;
|
||||
break;
|
||||
case TIOCMSET:
|
||||
uci_dev->sigs = val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TIOCMGET:
|
||||
ret = put_user(uci_dev->sigs | TIOCM_RTS, (uint32_t *)arg);
|
||||
break;
|
||||
|
||||
case TCFLSH:
|
||||
ret = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = mhi_ioctl(mhi_dev, cmd, arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mhi_uci_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct uci_dev *uci_dev = file->private_data;
|
||||
|
||||
mutex_lock(&uci_dev->mutex);
|
||||
uci_dev->ref_count--;
|
||||
if (!uci_dev->ref_count) {
|
||||
struct uci_buf *itr, *tmp;
|
||||
struct uci_chan *uci_chan;
|
||||
|
||||
MSG_LOG("Last client left, closing node\n");
|
||||
|
||||
if (uci_dev->enabled)
|
||||
mhi_unprepare_from_transfer(uci_dev->mhi_dev);
|
||||
|
||||
/* clean inbound channel */
|
||||
uci_chan = &uci_dev->dl_chan;
|
||||
list_for_each_entry_safe(itr, tmp, &uci_chan->pending, node) {
|
||||
list_del(&itr->node);
|
||||
kfree(itr->data);
|
||||
}
|
||||
if (uci_chan->cur_buf)
|
||||
kfree(uci_chan->cur_buf->data);
|
||||
|
||||
uci_chan->cur_buf = NULL;
|
||||
|
||||
if (!uci_dev->enabled) {
|
||||
MSG_LOG("Node is deleted, freeing dev node\n");
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
mutex_destroy(&uci_dev->mutex);
|
||||
clear_bit(MINOR(uci_dev->devt), uci_minors);
|
||||
kfree(uci_dev);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
|
||||
MSG_LOG("exit: ref_count:%d\n", uci_dev->ref_count);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int mhi_uci_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct uci_dev *uci_dev = file->private_data;
|
||||
struct mhi_device *mhi_dev = uci_dev->mhi_dev;
|
||||
struct uci_chan *uci_chan;
|
||||
unsigned int mask = 0;
|
||||
|
||||
poll_wait(file, &uci_dev->dl_chan.wq, wait);
|
||||
poll_wait(file, &uci_dev->ul_chan.wq, wait);
|
||||
|
||||
uci_chan = &uci_dev->dl_chan;
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
if (!uci_dev->enabled) {
|
||||
mask = POLLERR;
|
||||
} else if (!list_empty(&uci_chan->pending) || uci_chan->cur_buf) {
|
||||
MSG_VERB("Client can read from node\n");
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
}
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
uci_chan = &uci_dev->ul_chan;
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
if (!uci_dev->enabled) {
|
||||
mask |= POLLERR;
|
||||
} else if (mhi_get_no_free_descriptors(mhi_dev, DMA_TO_DEVICE) > 0) {
|
||||
MSG_VERB("Client can write to node\n");
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
}
|
||||
|
||||
if (uci_dev->disconnect)
|
||||
mask |= POLLHUP;
|
||||
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
MSG_VERB("Client attempted to poll, returning mask 0x%x\n", mask);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t mhi_uci_write(struct file *file,
|
||||
const char __user *buf,
|
||||
size_t count,
|
||||
loff_t *offp)
|
||||
{
|
||||
struct uci_dev *uci_dev = file->private_data;
|
||||
struct mhi_device *mhi_dev = uci_dev->mhi_dev;
|
||||
struct uci_chan *uci_chan = &uci_dev->ul_chan;
|
||||
size_t bytes_xfered = 0;
|
||||
int ret;
|
||||
|
||||
if (!buf || !count)
|
||||
return -EINVAL;
|
||||
|
||||
/* confirm channel is active */
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
if (!uci_dev->enabled) {
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
MSG_VERB("Enter: to xfer:%zd bytes\n", count);
|
||||
|
||||
while (count) {
|
||||
size_t xfer_size;
|
||||
void *kbuf;
|
||||
enum MHI_FLAGS flags;
|
||||
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
if (mhi_get_no_free_descriptors(mhi_dev, DMA_TO_DEVICE) == 0 && (file->f_mode & FMODE_NDELAY))
|
||||
break;
|
||||
|
||||
/* wait for free descriptors */
|
||||
ret = wait_event_interruptible(uci_chan->wq,
|
||||
(!uci_dev->enabled) ||
|
||||
mhi_get_no_free_descriptors
|
||||
(mhi_dev, DMA_TO_DEVICE) > 0);
|
||||
|
||||
if (ret == -ERESTARTSYS) {
|
||||
MSG_LOG("Exit signal caught for node\n");
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
xfer_size = min_t(size_t, count, uci_dev->mtu);
|
||||
kbuf = kmalloc(xfer_size, GFP_KERNEL);
|
||||
if (!kbuf) {
|
||||
MSG_ERR("Failed to allocate memory %zd\n", xfer_size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = copy_from_user(kbuf, buf, xfer_size);
|
||||
if (unlikely(ret)) {
|
||||
kfree(kbuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
flags = MHI_EOT;
|
||||
if (uci_dev->enabled)
|
||||
ret = mhi_queue_transfer(mhi_dev, DMA_TO_DEVICE, kbuf,
|
||||
xfer_size, flags);
|
||||
else
|
||||
ret = -ERESTARTSYS;
|
||||
|
||||
if (ret) {
|
||||
kfree(kbuf);
|
||||
goto sys_interrupt;
|
||||
}
|
||||
|
||||
bytes_xfered += xfer_size;
|
||||
count -= xfer_size;
|
||||
buf += xfer_size;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
MSG_VERB("Exit: Number of bytes xferred:%zd\n", bytes_xfered);
|
||||
|
||||
return bytes_xfered;
|
||||
|
||||
sys_interrupt:
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t mhi_uci_read(struct file *file,
|
||||
char __user *buf,
|
||||
size_t count,
|
||||
loff_t *ppos)
|
||||
{
|
||||
struct uci_dev *uci_dev = file->private_data;
|
||||
struct mhi_device *mhi_dev = uci_dev->mhi_dev;
|
||||
struct uci_chan *uci_chan = &uci_dev->dl_chan;
|
||||
struct uci_buf *uci_buf;
|
||||
char *ptr;
|
||||
size_t to_copy;
|
||||
int ret = 0;
|
||||
|
||||
if (!buf)
|
||||
return -EINVAL;
|
||||
|
||||
MSG_VERB("Client provided buf len:%zd\n", count);
|
||||
|
||||
/* confirm channel is active */
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
if (!uci_dev->enabled) {
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
/* No data available to read, wait */
|
||||
if (!uci_chan->cur_buf && list_empty(&uci_chan->pending)) {
|
||||
MSG_VERB("No data available to read waiting\n");
|
||||
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
if (file->f_mode & FMODE_NDELAY)
|
||||
return -EAGAIN;
|
||||
|
||||
ret = wait_event_interruptible(uci_chan->wq,
|
||||
(!uci_dev->enabled ||
|
||||
!list_empty(&uci_chan->pending)));
|
||||
if (ret == -ERESTARTSYS) {
|
||||
MSG_LOG("Exit signal caught for node\n");
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
if (!uci_dev->enabled) {
|
||||
MSG_LOG("node is disabled\n");
|
||||
ret = -ERESTARTSYS;
|
||||
goto read_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* new read, get the next descriptor from the list */
|
||||
if (!uci_chan->cur_buf) {
|
||||
uci_buf = list_first_entry_or_null(&uci_chan->pending,
|
||||
struct uci_buf, node);
|
||||
if (unlikely(!uci_buf)) {
|
||||
ret = -EIO;
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
list_del(&uci_buf->node);
|
||||
uci_chan->cur_buf = uci_buf;
|
||||
uci_chan->rx_size = uci_buf->len;
|
||||
MSG_VERB("Got pkt of size:%zd\n", uci_chan->rx_size);
|
||||
}
|
||||
|
||||
uci_buf = uci_chan->cur_buf;
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
/* Copy the buffer to user space */
|
||||
to_copy = min_t(size_t, count, uci_chan->rx_size);
|
||||
ptr = uci_buf->data + (uci_buf->len - uci_chan->rx_size);
|
||||
ret = copy_to_user(buf, ptr, to_copy);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
MSG_VERB("Copied %zd of %zd bytes\n", to_copy, uci_chan->rx_size);
|
||||
uci_chan->rx_size -= to_copy;
|
||||
|
||||
/* we finished with this buffer, queue it back to hardware */
|
||||
if (!uci_chan->rx_size) {
|
||||
spin_lock_bh(&uci_chan->lock);
|
||||
uci_chan->cur_buf = NULL;
|
||||
|
||||
if (uci_dev->enabled)
|
||||
ret = mhi_queue_transfer(mhi_dev, DMA_FROM_DEVICE,
|
||||
uci_buf->data, uci_dev->mtu,
|
||||
MHI_EOT);
|
||||
else
|
||||
ret = -ERESTARTSYS;
|
||||
|
||||
if (ret) {
|
||||
MSG_ERR("Failed to recycle element\n");
|
||||
kfree(uci_buf->data);
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
}
|
||||
|
||||
MSG_VERB("Returning %zd bytes\n", to_copy);
|
||||
|
||||
return to_copy;
|
||||
|
||||
read_error:
|
||||
spin_unlock_bh(&uci_chan->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mhi_uci_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
struct uci_dev *uci_dev;
|
||||
int ret = -EIO;
|
||||
struct uci_buf *buf_itr, *tmp;
|
||||
struct uci_chan *dl_chan;
|
||||
|
||||
mutex_lock(&mhi_uci_drv.lock);
|
||||
list_for_each_entry(uci_dev, &mhi_uci_drv.head, node) {
|
||||
if (uci_dev->devt == inode->i_rdev) {
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
mutex_unlock(&mhi_uci_drv.lock);
|
||||
|
||||
/* could not find a minor node */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&uci_dev->mutex);
|
||||
if (!uci_dev->enabled) {
|
||||
MSG_ERR("Node exist, but not in active state!\n");
|
||||
goto error_open_chan;
|
||||
}
|
||||
|
||||
uci_dev->ref_count++;
|
||||
|
||||
MSG_LOG("Node open, ref counts %u\n", uci_dev->ref_count);
|
||||
|
||||
if (uci_dev->ref_count == 1) {
|
||||
MSG_LOG("Starting channel\n");
|
||||
ret = mhi_prepare_for_transfer(uci_dev->mhi_dev);
|
||||
if (ret) {
|
||||
MSG_ERR("Error starting transfer channels\n");
|
||||
uci_dev->ref_count--;
|
||||
goto error_open_chan;
|
||||
}
|
||||
|
||||
ret = mhi_queue_inbound(uci_dev);
|
||||
if (ret)
|
||||
goto error_rx_queue;
|
||||
|
||||
#ifdef QUEC_MHI_UCI_ALWAYS_OPEN
|
||||
uci_dev->ref_count++;
|
||||
if (uci_dev->mhi_dev->dl_chan_id == MHI_CLIENT_QMI_IN) {
|
||||
}
|
||||
if (uci_dev->mhi_dev->dl_chan_id == MHI_CLIENT_MBIM_IN) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
filp->private_data = uci_dev;
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
|
||||
return 0;
|
||||
|
||||
error_rx_queue:
|
||||
dl_chan = &uci_dev->dl_chan;
|
||||
mhi_unprepare_from_transfer(uci_dev->mhi_dev);
|
||||
list_for_each_entry_safe(buf_itr, tmp, &dl_chan->pending, node) {
|
||||
list_del(&buf_itr->node);
|
||||
kfree(buf_itr->data);
|
||||
}
|
||||
|
||||
error_open_chan:
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations mhidev_fops = {
|
||||
.open = mhi_uci_open,
|
||||
.release = mhi_uci_release,
|
||||
.read = mhi_uci_read,
|
||||
.write = mhi_uci_write,
|
||||
.poll = mhi_uci_poll,
|
||||
.unlocked_ioctl = mhi_uci_ioctl,
|
||||
};
|
||||
|
||||
static void mhi_uci_remove(struct mhi_device *mhi_dev)
|
||||
{
|
||||
struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev);
|
||||
|
||||
MSG_LOG("Enter\n");
|
||||
|
||||
/* disable the node */
|
||||
mutex_lock(&uci_dev->mutex);
|
||||
spin_lock_irq(&uci_dev->dl_chan.lock);
|
||||
spin_lock_irq(&uci_dev->ul_chan.lock);
|
||||
uci_dev->enabled = false;
|
||||
uci_dev->disconnect = true;
|
||||
spin_unlock_irq(&uci_dev->ul_chan.lock);
|
||||
spin_unlock_irq(&uci_dev->dl_chan.lock);
|
||||
wake_up(&uci_dev->dl_chan.wq);
|
||||
wake_up(&uci_dev->ul_chan.wq);
|
||||
|
||||
/* delete the node to prevent new opens */
|
||||
device_destroy(mhi_uci_drv.class, uci_dev->devt);
|
||||
uci_dev->dev = NULL;
|
||||
mutex_lock(&mhi_uci_drv.lock);
|
||||
list_del(&uci_dev->node);
|
||||
mutex_unlock(&mhi_uci_drv.lock);
|
||||
|
||||
#ifdef QUEC_MHI_UCI_ALWAYS_OPEN
|
||||
if (uci_dev->ref_count > 0)
|
||||
uci_dev->ref_count--;
|
||||
#endif
|
||||
|
||||
/* safe to free memory only if all file nodes are closed */
|
||||
if (!uci_dev->ref_count) {
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
mutex_destroy(&uci_dev->mutex);
|
||||
clear_bit(MINOR(uci_dev->devt), uci_minors);
|
||||
kfree(uci_dev);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
MSG_LOG("Exit\n");
|
||||
}
|
||||
|
||||
static int mhi_uci_probe(struct mhi_device *mhi_dev,
|
||||
const struct mhi_device_id *id)
|
||||
{
|
||||
struct uci_dev *uci_dev;
|
||||
int minor;
|
||||
int dir;
|
||||
|
||||
uci_dev = kzalloc(sizeof(*uci_dev), GFP_KERNEL);
|
||||
if (!uci_dev)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&uci_dev->mutex);
|
||||
uci_dev->mhi_dev = mhi_dev;
|
||||
|
||||
minor = find_first_zero_bit(uci_minors, MAX_UCI_DEVICES);
|
||||
if (minor >= MAX_UCI_DEVICES) {
|
||||
kfree(uci_dev);
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
||||
mutex_lock(&uci_dev->mutex);
|
||||
mutex_lock(&mhi_uci_drv.lock);
|
||||
|
||||
uci_dev->devt = MKDEV(mhi_uci_drv.major, minor);
|
||||
|
||||
uci_dev->dev = device_create(mhi_uci_drv.class, &mhi_dev->dev,
|
||||
uci_dev->devt, uci_dev,
|
||||
DEVICE_NAME "_%s",
|
||||
mhi_dev->chan_name);
|
||||
|
||||
set_bit(minor, uci_minors);
|
||||
|
||||
for (dir = 0; dir < 2; dir++) {
|
||||
struct uci_chan *uci_chan = (dir) ?
|
||||
&uci_dev->ul_chan : &uci_dev->dl_chan;
|
||||
spin_lock_init(&uci_chan->lock);
|
||||
init_waitqueue_head(&uci_chan->wq);
|
||||
INIT_LIST_HEAD(&uci_chan->pending);
|
||||
};
|
||||
|
||||
uci_dev->termios = tty_std_termios;
|
||||
uci_dev->sigs = 0;
|
||||
|
||||
uci_dev->mtu = id->driver_data;
|
||||
mhi_device_set_devdata(mhi_dev, uci_dev);
|
||||
uci_dev->enabled = true;
|
||||
|
||||
list_add(&uci_dev->node, &mhi_uci_drv.head);
|
||||
mutex_unlock(&mhi_uci_drv.lock);
|
||||
mutex_unlock(&uci_dev->mutex);
|
||||
|
||||
MSG_LOG("channel:%s successfully probed\n", mhi_dev->chan_name);
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
static void mhi_ul_xfer_cb(struct mhi_device *mhi_dev,
|
||||
struct mhi_result *mhi_result)
|
||||
{
|
||||
struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev);
|
||||
struct uci_chan *uci_chan = &uci_dev->ul_chan;
|
||||
|
||||
MSG_VERB("status:%d xfer_len:%zu\n", mhi_result->transaction_status,
|
||||
mhi_result->bytes_xferd);
|
||||
|
||||
kfree(mhi_result->buf_addr);
|
||||
if (!mhi_result->transaction_status)
|
||||
wake_up(&uci_chan->wq);
|
||||
}
|
||||
|
||||
static void mhi_dl_xfer_cb(struct mhi_device *mhi_dev,
|
||||
struct mhi_result *mhi_result)
|
||||
{
|
||||
struct uci_dev *uci_dev = mhi_device_get_devdata(mhi_dev);
|
||||
struct uci_chan *uci_chan = &uci_dev->dl_chan;
|
||||
unsigned long flags;
|
||||
struct uci_buf *buf;
|
||||
|
||||
MSG_VERB("chan:mhi_dev->dl_chan_id:%d, status:%d receive_len:%zu\n",
|
||||
mhi_dev->dl_chan_id, mhi_result->transaction_status, mhi_result->bytes_xferd);
|
||||
|
||||
if (mhi_result->transaction_status == -ENOTCONN) {
|
||||
kfree(mhi_result->buf_addr);
|
||||
return;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&uci_chan->lock, flags);
|
||||
buf = mhi_result->buf_addr + uci_dev->mtu;
|
||||
if (buf->data != mhi_result->buf_addr) {
|
||||
MSG_LOG("%p, %p\n", buf->data, mhi_result->buf_addr);
|
||||
}
|
||||
buf->data = mhi_result->buf_addr;
|
||||
buf->len = mhi_result->bytes_xferd;
|
||||
|
||||
if (uci_dev->mhi_dev->dl_chan_id == MHI_CLIENT_QMI_IN) {
|
||||
PQCQMI_HDR pHdr = (PQCQMI_HDR) (buf->data);
|
||||
u16 qmiLength = (le16_to_cpu(pHdr->Length) + 1);
|
||||
|
||||
// open qmi chan, but not read data from the chan, will cause next error, donot know why by now, so it is not recomment to use uqmi&libqmi?
|
||||
// dmesg -c > /dev/null; echo 1 > /dev/mhi_QMI0; sleep 3; ./FIBO-CM -d /dev/mhi_QMI0 -v
|
||||
if (qmiLength != buf->len) {
|
||||
unsigned char *d = (unsigned char *) pHdr;
|
||||
MSG_ERR("bytes_xferd=%zd, qmiLength=%d %02x%02x%02x%02x - %02x%02x%02x%02x\n", buf->len, qmiLength,
|
||||
d[0],d[1],d[2],d[3],d[qmiLength+0],d[qmiLength+1],d[qmiLength+2],d[qmiLength+3]);
|
||||
if (buf->len > qmiLength)
|
||||
buf->len = qmiLength;
|
||||
}
|
||||
}
|
||||
|
||||
list_add_tail(&buf->node, &uci_chan->pending);
|
||||
spin_unlock_irqrestore(&uci_chan->lock, flags);
|
||||
|
||||
wake_up(&uci_chan->wq);
|
||||
}
|
||||
|
||||
#define DIAG_MAX_PCIE_PKT_SZ 2048 //define by module
|
||||
|
||||
/* .driver_data stores max mtu */
|
||||
static const struct mhi_device_id mhi_uci_match_table[] = {
|
||||
{ .chan = "LOOPBACK", .driver_data = 0x1000 },
|
||||
{ .chan = "SAHARA", .driver_data = 0x4000 },
|
||||
{ .chan = "EDL", .driver_data = 0x4000 },
|
||||
{ .chan = "DIAG", .driver_data = DIAG_MAX_PCIE_PKT_SZ },
|
||||
{ .chan = "EFS", .driver_data = 0x1000 },
|
||||
#ifdef CONFIG_MHI_NETDEV_MBIM
|
||||
{ .chan = "MBIM", .driver_data = 0x1000 },
|
||||
#else
|
||||
{ .chan = "QMI0", .driver_data = 0x1000 },
|
||||
{ .chan = "QMI1", .driver_data = 0x1000 },
|
||||
#endif
|
||||
{ .chan = "TF", .driver_data = 0x1000 },
|
||||
{ .chan = "BL", .driver_data = 0x1000 },
|
||||
{ .chan = "DUN", .driver_data = 0x1000 },
|
||||
{ .chan = "GNSS", .driver_data = 0x1000 },
|
||||
{ .chan = "AUDIO", .driver_data = 0x1000 },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct mhi_driver mhi_uci_driver = {
|
||||
.id_table = mhi_uci_match_table,
|
||||
.remove = mhi_uci_remove,
|
||||
.probe = mhi_uci_probe,
|
||||
.ul_xfer_cb = mhi_ul_xfer_cb,
|
||||
.dl_xfer_cb = mhi_dl_xfer_cb,
|
||||
.driver = {
|
||||
.name = MHI_UCI_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
};
|
||||
|
||||
int mhi_device_uci_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = register_chrdev(0, MHI_UCI_DRIVER_NAME, &mhidev_fops);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
mhi_uci_drv.major = ret;
|
||||
mhi_uci_drv.class = class_create(THIS_MODULE, MHI_UCI_DRIVER_NAME);
|
||||
if (IS_ERR(mhi_uci_drv.class)) {
|
||||
unregister_chrdev(mhi_uci_drv.major, MHI_UCI_DRIVER_NAME);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
mutex_init(&mhi_uci_drv.lock);
|
||||
INIT_LIST_HEAD(&mhi_uci_drv.head);
|
||||
|
||||
ret = mhi_driver_register(&mhi_uci_driver);
|
||||
if (ret) {
|
||||
class_destroy(mhi_uci_drv.class);
|
||||
unregister_chrdev(mhi_uci_drv.major, MHI_UCI_DRIVER_NAME);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mhi_device_uci_exit(void)
|
||||
{
|
||||
mhi_driver_unregister(&mhi_uci_driver);
|
||||
class_destroy(mhi_uci_drv.class);
|
||||
unregister_chrdev(mhi_uci_drv.major, MHI_UCI_DRIVER_NAME);
|
||||
}
|
||||
47
package/fish/fibocom_QMI_WWAN/Makefile
Normal file
47
package/fish/fibocom_QMI_WWAN/Makefile
Normal file
@ -0,0 +1,47 @@
|
||||
#
|
||||
# Copyright (C) 2015 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=qmi_wwan_f
|
||||
PKG_VERSION:=1.0
|
||||
PKG_RELEASE:=2
|
||||
|
||||
include $(INCLUDE_DIR)/kernel.mk
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define KernelPackage/qmi_wwan_f
|
||||
SUBMENU:=WWAN Support
|
||||
TITLE:=Fibocom Linux USB QMI WWAN Driver
|
||||
DEPENDS:=+kmod-usb-net +kmod-usb-wdm
|
||||
FILES:=$(PKG_BUILD_DIR)/qmi_wwan_f.ko
|
||||
AUTOLOAD:=$(call AutoLoad,82,qmi_wwan_f)
|
||||
endef
|
||||
|
||||
define KernelPackage/qmi_wwan_f/description
|
||||
Fibocom Linux USB QMI WWAN Driver
|
||||
endef
|
||||
|
||||
MAKE_OPTS:= \
|
||||
ARCH="$(LINUX_KARCH)" \
|
||||
CROSS_COMPILE="$(TARGET_CROSS)" \
|
||||
CXXFLAGS="$(TARGET_CXXFLAGS)" \
|
||||
M="$(PKG_BUILD_DIR)" \
|
||||
$(EXTRA_KCONFIG)
|
||||
|
||||
define Build/Prepare
|
||||
mkdir -p $(PKG_BUILD_DIR)
|
||||
$(CP) ./src/* $(PKG_BUILD_DIR)/
|
||||
endef
|
||||
|
||||
define Build/Compile
|
||||
$(MAKE) -C "$(LINUX_DIR)" \
|
||||
$(MAKE_OPTS) \
|
||||
modules
|
||||
endef
|
||||
|
||||
$(eval $(call KernelPackage,qmi_wwan_f))
|
||||
38
package/fish/fibocom_QMI_WWAN/src/Makefile
Normal file
38
package/fish/fibocom_QMI_WWAN/src/Makefile
Normal file
@ -0,0 +1,38 @@
|
||||
obj-m += qmi_wwan_f.o
|
||||
|
||||
PWD := $(shell pwd)
|
||||
OUTPUTDIR=/lib/modules/`uname -r`/kernel/drivers/net/usb/
|
||||
|
||||
ifeq ($(ARCH),)
|
||||
ARCH := $(shell uname -m)
|
||||
endif
|
||||
ifeq ($(CROSS_COMPILE),)
|
||||
CROSS_COMPILE :=
|
||||
endif
|
||||
ifeq ($(KDIR),)
|
||||
KDIR := /lib/modules/$(shell uname -r)/build
|
||||
ifeq ($(ARCH),i686)
|
||||
ifeq ($(wildcard $KDIR/arch/$ARCH),)
|
||||
ARCH=i386
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(findstring &,${PWD}),)
|
||||
$(warning "${PWD}")
|
||||
$(warning "current directory contain special char '&' !")
|
||||
$(error "please remove it!")
|
||||
endif
|
||||
|
||||
default:
|
||||
$(MAKE) ARCH=${ARCH} CROSS_COMPILE=${CROSS_COMPILE} -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
install: default
|
||||
cp $(PWD)/qmi_wwan_f.ko /lib/modules/$(shell uname -r)/kernel/drivers/net/usb/
|
||||
depmod
|
||||
modprobe -r qmi_wwan_f
|
||||
modprobe -r qmi_wwan
|
||||
modprobe qmi_wwan_f
|
||||
clean:
|
||||
rm -rf *~ .tmp_versions modules.order Module.symvers
|
||||
find . -type f -name "*~" -o -name "*.o" -o -name "*.ko" -o -name "*.cmd" -o -name "*.mod.c" | xargs rm -rf
|
||||
2534
package/fish/fibocom_QMI_WWAN/src/qmi_wwan_f.c
Normal file
2534
package/fish/fibocom_QMI_WWAN/src/qmi_wwan_f.c
Normal file
File diff suppressed because it is too large
Load Diff
34
package/fish/luci-app-cpe/Makefile
Normal file
34
package/fish/luci-app-cpe/Makefile
Normal file
@ -0,0 +1,34 @@
|
||||
#将openwrt顶层目录下的rules.mk文件中的内容导入进来
|
||||
include $(TOPDIR)/rules.mk
|
||||
#软件包名
|
||||
PKG_NAME:=luci-app-cpe
|
||||
#软件包版本
|
||||
PKG_VERSION:=5.0.1
|
||||
#真正编译当前软件包的目录
|
||||
PKG_BUILD_DIR:= $(BUILD_DIR)/$(PKG_NAME)
|
||||
|
||||
|
||||
#将$(TOPDIR)/include目录下的package.mk文件中的内容导入进来
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
define Package/luci-app-cpe
|
||||
PKGARCH:=all
|
||||
SECTION:=wrtnode
|
||||
CATEGORY:=Daocaoren
|
||||
SUBMENU :=CPE
|
||||
TITLE:=luci-app-cpe
|
||||
DEPENDS:=+sendat + luci-compat +kmod-usb-net +kmod-usb-net-cdc-ether +kmod-usb-acm \
|
||||
+kmod-usb-net-qmi-wwan +kmod-usb-net-rndis +kmod-usb-serial-qualcomm \
|
||||
+kmod-usb-net-sierrawireless +kmod-usb-ohci +kmod-usb-serial \
|
||||
+kmod-usb-serial-option +kmod-usb-wdm \
|
||||
+kmod-usb2 +kmod-usb3 \
|
||||
+quectel-CM-5G +kmod-usb-net-cdc-mbim +usbutils
|
||||
endef
|
||||
|
||||
PKG_LICENSE:=GPLv3
|
||||
PKG_LINCESE_FILES:=LICENSE
|
||||
PKF_MAINTAINER:=daocaoren <168620188@qq.com>
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
|
||||
189
package/fish/luci-app-cpe/luasrc/controller/admin/cpe.lua
Normal file
189
package/fish/luci-app-cpe/luasrc/controller/admin/cpe.lua
Normal file
@ -0,0 +1,189 @@
|
||||
module("luci.controller.admin.cpe", package.seeall)
|
||||
|
||||
I18N = require "luci.i18n"
|
||||
translate = I18N.translate
|
||||
|
||||
function index()
|
||||
entry({"admin", "modem"}, firstchild(), translate("移动数据"), 25).dependent=false
|
||||
entry({"admin", "modem", "nets"}, template("cpe/net_status"), translate("信号状态"), 0)
|
||||
entry({"admin", "modem", "get_csq"}, call("action_get_csq"))
|
||||
entry({"admin", "modem", "send_atcmd"}, call("action_send_atcmd"))
|
||||
|
||||
-- entry({"admin", "modem", "sms"}, template("cpe/sms"), translate("短信信息"), 1)
|
||||
-- entry({"admin", "modem", "band"}, template("cpe/band"), translate("锁频段/锁PCI"), 1)
|
||||
entry({"admin", "modem", "at"}, template("cpe/at"), translate("AT工具"), 98)
|
||||
|
||||
if not nixio.fs.access("/etc/config/modem") then
|
||||
return
|
||||
end
|
||||
entry({"admin", "modem", "modem"}, cbi("cpe/modem"), _("模块设置"), 99)
|
||||
|
||||
end
|
||||
|
||||
function action_send_atcmd()
|
||||
local rv ={}
|
||||
local file
|
||||
local p = luci.http.formvalue("p")
|
||||
local set = luci.http.formvalue("set")
|
||||
fixed = string.gsub(set, "\"", "~")
|
||||
port= string.gsub(p, "\"", "~")
|
||||
rv["at"] = fixed
|
||||
rv["port"] = port
|
||||
|
||||
os.execute("/usr/share/cpe/atcmd.sh \'" .. port .. "\' \'" .. fixed .. "\'")
|
||||
result = "/tmp/result.at"
|
||||
file = io.open(result, "r")
|
||||
if file ~= nil then
|
||||
rv["result"] = file:read("*all")
|
||||
file:close()
|
||||
else
|
||||
rv["result"] = " "
|
||||
end
|
||||
os.execute("/usr/share/cpe/delatcmd.sh")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(rv)
|
||||
|
||||
end
|
||||
|
||||
function action_get_csq()
|
||||
local file
|
||||
stat = "/tmp/cpe_cell.file"
|
||||
file = io.open(stat, "r")
|
||||
local rv ={}
|
||||
|
||||
-- echo 'RM520N-GL'
|
||||
-- echo 'conntype'
|
||||
-- echo '1e0e:9001'
|
||||
-- echo $COPS #运营商
|
||||
-- echo '' #端口
|
||||
-- echo '' #温度
|
||||
-- echo '' #协议
|
||||
rv["modem"] = file:read("*line")
|
||||
rv["conntype"] = file:read("*line")
|
||||
rv["modid"] = file:read("*line")
|
||||
rv["cops"] = file:read("*line")
|
||||
rv["port"] = file:read("*line")
|
||||
rv["tempur"] = file:read("*line")
|
||||
rv["proto"] = file:read("*line")
|
||||
file:read("*line")
|
||||
|
||||
|
||||
-- echo $IMEI #imei
|
||||
-- echo $IMSI #imsi
|
||||
-- echo $ICCID #iccid
|
||||
-- echo $phone #phone
|
||||
rv["imei"] = file:read("*line")
|
||||
rv["imsi"] = file:read("*line")
|
||||
rv["iccid"] =file:read("*line")
|
||||
rv["phone"] = file:read("*line")
|
||||
file:read("*line")
|
||||
|
||||
|
||||
-- echo $MODE
|
||||
-- echo $CSQ
|
||||
-- echo $CSQ_PER
|
||||
-- echo $CSQ_RSSI
|
||||
-- echo '' #参考信号接收质量 RSRQ ecio
|
||||
-- echo '' #参考信号接收质量 RSRQ ecio1
|
||||
-- echo '' #参考信号接收功率 RSRP rscp
|
||||
-- echo '' #参考信号接收功率 RSRP rscp1
|
||||
-- echo '' #信噪比 SINR rv["sinr"]
|
||||
-- echo '' #连接状态监控 rv["netmode"]
|
||||
rv["mode"] = file:read("*line")
|
||||
rv["csq"] = file:read("*line")
|
||||
rv["per"] = file:read("*line")
|
||||
rv["rssi"] = file:read("*line")
|
||||
rv["ecio"] = file:read("*line")
|
||||
rv["ecio1"] = file:read("*line")
|
||||
rv["rscp"] = file:read("*line")
|
||||
rv["rscp1"] = file:read("*line")
|
||||
rv["sinr"] = file:read("*line")
|
||||
rv["netmode"] = file:read("*line")
|
||||
file:read("*line")
|
||||
|
||||
rssi = rv["rssi"]
|
||||
ecio = rv["ecio"]
|
||||
rscp = rv["rscp"]
|
||||
ecio1 = rv["ecio1"]
|
||||
rscp1 = rv["rscp1"]
|
||||
if ecio == nil then
|
||||
ecio = "-"
|
||||
end
|
||||
if ecio1 == nil then
|
||||
ecio1 = "-"
|
||||
end
|
||||
if rscp == nil then
|
||||
rscp = "-"
|
||||
end
|
||||
if rscp1 == nil then
|
||||
rscp1 = "-"
|
||||
end
|
||||
|
||||
if ecio ~= "-" then
|
||||
rv["ecio"] = ecio .. " dB"
|
||||
end
|
||||
if rscp ~= "-" then
|
||||
rv["rscp"] = rscp .. " dBm"
|
||||
end
|
||||
if ecio1 ~= " " then
|
||||
rv["ecio1"] = " (" .. ecio1 .. " dB)"
|
||||
end
|
||||
if rscp1 ~= " " then
|
||||
rv["rscp1"] = " (" .. rscp1 .. " dBm)"
|
||||
end
|
||||
|
||||
rv["mcc"] = file:read("*line")
|
||||
rv["mnc"] = file:read("*line")
|
||||
rv["rnc"] = file:read("*line")
|
||||
rv["rncn"] = file:read("*line")
|
||||
rv["lac"] = file:read("*line")
|
||||
rv["lacn"] = file:read("*line")
|
||||
rv["cid"] = file:read("*line")
|
||||
rv["cidn"] = file:read("*line")
|
||||
rv["lband"] = file:read("*line")
|
||||
rv["channel"] = file:read("*line")
|
||||
rv["pci"] = file:read("*line")
|
||||
|
||||
rv["date"] = file:read("*line")
|
||||
|
||||
-- rv["phonen"] = file:read("*line")
|
||||
--rv["host"] = "0"
|
||||
|
||||
-- rv["simerr"] = "0"
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
|
||||
|
||||
-- rv["down"] = file:read("*line")
|
||||
-- rv["up"] = file:read("*line")
|
||||
--
|
||||
--
|
||||
|
||||
--
|
||||
-- rv["cell"] = file:read("*line")
|
||||
-- rv["modtype"] = file:read("*line")
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
--
|
||||
|
||||
|
||||
-- rv["lat"] = "-"
|
||||
-- rv["long"] = "-"
|
||||
|
||||
|
||||
|
||||
rv["crate"] = translate("快速(每10秒更新一次)")
|
||||
luci.http.prepare_content("application/json")
|
||||
luci.http.write_json(rv)
|
||||
end
|
||||
144
package/fish/luci-app-cpe/luasrc/model/cbi/cpe/modem.lua
Normal file
144
package/fish/luci-app-cpe/luasrc/model/cbi/cpe/modem.lua
Normal file
@ -0,0 +1,144 @@
|
||||
local m, section, m2, s2
|
||||
|
||||
m = Map("modem", translate("Mobile Network"))
|
||||
m.description = translate("Modem Server For OpenWrt")
|
||||
|
||||
|
||||
-------------------------------Fibocom Wireless Inc. FM650 Module----------------------------------
|
||||
if (string.gsub(luci.sys.exec('lsusb |grep "ID 2cb7:0a05 " | wc -l'),"%s+","")=="1") then
|
||||
section = m:section(TypedSection, "ndis", translate("FMFM650-CN Settings"), translate("[1]Automatic start upon startup: Check</br>[2] FMFMFM650-CN module default ECM (36) mode. If not, please modify it, otherwise dialing cannot proceed normally</br>"))
|
||||
section.anonymous = true
|
||||
section.addremove = false
|
||||
enable = section:option(Flag, "enabled", translate("Enable"))
|
||||
enable.rmempty = false
|
||||
else
|
||||
section = m:section(TypedSection, "ndis", translate("SIM Settings"), translate("Automatic operation upon startup \r\n ooo"))
|
||||
section.anonymous = true
|
||||
section.addremove = false
|
||||
section:tab("general", translate("General Setup"))
|
||||
section:tab("advanced", translate("Advanced Settings"))
|
||||
|
||||
|
||||
enable = section:taboption("general", Flag, "enabled", translate("Enable"))
|
||||
enable.rmempty = false
|
||||
|
||||
device = section:taboption("general",Value, "device", translate("Modem device"))
|
||||
device.rmempty = false
|
||||
local device_suggestions = nixio.fs.glob("/dev/cdc-wdm*")
|
||||
if device_suggestions then
|
||||
local node
|
||||
for node in device_suggestions do
|
||||
device:value(node)
|
||||
end
|
||||
end
|
||||
apn = section:taboption("general", Value, "apn", translate("APN"))
|
||||
username = section:taboption("general", Value, "username", translate("PAP/CHAP Username"))
|
||||
password = section:taboption("general", Value, "password", translate("PAP/CHAP Password"))
|
||||
password.password = true
|
||||
pincode = section:taboption("general", Value, "pincode", translate("PIN Code"))
|
||||
auth = section:taboption("general", Value, "auth", translate("Authentication Type"))
|
||||
auth.rmempty = true
|
||||
auth:value("", translate("-- Please choose --"))
|
||||
auth:value("both", "PAP/CHAP (both)")
|
||||
auth:value("pap", "PAP")
|
||||
auth:value("chap", "CHAP")
|
||||
auth:value("none", "NONE")
|
||||
tool = section:taboption("general", Value, "tool", translate("Tools"))
|
||||
tool:value("quectel-CM", "quectel-CM")
|
||||
tool.rmempty = true
|
||||
PdpType= section:taboption("general", Value, "pdptype", translate("PdpType"))
|
||||
PdpType:value("IPV4", "IPV4")
|
||||
PdpType:value("IPV6", "IPV6")
|
||||
PdpType:value("IPV4V6", "IPV4V6")
|
||||
PdpType.rmempty = true
|
||||
|
||||
|
||||
---------------------------advanced------------------------------
|
||||
bandlist = section:taboption("advanced", ListValue, "bandlist", translate("Lock Band List"))
|
||||
-- if (string.gsub(luci.sys.exec('uci get system.@system[0].modem |grep lte |wc -l'),"%s+","")=="1") then
|
||||
-- bandlist.default = "0"
|
||||
-- bandlist:value("1", "LTE BAND1")
|
||||
-- bandlist:value("2", "LTE BAND2")
|
||||
-- bandlist:value("3", "LTE BAND3")
|
||||
-- bandlist:value("4", "LTE BAND4")
|
||||
-- bandlist:value("5", "LTE BAND5")
|
||||
-- bandlist:value("7", "LTE BAND7")
|
||||
-- bandlist:value("8", "LTE BAND8")
|
||||
-- bandlist:value("20", "LTE BAND20")
|
||||
-- bandlist:value("38", "LTE BAND38")
|
||||
-- bandlist:value("40", "LTE BAND40")
|
||||
-- bandlist:value("41", "LTE BAND41")
|
||||
-- bandlist:value("28", "LTE BAND28")
|
||||
-- bandlist:value("A", "AUTO")
|
||||
-- end
|
||||
bandlist:value("0", translate("Disable"))
|
||||
|
||||
servertype = section:taboption("advanced", ListValue, "servertype", translate("Server Type"))
|
||||
servertype.default = "0"
|
||||
|
||||
--if (string.gsub(luci.sys.exec('uci get system.@system[0].modem |grep nr5g |wc -l'),"%s+","")=="1") then
|
||||
servertype:value("1", "5G Only")
|
||||
servertype:value("5", "4G/5G Only")
|
||||
--end
|
||||
servertype:value("2", "4G Only")
|
||||
servertype:value("3", "3G Only")
|
||||
servertype:value("4", "2G Only")
|
||||
servertype:value("0", "AUTO")
|
||||
|
||||
|
||||
-- s1 = m:section(TypedSection, "ndis", translate("AT Port Settings"),translate("Set tyyUSB port"))
|
||||
-- s1.anonymous = true
|
||||
-- s1.addremove = false
|
||||
-- tyyusb= s1:option(Value, "tyyusb", translate("tyyUSB port"))
|
||||
-- tyyusb.default = "2"
|
||||
-- tyyusb:value("0", "0")
|
||||
-- tyyusb:value("1", "1")
|
||||
-- tyyusb:value("2", "2")
|
||||
-- tyyusb:value("3", "3")
|
||||
-- tyyusb:value("4", "4")
|
||||
-- tyyusb.rmempty=false
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
s2 = m:section(TypedSection, "ndis", translate("Network Diagnostics"),translate("Network exception handling: \
|
||||
check the network connection in a loop for 5 seconds. If the Ping IP address is not successful, After the network \
|
||||
exceeds the abnormal number, restart and search the registered network again."))
|
||||
s2.anonymous = true
|
||||
s2.addremove = false
|
||||
|
||||
en = s2:option(Flag, "en", translate("Enable"))
|
||||
en.rmempty = false
|
||||
|
||||
|
||||
|
||||
ipaddress= s2:option(Value, "ipaddress", translate("Ping IP address"))
|
||||
ipaddress.default = "114.114.114.114"
|
||||
ipaddress.rmempty=false
|
||||
|
||||
an = s2:option(Value, "an", translate("Abnormal number"))
|
||||
an.default = "15"
|
||||
an:value("3", "3")
|
||||
an:value("5", "5")
|
||||
an:value("10", "10")
|
||||
an:value("15", "15")
|
||||
an:value("20", "20")
|
||||
an:value("25", "25")
|
||||
an:value("30", "30")
|
||||
an.rmempty=false
|
||||
|
||||
|
||||
|
||||
local apply = luci.http.formvalue("cbi.apply")
|
||||
if apply then
|
||||
-- io.popen("/etc/init.d/modeminit restart")
|
||||
io.popen("/etc/init.d/modem restart")
|
||||
end
|
||||
|
||||
return m,m2
|
||||
152
package/fish/luci-app-cpe/luasrc/view/cpe/at.htm
Normal file
152
package/fish/luci-app-cpe/luasrc/view/cpe/at.htm
Normal file
@ -0,0 +1,152 @@
|
||||
<%+header%>
|
||||
<%
|
||||
local sys = require "luci.sys"
|
||||
local utl = require "luci.util"
|
||||
local fs = require "nixio.fs"
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local s = uci:get("custom", "bandlock", "enabled")
|
||||
local a = uci:get("custom", "atcmd", "enabled")
|
||||
|
||||
local multilock = uci:get("custom", "multiuser", "multi") or "0"
|
||||
local rootlock = uci:get("custom", "multiuser", "root") or "0"
|
||||
nomulti=1
|
||||
if (multilock == "0") or (multilock == "1" and rootlock == "1") then
|
||||
nosms = 1
|
||||
if a == "1" then
|
||||
nosms = 0
|
||||
end
|
||||
else
|
||||
nosms = 1
|
||||
nomulti = 0
|
||||
end
|
||||
block = 1
|
||||
if s == "1" then
|
||||
block = 0
|
||||
end
|
||||
|
||||
function showicon(lck)
|
||||
end
|
||||
|
||||
-%>
|
||||
<script type="text/javascript" src="<%=resource%>/xhr.js"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
|
||||
function sendcmd(event)
|
||||
{
|
||||
|
||||
var v = document.getElementById("drop1").value;
|
||||
var s = document.getElementById("atcmd").value;
|
||||
var r =document.getElementById("attxt").value;
|
||||
if ( s.length == 0 )
|
||||
{
|
||||
|
||||
document.getElementById("attxt").value= '<%:请输入AT命令!%>\r' + r;
|
||||
return false;
|
||||
}
|
||||
XHR.get('<%=luci.dispatcher.build_url("admin", "modem", "send_atcmd")%>',
|
||||
{ set: s , p: v},
|
||||
function(x, rv)
|
||||
{
|
||||
var pd = rv.result;
|
||||
document.getElementById("attxt").value=pd + r;
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
function sendclean(event)
|
||||
{
|
||||
document.getElementById("attxt").value='';
|
||||
}
|
||||
|
||||
|
||||
//]]></script>
|
||||
|
||||
|
||||
<div class="cbi-map" id="cbi-misc">
|
||||
<h2><a id="content" name="content"><%:AT命令工具%></a></h2>
|
||||
<div class="cbi-map-descr"><%:AT命令工具%></div>
|
||||
<head>
|
||||
<style>
|
||||
input {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
#popup {
|
||||
width:560px;
|
||||
height:190px;
|
||||
padding:20px;
|
||||
background-color:gainsboro;
|
||||
border-style : solid;
|
||||
position:fixed;
|
||||
top : 40%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
display:none;
|
||||
}
|
||||
textarea{
|
||||
background:#373737;
|
||||
border:none;
|
||||
color:#FFF;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<fieldset class="cbi-section" id="cbi-term">
|
||||
<legend><%:AT命令终端%></legend>
|
||||
<div id="popup">
|
||||
<table width="500" border="0">
|
||||
<tr>
|
||||
<td width="50px"><div><%:Enter Password to Unlock Full Terminal%></div></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td width="200px"><input id="pass" type="password"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="image" src="<%=showicon(0)%>" style="width:48px;height:48px;" onclick="return done()" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<table width="700" border="0" id="droptxt">
|
||||
<tr>
|
||||
<td width="10%"><div align="right"><%:模块端口 : %></div></td>
|
||||
<td width="15%">
|
||||
<select style="width:200px" name="atdrop" id="drop1">
|
||||
<option value="0">ttyUSB0</option>
|
||||
<option value="1">ttyUSB1</option>
|
||||
<option value="2" selected>ttyUSB2</option>
|
||||
<option value="3">ttyUSB3</option>
|
||||
<option value="4">ttyUSB4</option>
|
||||
<option value="5">ttyUSB5</option>
|
||||
<option value="6">ttyUSB6</option>
|
||||
<option value="7">ttyUSB7</option>
|
||||
<option value="8">ttyUSB8</option>
|
||||
<option value="9">ttyUSB9</option>
|
||||
<option value="10">ttyUSB10</option>
|
||||
<option value="11">ttyUSB11</option>
|
||||
<option value="12">ttyUSB12</option>
|
||||
</select>
|
||||
</td>
|
||||
<td width="10%"><div align="right"><%:AT命令 : %></div></td>
|
||||
<td width="15%"><input style="visibility:visible;width: 500px;maxlength="200" type="text" name="atcmdlck" id="atcmd" class="cbi-input-text"></input></td>
|
||||
<td width="10%">
|
||||
<input style="visibility:visible" type="submit" id="sendat" class="cbi-button cbi-button-apply" value="<%:发送%>" onclick="return sendcmd()" />
|
||||
<input style="visibility:visible" type="submit" id="sendclean" class="cbi-button cbi-button-reset" value="<%:清除%>" onclick="return sendclean()" />
|
||||
</td>
|
||||
<td width="47%"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<textarea readonly="readonly" name="attxt" id="attxt" rows="50" style="width: 100%;" maxlength="160"></textarea>
|
||||
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
||||
296
package/fish/luci-app-cpe/luasrc/view/cpe/net_status.htm
Normal file
296
package/fish/luci-app-cpe/luasrc/view/cpe/net_status.htm
Normal file
@ -0,0 +1,296 @@
|
||||
<%+header%>
|
||||
<%
|
||||
local fs = require "nixio.fs"
|
||||
nosms = 1
|
||||
if not fs.stat("/etc/nosim") then
|
||||
nosms = 0
|
||||
end
|
||||
havegps = 0
|
||||
if fs.stat("/etc/havegps") then
|
||||
havegps = 1
|
||||
end
|
||||
-%>
|
||||
<style>g {color:grey; font-size:75%; vertical-align: super;}</style>
|
||||
<script type="text/javascript" src="<%=resource%>/xhr.js?v=git-23.159.15540-7154b89"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
|
||||
modemtype=0;
|
||||
cell=0;
|
||||
portx="-";
|
||||
phonenx = "";
|
||||
hided = 0;
|
||||
|
||||
XHR.poll(2, '<%=luci.dispatcher.build_url("admin", "modem", "get_csq")%>', null,
|
||||
function(x, rv)
|
||||
{
|
||||
document.getElementById('date').innerHTML=rv.date;
|
||||
|
||||
document.getElementById('csq').innerHTML=rv.csq;
|
||||
document.getElementById('per').innerHTML=rv.per;
|
||||
document.getElementById('rssi').innerHTML=rv.rssi;
|
||||
document.getElementById('modem').innerHTML=rv.modem;
|
||||
document.getElementById('cops').innerHTML=rv.cops;
|
||||
document.getElementById('mode').innerHTML=rv.mode;
|
||||
document.getElementById('lac').innerHTML=rv.lac;
|
||||
document.getElementById('cid').innerHTML=rv.cid;
|
||||
document.getElementById('lacn').innerHTML=rv.lacn;
|
||||
document.getElementById('cidn').innerHTML=rv.cidn;
|
||||
document.getElementById('mcc').innerHTML=rv.mcc;
|
||||
document.getElementById('mnc').innerHTML=rv.mnc;
|
||||
document.getElementById('rnc').innerHTML=rv.rnc;
|
||||
document.getElementById('rncn').innerHTML=rv.rncn;
|
||||
document.getElementById('down').innerHTML=rv.down;
|
||||
document.getElementById('up').innerHTML=rv.up;
|
||||
document.getElementById('ecio').innerHTML=rv.ecio;
|
||||
document.getElementById('rscp').innerHTML=rv.rscp;
|
||||
document.getElementById('ecio1').innerHTML=rv.ecio1;
|
||||
document.getElementById('rscp1').innerHTML=rv.rscp1;
|
||||
document.getElementById('conntype').innerHTML=rv.conntype;
|
||||
document.getElementById('chan').innerHTML=rv.channel;
|
||||
document.getElementById('lband').innerHTML=rv.lband;
|
||||
document.getElementById('conmon').innerHTML=rv.netmode;
|
||||
document.getElementById('tempur').innerHTML=rv.tempur;
|
||||
|
||||
document.getElementById('pci').innerHTML=rv.pci;
|
||||
document.getElementById('sinr').innerHTML=rv.sinr;
|
||||
|
||||
document.getElementById('imei').innerHTML=rv.imei;
|
||||
document.getElementById('imsi').innerHTML=rv.imsi;
|
||||
document.getElementById('iccid').innerHTML=rv.iccid;
|
||||
document.getElementById('phone').innerHTML=rv.phone;
|
||||
|
||||
|
||||
<% if havegps == 1 then %>
|
||||
document.getElementById('lat').innerHTML=rv.lat;
|
||||
document.getElementById('long').innerHTML=rv.long;
|
||||
<% end %>
|
||||
// document.getElementById('idvp').innerHTML=rv.modid;
|
||||
// document.getElementById('proto').innerHTML=rv.proto;
|
||||
// document.getElementById('port').innerHTML=rv.port;
|
||||
|
||||
// document.getElementById('crate').innerHTML=rv.crate;
|
||||
// if (phonenx == "")
|
||||
// {
|
||||
// document.getElementById('phone').value=rv.phone;
|
||||
// document.getElementById('phonen').value=rv.phonen;
|
||||
// phonenx = document.getElementById('phone').value;
|
||||
// document.getElementById("phone").disabled=false;
|
||||
// document.getElementById("phonen").disabled=false;
|
||||
// document.getElementById("pho").disabled=false;
|
||||
// }
|
||||
|
||||
// if (rv.phone == "-")
|
||||
// {
|
||||
// document.getElementById('phone').value="-";
|
||||
// document.getElementById('phonen').value="-";
|
||||
// document.getElementById("pho").disabled=true;
|
||||
// document.getElementById("phone").disabled=true;
|
||||
// document.getElementById("phonen").disabled=true;
|
||||
// phonenx = "";
|
||||
// }
|
||||
|
||||
// simerr = rv.simerr;
|
||||
// if (simerr == "0")
|
||||
// {
|
||||
// document.getElementById("simwarn").style.display="none";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// document.getElementById("simwarn").style.display="block";
|
||||
// document.getElementById("simsg").style.color = "red";
|
||||
// if (simerr == "1")
|
||||
// {
|
||||
// document.getElementById("simsg").innerHTML = "<%:SIM卡已锁定,个人资料中未输入SIM Pin!!%>";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (simerr == "2")
|
||||
// {
|
||||
// document.getElementById("simsg").innerHTML = "<%:解锁SIM卡的Pin不正确%>";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (simerr == "3")
|
||||
// {
|
||||
// document.getElementById("simsg").innerHTML = "<%:无效SIM卡%>";
|
||||
// } else
|
||||
// {
|
||||
// document.getElementById("simsg").innerHTML = "<%:SIM卡未锁定.错误的SIM卡%>";
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
// reslt=rv.result
|
||||
|
||||
// portx=rv.port
|
||||
// if (portx == "-" )
|
||||
// {
|
||||
// document.getElementById('inc1').style.display="none";
|
||||
// document.getElementById('dec1').style.display="none";
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// document.getElementById('inc1').style.display="block";
|
||||
// document.getElementById('dec1').style.display="block";
|
||||
// }
|
||||
|
||||
// host = rv.host;
|
||||
// if(host == "1")
|
||||
// {
|
||||
// document.getElementById("pho").disabled=true;
|
||||
// }
|
||||
}
|
||||
);
|
||||
|
||||
function clear_data()
|
||||
{
|
||||
document.getElementById('port').innerHTML="<%:Changing Port%>";
|
||||
document.getElementById('csq').innerHTML="-";
|
||||
document.getElementById('per').innerHTML="-";
|
||||
document.getElementById('rssi').innerHTML="-";
|
||||
document.getElementById('modem').innerHTML="-";
|
||||
document.getElementById('cops').innerHTML="-";
|
||||
document.getElementById('mode').innerHTML="-";
|
||||
document.getElementById('lac').innerHTML="-";
|
||||
document.getElementById('cid').innerHTML="-";
|
||||
document.getElementById('lacn').innerHTML="-";
|
||||
document.getElementById('cidn').innerHTML="-";
|
||||
document.getElementById('mcc').innerHTML="-";
|
||||
document.getElementById('mnc').innerHTML="-";
|
||||
document.getElementById('rnc').innerHTML="-";
|
||||
document.getElementById('rncn').innerHTML="-";
|
||||
document.getElementById('down').innerHTML="-";
|
||||
document.getElementById('up').innerHTML="-";
|
||||
document.getElementById('ecio').innerHTML="-";
|
||||
document.getElementById('rscp').innerHTML="-";
|
||||
document.getElementById('ecio1').innerHTML="-";
|
||||
document.getElementById('rscp1').innerHTML="-";
|
||||
document.getElementById('netmode').innerHTML="-";
|
||||
document.getElementById('conntype').innerHTML=" ";
|
||||
document.getElementById('chan').innerHTML=" ";
|
||||
document.getElementById('conmon').innerHTML="-";
|
||||
document.getElementById('phone').value="-";
|
||||
|
||||
|
||||
document.getElementById('imei').innerHTML="-";
|
||||
document.getElementById('imsi').innerHTML="-";
|
||||
document.getElementById('iccid').innerHTML="-";
|
||||
document.getElementById('lband').innerHTML="-";
|
||||
document.getElementById('pci').innerHTML="-";
|
||||
<% if havegps == 1 then %>
|
||||
document.getElementById('lat').innerHTML="-";
|
||||
document.getElementById('long').innerHTML="-";
|
||||
<% end %>
|
||||
|
||||
// document.getElementById('idvp').innerHTML="-";
|
||||
// document.getElementById('phonen').value="-";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//]]></script>
|
||||
|
||||
|
||||
<div class="cbi-map" id="cbi-modem">
|
||||
<h2><a id="content" name="content"><%:信号状态/模块信息%></a></h2>
|
||||
<div class="cbi-map-descr">请注意该插件所有功能并无适配所有5G模块,不用妄想冷门模块插上就能用(有能力者自行适配)
|
||||
</div>
|
||||
|
||||
<fieldset class="cbi-section" id="simwarn" style="display:none;">
|
||||
<legend><%:SIM警告%></legend>
|
||||
<table width="550" border="0">
|
||||
<tr>
|
||||
<td width="10%"></td>
|
||||
<td width="60%"><div align="left" id="simsg" style="font-size:1.875em"><strong></strong></div></td>
|
||||
<td width="30%"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<fieldset class="cbi-section" id="cbi-mod">
|
||||
<legend><%:综合信息%></legend>
|
||||
<table width="100%" cellspacing="10">
|
||||
<tr><td width="20%"><%:模块 :%></td><td id="modem">-</td><td></td></tr>
|
||||
<tr><td width="20%"><%:制造商 :%></td><td id="conntype"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:温度 : %></td><td id="tempur"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:更新时间 : %></td><td id="date"></td><td></td></tr>
|
||||
<!-- <tr><td width="20%"><%:ID : %></td><td id="idvp"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:端口 : %></td><td id="port"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:协议 : %></td><td id="proto"></td><td></td></tr> -->
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<% if nosms == 0 then %>
|
||||
<% end %>
|
||||
|
||||
<fieldset class="cbi-section" id="cbi-msinfo">
|
||||
<legend><%:通信模块/SIM卡信息%></legend>
|
||||
<table width="100%" cellspacing="10">
|
||||
<tr><td width="20%"><%:运营商 : %></td><td id="cops"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:IMEI :%></td><td id="imei"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:IMSI : %></td><td id="imsi"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:ICCID : %></td><td id="iccid"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:SIM卡号码 : %></td><td id="phone"></td><td></td></tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<fieldset class="cbi-section" id="cbi-sig">
|
||||
<legend><%:信号状态%></legend>
|
||||
<table width="100%" cellspacing="10">
|
||||
<tr><td width="20%"><%:蜂窝网络类型 :%></td><td id="mode"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:CSQ : %></td><td id="csq"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:信号强度 : %></td><td id="per"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:信号接收强度 RSSI : %></td><td id="rssi"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:参考信号接收质量 RSRQ : %></td><td><ul><span id="ecio" class="r"></span><span id="ecio1" class="r"></span></ul></td><td></td></tr>
|
||||
<tr><td width="20%"><%:参考信号接收功率 RSRP : %></td><td><ul><span id="rscp" class="r"></span><span id="rscp1" class="r"></span></ul></td><td></td></tr>
|
||||
<tr><td width="20%"><%:信噪比 SINR : %></td><td id="sinr"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:连接状态监控 : %></td><td id="conmon"></td><td></td></tr>
|
||||
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
<fieldset class="cbi-section" id="cbi-sig">
|
||||
<legend><%:基站信息%></legend>
|
||||
<table width="100%" cellspacing="10">
|
||||
<tr><td width="20%"><%:MCC / MNC :%></td><td id="mcc"></td><td id="mnc"></td></tr>
|
||||
<tr><td width="20%"><%:eNB ID : %></td><td><ul><span id="rnc" class="r"></span><span id="rncn" class="r"></span></ul></td><td></td></tr>
|
||||
<tr><td width="20%"><%:TAC : %></td><td><ul><span id="lac" class="r"></span><span id="lacn" class="r"></span></ul></td><td></td></tr>
|
||||
<tr><td width="20%"><%:Cell ID : %></td><td><ul><span id="cid" class="r"></span><span id="cidn" class="r"></span></ul></td><td></td></tr>
|
||||
<tr><td width="20%"><%:频段 Band : %></td><td id="lband"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:频点 Channel : %></td><td id="chan"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:物理小区标识 PCI : %></td><td id="pci"></td><td></td></tr>
|
||||
<tr><td width="20%"><%:最大Qos级别 Maximum Qos : %></td><td><ul><span id="down" class="r"></span><span id="up" class="r"></span></ul></td><td></td></tr>
|
||||
|
||||
</table>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<% if havegps == 1 then %>
|
||||
<fieldset class="cbi-section" id="cbi-gps">
|
||||
<legend><%:GPS 定位%></legend>
|
||||
<table width="550" border="0">
|
||||
<tr>
|
||||
<td width="30%"><div align="right"><%:纬度 :%></div></td>
|
||||
<td><ul id="lat"></ul></td>
|
||||
<td width="1%"> </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><div align="right"><%:经度 :%></div></td>
|
||||
<td><ul id="long"></ul></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</fieldset>
|
||||
<% end %>
|
||||
|
||||
|
||||
</div>
|
||||
<%+footer%>
|
||||
|
||||
73
package/fish/luci-app-cpe/po/zh-cn/modem.po
Normal file
73
package/fish/luci-app-cpe/po/zh-cn/modem.po
Normal file
@ -0,0 +1,73 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
|
||||
msgid "Mobile Network"
|
||||
msgstr "模块设置"
|
||||
|
||||
|
||||
msgid "Automatic operation upon startup ooo"
|
||||
msgstr "开机自动启动:勾选"
|
||||
|
||||
msgid "Tools"
|
||||
msgstr "拨号工具"
|
||||
|
||||
msgid "PAP/CHAP Username"
|
||||
msgstr "PAP/CHAP 用户"
|
||||
|
||||
msgid "PAP/CHAP Password"
|
||||
msgstr "PAP/CHAP 密码"
|
||||
|
||||
|
||||
msgid "Modem Server For OpenWrt"
|
||||
msgstr "4G/5G模块管理"
|
||||
|
||||
|
||||
msgid "SIM Settings"
|
||||
msgstr "SIM 配置 (联通ANP:3gnet) (电信APN:ctnet) (移动APN:cmnet) (广电APN:cbnet) "
|
||||
|
||||
msgid "PdpType"
|
||||
msgstr "IP获取方式"
|
||||
|
||||
msgid "AT Port Settings"
|
||||
msgstr "AT 模块配置"
|
||||
|
||||
msgid "Set tyyUSB port"
|
||||
msgstr "AT 模块端口配置 (全模块指定端口)"
|
||||
|
||||
msgid "tyyUSB port"
|
||||
msgstr "ttyUSB 配置ID"
|
||||
|
||||
msgid "Network Diagnostics"
|
||||
msgstr "网络诊断"
|
||||
|
||||
|
||||
msgid "Network Diagnostics"
|
||||
msgstr "网络诊断"
|
||||
|
||||
|
||||
msgid "Network exception handling: check the network connection in a loop for 5 seconds. If the Ping IP address is not successful, After the network exceeds the abnormal number, restart and search the registered network again."
|
||||
msgstr "网络异常处理:循环检查网络连接5秒。如果Ping IP地址不成功,则在网络超过异常数量后,重新启动并搜索已注册的网络。"
|
||||
|
||||
msgid "Ping IP address"
|
||||
msgstr "Ping IP地址"
|
||||
|
||||
msgid "Abnormal number"
|
||||
msgstr "异常次数"
|
||||
|
||||
msgid "Lock Band List"
|
||||
msgstr "锁定频段列表"
|
||||
|
||||
msgid "Server Type"
|
||||
msgstr "服务类型"
|
||||
|
||||
msgid "FMFM650-CN Settings"
|
||||
msgstr "FMFM650-CN 设置"
|
||||
|
||||
msgid "[1]Automatic start upon startup: Check</br>[2] FMFMFM650-CN module default ECM (36) mode. If not, please modify it, otherwise dialing cannot proceed normally</br>"
|
||||
msgstr "【1】 开机自动启动:勾选 </br> 【2】 FMFM650-CN 模块默认 ECM (36)模式如果不是请修改 否则不能正常进行拨号 </br>"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
1
package/fish/luci-app-cpe/po/zh_Hans
Normal file
1
package/fish/luci-app-cpe/po/zh_Hans
Normal file
@ -0,0 +1 @@
|
||||
zh-cn
|
||||
12
package/fish/luci-app-cpe/root/etc/config/modem
Normal file
12
package/fish/luci-app-cpe/root/etc/config/modem
Normal file
@ -0,0 +1,12 @@
|
||||
config ndis
|
||||
option enabled '0'
|
||||
option bandlist '0'
|
||||
option servertype '0'
|
||||
option ipaddress '114.114.114.114'
|
||||
option en '0'
|
||||
option an '5'
|
||||
option model 'nr5g'
|
||||
option tyyusb '2'
|
||||
option tool 'quectel-CM'
|
||||
option device '/dev/cdc-wdm0'
|
||||
option pdptype 'IPV4V6'
|
||||
7
package/fish/luci-app-cpe/root/etc/init.d/cpeinit
Normal file
7
package/fish/luci-app-cpe/root/etc/init.d/cpeinit
Normal file
@ -0,0 +1,7 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
|
||||
start() {
|
||||
/bin/sh /usr/share/cpe/rssi &
|
||||
}
|
||||
103
package/fish/luci-app-cpe/root/etc/init.d/modem
Normal file
103
package/fish/luci-app-cpe/root/etc/init.d/modem
Normal file
@ -0,0 +1,103 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
# Copyright (C) 2006-2014 OpenWrt.org
|
||||
|
||||
START=16
|
||||
STOP=16
|
||||
USE_PROCD=1
|
||||
#使用procd启动
|
||||
|
||||
|
||||
# start启动服务
|
||||
# stop停止服务
|
||||
# restart重新启动服务
|
||||
# reload重新加载配置文件(如果服务未实现重新加载,则重新启动)
|
||||
# enable启用服务自动启动
|
||||
# disable禁用服务自动启动
|
||||
# enabled检查服务是否在启动时启动
|
||||
# 正在运行检查服务是否正在运行
|
||||
# status服务状态
|
||||
# trace从系统调用跟踪开始
|
||||
|
||||
runModem()
|
||||
{
|
||||
local enabled
|
||||
config_get_bool enabled $1 enabled
|
||||
echo "run runModem" >> /tmp/log4g
|
||||
if [ "$enabled" = "1" ]; then
|
||||
|
||||
|
||||
local user
|
||||
local password
|
||||
local apn
|
||||
local auth
|
||||
local pincode
|
||||
local device
|
||||
local tool
|
||||
local pdptype
|
||||
|
||||
|
||||
config_get user $1 user
|
||||
config_get password $1 password
|
||||
config_get apn $1 apn
|
||||
config_get auth $1 auth
|
||||
config_get pincode $1 pincode
|
||||
config_get device $1 device
|
||||
config_get tool $1 tool
|
||||
config_get pdptype $1 pdptype
|
||||
config_get tty $1 tty
|
||||
config_get atcmd $1 atcmd
|
||||
|
||||
if [ "$pdptype" = "IPV4V6" ]; then
|
||||
pdptype='-4 -6'
|
||||
elif [ "$pdptype" = "IPV6" ]; then
|
||||
pdptype='-6'
|
||||
else
|
||||
pdptype=''
|
||||
fi
|
||||
|
||||
devname="$(basename "$device")"
|
||||
devpath="$(readlink -f /sys/class/usbmisc/$devname/device/)"
|
||||
ifname="$( ls "$devpath"/net )"
|
||||
|
||||
|
||||
procd_open_instance
|
||||
#创建一个实例, 在procd看来一个应用程序可以多个实\E4\BE?
|
||||
#ubus call service list 可以查看实例
|
||||
procd_set_param command $tool -i $ifname -s $apn $pdptype
|
||||
if [ "$password" != "" ];then
|
||||
procd_append_param command $user $password $auth
|
||||
fi
|
||||
if [ "$pincode" != "" ]; then
|
||||
procd_append_param command -p $pincode
|
||||
fi
|
||||
# procd_append_param command -f /tmp/4g.log
|
||||
procd_set_param respawn
|
||||
echo "quectel-CM has started."
|
||||
procd_close_instance
|
||||
#关闭实例
|
||||
fi
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
service_triggers()
|
||||
{
|
||||
procd_add_reload_trigger "modem"
|
||||
}
|
||||
|
||||
start_service() {
|
||||
config_load modem
|
||||
config_foreach runModem ndis
|
||||
}
|
||||
|
||||
stop_service()
|
||||
{
|
||||
echo "runModem stop" >> /tmp/log4g
|
||||
killall quectel-CM
|
||||
echo "quectel-CM has stoped."
|
||||
}
|
||||
|
||||
11
package/fish/luci-app-cpe/root/etc/uci-defaults/luci-modem
Normal file
11
package/fish/luci-app-cpe/root/etc/uci-defaults/luci-modem
Normal file
@ -0,0 +1,11 @@
|
||||
#!/bin/sh
|
||||
|
||||
uci -q batch <<-EOF >/dev/null
|
||||
delete ucitrack.@modem[-1]
|
||||
add ucitrack modem
|
||||
set ucitrack.@modem[-1].init=modem
|
||||
commit ucitrack
|
||||
EOF
|
||||
|
||||
rm -f /tmp/luci-indexcache
|
||||
exit 0
|
||||
19
package/fish/luci-app-cpe/root/usr/bin/bmask128
Normal file
19
package/fish/luci-app-cpe/root/usr/bin/bmask128
Normal file
@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
printf "Band 128-bit bandmask\n"
|
||||
LBAND=1
|
||||
BBAND=1
|
||||
while [ $LBAND -le 48 ]
|
||||
do
|
||||
printf "%-6s%016X%016X\n" "$LBAND" "0" "$BBAND"
|
||||
LBAND=$(( $LBAND + 1 ))
|
||||
BBAND=$(( $BBAND * 2 ))
|
||||
done
|
||||
LBAND=65
|
||||
BBAND=1
|
||||
while [ $LBAND -le 85 ]
|
||||
do
|
||||
printf "%-6s%016X%016X\n" "$LBAND" "$BBAND" "0"
|
||||
LBAND=$(( $LBAND + 1 ))
|
||||
BBAND=$(( $BBAND * 2 ))
|
||||
done
|
||||
317
package/fish/luci-app-cpe/root/usr/bin/chan2band.sh
Normal file
317
package/fish/luci-app-cpe/root/usr/bin/chan2band.sh
Normal file
@ -0,0 +1,317 @@
|
||||
#!/bin/sh
|
||||
CHAN=$1
|
||||
CHAN=$(echo "$CHAN" | grep -o "[0-9]*")
|
||||
|
||||
decode_lte() {
|
||||
if [ $CHAN -lt 600 ]; then
|
||||
BAND="B1"
|
||||
elif [ $CHAN -lt 1200 ]; then
|
||||
BAND="B2"
|
||||
elif [ $CHAN -lt 1950 ]; then
|
||||
BAND="B3"
|
||||
elif [ $CHAN -lt 2400 ]; then
|
||||
BAND="B4"
|
||||
elif [ $CHAN -lt 2650 ]; then
|
||||
BAND="B5"
|
||||
elif [ $CHAN -lt 2750 ]; then
|
||||
BAND="B6"
|
||||
elif [ $CHAN -lt 3450 ]; then
|
||||
BAND="B7"
|
||||
elif [ $CHAN -lt 3800 ]; then
|
||||
BAND="B8"
|
||||
elif [ $CHAN -lt 4150 ]; then
|
||||
BAND="B9"
|
||||
elif [ $CHAN -lt 4750 ]; then
|
||||
BAND="B10"
|
||||
elif [ $CHAN -lt 4950 ]; then
|
||||
BAND="B11"
|
||||
elif [ $CHAN -lt 5010 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 5180 ]; then
|
||||
BAND="B12"
|
||||
elif [ $CHAN -lt 5280 ]; then
|
||||
BAND="B13"
|
||||
elif [ $CHAN -lt 5380 ]; then
|
||||
BAND="B14"
|
||||
elif [ $CHAN -lt 5730 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 5850 ]; then
|
||||
BAND="B17"
|
||||
elif [ $CHAN -lt 6000 ]; then
|
||||
BAND="B18"
|
||||
elif [ $CHAN -lt 6150 ]; then
|
||||
BAND="B19"
|
||||
elif [ $CHAN -lt 6450 ]; then
|
||||
BAND="B20"
|
||||
elif [ $CHAN -lt 6600 ]; then
|
||||
BAND="B21"
|
||||
elif [ $CHAN -lt 7400 ]; then
|
||||
BAND="B22"
|
||||
elif [ $CHAN -lt 7500 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 7700 ]; then
|
||||
BAND="B23"
|
||||
elif [ $CHAN -lt 8040 ]; then
|
||||
BAND="B24"
|
||||
elif [ $CHAN -lt 8690 ]; then
|
||||
BAND="B25"
|
||||
elif [ $CHAN -lt 9040 ]; then
|
||||
BAND="B26"
|
||||
elif [ $CHAN -lt 9210 ]; then
|
||||
BAND="B27"
|
||||
elif [ $CHAN -lt 9660 ]; then
|
||||
BAND="B28"
|
||||
elif [ $CHAN -lt 9770 ]; then
|
||||
BAND="B29"
|
||||
elif [ $CHAN -lt 9870 ]; then
|
||||
BAND="B30"
|
||||
elif [ $CHAN -lt 9920 ]; then
|
||||
BAND="B31"
|
||||
elif [ $CHAN -lt 10400 ]; then
|
||||
BAND="B32"
|
||||
elif [ $CHAN -lt 36000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 36200 ]; then
|
||||
BAND="B33"
|
||||
elif [ $CHAN -lt 36350 ]; then
|
||||
BAND="B34"
|
||||
elif [ $CHAN -lt 36950 ]; then
|
||||
BAND="B35"
|
||||
elif [ $CHAN -lt 37550 ]; then
|
||||
BAND="B36"
|
||||
elif [ $CHAN -lt 37750 ]; then
|
||||
BAND="B37"
|
||||
elif [ $CHAN -lt 38250 ]; then
|
||||
BAND="B38"
|
||||
elif [ $CHAN -lt 38650 ]; then
|
||||
BAND="B39"
|
||||
elif [ $CHAN -lt 39650 ]; then
|
||||
BAND="B40"
|
||||
elif [ $CHAN -lt 41590 ]; then
|
||||
BAND="B41"
|
||||
elif [ $CHAN -lt 43590 ]; then
|
||||
BAND="B42"
|
||||
elif [ $CHAN -lt 45590 ]; then
|
||||
BAND="B43"
|
||||
elif [ $CHAN -lt 46590 ]; then
|
||||
BAND="B44"
|
||||
elif [ $CHAN -lt 46790 ]; then
|
||||
BAND="B45"
|
||||
elif [ $CHAN -lt 54540 ]; then
|
||||
BAND="B46"
|
||||
elif [ $CHAN -lt 55240 ]; then
|
||||
BAND="B47"
|
||||
elif [ $CHAN -lt 56740 ]; then
|
||||
BAND="B48"
|
||||
elif [ $CHAN -lt 58240 ]; then
|
||||
BAND="B49"
|
||||
elif [ $CHAN -lt 59090 ]; then
|
||||
BAND="B50"
|
||||
elif [ $CHAN -lt 59140 ]; then
|
||||
BAND="B51"
|
||||
elif [ $CHAN -lt 60140 ]; then
|
||||
BAND="B52"
|
||||
elif [ $CHAN -lt 60255 ]; then
|
||||
BAND="B53"
|
||||
elif [ $CHAN -lt 65536 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 66436 ]; then
|
||||
BAND="B65"
|
||||
elif [ $CHAN -lt 67336 ]; then
|
||||
BAND="B66"
|
||||
elif [ $CHAN -lt 67536 ]; then
|
||||
BAND="B67"
|
||||
elif [ $CHAN -lt 67836 ]; then
|
||||
BAND="B68"
|
||||
elif [ $CHAN -lt 68336 ]; then
|
||||
BAND="B69"
|
||||
elif [ $CHAN -lt 68586 ]; then
|
||||
BAND="B70"
|
||||
elif [ $CHAN -lt 68936 ]; then
|
||||
BAND="B71"
|
||||
elif [ $CHAN -lt 68986 ]; then
|
||||
BAND="B72"
|
||||
elif [ $CHAN -lt 69036 ]; then
|
||||
BAND="B73"
|
||||
elif [ $CHAN -lt 69466 ]; then
|
||||
BAND="B74"
|
||||
elif [ $CHAN -lt 70316 ]; then
|
||||
BAND="B75"
|
||||
elif [ $CHAN -lt 70366 ]; then
|
||||
BAND="B76"
|
||||
elif [ $CHAN -lt 70546 ]; then
|
||||
BAND="B85"
|
||||
elif [ $CHAN -lt 70596 ]; then
|
||||
BAND="B87"
|
||||
elif [ $CHAN -lt 70646 ]; then
|
||||
BAND="B88"
|
||||
else
|
||||
BAND="-"
|
||||
fi
|
||||
}
|
||||
|
||||
decode_nr5g() {
|
||||
if [ $CHAN -lt 123400 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 130400 ]; then
|
||||
BAND="n71"
|
||||
elif [ $CHAN -lt 143400 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 145600 ]; then
|
||||
BAND="n29"
|
||||
elif [ $CHAN -eq 145600 ]; then
|
||||
BAND="n29|n85"
|
||||
elif [ $CHAN -lt 145800 ]; then
|
||||
BAND="n85"
|
||||
elif [ $CHAN -eq 145800 ]; then
|
||||
BAND="n12|n85"
|
||||
elif [ $CHAN -lt 147600 ]; then
|
||||
BAND="n12|n85"
|
||||
elif [ $CHAN -lt 149200 ]; then
|
||||
BAND="n12|n67|n85"
|
||||
elif [ $CHAN -eq 149200 ]; then
|
||||
BAND="n12|n13|n67|n85"
|
||||
elif [ $CHAN -le 151200 ]; then
|
||||
BAND="n13|n67"
|
||||
elif [ $CHAN -lt 151600 ]; then
|
||||
BAND="n67"
|
||||
elif [ $CHAN -eq 151600 ]; then
|
||||
BAND="n14|n28|n67"
|
||||
elif [ $CHAN -le 153600 ]; then
|
||||
BAND="n14|n28"
|
||||
elif [ $CHAN -lt 158200 ]; then
|
||||
BAND="n28"
|
||||
elif [ $CHAN -eq 158200 ]; then
|
||||
BAND="n14|n20|n28"
|
||||
elif [ $CHAN -le 160600 ]; then
|
||||
BAND="n20|n28"
|
||||
elif [ $CHAN -le 164200 ]; then
|
||||
BAND="n20"
|
||||
elif [ $CHAN -lt 171800 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 172000 ]; then
|
||||
BAND="n26"
|
||||
elif [ $CHAN -lt 173800 ]; then
|
||||
BAND="n18|n26"
|
||||
elif [ $CHAN -le 175000 ]; then
|
||||
BAND="n5|n18|n26"
|
||||
elif [ $CHAN -le 178800 ]; then
|
||||
BAND="n5|n26"
|
||||
elif [ $CHAN -lt 185000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 192000 ]; then
|
||||
BAND="n8"
|
||||
elif [ $CHAN -lt 285400 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 286400 ]; then
|
||||
BAND="n51|n76|n91|n93"
|
||||
elif [ $CHAN -eq 286400 ]; then
|
||||
BAND="n50|n51|n75|n76|n91|92|n93|94"
|
||||
elif [ $CHAN -lt 295000 ]; then
|
||||
BAND="n50|n75|n92|n94"
|
||||
elif [ $CHAN -eq 295000 ]; then
|
||||
BAND="n50|n74|n75|n92|n94"
|
||||
elif [ $CHAN -le 303400 ]; then
|
||||
BAND="n50|n74|n75|n92|n94"
|
||||
elif [ $CHAN -le 303600 ]; then
|
||||
BAND="n74"
|
||||
elif [ $CHAN -lt 305000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 311800 ]; then
|
||||
BAND="n24"
|
||||
elif [ $CHAN -lt 361000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 376000 ]; then
|
||||
BAND="n3"
|
||||
elif [ $CHAN -eq 376000 ]; then
|
||||
BAND="n3|n39"
|
||||
elif [ $CHAN -le 384000 ]; then
|
||||
BAND="n39"
|
||||
elif [ $CHAN -lt 386000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 398000 ]; then
|
||||
BAND="n2|n25"
|
||||
elif [ $CHAN -lt 399000 ]; then
|
||||
BAND="n25"
|
||||
elif [ $CHAN -eq 399000 ]; then
|
||||
BAND="n25|n70"
|
||||
elif [ $CHAN -lt 402000 ]; then
|
||||
BAND="n70"
|
||||
elif [ $CHAN -eq 402000 ]; then
|
||||
BAND="n34|n70"
|
||||
elif [ $CHAN -le 404000 ]; then
|
||||
BAND="n34|n70"
|
||||
elif [ $CHAN -le 405000 ]; then
|
||||
BAND="n34"
|
||||
elif [ $CHAN -lt 422000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 434000 ]; then
|
||||
BAND="n1|n65|n66"
|
||||
elif [ $CHAN -le 440000 ]; then
|
||||
BAND="n65|n66"
|
||||
elif [ $CHAN -lt 460000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 470000 ]; then
|
||||
BAND="n40"
|
||||
elif [ $CHAN -eq 470000 ]; then
|
||||
BAND="n30|n40"
|
||||
elif [ $CHAN -le 472000 ]; then
|
||||
BAND="n30|n40"
|
||||
elif [ $CHAN -le 480000 ]; then
|
||||
BAND="n40"
|
||||
elif [ $CHAN -lt 496700 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 499000 ]; then
|
||||
BAND="n53"
|
||||
elif [ $CHAN -lt 499200 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 514000 ]; then
|
||||
BAND="n41|n90"
|
||||
elif [ $CHAN -eq 514000 ]; then
|
||||
BAND="n38|n41|n90"
|
||||
elif [ $CHAN -lt 524000 ]; then
|
||||
BAND="n38|n41|n90"
|
||||
elif [ $CHAN -eq 524000 ]; then
|
||||
BAND="n7|n38|n41|n90"
|
||||
elif [ $CHAN -lt 538000 ]; then
|
||||
BAND="n7|n41|n90"
|
||||
elif [ $CHAN -eq 538000 ]; then
|
||||
BAND="n7|n90"
|
||||
elif [ $CHAN -lt 620000 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 636667 ]; then
|
||||
BAND="n77|n78"
|
||||
elif [ $CHAN -le 646666 ]; then
|
||||
BAND="n48|n77|n78"
|
||||
elif [ $CHAN -le 653333 ]; then
|
||||
BAND="n77|n78"
|
||||
elif [ $CHAN -le 680000 ]; then
|
||||
BAND="n77"
|
||||
elif [ $CHAN -lt 693334 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -le 733333 ]; then
|
||||
BAND="n79"
|
||||
elif [ $CHAN -lt 743333 ]; then
|
||||
BAND="-"
|
||||
elif [ $CHAN -lt 795000 ]; then
|
||||
BAND="n46"
|
||||
elif [ $CHAN -eq 795000 ]; then
|
||||
BAND="n46|n96"
|
||||
elif [ $CHAN -le 875000 ]; then
|
||||
BAND="n96"
|
||||
else
|
||||
BAND="-"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z "$CHAN" ]; then
|
||||
BAND="-"
|
||||
elif [ "$CHAN" -lt 123400 ]; then
|
||||
decode_lte
|
||||
elif [ "$CHAN" -le 875000 ]; then
|
||||
decode_nr5g
|
||||
else
|
||||
BAND="-"
|
||||
fi
|
||||
echo $BAND
|
||||
exit
|
||||
24
package/fish/luci-app-cpe/root/usr/bin/encodemask
Normal file
24
package/fish/luci-app-cpe/root/usr/bin/encodemask
Normal file
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
mtab = {}
|
||||
vtab = {1, 2, 4, 8}
|
||||
|
||||
for i = 1, 32 do
|
||||
mtab[i] = 0
|
||||
end
|
||||
|
||||
numarg = #arg
|
||||
for argval = 1, numarg do
|
||||
band = arg[argval]
|
||||
if tonumber(band) <= 128 then
|
||||
idx = math.floor((band - 1) / 4) + 1
|
||||
idxr = 33 - idx
|
||||
val = vtab[(band - ((idx - 1) * 4 ))]
|
||||
mtab[idxr] = mtab[idxr] + val
|
||||
end
|
||||
end
|
||||
for i = 1, 32 do
|
||||
mtab[i] = string.format("%X", mtab[i])
|
||||
end
|
||||
|
||||
print(table.concat(mtab))
|
||||
9
package/fish/luci-app-cpe/root/usr/bin/jkillall
Normal file
9
package/fish/luci-app-cpe/root/usr/bin/jkillall
Normal file
@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
LOOKFOR=$1
|
||||
KILLLIST=$(ps | grep $LOOKFOR)
|
||||
echo "$KILLLIST" | while read line; do
|
||||
if `echo "$line" | grep "/$LOOKFOR" > /dev/null` ; then
|
||||
PIDV=$(echo $line | grep -o "^[0-9]\{1,5\}" | grep -o "[0-9]\{1,5\}")
|
||||
kill $PIDV
|
||||
fi
|
||||
done
|
||||
21
package/fish/luci-app-cpe/root/usr/bin/rsrp2rssi
Normal file
21
package/fish/luci-app-cpe/root/usr/bin/rsrp2rssi
Normal file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/lua
|
||||
|
||||
rsrp = tonumber(arg[1])
|
||||
bw = tonumber(arg[2])
|
||||
if bw == 1.4 then
|
||||
n = 6
|
||||
else
|
||||
n = bw * 5
|
||||
end
|
||||
|
||||
if tonumber(string.match(_VERSION, "%d+%.%d")) > 5.1 then
|
||||
rssi = rsrp + (10 * math.log(n * 12, 10))
|
||||
else
|
||||
rssi = rsrp + (10 * math.log10(n * 12))
|
||||
end
|
||||
if rssi < -113 then
|
||||
rssi = -113
|
||||
elseif rssi > -51 then
|
||||
rssi = -51
|
||||
end
|
||||
print(math.floor(rssi))
|
||||
18
package/fish/luci-app-cpe/root/usr/bin/set_gpio
Normal file
18
package/fish/luci-app-cpe/root/usr/bin/set_gpio
Normal file
@ -0,0 +1,18 @@
|
||||
#!/bin/sh
|
||||
|
||||
PIN=$1
|
||||
VALUE=$2
|
||||
|
||||
PIN_FILE=/sys/class/gpio/gpio$PIN
|
||||
|
||||
if [ -z "$PIN" -o -z "$VALUE" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo $PIN >/sys/class/gpio/export
|
||||
|
||||
if [ $(cat $PIN_FILE/direction) = "out" ]; then
|
||||
echo $VALUE >$PIN_FILE/value
|
||||
fi
|
||||
|
||||
echo $PIN >/sys/class/gpio/unexport
|
||||
285
package/fish/luci-app-cpe/root/usr/share/cpe/Fibocom
Normal file
285
package/fish/luci-app-cpe/root/usr/share/cpe/Fibocom
Normal file
@ -0,0 +1,285 @@
|
||||
#!/bin/sh
|
||||
ATPORT=1
|
||||
|
||||
|
||||
|
||||
# SIMCOM获取基站信息
|
||||
Fibocom_Cellinfo()
|
||||
{
|
||||
#baseinfo.gcom
|
||||
OX=$( sendat $ATPORT "ATI")
|
||||
OX=$( sendat $ATPORT "AT+CGEQNEG=1")
|
||||
|
||||
#cellinfo0.gcom
|
||||
OX1=$( sendat $ATPORT "AT+COPS=3,0;+COPS?")
|
||||
OX2=$( sendat $ATPORT "AT+COPS=3,2;+COPS?")
|
||||
OX=$OX1" "$OX2
|
||||
|
||||
#cellinfo.gcom
|
||||
OY1=$( sendat $ATPORT "AT+CREG=2;+CREG?;+CREG=0")
|
||||
OY2=$( sendat $ATPORT "AT+CEREG=2;+CEREG?;+CEREG=0")
|
||||
OY3=$( sendat $ATPORT "AT+C5GREG=2;+C5GREG?;+C5GREG=0")
|
||||
OY=$OY1" "$OY2" "$OY3
|
||||
|
||||
|
||||
OXx=$OX
|
||||
OX=$(echo $OX | tr 'a-z' 'A-Z')
|
||||
OY=$(echo $OY | tr 'a-z' 'A-Z')
|
||||
OX=$OX" "$OY
|
||||
|
||||
#Debug "$OX"
|
||||
#Debug "$OY"
|
||||
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
COPSX=$(echo $OXx | grep -o "+COPS: [01],0,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS=$COPSX
|
||||
fi
|
||||
|
||||
COPSX=$(echo $OX | grep -o "+COPS: [01],2,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS_MCC=${COPSX:0:3}
|
||||
COPS_MNC=${COPSX:3:3}
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(awk -F[\;] '/'$COPS'/ {print $2}' $ROOTER/signal/mccmnc.data)
|
||||
[ "x$COPS" = "x" ] && COPS="-"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(echo "$O" | awk -F[\"] '/^\+COPS: 0,0/ {print $2}')
|
||||
if [ "x$COPS" = "x" ]; then
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
fi
|
||||
fi
|
||||
COPS_MNC=" "$COPS_MNC
|
||||
|
||||
OX=$(echo "${OX//[ \"]/}")
|
||||
CID=""
|
||||
CID5=""
|
||||
RAT=""
|
||||
REGV=$(echo "$OX" | grep -o "+C5GREG:2,[0-9],[A-F0-9]\{2,6\},[A-F0-9]\{5,10\},[0-9]\{1,2\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC5=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC5=$LAC5" ($(printf "%d" 0x$LAC5))"
|
||||
CID5=$(echo "$REGV" | cut -d, -f4)
|
||||
CID5L=$(printf "%010X" 0x$CID5)
|
||||
RNC5=${CID5L:1:6}
|
||||
RNC5=$RNC5" ($(printf "%d" 0x$RNC5))"
|
||||
CID5=${CID5L:7:3}
|
||||
CID5="Short $(printf "%X" 0x$CID5) ($(printf "%d" 0x$CID5)), Long $(printf "%X" 0x$CID5L) ($(printf "%d" 0x$CID5L))"
|
||||
RAT=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="3GPP"
|
||||
if [ -z "$REGV" ]; then
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{1,3\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="SW"
|
||||
fi
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
if [ $REGFMT = "3GPP" ]; then
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
else
|
||||
CID=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:5}
|
||||
RNC=$RNC" ($(printf "%d" 0x$RNC))"
|
||||
CID=${CIDL:6:2}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
|
||||
else
|
||||
REGV=$(echo "$OX" | grep -o "+CREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{2,8\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
if [ ${#CID} -gt 4 ]; then
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:3}
|
||||
CID=${CIDL:4:4}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
fi
|
||||
REGSTAT=$(echo "$REGV" | cut -d, -f2)
|
||||
if [ "$REGSTAT" == "5" -a "$COPS" != "-" ]; then
|
||||
COPS_MNC=$COPS_MNC" (Roaming)"
|
||||
fi
|
||||
if [ -n "$CID" -a -n "$CID5" ] && [ "$RAT" == "13" -o "$RAT" == "10" ]; then
|
||||
LAC="4G $LAC, 5G $LAC5"
|
||||
CID="4G $CID<br />5G $CID5"
|
||||
RNC="4G $RNC, 5G $RNC5"
|
||||
elif [ -n "$CID5" ]; then
|
||||
LAC=$LAC5
|
||||
CID=$CID5
|
||||
RNC=$RNC5
|
||||
fi
|
||||
if [ -z "$LAC" ]; then
|
||||
LAC="-"
|
||||
CID="-"
|
||||
RNC="-"
|
||||
fi
|
||||
}
|
||||
Fibocom_SIMINFO()
|
||||
{
|
||||
Debug "Fibocom_SIMINFO"
|
||||
# 获取IMEI
|
||||
IMEI=$( sendat $ATPORT "AT+CGSN" | sed -n '2p' )
|
||||
# 获取IMSI
|
||||
IMSI=$( sendat $ATPORT "AT+CIMI" | sed -n '2p' )
|
||||
# 获取ICCID
|
||||
ICCID=$( sendat $ATPORT "AT+ICCID" | grep -o "+ICCID:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}" )
|
||||
# 获取电话号码
|
||||
phone=$( sendat $ATPORT "AT+CNUM" | grep "+CNUM:" )
|
||||
}
|
||||
|
||||
#SIMCOM查找基站AT
|
||||
Fibocom_AT()
|
||||
{
|
||||
Debug "Fibocom_AT"
|
||||
ATPORT
|
||||
All_CSQ
|
||||
Fibocom_SIMINFO
|
||||
Fibocom_Cellinfo
|
||||
|
||||
#温度
|
||||
OX=$( sendat $ATPORT "AT+CPMUTEMP")
|
||||
TEMP=$(echo "$OX" | grep -o "+CPMUTEMP:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}")
|
||||
if [ -n "$TEMP" ]; then
|
||||
TEMP=$(echo $TEMP)$(printf "\xc2\xb0")"C"
|
||||
fi
|
||||
|
||||
|
||||
#基站信息
|
||||
OX=$( sendat $ATPORT "AT+CPSI?")
|
||||
rec=$(echo "$OX" | grep "+CPSI:")
|
||||
w=$(echo $rec |grep "NO SERVICE"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "NO SERVICE"
|
||||
return
|
||||
fi
|
||||
w=$(echo $rec |grep "NR5G_"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
|
||||
w=$(echo $rec |grep "32768"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "-32768"
|
||||
return
|
||||
fi
|
||||
|
||||
Debug "$rec"
|
||||
rec1=${rec##*+CPSI:}
|
||||
#echo "$rec1"
|
||||
MODE="${rec1%%,*}" # MODE="NR5G"
|
||||
rect1=${rec1#*,}
|
||||
rect1s="${rect1%%,*}" #Online
|
||||
rect2=${rect1#*,}
|
||||
rect2s="${rect2%%,*}" #460-11
|
||||
rect3=${rect2#*,}
|
||||
rect3s="${rect3%%,*}" #0xCFA102
|
||||
rect4=${rect3#*,}
|
||||
rect4s="${rect4%%,*}" #55744245764
|
||||
rect5=${rect4#*,}
|
||||
rect5s="${rect5%%,*}" #196
|
||||
rect6=${rect5#*,}
|
||||
rect6s="${rect6%%,*}" #NR5G_BAND78
|
||||
rect7=${rect6#*,}
|
||||
rect7s="${rect7%%,*}" #627264
|
||||
rect8=${rect7#*,}
|
||||
rect8s="${rect8%%,*}" #-940
|
||||
rect9=${rect8#*,}
|
||||
rect9s="${rect9%%,*}" #-110
|
||||
# "${rec1##*,}" #最后一位
|
||||
rect10=${rect9#*,}
|
||||
rect10s="${rect10%%,*}" #最后一位
|
||||
PCI=$rect5s
|
||||
LBAND="n"$(echo $rect6s | cut -d, -f0 | grep -o "BAND[0-9]\{1,3\}" | grep -o "[0-9]\+")
|
||||
CHANNEL=$rect7s
|
||||
RSCP=$(($(echo $rect8s | cut -d, -f0) / 10))
|
||||
ECIO=$(($(echo $rect9s | cut -d, -f0) / 10))
|
||||
if [ "$CSQ_PER" = "-" ]; then
|
||||
CSQ_PER=$((100 - (($RSCP + 31) * 100/-125)))"%"
|
||||
fi
|
||||
SINR=$(($(echo $rect10s | cut -d, -f0) / 10))" dB"
|
||||
fi
|
||||
w=$(echo $rec |grep "LTE"|grep "EUTRAN"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
rec1=${rec#*EUTRAN-}
|
||||
lte_band=${rec1%%,*} #EUTRAN-BAND
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
#rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
lte_rssi=${rec1%%,*} #LTE_RSSI
|
||||
lte_rssi=`expr $lte_rssi / 10` #LTE_RSSI
|
||||
Debug "LTE_BAND=$lte_band LTE_RSSI=$lte_rssi"
|
||||
if [ $rssi == 0 ];then
|
||||
rssi=$lte_rssi
|
||||
fi
|
||||
fi
|
||||
w=$(echo $rec |grep "WCDMA"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
w=$(echo $rec |grep "UNKNOWN"|wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "UNKNOWN BAND"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#CNMP
|
||||
OX=$( sendat $ATPORT "AT+CNMP?")
|
||||
CNMP=$(echo "$OX" | grep -o "+CNMP:[ ]*[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$CNMP" ]; then
|
||||
case $CNMP in
|
||||
"2"|"55" )
|
||||
NETMODE="1" ;;
|
||||
"13" )
|
||||
NETMODE="3" ;;
|
||||
"14" )
|
||||
NETMODE="5" ;;
|
||||
"38" )
|
||||
NETMODE="7" ;;
|
||||
"71" )
|
||||
NETMODE="9" ;;
|
||||
"109" )
|
||||
NETMODE="8" ;;
|
||||
* )
|
||||
NETMODE="0" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# CMGRMI 信息
|
||||
OX=$( sendat $ATPORT "AT+CMGRMI=4")
|
||||
CAINFO=$(echo "$OX" | grep -o "$REGXz" | tr ' ' ':')
|
||||
if [ -n "$CAINFO" ]; then
|
||||
for CASV in $(echo "$CAINFO"); do
|
||||
LBAND=$LBAND"<br />B"$(echo "$CASV" | cut -d, -f4)
|
||||
BW=$(echo "$CASV" | cut -d, -f5)
|
||||
decode_bw
|
||||
LBAND=$LBAND" (CA, Bandwidth $BW MHz)"
|
||||
CHANNEL="$CHANNEL, "$(echo "$CASV" | cut -d, -f2)
|
||||
PCI="$PCI, "$(echo "$CASV" | cut -d, -f7)
|
||||
done
|
||||
fi
|
||||
|
||||
}
|
||||
507
package/fish/luci-app-cpe/root/usr/share/cpe/Quectel
Normal file
507
package/fish/luci-app-cpe/root/usr/share/cpe/Quectel
Normal file
@ -0,0 +1,507 @@
|
||||
#!/bin/sh
|
||||
ATPORT=1
|
||||
#Quectel
|
||||
lte_bw() {
|
||||
BW=$(echo $BW | grep -o "[0-5]\{1\}")
|
||||
case $BW in
|
||||
"0")
|
||||
BW="1.4" ;;
|
||||
"1")
|
||||
BW="3" ;;
|
||||
"2"|"3"|"4"|"5")
|
||||
BW=$((($(echo $BW) - 1) * 5)) ;;
|
||||
esac
|
||||
}
|
||||
#Quectel
|
||||
nr_bw() {
|
||||
BW=$(echo $BW | grep -o "[0-9]\{1,2\}")
|
||||
case $BW in
|
||||
"0"|"1"|"2"|"3"|"4"|"5")
|
||||
BW=$((($(echo $BW) + 1) * 5)) ;;
|
||||
"6"|"7"|"8"|"9"|"10"|"11"|"12")
|
||||
BW=$((($(echo $BW) - 2) * 10)) ;;
|
||||
"13")
|
||||
BW="200" ;;
|
||||
"14")
|
||||
BW="400" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
#查询信息强度
|
||||
All_CSQ()
|
||||
{
|
||||
Debug "All_CSQ"
|
||||
#信号
|
||||
OX=$( sendat $ATPORT "AT+CSQ" |grep "+CSQ:")
|
||||
OX=$(echo $OX | tr 'a-z' 'A-Z')
|
||||
CSQ=$(echo "$OX" | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}")
|
||||
if [ $CSQ = "99" ]; then
|
||||
CSQ=""
|
||||
fi
|
||||
if [ -n "$CSQ" ]; then
|
||||
CSQ_PER=$(($CSQ * 100/31))"%"
|
||||
CSQ_RSSI=$((2 * CSQ - 113))" dBm"
|
||||
else
|
||||
CSQ="-"
|
||||
CSQ_PER="-"
|
||||
CSQ_RSSI="-"
|
||||
fi
|
||||
}
|
||||
|
||||
Quectel_SIMINFO()
|
||||
{
|
||||
Debug "Quectel_SIMINFO"
|
||||
# 获取IMEI
|
||||
IMEI=$( sendat $ATPORT "AT+CGSN" | sed -n '2p' )
|
||||
# 获取IMSI
|
||||
IMSI=$( sendat $ATPORT "AT+CIMI" | sed -n '2p' )
|
||||
# 获取ICCID
|
||||
ICCID=$( sendat $ATPORT "AT+ICCID" | grep -o "+ICCID:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}" )
|
||||
# 获取电话号码
|
||||
phone=$( sendat $ATPORT "AT+CNUM" | grep "+CNUM:" )
|
||||
|
||||
}
|
||||
# SIMCOM获取基站信息
|
||||
Quectel_Cellinfo()
|
||||
{
|
||||
# return
|
||||
#cellinfo0.gcom
|
||||
OX1=$( sendat $ATPORT "AT+COPS=3,0;+COPS?")
|
||||
OX2=$( sendat $ATPORT "AT+COPS=3,2;+COPS?")
|
||||
OX=$OX1" "$OX2
|
||||
|
||||
#cellinfo.gcom
|
||||
OY1=$( sendat $ATPORT "AT+CREG=2;+CREG?;+CREG=0")
|
||||
OY2=$( sendat $ATPORT "AT+CEREG=2;+CEREG?;+CEREG=0")
|
||||
OY3=$( sendat $ATPORT "AT+C5GREG=2;+C5GREG?;+C5GREG=0")
|
||||
OY=$OY1" "$OY2" "$OY3
|
||||
|
||||
|
||||
OXx=$OX
|
||||
OX=$(echo $OX | tr 'a-z' 'A-Z')
|
||||
OY=$(echo $OY | tr 'a-z' 'A-Z')
|
||||
OX=$OX" "$OY
|
||||
|
||||
#Debug "$OX"
|
||||
#Debug "$OY"
|
||||
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
COPSX=$(echo $OXx | grep -o "+COPS: [01],0,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS=$COPSX
|
||||
fi
|
||||
|
||||
COPSX=$(echo $OX | grep -o "+COPS: [01],2,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS_MCC=${COPSX:0:3}
|
||||
COPS_MNC=${COPSX:3:3}
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(awk -F[\;] '/'$COPS'/ {print $2}' $ROOTER/signal/mccmnc.data)
|
||||
[ "x$COPS" = "x" ] && COPS="-"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(echo "$O" | awk -F[\"] '/^\+COPS: 0,0/ {print $2}')
|
||||
if [ "x$COPS" = "x" ]; then
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
fi
|
||||
fi
|
||||
COPS_MNC=" "$COPS_MNC
|
||||
|
||||
OX=$(echo "${OX//[ \"]/}")
|
||||
CID=""
|
||||
CID5=""
|
||||
RAT=""
|
||||
REGV=$(echo "$OX" | grep -o "+C5GREG:2,[0-9],[A-F0-9]\{2,6\},[A-F0-9]\{5,10\},[0-9]\{1,2\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC5=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC5=$LAC5" ($(printf "%d" 0x$LAC5))"
|
||||
CID5=$(echo "$REGV" | cut -d, -f4)
|
||||
CID5L=$(printf "%010X" 0x$CID5)
|
||||
RNC5=${CID5L:1:6}
|
||||
RNC5=$RNC5" ($(printf "%d" 0x$RNC5))"
|
||||
CID5=${CID5L:7:3}
|
||||
CID5="Short $(printf "%X" 0x$CID5) ($(printf "%d" 0x$CID5)), Long $(printf "%X" 0x$CID5L) ($(printf "%d" 0x$CID5L))"
|
||||
RAT=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="3GPP"
|
||||
if [ -z "$REGV" ]; then
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{1,3\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="SW"
|
||||
fi
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
if [ $REGFMT = "3GPP" ]; then
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
else
|
||||
CID=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:5}
|
||||
RNC=$RNC" ($(printf "%d" 0x$RNC))"
|
||||
CID=${CIDL:6:2}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
|
||||
else
|
||||
REGV=$(echo "$OX" | grep -o "+CREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{2,8\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
if [ ${#CID} -gt 4 ]; then
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:3}
|
||||
CID=${CIDL:4:4}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
fi
|
||||
REGSTAT=$(echo "$REGV" | cut -d, -f2)
|
||||
if [ "$REGSTAT" == "5" -a "$COPS" != "-" ]; then
|
||||
COPS_MNC=$COPS_MNC" (Roaming)"
|
||||
fi
|
||||
if [ -n "$CID" -a -n "$CID5" ] && [ "$RAT" == "13" -o "$RAT" == "10" ]; then
|
||||
LAC="4G $LAC, 5G $LAC5"
|
||||
CID="4G $CID<br />5G $CID5"
|
||||
RNC="4G $RNC, 5G $RNC5"
|
||||
elif [ -n "$CID5" ]; then
|
||||
LAC=$LAC5
|
||||
CID=$CID5
|
||||
RNC=$RNC5
|
||||
fi
|
||||
if [ -z "$LAC" ]; then
|
||||
LAC="-"
|
||||
CID="-"
|
||||
RNC="-"
|
||||
fi
|
||||
}
|
||||
|
||||
#Quectel公司查找基站AT
|
||||
Quectel_AT()
|
||||
{
|
||||
Debug "Quectel_AT"
|
||||
ATPORT
|
||||
|
||||
Quectel_SIMINFO
|
||||
All_CSQ
|
||||
|
||||
Quectel_Cellinfo
|
||||
|
||||
#
|
||||
OX=$( sendat $ATPORT 'AT+QENG="servingcell"' | grep "+QENG:" )
|
||||
NR_NSA=$(echo $OX | grep -o -i "+QENG:[ ]\?\"NR5G-NSA\",")
|
||||
NR_SA=$(echo $OX | grep -o -i "+QENG: \"SERVINGCELL\",[^,]\+,\"NR5G-SA\",\"[DFT]\{3\}\",")
|
||||
if [ -n "$NR_NSA" ]; then
|
||||
QENG=",,"$(echo $OX" " | grep -o -i "+QENG: \"LTE\".\+\"NR5G-NSA\"," | tr " " ",")
|
||||
QENG5=$(echo $OX | grep -o -i "+QENG:[ ]\?\"NR5G-NSA\",[0-9]\{3\},[0-9]\{2,3\},[0-9]\{1,5\},-[0-9]\{2,5\},[-0-9]\{1,3\},-[0-9]\{2,3\},[0-9]\{1,7\},[0-9]\{1,3\}.\{1,6\}")
|
||||
if [ -z "$QENG5" ]; then
|
||||
QENG5=$(echo $OX | grep -o -i "+QENG:[ ]\?\"NR5G-NSA\",[0-9]\{3\},[0-9]\{2,3\},[0-9]\{1,5\},-[0-9]\{2,3\},[-0-9]\{1,3\},-[0-9]\{2,3\}")
|
||||
if [ -n "$QENG5" ]; then
|
||||
QENG5=$QENG5",,"
|
||||
fi
|
||||
fi
|
||||
elif [ -n "$NR_SA" ]; then
|
||||
QENG=$(echo $NR_SA | tr " " ",")
|
||||
QENG5=$(echo $OX | grep -o -i "+QENG: \"SERVINGCELL\",[^,]\+,\"NR5G-SA\",\"[DFT]\{3\}\",[ 0-9]\{3,4\},[0-9]\{2,3\},[0-9A-F]\{1,10\},[0-9]\{1,5\},[0-9A-F]\{2,6\},[0-9]\{6,7\},[0-9]\{1,3\},[0-9]\{1,2\},-[0-9]\{2,5\},-[0-9]\{2,3\},[-0-9]\{1,3\}")
|
||||
else
|
||||
QENG=$(echo $OX" " | grep -o -i "+QENG: [^ ]\+ " | tr " " ",")
|
||||
fi
|
||||
|
||||
|
||||
# Debug "$QENG"
|
||||
# Debug "$QENG5"
|
||||
|
||||
RAT=$(echo $QENG | cut -d, -f4 | grep -o "[-A-Z5]\{3,7\}")
|
||||
case $RAT in
|
||||
"GSM")
|
||||
MODE="GSM"
|
||||
;;
|
||||
"WCDMA")
|
||||
MODE="WCDMA"
|
||||
CHANNEL=$(echo $QENG | cut -d, -f9)
|
||||
RSCP=$(echo $QENG | cut -d, -f12)
|
||||
RSCP="-"$(echo $RSCP | grep -o "[0-9]\{1,3\}")
|
||||
ECIO=$(echo $QENG | cut -d, -f13)
|
||||
ECIO="-"$(echo $ECIO | grep -o "[0-9]\{1,3\}")
|
||||
;;
|
||||
"LTE"|"CAT-M"|"CAT-NB")
|
||||
MODE=$(echo $QENG | cut -d, -f5 | grep -o "[DFT]\{3\}")
|
||||
if [ -n "$MODE" ]; then
|
||||
MODE="$RAT $MODE"
|
||||
else
|
||||
MODE="$RAT"
|
||||
fi
|
||||
PCI=$(echo $QENG | cut -d, -f9)
|
||||
CHANNEL=$(echo $QENG | cut -d, -f10)
|
||||
LBAND=$(echo $QENG | cut -d, -f11 | grep -o "[0-9]\{1,3\}")
|
||||
BW=$(echo $QENG | cut -d, -f12)
|
||||
lte_bw
|
||||
BWU=$BW
|
||||
BW=$(echo $QENG | cut -d, -f13)
|
||||
lte_bw
|
||||
BWD=$BW
|
||||
if [ -z "$BWD" ]; then
|
||||
BWD="unknown"
|
||||
fi
|
||||
if [ -z "$BWU" ]; then
|
||||
BWU="unknown"
|
||||
fi
|
||||
if [ -n "$LBAND" ]; then
|
||||
LBAND="B"$LBAND" (Bandwidth $BWD MHz Down | $BWU MHz Up)"
|
||||
fi
|
||||
RSRP=$(echo $QENG | cut -d, -f15 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$RSRP" ]; then
|
||||
RSCP="-"$RSRP
|
||||
RSRPLTE=$RSCP
|
||||
fi
|
||||
RSRQ=$(echo $QENG | cut -d, -f16 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$RSRQ" ]; then
|
||||
ECIO="-"$RSRQ
|
||||
fi
|
||||
RSSI=$(echo $QENG | cut -d, -f17 | grep -o "\-[0-9]\{1,3\}")
|
||||
if [ -n "$RSSI" ]; then
|
||||
CSQ_RSSI=$RSSI" dBm"
|
||||
fi
|
||||
SINRR=$(echo $QENG | cut -d, -f18 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$SINRR" ]; then
|
||||
if [ $SINRR -le 25 ]; then
|
||||
SINR=$((($(echo $SINRR) * 2) -20))" dB"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -n "$NR_NSA" ]; then
|
||||
MODE="LTE/NR EN-DC"
|
||||
echo "0" > /tmp/modnetwork
|
||||
if [ -n "$QENG5" ] && [ -n "$LBAND" ] && [ "$RSCP" != "-" ] && [ "$ECIO" != "-" ]; then
|
||||
PCI="$PCI, "$(echo $QENG5 | cut -d, -f4)
|
||||
SCHV=$(echo $QENG5 | cut -d, -f8)
|
||||
SLBV=$(echo $QENG5 | cut -d, -f9)
|
||||
BW=$(echo $QENG5 | cut -d, -f10 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$SLBV" ]; then
|
||||
LBAND=$LBAND"<br />n"$SLBV
|
||||
if [ -n "$BW" ]; then
|
||||
nr_bw
|
||||
LBAND=$LBAND" (Bandwidth $BW MHz)"
|
||||
fi
|
||||
if [ "$SCHV" -ge 123400 ]; then
|
||||
CHANNEL=$CHANNEL", "$SCHV
|
||||
else
|
||||
CHANNEL=$CHANNEL", -"
|
||||
fi
|
||||
else
|
||||
LBAND=$LBAND"<br />nxx (unknown NR5G band)"
|
||||
CHANNEL=$CHANNEL", -"
|
||||
fi
|
||||
RSCP=$RSCP" dBm<br />"$(echo $QENG5 | cut -d, -f5)
|
||||
SINRR=$(echo $QENG5 | cut -d, -f6 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$SINRR" ]; then
|
||||
if [ $SINRR -le 30 ]; then
|
||||
SINR=$SINR"<br />"$((($(echo $SINRR) * 2) -20))" dB"
|
||||
fi
|
||||
fi
|
||||
ECIO=$ECIO" (4G) dB<br />"$(echo $QENG5 | cut -d, -f7)" (5G) "
|
||||
fi
|
||||
fi
|
||||
if [ -z "$LBAND" ]; then
|
||||
LBAND="-"
|
||||
else
|
||||
if [ -n "$QCA" ]; then
|
||||
QCA=$(echo $QCA | grep -o "\"S[CS]\{2\}\"[-0-9A-Z,\"]\+")
|
||||
for QCAL in $(echo "$QCA"); do
|
||||
if [ $(echo "$QCAL" | cut -d, -f7) = "2" ]; then
|
||||
SCHV=$(echo $QCAL | cut -d, -f2 | grep -o "[0-9]\+")
|
||||
SRATP="B"
|
||||
if [ -n "$SCHV" ]; then
|
||||
CHANNEL="$CHANNEL, $SCHV"
|
||||
if [ "$SCHV" -gt 123400 ]; then
|
||||
SRATP="n"
|
||||
fi
|
||||
fi
|
||||
SLBV=$(echo $QCAL | cut -d, -f6 | grep -o "[0-9]\{1,2\}")
|
||||
if [ -n "$SLBV" ]; then
|
||||
LBAND=$LBAND"<br />"$SRATP$SLBV
|
||||
BWD=$(echo $QCAL | cut -d, -f3 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$BWD" ]; then
|
||||
UPDOWN=$(echo $QCAL | cut -d, -f13)
|
||||
case "$UPDOWN" in
|
||||
"UL" )
|
||||
CATYPE="CA"$(printf "\xe2\x86\x91") ;;
|
||||
"DL" )
|
||||
CATYPE="CA"$(printf "\xe2\x86\x93") ;;
|
||||
* )
|
||||
CATYPE="CA" ;;
|
||||
esac
|
||||
if [ $BWD -gt 14 ]; then
|
||||
LBAND=$LBAND" ("$CATYPE", Bandwidth "$(($(echo $BWD) / 5))" MHz)"
|
||||
else
|
||||
LBAND=$LBAND" ("$CATYPE", Bandwidth 1.4 MHz)"
|
||||
fi
|
||||
fi
|
||||
LBAND=$LBAND
|
||||
fi
|
||||
PCI="$PCI, "$(echo $QCAL | cut -d, -f8)
|
||||
fi
|
||||
done
|
||||
fi
|
||||
fi
|
||||
if [ $RAT = "CAT-M" ] || [ $RAT = "CAT-NB" ]; then
|
||||
LBAND="B$(echo $QENG | cut -d, -f11) ($RAT)"
|
||||
fi
|
||||
;;
|
||||
"NR5G-SA")
|
||||
MODE="NR5G-SA"
|
||||
if [ -n "$QENG5" ]; then
|
||||
#AT+qnwcfg="NR5G_AMBR" #查询速度
|
||||
MODE="$RAT $(echo $QENG5 | cut -d, -f4)"
|
||||
PCI=$(echo $QENG5 | cut -d, -f8)
|
||||
CHANNEL=$(echo $QENG5 | cut -d, -f10)
|
||||
LBAND=$(echo $QENG5 | cut -d, -f11)
|
||||
BW=$(echo $QENG5 | cut -d, -f12)
|
||||
nr_bw
|
||||
LBAND="n"$LBAND" (Bandwidth $BW MHz)"
|
||||
RSCP=$(echo $QENG5 | cut -d, -f13)
|
||||
ECIO=$(echo $QENG5 | cut -d, -f14)
|
||||
if [ "$CSQ_PER" = "-" ]; then
|
||||
RSSI=$(rsrp2rssi $RSCP $BW)
|
||||
CSQ_PER=$((100 - (($RSSI + 51) * 100/-62)))"%"
|
||||
CSQ=$((($RSSI + 113) / 2))
|
||||
CSQ_RSSI=$RSSI" dBm"
|
||||
fi
|
||||
SINRR=$(echo $QENG5 | cut -d, -f15 | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$SINRR" ]; then
|
||||
if [ $SINRR -le 30 ]; then
|
||||
SINR=$((($(echo $SINRR) * 2) -20))" dB"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#
|
||||
OX=$( sendat $ATPORT "AT+QCAINFO" | grep "+QCAINFO:" )
|
||||
QCA=$(echo $OX" " | grep -o -i "+QCAINFO: \"S[CS]\{2\}\".\+NWSCANMODE" | tr " " ",")
|
||||
|
||||
|
||||
#
|
||||
OX=$( sendat $ATPORT 'AT+QCFG="nwscanmode"' | grep "+QCAINFO:" )
|
||||
QNSM=$(echo $OX | grep -o -i "+QCFG: \"NWSCANMODE\",[0-9]")
|
||||
QNSM=$(echo "$QNSM" | grep -o "[0-9]")
|
||||
if [ -n "$QNSM" ]; then
|
||||
MODTYPE="6"
|
||||
case $QNSM in
|
||||
"0" )
|
||||
NETMODE="1" ;;
|
||||
"1" )
|
||||
NETMODE="3" ;;
|
||||
"2"|"5" )
|
||||
NETMODE="5" ;;
|
||||
"3" )
|
||||
NETMODE="7" ;;
|
||||
esac
|
||||
fi
|
||||
if [ -n "$QNWP" ]; then
|
||||
MODTYPE="6"
|
||||
case $QNWP in
|
||||
"AUTO" )
|
||||
NETMODE="1" ;;
|
||||
"WCDMA" )
|
||||
NETMODE="5" ;;
|
||||
"LTE" )
|
||||
NETMODE="7" ;;
|
||||
"LTE:NR5G" )
|
||||
NETMODE="8" ;;
|
||||
"NR5G" )
|
||||
NETMODE="9" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
|
||||
#
|
||||
OX=$( sendat $ATPORT 'AT+QNWPREFCFG="mode_pref"' | grep "+QNWPREFCFG:" )
|
||||
QNWP=$(echo $OX | grep -o -i "+QNWPREFCFG: \"MODE_PREF\",[A-Z5:]\+" | cut -d, -f2)
|
||||
|
||||
#温度
|
||||
OX=$( sendat $ATPORT 'AT+QTEMP' | grep "+QTEMP:" )
|
||||
QTEMP=$(echo $OX | grep -o -i "+QTEMP: [0-9]\{1,3\}")
|
||||
if [ -z "$QTEMP" ]; then
|
||||
QTEMP=$(echo $OX | grep -o -i "+QTEMP:[ ]\?\"XO[_-]THERM[_-][^,]\+,[\"]\?[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}")
|
||||
fi
|
||||
if [ -z "$QTEMP" ]; then
|
||||
QTEMP=$(echo $OX | grep -o -i "+QTEMP:[ ]\?\"MDM-CORE-USR.\+[0-9]\{1,3\}\"" | cut -d\" -f4)
|
||||
fi
|
||||
if [ -z "$QTEMP" ]; then
|
||||
QTEMP=$(echo $OX | grep -o -i "+QTEMP:[ ]\?\"MDMSS.\+[0-9]\{1,3\}\"" | cut -d\" -f4)
|
||||
fi
|
||||
if [ -n "$QTEMP" ]; then
|
||||
CTEMP=$(echo $QTEMP | grep -o -i "[0-9]\{1,3\}")$(printf "\xc2\xb0")"C"
|
||||
fi
|
||||
|
||||
|
||||
|
||||
#
|
||||
OX=$( sendat $ATPORT "AT+QRSRP" | grep "+QRSRP:" )
|
||||
QRSRP=$(echo "$OX" | grep -o -i "+QRSRP:[^,]\+,-[0-9]\{1,5\},-[0-9]\{1,5\},-[0-9]\{1,5\}[^ ]*")
|
||||
if [ -n "$QRSRP" ] && [ "$RAT" != "WCDMA" ]; then
|
||||
QRSRP1=$(echo $QRSRP | cut -d, -f1 | grep -o "[-0-9]\+")
|
||||
QRSRP2=$(echo $QRSRP | cut -d, -f2)
|
||||
QRSRP3=$(echo $QRSRP | cut -d, -f3)
|
||||
QRSRP4=$(echo $QRSRP | cut -d, -f4)
|
||||
QRSRPtype=$(echo $QRSRP | cut -d, -f5)
|
||||
if [ "$QRSRPtype" == "NR5G" ]; then
|
||||
if [ -n "$NR_SA" ]; then
|
||||
RSCP=$QRSRP1
|
||||
if [ -n "$QRPRP2" -a "$QRSRP2" != "-32768" ]; then
|
||||
RSCP1="RxD "$QRSRP2
|
||||
fi
|
||||
if [ -n "$QRSRP3" -a "$QRSRP3" != "-32768" ]; then
|
||||
RSCP=$RSCP" dBm<br />"$QRSRP3
|
||||
fi
|
||||
if [ -n "$QRSRP4" -a "$QRSRP4" != "-32768" ]; then
|
||||
RSCP1="RxD "$QRSRP4
|
||||
fi
|
||||
else
|
||||
RSCP=$RSRPLTE
|
||||
if [ -n "$QRSRP1" -a "$QRSRP1" != "-32768" ]; then
|
||||
RSCP=$RSCP" (4G) dBm<br />"$QRSRP1
|
||||
if [ -n "$QRSRP2" -a "$QRSRP2" != "-32768" ]; then
|
||||
RSCP="$RSCP,$QRSRP2"
|
||||
if [ -n "$QRSRP3" -a "$QRSRP3" != "-32768" ]; then
|
||||
RSCP="$RSCP,$QRSRP3"
|
||||
if [ -n "$QRSRP4" -a "$QRSRP4" != "-32768" ]; then
|
||||
RSCP="$RSCP,$QRSRP4"
|
||||
fi
|
||||
fi
|
||||
RSCP=$RSCP" (5G) "
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
elif [ "$QRSRP2$QRSRP3$QRSRP4" != "-44-44-44" -a -z "$QENG5" ]; then
|
||||
RSCP=$QRSRP1
|
||||
if [ "$QRSRP3$QRSRP4" == "-140-140" -o "$QRSRP3$QRSRP4" == "-44-44" -o "$QRSRP3$QRSRP4" == "-32768-32768" ]; then
|
||||
RSCP1="RxD "$(echo $QRSRP | cut -d, -f2)
|
||||
else
|
||||
RSCP=$RSCP" dBm (RxD "$QRSRP2" dBm)<br />"$QRSRP3
|
||||
RSCP1="RxD "$QRSRP4
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
}
|
||||
303
package/fish/luci-app-cpe/root/usr/share/cpe/SIMCOM
Normal file
303
package/fish/luci-app-cpe/root/usr/share/cpe/SIMCOM
Normal file
@ -0,0 +1,303 @@
|
||||
#!/bin/sh
|
||||
ATPORT=1
|
||||
|
||||
#查询信息强度
|
||||
All_CSQ()
|
||||
{
|
||||
Debug "All_CSQ"
|
||||
#信号
|
||||
OX=$( sendat $ATPORT "AT+CSQ" |grep "+CSQ:")
|
||||
OX=$(echo $OX | tr 'a-z' 'A-Z')
|
||||
CSQ=$(echo "$OX" | grep -o "+CSQ: [0-9]\{1,2\}" | grep -o "[0-9]\{1,2\}")
|
||||
if [ $CSQ = "99" ]; then
|
||||
CSQ=""
|
||||
fi
|
||||
if [ -n "$CSQ" ]; then
|
||||
CSQ_PER=$(($CSQ * 100/31))"%"
|
||||
CSQ_RSSI=$((2 * CSQ - 113))" dBm"
|
||||
else
|
||||
CSQ="-"
|
||||
CSQ_PER="-"
|
||||
CSQ_RSSI="-"
|
||||
fi
|
||||
}
|
||||
|
||||
# SIMCOM获取基站信息
|
||||
SIMCOM_Cellinfo()
|
||||
{
|
||||
#baseinfo.gcom
|
||||
OX=$( sendat 2 "ATI")
|
||||
OX=$( sendat 2 "AT+CGEQNEG=1")
|
||||
|
||||
#cellinfo0.gcom
|
||||
OX1=$( sendat 2 "AT+COPS=3,0;+COPS?")
|
||||
OX2=$( sendat 2 "AT+COPS=3,2;+COPS?")
|
||||
OX=$OX1" "$OX2
|
||||
|
||||
#cellinfo.gcom
|
||||
OY1=$( sendat 2 "AT+CREG=2;+CREG?;+CREG=0")
|
||||
OY2=$( sendat 2 "AT+CEREG=2;+CEREG?;+CEREG=0")
|
||||
OY3=$( sendat 2 "AT+C5GREG=2;+C5GREG?;+C5GREG=0")
|
||||
OY=$OY1" "$OY2" "$OY3
|
||||
|
||||
|
||||
OXx=$OX
|
||||
OX=$(echo $OX | tr 'a-z' 'A-Z')
|
||||
OY=$(echo $OY | tr 'a-z' 'A-Z')
|
||||
OX=$OX" "$OY
|
||||
|
||||
#Debug "$OX"
|
||||
#Debug "$OY"
|
||||
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
COPSX=$(echo $OXx | grep -o "+COPS: [01],0,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS=$COPSX
|
||||
fi
|
||||
|
||||
COPSX=$(echo $OX | grep -o "+COPS: [01],2,.\+," | cut -d, -f3 | grep -o "[^\"]\+")
|
||||
|
||||
if [ "x$COPSX" != "x" ]; then
|
||||
COPS_MCC=${COPSX:0:3}
|
||||
COPS_MNC=${COPSX:3:3}
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(awk -F[\;] '/'$COPS'/ {print $2}' $ROOTER/signal/mccmnc.data)
|
||||
[ "x$COPS" = "x" ] && COPS="-"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$COPS" = "-" ]; then
|
||||
COPS=$(echo "$O" | awk -F[\"] '/^\+COPS: 0,0/ {print $2}')
|
||||
if [ "x$COPS" = "x" ]; then
|
||||
COPS="-"
|
||||
COPS_MCC="-"
|
||||
COPS_MNC="-"
|
||||
fi
|
||||
fi
|
||||
COPS_MNC=" "$COPS_MNC
|
||||
|
||||
OX=$(echo "${OX//[ \"]/}")
|
||||
CID=""
|
||||
CID5=""
|
||||
RAT=""
|
||||
REGV=$(echo "$OX" | grep -o "+C5GREG:2,[0-9],[A-F0-9]\{2,6\},[A-F0-9]\{5,10\},[0-9]\{1,2\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC5=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC5=$LAC5" ($(printf "%d" 0x$LAC5))"
|
||||
CID5=$(echo "$REGV" | cut -d, -f4)
|
||||
CID5L=$(printf "%010X" 0x$CID5)
|
||||
RNC5=${CID5L:1:6}
|
||||
RNC5=$RNC5" ($(printf "%d" 0x$RNC5))"
|
||||
CID5=${CID5L:7:3}
|
||||
CID5="Short $(printf "%X" 0x$CID5) ($(printf "%d" 0x$CID5)), Long $(printf "%X" 0x$CID5L) ($(printf "%d" 0x$CID5L))"
|
||||
RAT=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="3GPP"
|
||||
if [ -z "$REGV" ]; then
|
||||
REGV=$(echo "$OX" | grep -o "+CEREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{1,3\},[A-F0-9]\{5,8\}")
|
||||
REGFMT="SW"
|
||||
fi
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
if [ $REGFMT = "3GPP" ]; then
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
else
|
||||
CID=$(echo "$REGV" | cut -d, -f5)
|
||||
fi
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:5}
|
||||
RNC=$RNC" ($(printf "%d" 0x$RNC))"
|
||||
CID=${CIDL:6:2}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
|
||||
else
|
||||
REGV=$(echo "$OX" | grep -o "+CREG:2,[0-9],[A-F0-9]\{2,4\},[A-F0-9]\{2,8\}")
|
||||
if [ -n "$REGV" ]; then
|
||||
LAC=$(echo "$REGV" | cut -d, -f3)
|
||||
CID=$(echo "$REGV" | cut -d, -f4)
|
||||
if [ ${#CID} -gt 4 ]; then
|
||||
LAC=$(printf "%04X" 0x$LAC)" ($(printf "%d" 0x$LAC))"
|
||||
CIDL=$(printf "%08X" 0x$CID)
|
||||
RNC=${CIDL:1:3}
|
||||
CID=${CIDL:4:4}
|
||||
CID="Short $(printf "%X" 0x$CID) ($(printf "%d" 0x$CID)), Long $(printf "%X" 0x$CIDL) ($(printf "%d" 0x$CIDL))"
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
else
|
||||
LAC=""
|
||||
fi
|
||||
fi
|
||||
REGSTAT=$(echo "$REGV" | cut -d, -f2)
|
||||
if [ "$REGSTAT" == "5" -a "$COPS" != "-" ]; then
|
||||
COPS_MNC=$COPS_MNC" (Roaming)"
|
||||
fi
|
||||
if [ -n "$CID" -a -n "$CID5" ] && [ "$RAT" == "13" -o "$RAT" == "10" ]; then
|
||||
LAC="4G $LAC, 5G $LAC5"
|
||||
CID="4G $CID<br />5G $CID5"
|
||||
RNC="4G $RNC, 5G $RNC5"
|
||||
elif [ -n "$CID5" ]; then
|
||||
LAC=$LAC5
|
||||
CID=$CID5
|
||||
RNC=$RNC5
|
||||
fi
|
||||
if [ -z "$LAC" ]; then
|
||||
LAC="-"
|
||||
CID="-"
|
||||
RNC="-"
|
||||
fi
|
||||
}
|
||||
SIMCOM_SIMINFO()
|
||||
{
|
||||
Debug "Quectel_SIMINFO"
|
||||
# 获取IMEI
|
||||
IMEI=$( sendat $ATPORT "AT+CGSN" | sed -n '2p' )
|
||||
# 获取IMSI
|
||||
IMSI=$( sendat $ATPORT "AT+CIMI" | sed -n '2p' )
|
||||
# 获取ICCID
|
||||
ICCID=$( sendat $ATPORT "AT+ICCID" | grep -o "+ICCID:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}" )
|
||||
# 获取电话号码
|
||||
phone=$( sendat $ATPORT "AT+CNUM" | grep "+CNUM:" )
|
||||
}
|
||||
#SIMCOM查找基站AT
|
||||
SIMCOM_AT()
|
||||
{
|
||||
Debug "SIMCOM_AT"
|
||||
ATPORT
|
||||
All_CSQ
|
||||
SIMCOM_SIMINFO
|
||||
SIMCOM_Cellinfo
|
||||
|
||||
#温度
|
||||
OX=$( sendat $ATPORT "AT+CPMUTEMP")
|
||||
TEMP=$(echo "$OX" | grep -o "+CPMUTEMP:[ ]*[-0-9]\+" | grep -o "[-0-9]\{1,4\}")
|
||||
if [ -n "$TEMP" ]; then
|
||||
TEMP=$(echo $TEMP)$(printf "\xc2\xb0")"C"
|
||||
fi
|
||||
|
||||
|
||||
#基站信息
|
||||
OX=$( sendat $ATPORT "AT+CPSI?")
|
||||
rec=$(echo "$OX" | grep "+CPSI:")
|
||||
w=$(echo $rec |grep "NO SERVICE"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "NO SERVICE"
|
||||
return
|
||||
fi
|
||||
w=$(echo $rec |grep "NR5G_"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
|
||||
w=$(echo $rec |grep "32768"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "-32768"
|
||||
return
|
||||
fi
|
||||
|
||||
Debug "$rec"
|
||||
rec1=${rec##*+CPSI:}
|
||||
#echo "$rec1"
|
||||
MODE="${rec1%%,*}" # MODE="NR5G"
|
||||
rect1=${rec1#*,}
|
||||
rect1s="${rect1%%,*}" #Online
|
||||
rect2=${rect1#*,}
|
||||
rect2s="${rect2%%,*}" #460-11
|
||||
rect3=${rect2#*,}
|
||||
rect3s="${rect3%%,*}" #0xCFA102
|
||||
rect4=${rect3#*,}
|
||||
rect4s="${rect4%%,*}" #55744245764
|
||||
rect5=${rect4#*,}
|
||||
rect5s="${rect5%%,*}" #196
|
||||
rect6=${rect5#*,}
|
||||
rect6s="${rect6%%,*}" #NR5G_BAND78
|
||||
rect7=${rect6#*,}
|
||||
rect7s="${rect7%%,*}" #627264
|
||||
rect8=${rect7#*,}
|
||||
rect8s="${rect8%%,*}" #-940
|
||||
rect9=${rect8#*,}
|
||||
rect9s="${rect9%%,*}" #-110
|
||||
# "${rec1##*,}" #最后一位
|
||||
rect10=${rect9#*,}
|
||||
rect10s="${rect10%%,*}" #最后一位
|
||||
PCI=$rect5s
|
||||
LBAND="n"$(echo $rect6s | cut -d, -f0 | grep -o "BAND[0-9]\{1,3\}" | grep -o "[0-9]\+")
|
||||
CHANNEL=$rect7s
|
||||
RSCP=$(($(echo $rect8s | cut -d, -f0) / 10))
|
||||
ECIO=$(($(echo $rect9s | cut -d, -f0) / 10))
|
||||
if [ "$CSQ_PER" = "-" ]; then
|
||||
CSQ_PER=$((100 - (($RSCP + 31) * 100/-125)))"%"
|
||||
fi
|
||||
SINR=$(($(echo $rect10s | cut -d, -f0) / 10))" dB"
|
||||
fi
|
||||
w=$(echo $rec |grep "LTE"|grep "EUTRAN"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
rec1=${rec#*EUTRAN-}
|
||||
lte_band=${rec1%%,*} #EUTRAN-BAND
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
#rec1=${rec1#*,}
|
||||
rec1=${rec1#*,}
|
||||
lte_rssi=${rec1%%,*} #LTE_RSSI
|
||||
lte_rssi=`expr $lte_rssi / 10` #LTE_RSSI
|
||||
Debug "LTE_BAND=$lte_band LTE_RSSI=$lte_rssi"
|
||||
if [ $rssi == 0 ];then
|
||||
rssi=$lte_rssi
|
||||
fi
|
||||
fi
|
||||
w=$(echo $rec |grep "WCDMA"| wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
w=$(echo $rec |grep "UNKNOWN"|wc -l)
|
||||
if [ $w -ge 1 ];then
|
||||
Debug "UNKNOWN BAND"
|
||||
return
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#CNMP
|
||||
OX=$( sendat $ATPORT "AT+CNMP?")
|
||||
CNMP=$(echo "$OX" | grep -o "+CNMP:[ ]*[0-9]\{1,3\}" | grep -o "[0-9]\{1,3\}")
|
||||
if [ -n "$CNMP" ]; then
|
||||
case $CNMP in
|
||||
"2"|"55" )
|
||||
NETMODE="1" ;;
|
||||
"13" )
|
||||
NETMODE="3" ;;
|
||||
"14" )
|
||||
NETMODE="5" ;;
|
||||
"38" )
|
||||
NETMODE="7" ;;
|
||||
"71" )
|
||||
NETMODE="9" ;;
|
||||
"109" )
|
||||
NETMODE="8" ;;
|
||||
* )
|
||||
NETMODE="0" ;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# CMGRMI 信息
|
||||
OX=$( sendat $ATPORT "AT+CMGRMI=4")
|
||||
CAINFO=$(echo "$OX" | grep -o "$REGXz" | tr ' ' ':')
|
||||
if [ -n "$CAINFO" ]; then
|
||||
for CASV in $(echo "$CAINFO"); do
|
||||
LBAND=$LBAND"<br />B"$(echo "$CASV" | cut -d, -f4)
|
||||
BW=$(echo "$CASV" | cut -d, -f5)
|
||||
decode_bw
|
||||
LBAND=$LBAND" (CA, Bandwidth $BW MHz)"
|
||||
CHANNEL="$CHANNEL, "$(echo "$CASV" | cut -d, -f2)
|
||||
PCI="$PCI, "$(echo "$CASV" | cut -d, -f7)
|
||||
done
|
||||
fi
|
||||
|
||||
}
|
||||
3
package/fish/luci-app-cpe/root/usr/share/cpe/atcmd.sh
Normal file
3
package/fish/luci-app-cpe/root/usr/share/cpe/atcmd.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
rec=$(sendat $1 $2)
|
||||
echo $rec >> /tmp/result.at
|
||||
27
package/fish/luci-app-cpe/root/usr/share/cpe/cpedebug
Normal file
27
package/fish/luci-app-cpe/root/usr/share/cpe/cpedebug
Normal file
@ -0,0 +1,27 @@
|
||||
#!/bin/sh
|
||||
|
||||
en=1 #调试开关:0关闭,1打开 ,2输出到文件
|
||||
outfile="/tmp/cpe.log" #输出文件
|
||||
#日志信息
|
||||
Debug()
|
||||
{
|
||||
tim=$(date "+%Y-%m-%d %H:%M:%S") #获取系统时间
|
||||
if [ $en == 1 ]; then
|
||||
echo $tim $1 #打印输出
|
||||
elif [ $en == 2 ]; then
|
||||
echo $tim $1 >> $outfile #输出到文件
|
||||
fi
|
||||
}
|
||||
ATPORT()
|
||||
{
|
||||
MODEMNAME="ALL"
|
||||
# ATPORT=$(uci -q get modem.@ndis[0].tyyusb)
|
||||
lsusb=$( lsusb )
|
||||
RDFM650=$(echo "$lsusb" | grep "ID 2cb7:0a05 " | wc -l)
|
||||
if [ "$RDFM650" == 1 ]; then
|
||||
ATPORT=0
|
||||
MODEMNAME="FM650CN"
|
||||
else
|
||||
ATPORT=2
|
||||
fi
|
||||
}
|
||||
2
package/fish/luci-app-cpe/root/usr/share/cpe/delatcmd.sh
Normal file
2
package/fish/luci-app-cpe/root/usr/share/cpe/delatcmd.sh
Normal file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
rm -f /tmp/result.at
|
||||
418
package/fish/luci-app-cpe/root/usr/share/cpe/rssi
Normal file
418
package/fish/luci-app-cpe/root/usr/share/cpe/rssi
Normal file
@ -0,0 +1,418 @@
|
||||
#!/bin/sh
|
||||
source /usr/share/cpe/cpedebug
|
||||
source /usr/share/cpe/SIMCOM
|
||||
source /usr/share/cpe/Quectel
|
||||
source /usr/share/cpe/Fibocom
|
||||
|
||||
#初值化数据结构
|
||||
InitData()
|
||||
{
|
||||
Date=''
|
||||
CHANNEL="-"
|
||||
ECIO="-"
|
||||
RSCP="-"
|
||||
ECIO1=" "
|
||||
RSCP1=" "
|
||||
NETMODE="-"
|
||||
LBAND="-"
|
||||
PCI="-"
|
||||
CTEMP="-"
|
||||
MODE="-"
|
||||
SINR="-"
|
||||
IMEI='-'
|
||||
IMSI='-'
|
||||
ICCID='-'
|
||||
phone='-'
|
||||
conntype=''
|
||||
Model=''
|
||||
|
||||
|
||||
}
|
||||
#写数据
|
||||
SETData()
|
||||
{
|
||||
{
|
||||
echo $Model #'RM520N-GL'
|
||||
echo $conntype #'conntype'
|
||||
echo '1e0e:9001'
|
||||
echo $COPS #运营商
|
||||
echo 'ttyUSB2' #端口
|
||||
echo $TEMP #温度
|
||||
echo 'QMI' #协议
|
||||
echo '---------------------------------'
|
||||
echo $IMEI #imei
|
||||
echo $IMSI #imsi
|
||||
echo $ICCID #iccid
|
||||
echo $phone #phone
|
||||
echo '---------------------------------'
|
||||
|
||||
echo $MODE
|
||||
echo $CSQ
|
||||
echo $CSQ_PER
|
||||
echo $CSQ_RSSI
|
||||
echo $ECIO #参考信号接收质量 RSRQ ecio
|
||||
echo $ECIO1 #参考信号接收质量 RSRQ ecio1
|
||||
echo $RSCP #参考信号接收功率 RSRP rscp0
|
||||
echo $RSCP1 #参考信号接收功率 RSRP rscp1
|
||||
echo $SINR #信噪比 SINR rv["sinr"]
|
||||
echo $NETMODE #连接状态监控 rv["netmode"]
|
||||
echo '---------------------------------'
|
||||
|
||||
|
||||
echo $COPS_MCC #MCC
|
||||
echo $$COPS_MNC #MNC
|
||||
echo $LAC #eNB ID
|
||||
echo '' #LAC_NUM
|
||||
echo $RNC #TAC
|
||||
echo '' #RNC_NUM
|
||||
echo $CID
|
||||
echo '' #CID_NUM
|
||||
echo $LBAND
|
||||
echo $CHANNEL
|
||||
echo $PCI
|
||||
|
||||
echo $Date
|
||||
|
||||
|
||||
|
||||
echo $MODTYPE
|
||||
echo $QTEMP
|
||||
|
||||
} > /tmp/cpe_cell.file
|
||||
}
|
||||
ATPORT=1
|
||||
|
||||
# 自动处理模块信号
|
||||
AUTO_CPE()
|
||||
{
|
||||
Debug "------------------------------端口$ATPORT---------------------------"
|
||||
Debug "AUTO_CPE"
|
||||
Date=$(date "+%Y-%m-%d %H:%M:%S")
|
||||
|
||||
|
||||
#检测设备是否准备好
|
||||
rec=$(sendat $ATPORT "AT" 500 |grep OK |wc -l)
|
||||
if [ $rec == "1" ];then
|
||||
sleep 1s
|
||||
else
|
||||
sleep 5s
|
||||
return
|
||||
fi
|
||||
#读取模块信息
|
||||
# if [ "$conntype" == "" ]; then
|
||||
# {
|
||||
# Debug "计算模块"
|
||||
# ATATI=$( sendat $ATPORT "ATI")
|
||||
# Getconntype=$(echo "$ATATI" | sed -n '2p')
|
||||
# if [ "$Getconntype" == "" ]; then
|
||||
# {
|
||||
# sleep 5s
|
||||
# return
|
||||
# }
|
||||
# fi
|
||||
# Model=$(echo "$ATATI" | sed -n '3p')
|
||||
# conntype=$Getconntype
|
||||
# }
|
||||
# fi
|
||||
|
||||
Debug "读取模块信息 计算模块"
|
||||
ATATI=$( sendat $ATPORT "ATI")
|
||||
Getconntype=$(echo "$ATATI" | sed -n '2p')
|
||||
if [ "$Getconntype" == "" ]; then
|
||||
{
|
||||
sleep 5s
|
||||
return
|
||||
}
|
||||
fi
|
||||
Model=$(echo "$ATATI" | sed -n '3p')
|
||||
conntype=$Getconntype
|
||||
|
||||
cpin=$( sendat $ATPORT "at+cpin?")
|
||||
ERR=$(echo "$cpin" | grep "ERROR")
|
||||
if [ ! -z "$ERR" ]; then # No SIM
|
||||
Debug "No SIM"
|
||||
sleep 5s
|
||||
return
|
||||
fi
|
||||
RDY=$(echo "$cpin" | grep "READY")
|
||||
if [ -z "$RDY" ]; then # SIM Locked
|
||||
Debug "Correct Pin"
|
||||
sleep 5s
|
||||
return
|
||||
else
|
||||
Debug "Not Locked"
|
||||
fi
|
||||
#执行对应模块
|
||||
if [ $(echo $conntype |grep "Quectel"| wc -l) -ge 1 ];then
|
||||
{
|
||||
Quectel_AT
|
||||
}
|
||||
elif [ $(echo $conntype |grep "SIMCOM"| wc -l) -ge 1 ];then
|
||||
{
|
||||
SIMCOM_AT
|
||||
}
|
||||
elif [ $(echo $conntype |grep "Fibocom"| wc -l) -ge 1 ];then
|
||||
{
|
||||
Fibocom_AT
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug "null "
|
||||
}
|
||||
fi
|
||||
}
|
||||
#重新联网
|
||||
modem_reset()
|
||||
{
|
||||
|
||||
echo "Abnormal network restart"
|
||||
lsusb=$( lsusb )
|
||||
RDFM650=$(echo "$lsusb" | grep "ID 2cb7:0a05 " | wc -l)
|
||||
echo "RDFM650 $RDFM650"
|
||||
if [ "$RDFM650" == 1 ]; then
|
||||
{
|
||||
GTRNDIS=$(sendat $ATPORT "AT+GTRNDIS=1,1" 500 |grep OK |wc -l)
|
||||
sleep 2s
|
||||
}
|
||||
else
|
||||
{
|
||||
start="$( /etc/init.d/modem stop )"
|
||||
sleep 2s
|
||||
start="$( /etc/init.d/modem start )"
|
||||
sleep 5s
|
||||
}
|
||||
fi
|
||||
}
|
||||
#检测SIM卡是否插入,10次检测不到则重启模块
|
||||
check_sim()
|
||||
{
|
||||
while [ 1 ]
|
||||
do
|
||||
enabled=$(uci -q get modem.@ndis[0].enabled)
|
||||
if [ $enabled == '1' ] ;then
|
||||
echo "Check the sim"
|
||||
rec=$( sendat 2 "AT+CPIN?")
|
||||
rec1=$(echo $rec | grep "READY" | wc -l )
|
||||
if [ $rec1 == 1 ]; then
|
||||
x=0
|
||||
echo "SIM is READY"
|
||||
else
|
||||
let x++
|
||||
if [ $x == 10 ]; then
|
||||
echo "SIM abnormal restart"
|
||||
modem_reset #重启模块
|
||||
x=0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
sleep 6s
|
||||
done
|
||||
}
|
||||
#检测网络状态第一次开机
|
||||
chenk_firstdns()
|
||||
{
|
||||
while [ 1 ]
|
||||
do
|
||||
enabled=$(uci -q get modem.@ndis[0].enabled)
|
||||
en1=$(uci -q get modem.@ndis[0].en)
|
||||
if [ $enabled == '1' ] ;then
|
||||
if [ $en1 == '1' ] ;then
|
||||
echo "------------------------------开启任务---------------------------"
|
||||
ipadd=$(uci -q get modem.@ndis[0].ipaddress)
|
||||
ping -c 1 -w 1 $ipadd > /dev/null 2>&1
|
||||
if [ $? -eq 0 ];then
|
||||
echo "网络连接正常"
|
||||
xx=0
|
||||
return
|
||||
else
|
||||
echo "网络连接异常 $ipadd"
|
||||
let xx++
|
||||
let pxx++
|
||||
fi
|
||||
fi
|
||||
if [ $xx == 5 ];then
|
||||
xx=0
|
||||
modem_reset
|
||||
fi
|
||||
if [ $pxx == 10 ];then
|
||||
xx=0
|
||||
pxx=0
|
||||
return
|
||||
fi
|
||||
echo "------------------------------结束任务---------------------------"
|
||||
fi
|
||||
sleep 1s
|
||||
done
|
||||
}
|
||||
#检测网络状态
|
||||
chenk_dns()
|
||||
{
|
||||
en1=$(uci -q get modem.@ndis[0].en)
|
||||
if [ $en1 == '1' ] ;then
|
||||
echo "------------------------------开启任务---------------------------"
|
||||
ipadd=$(uci -q get modem.@ndis[0].ipaddress)
|
||||
ping -c 1 -w 1 $ipadd > /dev/null 2>&1
|
||||
if [ $? -eq 0 ];then
|
||||
echo "网络连接正常"
|
||||
xx=0
|
||||
else
|
||||
echo "网络连接异常 $ipadd 次数$xx"
|
||||
let xx++
|
||||
fi
|
||||
fi
|
||||
an=$(uci -q get modem.@ndis[0].an)
|
||||
if [ $xx == $an ];then
|
||||
xx=0
|
||||
modem_reset
|
||||
fi
|
||||
echo "------------------------------结束任务---------------------------"
|
||||
|
||||
}
|
||||
# 信号任务
|
||||
chenk_Task()
|
||||
{
|
||||
while [ 1 ]
|
||||
do
|
||||
enabled=$(uci -q get modem.@ndis[0].enabled)
|
||||
if [ $enabled == '1' ] ;then
|
||||
ATPORT
|
||||
Debug "------------------------------开启任务---------------------------"
|
||||
AUTO_CPE
|
||||
SETData
|
||||
chenk_dns
|
||||
Debug "------------------------------结束任务---------------------------"
|
||||
fi
|
||||
sleep 10s
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
#注册网卡
|
||||
RegisterNetwork()
|
||||
{
|
||||
# ATPORT
|
||||
Debug "RegisterNetwork 注册网卡 $ $MODEMNAME"
|
||||
# if [ "$MODEMNAME" == "FM650CN" ]; then
|
||||
# getFM650=$(uci -q get network.wwan5g |grep "interface"| wc -l)
|
||||
# if [ $getFM650 == "0" ] ;then
|
||||
# uci set network.wwan5g=interface
|
||||
# uci set network.wwan5g.ifname='usb0'
|
||||
# uci set network.wwan5g.proto=dhcp
|
||||
# uci commit network
|
||||
|
||||
# uci set firewall.@zone[1].network="wan wan6 wwan5g wwan5g6 wlan"
|
||||
# uci commit firewall
|
||||
|
||||
# $(/etc/init.d/network reload)
|
||||
# fi
|
||||
# getFM650=$(uci -q get network.wwan5g6|grep "interface"| wc -l)
|
||||
# if [ $getFM650 == "0" ] ;then
|
||||
# uci set network.wwan5g6=interface
|
||||
# uci set network.wwan5g6.ifname='usb0'
|
||||
# uci set network.wwan5g6.proto='dhcpv6'
|
||||
# uci set network.wwan5g6.reqaddress='try'
|
||||
# uci set network.wwan5g6.reqprefix='auto'
|
||||
# uci set network.wwan5g6._orig_ifname='usb0'
|
||||
# uci set network.wwan5g6._orig_bridge='false'
|
||||
# uci set network.wwan5g6.extendprefix='1'
|
||||
# uci commit network
|
||||
# uci set firewall.@zone[1].network="wan wan6 wwan wwan5g wwan5g6 wlan"
|
||||
# uci commit firewall
|
||||
# $(/etc/init.d/network reload)
|
||||
# fi
|
||||
# fi
|
||||
|
||||
|
||||
|
||||
if [ $(uci -q get network.wwan5g |grep "interface"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g=interface
|
||||
if [ "$MODEMNAME" == "FM650CN" ]; then
|
||||
uci set network.wwan5g.ifname='usb0'
|
||||
else
|
||||
uci set network.wwan5g.ifname='wwan0'
|
||||
fi
|
||||
uci set network.wwan5g.proto=dhcp
|
||||
uci commit network
|
||||
uci set firewall.@zone[1].network="wan wan6 wwan5g wwan5g6 wlan"
|
||||
uci commit firewall
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
if [ $(uci -q get network.wwan5g6 |grep "interface"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g6=interface
|
||||
if [ "$MODEMNAME" == "FM650CN" ]; then
|
||||
uci set network.wwan5g6.ifname='usb0'
|
||||
uci set network.wwan5g6._orig_ifname='usb0'
|
||||
else
|
||||
uci set network.wwan5g6.ifname='wwan0'
|
||||
uci set network.wwan5g6._orig_ifname='wwan0'
|
||||
fi
|
||||
uci set network.wwan5g6.proto='dhcpv6'
|
||||
uci set network.wwan5g6.reqaddress='try'
|
||||
uci set network.wwan5g6.reqprefix='auto'
|
||||
uci set network.wwan5g6._orig_bridge='false'
|
||||
uci set network.wwan5g6.extendprefix='1'
|
||||
uci commit network
|
||||
uci set firewall.@zone[1].network="wan wan6 wwan wwan5g wwan5g6 wlan"
|
||||
uci commit firewall
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
if [ "$MODEMNAME" == "FM650CN" ]; then
|
||||
if [ $(uci -q get network.wwan5g.ifname |grep "usb0"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g.ifname='usb0'
|
||||
uci commit network
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
if [ $(uci -q get network.wwan5g6.ifname |grep "usb0"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g6.ifname='usb0'
|
||||
uci commit network
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
else
|
||||
if [ $(uci -q get network.wwan5g.ifname |grep "wwan0"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g.ifname='wwan0'
|
||||
uci commit network
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
if [ $(uci -q get network.wwan5g6.ifname |grep "wwan0"| wc -l) == "0" ] ;then
|
||||
uci set network.wwan5g6._orig_ifname='wwan0'
|
||||
uci set network.wwan5g6.ifname='wwan0'
|
||||
uci commit network
|
||||
$(/etc/init.d/network reload)
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# 运行入口
|
||||
first()
|
||||
{
|
||||
Debug "开启RSSI服务"
|
||||
# 初值化数据结构
|
||||
InitData
|
||||
Debug "初值化数据完成"
|
||||
sleep 1s
|
||||
# 计算模块AT端口号
|
||||
ATPORT
|
||||
# 注册网卡
|
||||
RegisterNetwork
|
||||
# 第一次获取模块信息数据
|
||||
AUTO_CPE
|
||||
# 保存结构数据
|
||||
SETData
|
||||
#开机直接运行网络注册
|
||||
modem_reset
|
||||
# 第一次开机检测是否联网
|
||||
chenk_firstdns
|
||||
chenk_Task
|
||||
}
|
||||
|
||||
#############################################
|
||||
# #
|
||||
# 进入主函数 #
|
||||
# #
|
||||
#############################################
|
||||
first
|
||||
48
package/fish/luci-app-fancontrol/Makefile
Normal file
48
package/fish/luci-app-fancontrol/Makefile
Normal file
@ -0,0 +1,48 @@
|
||||
# include $(TOPDIR)/rules.mk
|
||||
|
||||
# LUCI_TITLE:=Fan Control
|
||||
# LUCI_DEPENDS:=+luci-base
|
||||
# PKG_NAME:=luci-app-fan-control
|
||||
# PKG_VERSION:=1.0.0
|
||||
# PKG_RELEASE:=1
|
||||
|
||||
# include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
# define Package/$(PKG_NAME)
|
||||
# SECTION:=luci
|
||||
# CATEGORY:=LuCI
|
||||
# SUBMENU:=3. Applications
|
||||
# TITLE:=$(LUCI_TITLE)
|
||||
# DEPENDS:=$(LUCI_DEPENDS)
|
||||
# endef
|
||||
|
||||
# define Package/$(PKG_NAME)/install
|
||||
# $(INSTALL_DIR) $(1)/usr/sbin
|
||||
# $(INSTALL_BIN) $(PKG_BUILD_DIR)/root/usr/sbin/fan_control.sh $(1)/usr/sbin/
|
||||
# $(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
|
||||
# $(INSTALL_BIN) $(PKG_BUILD_DIR)/luasrc/controller/fan_control.lua $(1)/usr/lib/lua/luci/controller/
|
||||
# $(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi/fan_control
|
||||
# $(INSTALL_BIN) $(PKG_BUILD_DIR)/luasrc/model/cbi/fan_control/fan.lua $(1)/usr/lib/lua/luci/model/cbi/fan_control/
|
||||
# $(INSTALL_DIR) $(1)/usr/lib/lua/luci/view/fan_control
|
||||
# $(INSTALL_BIN) $(PKG_BUILD_DIR)/luasrc/view/fan_control/fan_status.htm $(1)/usr/lib/lua/luci/view/fan_control/
|
||||
# endef
|
||||
|
||||
# $(eval $(call BuildPackage,$(PKG_NAME)))
|
||||
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
|
||||
LUCI_TITLE:=Fan Control
|
||||
LUCI_DEPENDS:=+luci-base
|
||||
PKG_NAME:=luci-app-fancontrol
|
||||
PKG_VERSION:=1.0.0
|
||||
PKG_RELEASE:=1
|
||||
LUCI_DEPENDS:=+kmod-hwmon-pwmfan
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
#$(eval $(call BuildPackage,luci-app-fscan))
|
||||
@ -0,0 +1,11 @@
|
||||
module("luci.controller.fancontrol", package.seeall)
|
||||
|
||||
function index()
|
||||
if not nixio.fs.access("/etc/config/fancontrol") then
|
||||
return
|
||||
end
|
||||
entry({"admin", "h69k"},firstchild(),_("H69K"), 100).dependent = true
|
||||
|
||||
entry({"admin", "h69k", "fancontrol"}, cbi("fancontrol"), _("风扇控制"), 100).dependent = true
|
||||
entry({"admin", "h69k", "fancontrol", "status"}, template("fancontrol/fan_status")).leaf = true
|
||||
end
|
||||
@ -0,0 +1,34 @@
|
||||
m = Map("fancontrol", "风扇控制", "根据温度配置风扇控制设置。")
|
||||
|
||||
s = m:section(TypedSection, "fan", "设置")
|
||||
s.anonymous = true
|
||||
|
||||
enabled = s:option(Flag, "fan_enabled", "启用风扇控制", "启用或禁用风扇控制。")
|
||||
enabled.default = 1
|
||||
enabled.rmempty = false
|
||||
|
||||
temp_low = s:option(Value, "temp_low", "低温阈值 (°C)")
|
||||
temp_low.datatype = "uinteger"
|
||||
temp_low.default = 40
|
||||
|
||||
temp_mid = s:option(Value, "temp_mid", "中温阈值 (°C)")
|
||||
temp_mid.datatype = "uinteger"
|
||||
temp_mid.default = 50
|
||||
|
||||
temp_high = s:option(Value, "temp_high", "高温阈值(°C)")
|
||||
temp_high.datatype = "uinteger"
|
||||
temp_high.default = 60
|
||||
|
||||
speed_low = s:option(Value, "speed_low", "低速 PWM 值 (%)")
|
||||
speed_low.datatype = "range(0,100)"
|
||||
speed_low.default = 20
|
||||
|
||||
speed_mid = s:option(Value, "speed_mid", "中速 PWM 值 (%)")
|
||||
speed_mid.datatype = "range(0,100)"
|
||||
speed_mid.default = 50
|
||||
|
||||
speed_high = s:option(Value, "speed_high", "高速 PWM 值 (%)")
|
||||
speed_high.datatype = "range(0,100)"
|
||||
speed_high.default = 80
|
||||
|
||||
return m
|
||||
@ -0,0 +1,8 @@
|
||||
config fan 'settings'
|
||||
option temp_low '40'
|
||||
option temp_mid '50'
|
||||
option temp_high '60'
|
||||
option speed_low '20'
|
||||
option speed_mid '50'
|
||||
option speed_high '80'
|
||||
option fan_enabled '1'
|
||||
95
package/fish/luci-app-fancontrol/root/etc/init.d/fancontrol.sh
Executable file
95
package/fish/luci-app-fancontrol/root/etc/init.d/fancontrol.sh
Executable file
@ -0,0 +1,95 @@
|
||||
#!/bin/sh /etc/rc.common
|
||||
|
||||
START=99
|
||||
|
||||
start() {
|
||||
. /lib/functions.sh
|
||||
|
||||
# Unload pwm_fan module if loaded
|
||||
if lsmod | grep -q pwm_fan; then
|
||||
rmmod pwm_fan
|
||||
fi
|
||||
|
||||
local period=40000
|
||||
|
||||
# Initialize PWM interface
|
||||
init_pwm() {
|
||||
echo 0 > /sys/class/pwm/pwmchip0/export
|
||||
echo $period > /sys/class/pwm/pwmchip0/pwm0/period
|
||||
echo normal > /sys/class/pwm/pwmchip0/pwm0/polarity
|
||||
}
|
||||
|
||||
# Set fan speed by percentage
|
||||
set_fan_speed_percentage() {
|
||||
local percentage=$1
|
||||
local duty_cycle=$(( (percentage * period) / 100 ))
|
||||
echo $duty_cycle > /sys/class/pwm/pwmchip0/pwm0/duty_cycle
|
||||
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
|
||||
}
|
||||
|
||||
# Disable fan
|
||||
disable_fan() {
|
||||
echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable
|
||||
}
|
||||
|
||||
# Get temperature
|
||||
get_temperature() {
|
||||
temp=$(cat /sys/class/thermal/thermal_zone0/temp)
|
||||
temp_c=$((temp / 1000))
|
||||
echo $temp_c
|
||||
}
|
||||
|
||||
# Temperature control logic
|
||||
control_fan_based_on_temp() {
|
||||
temp=$(get_temperature)
|
||||
|
||||
if [ "$temp" -lt "$temp_low" ]; then
|
||||
set_fan_speed_percentage 0
|
||||
elif [ "$temp" -ge "$temp_low" ] && [ "$temp" -lt "$temp_mid" ]; then
|
||||
set_fan_speed_percentage $speed_low
|
||||
elif [ "$temp" -ge "$temp_mid" ] && [ "$temp" -lt "$temp_high" ]; then
|
||||
set_fan_speed_percentage $speed_mid
|
||||
else
|
||||
set_fan_speed_percentage $speed_high
|
||||
fi
|
||||
}
|
||||
|
||||
# Initialize PWM
|
||||
init_pwm
|
||||
|
||||
# Define a function to clean up resources on shutdown
|
||||
cleanup() {
|
||||
echo "Stopping fan control..."
|
||||
disable_fan
|
||||
exit 0
|
||||
}
|
||||
|
||||
# Trap signals for cleanup
|
||||
trap cleanup SIGTERM SIGINT
|
||||
|
||||
# Main loop running in the background
|
||||
control_fan_based_on_temp_loop() {
|
||||
while true; do
|
||||
# Reload configuration parameters in each loop
|
||||
config_load fancontrol
|
||||
config_get temp_low settings temp_low
|
||||
config_get temp_mid settings temp_mid
|
||||
config_get temp_high settings temp_high
|
||||
config_get speed_low settings speed_low
|
||||
config_get speed_mid settings speed_mid
|
||||
config_get speed_high settings speed_high
|
||||
config_get fan_enabled settings fan_enabled
|
||||
|
||||
if [ "$fan_enabled" -eq 1 ]; then
|
||||
control_fan_based_on_temp
|
||||
else
|
||||
disable_fan
|
||||
fi
|
||||
|
||||
sleep 10
|
||||
done
|
||||
}
|
||||
|
||||
# Run the loop in the background
|
||||
control_fan_based_on_temp_loop &
|
||||
}
|
||||
16
package/fish/luci-app-fscan/Makefile
Normal file
16
package/fish/luci-app-fscan/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-fscan
|
||||
PKG_VERSION:=1.3
|
||||
PKG_RELEASE:=3
|
||||
|
||||
include $(INCLUDE_DIR)/package.mk
|
||||
|
||||
|
||||
LUCI_PKGARCH:=all
|
||||
LUCI_TITLE:=Cell Scan Results
|
||||
LUCI_DEPENDS:=+coreutils +coreutils-timeout +sendat
|
||||
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
#$(eval $(call BuildPackage,luci-app-fscan))
|
||||
118
package/fish/luci-app-fscan/luasrc/controller/fscan.lua
Normal file
118
package/fish/luci-app-fscan/luasrc/controller/fscan.lua
Normal file
@ -0,0 +1,118 @@
|
||||
module("luci.controller.fscan", package.seeall)
|
||||
|
||||
function index()
|
||||
entry({"admin", "modem", "fscan"}, call("redirect_to_tab1"), _("基站扫描"), 80).dependent = true
|
||||
entry({"admin", "modem", "fscan", "fibocom"}, template("fscan/fscan_fibocom"), _("广和通"), 10).dependent = true
|
||||
entry({"admin", "modem", "fscan", "quectel"}, template("fscan/fscan_quectel"), _("移远"), 20).dependent = true
|
||||
entry({"admin", "modem", "fscan", "switch2"}, call("action_switch2"), nil)
|
||||
entry({"admin", "modem", "fscan", "switch3"}, call("action_switch3"), nil)
|
||||
end
|
||||
|
||||
function redirect_to_tab1()
|
||||
luci.http.redirect(luci.dispatcher.build_url("admin", "modem", "fscan", "fibocom"))
|
||||
end
|
||||
|
||||
function action_switch2()
|
||||
local sys = require "luci.sys"
|
||||
local http = require "luci.http"
|
||||
local confirm = http.formvalue("confirm")
|
||||
|
||||
if confirm and confirm == "yes" then
|
||||
os.execute("rm -rf /tmp/cellinfo")
|
||||
os.execute("/usr/share/fscan/fscan.sh &")
|
||||
http.write_json({ status = "success", message = "Fibocom扫描已启动" })
|
||||
else
|
||||
http.write_json({ status = "error", message = "确认参数无效" })
|
||||
end
|
||||
end
|
||||
|
||||
function action_switch3()
|
||||
local sys = require "luci.sys"
|
||||
local http = require "luci.http"
|
||||
local confirm = http.formvalue("confirm")
|
||||
|
||||
if confirm and confirm == "yes" then
|
||||
os.execute("rm -rf /tmp/yycellinfo")
|
||||
os.execute("/usr/share/fscan/yyfscan.sh &")
|
||||
http.write_json({ status = "success", message = "Quectel扫描已启动" })
|
||||
else
|
||||
http.write_json({ status = "error", message = "确认参数无效" })
|
||||
end
|
||||
end
|
||||
|
||||
function parse_results_fibocom()
|
||||
local results = {}
|
||||
local controller = {}
|
||||
-- Read and parse cellinfo file
|
||||
local cellinfo = io.open("/tmp/cellinfo", "r")
|
||||
|
||||
if cellinfo then
|
||||
for line in cellinfo:lines() do
|
||||
local mode, operator, band, earfcn, pci, rsrp, rsrq, cellid = line:match('(%w+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+),([^,]+)')
|
||||
if mode and operator and earfcn and pci and rsrp and rsrq and cellid then
|
||||
table.insert(controller, {
|
||||
mode = mode,
|
||||
operator = operator,
|
||||
band = band,
|
||||
earfcn = earfcn,
|
||||
pci = pci,
|
||||
rsrp = rsrp,
|
||||
rsrq = rsrq,
|
||||
cellid = cellid,
|
||||
lockit = '<button onclick="lockit();" class="cbi-button cbi-button-save">锁定它</button>'
|
||||
})
|
||||
end
|
||||
end
|
||||
cellinfo:close()
|
||||
else
|
||||
table.insert(controller, {
|
||||
mode = "wait for ctrl...",
|
||||
operator = "",
|
||||
band = "",
|
||||
earfcn = "",
|
||||
pci = "",
|
||||
rsrp = "",
|
||||
rsrq = "",
|
||||
cellid = "",
|
||||
lockit = ""
|
||||
})
|
||||
end
|
||||
return controller
|
||||
end
|
||||
|
||||
function parse_results_quectel()
|
||||
local results = {}
|
||||
local controller = {}
|
||||
-- Read and parse cellinfo file
|
||||
local cellinfo = io.open("/tmp/yycellinfo", "r")
|
||||
if cellinfo then
|
||||
for line in cellinfo:lines() do
|
||||
local mode, operator, band, earfcn, pci, rsrp, rsrq = line:match('+QSCAN: "(.-)",(.-),(.-),(.-),(.-),(.-),(.+)')
|
||||
if mode and operator and earfcn and pci and rsrp and rsrq then
|
||||
table.insert(controller, {
|
||||
mode = mode,
|
||||
operator = operator,
|
||||
band = band,
|
||||
earfcn = earfcn,
|
||||
pci = pci,
|
||||
rsrp = rsrp,
|
||||
rsrq = rsrq,
|
||||
lockit = '<button onclick="lockit();" class="cbi-button cbi-button-save">锁定它</button>'
|
||||
})
|
||||
end
|
||||
end
|
||||
cellinfo:close()
|
||||
else
|
||||
table.insert(controller, {
|
||||
mode = "wait for ctrl...",
|
||||
operator = "",
|
||||
band = "",
|
||||
earfcn = "",
|
||||
pci = "",
|
||||
rsrp = "",
|
||||
rsrq = "",
|
||||
lockit = ""
|
||||
})
|
||||
end
|
||||
return controller
|
||||
end
|
||||
7
package/fish/luci-app-fscan/luasrc/model/cbi/fscan.lua
Normal file
7
package/fish/luci-app-fscan/luasrc/model/cbi/fscan.lua
Normal file
@ -0,0 +1,7 @@
|
||||
module("luci.controller.fscan", package.seeall)
|
||||
|
||||
function index()
|
||||
local page = entry({"admin", "modem", "fscan"}, cbi("fscan"), _("扫描基站"))
|
||||
page.dependent = true
|
||||
end
|
||||
|
||||
243
package/fish/luci-app-fscan/luasrc/view/fscan/fscan_fibocom.htm
Normal file
243
package/fish/luci-app-fscan/luasrc/view/fscan/fscan_fibocom.htm
Normal file
@ -0,0 +1,243 @@
|
||||
<%+header%>
|
||||
|
||||
<script>
|
||||
function checkFibocomResult() {
|
||||
var mode = document.getElementById('mode').innerHTML;
|
||||
var operator = document.getElementById('operator').innerHTML;
|
||||
|
||||
if (mode !== "wait for ctrl...") {
|
||||
if (operator === "") {
|
||||
setTimeout(function() {
|
||||
reloadPage();
|
||||
document.getElementById('fibocomscanStatus').style.display = 'block'; // 显示扫描状态元素
|
||||
}, 10000);
|
||||
} else {
|
||||
document.getElementById('fibocomscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
// Do nothing, no further action needed
|
||||
}
|
||||
} else {
|
||||
document.getElementById('fibocomscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
// Do nothing, no further action needed
|
||||
}
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function lockit() {
|
||||
if (confirm("功能正在开发中")) {
|
||||
// 用户点击“确定”时的操作
|
||||
console.log("用户选择了确定");
|
||||
} else {
|
||||
// 用户点击“取消”时的操作
|
||||
console.log("用户选择了取消");
|
||||
}
|
||||
}
|
||||
|
||||
function startScanFibocom() {
|
||||
reloadPage();
|
||||
document.getElementById('fibocomscanStatus').innerHTML = '正在扫描中...';
|
||||
document.getElementById('fibocomscanStatus').style.display = 'block'; // 显示扫描状态元素
|
||||
setTimeout(function() {
|
||||
stopScan();
|
||||
}, 300000); // 5 minutes timeout
|
||||
}
|
||||
|
||||
function stopScanFibocom() {
|
||||
document.getElementById('fibocomscanStatus').innerHTML = '扫描超时,请点击执行扫描动作按钮进行重试。';
|
||||
document.getElementById('fibocomscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
clearInterval(refreshInterval); // Stop refreshing the page
|
||||
}
|
||||
|
||||
function submitForm(event) {
|
||||
event.preventDefault(); // 阻止默认提交
|
||||
|
||||
if (confirm('你确定吗?')) {
|
||||
const form = document.getElementById('switchForm');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: form.method,
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === "success") {
|
||||
startScanFibocom();
|
||||
} else {
|
||||
console.error("错误:" + data.message); // 显示错误提示
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('提交失败:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', checkFibocomResult);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cbi-map .large-button {
|
||||
width: 100%;
|
||||
background-color: #5e72e4;
|
||||
color: #5f6368;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cbi-map .scan-status {
|
||||
color: rgb(12, 12, 12);
|
||||
}
|
||||
|
||||
@keyframes scanning {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.scanning {
|
||||
animation: scanning 1s infinite;
|
||||
}
|
||||
|
||||
.cbi-map table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cbi-map th {
|
||||
background-color: rgb(255, 255, 255);
|
||||
color: rgb(87, 87, 87);
|
||||
}
|
||||
|
||||
.cbi-map .cbi-section-table tr:nth-child(even) {
|
||||
background-color: rgb(244, 244, 244);
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cbi-map h3 {
|
||||
background-color: #5e72e4;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.cbi-map table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="cbi-map">
|
||||
<h2>扫描基站
|
||||
|
||||
</h2>
|
||||
<h5>
|
||||
<span>使用说明:请勿在开机立刻进行此操作,进入此页面后点击“执行扫描动作”按钮,程序会自动开始执行扫描并刷新出数据。<p style="color: red;">注意:扫描期间请勿操作,等待扫描结果再进行其他操作。</p></span>
|
||||
</h5>
|
||||
<br>
|
||||
|
||||
|
||||
<div style="display: flex; justify-content: space-around;">
|
||||
<form id="switchForm" method="post" action="<%= luci.dispatcher.build_url('admin', 'modem', 'fscan', 'switch2') %>" onsubmit="submitForm(event)">
|
||||
<input type="hidden" name="confirm" value="yes">
|
||||
<input type="submit" value="执行广和通扫描" class="cbi-button cbi-button-save">
|
||||
</form>
|
||||
<div style="width: 100%;"></div>
|
||||
<button onclick="reloadPage();" class="cbi-button cbi-button-save">手动刷新扫描数据</button>
|
||||
</div>
|
||||
<br>
|
||||
<p id="fibocomscanStatus" class="scan-status scanning">正在扫描基站中...</p>
|
||||
<br>
|
||||
<h3>基站列表</h3>
|
||||
<p>
|
||||
<table id="fibocomResults" class="cbi-section-table">
|
||||
<tr>
|
||||
<th>网络制式</th>
|
||||
<th>运营商ISP</th>
|
||||
<th>频段 Band</th>
|
||||
<th>频点 EARFCN</th>
|
||||
<th>物理小区标识 PCI </th>
|
||||
<th>信号强度RSRP</th>
|
||||
<th>接收质量 RSRQ</th>
|
||||
<th>小区ID CELLID</th>
|
||||
<th>锁定它</th>
|
||||
</tr>
|
||||
<%
|
||||
local controller = require("luci.controller.fscan")
|
||||
local results = controller.parse_results_fibocom() or {}
|
||||
if #results > 0 then
|
||||
for _, result in ipairs(results) do
|
||||
%>
|
||||
<tr>
|
||||
<td id="mode">
|
||||
<%= result.mode %>
|
||||
</td>
|
||||
<td id="operator">
|
||||
<%= result.operator %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.band %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.earfcn %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.pci %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.rsrp %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.rsrq %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.cellid %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.lockit %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end
|
||||
else
|
||||
%>
|
||||
<tr>
|
||||
<td id="mode">scaning...</td>
|
||||
<td id="operator"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</p>
|
||||
<p id="fibocomscanStatus" class="scan-status"></p>
|
||||
</div>
|
||||
<%+footer%>
|
||||
238
package/fish/luci-app-fscan/luasrc/view/fscan/fscan_quectel.htm
Normal file
238
package/fish/luci-app-fscan/luasrc/view/fscan/fscan_quectel.htm
Normal file
@ -0,0 +1,238 @@
|
||||
<%+header%>
|
||||
|
||||
<script>
|
||||
function checQuectelResult() {
|
||||
var mode = document.getElementById('mode').innerHTML;
|
||||
var operator = document.getElementById('operator').innerHTML;
|
||||
|
||||
if (mode !== "wait for ctrl...") {
|
||||
if (operator === "") {
|
||||
setTimeout(function() {
|
||||
reloadPage();
|
||||
document.getElementById('quectelscanStatus').style.display = 'block'; // 显示扫描状态元素
|
||||
}, 10000);
|
||||
} else {
|
||||
document.getElementById('quectelscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
// Do nothing, no further action needed
|
||||
}
|
||||
} else {
|
||||
document.getElementById('quectelscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
// Do nothing, no further action needed
|
||||
}
|
||||
}
|
||||
|
||||
function reloadPage() {
|
||||
window.location.reload();
|
||||
}
|
||||
|
||||
function lockit() {
|
||||
if (confirm("功能正在开发中")) {
|
||||
// 用户点击“确定”时的操作
|
||||
console.log("用户选择了确定");
|
||||
} else {
|
||||
// 用户点击“取消”时的操作
|
||||
console.log("用户选择了取消");
|
||||
}
|
||||
}
|
||||
|
||||
function startScanQuectel() {
|
||||
reloadPage();
|
||||
document.getElementById('quectelscanStatus').innerHTML = '正在扫描中...';
|
||||
document.getElementById('quectelscanStatus').style.display = 'block'; // 显示扫描状态元素
|
||||
setTimeout(function() {
|
||||
stopScan();
|
||||
}, 300000); // 5 minutes timeout
|
||||
}
|
||||
|
||||
function stopScanQuectel() {
|
||||
document.getElementById('quectelscanStatus').innerHTML = '扫描超时,请点击执行扫描动作按钮进行重试。';
|
||||
document.getElementById('quectelscanStatus').style.display = 'none'; // 隐藏扫描状态元素
|
||||
clearInterval(refreshInterval); // Stop refreshing the page
|
||||
}
|
||||
|
||||
|
||||
function submitForm(event) {
|
||||
event.preventDefault(); // 阻止默认提交
|
||||
|
||||
if (confirm('你确定吗?')) {
|
||||
const form = document.getElementById('switchForm');
|
||||
const formData = new FormData(form);
|
||||
|
||||
fetch(form.action, {
|
||||
method: form.method,
|
||||
body: formData
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === "success") {
|
||||
startScanQuectel();
|
||||
} else {
|
||||
console.error("错误:" + data.message); // 显示错误提示
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('提交失败:', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('DOMContentLoaded', checQuectelResult);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.cbi-map .large-button {
|
||||
width: 100%;
|
||||
background-color: #5e72e4;
|
||||
color: #5f6368;
|
||||
border: none;
|
||||
padding: 10px;
|
||||
margin: 5px 0;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.cbi-map .scan-status {
|
||||
color: rgb(12, 12, 12);
|
||||
}
|
||||
|
||||
@keyframes scanning {
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.2;
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.scanning {
|
||||
animation: scanning 1s infinite;
|
||||
}
|
||||
|
||||
.cbi-map table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.cbi-map th {
|
||||
background-color: rgb(255, 255, 255);
|
||||
color: rgb(87, 87, 87);
|
||||
}
|
||||
|
||||
.cbi-map .cbi-section-table tr:nth-child(even) {
|
||||
background-color: rgb(244, 244, 244);
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cbi-map h3 {
|
||||
background-color: #5e72e4;
|
||||
color: rgb(255, 255, 255);
|
||||
}
|
||||
|
||||
.cbi-map table {
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cbi-map th,
|
||||
.cbi-map td {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<div class="cbi-map">
|
||||
<h2>扫描基站
|
||||
|
||||
</h2>
|
||||
<h5>
|
||||
<span>使用说明:请勿在开机立刻进行此操作,进入此页面后点击“执行扫描动作”按钮,程序会自动开始执行扫描并刷新出数据。<p style="color: red;">注意:扫描期间请勿操作,等待扫描结果再进行其他操作。</p></span>
|
||||
</h5>
|
||||
<br>
|
||||
<div style="display: flex; justify-content: space-around;">
|
||||
<form id="switchForm" method="post" action="<%= luci.dispatcher.build_url('admin', 'modem', 'fscan', 'switch3') %>" onsubmit="submitForm(event)">
|
||||
<input type="hidden" name="confirm" value="yes">
|
||||
<input type="submit" value="执行移远扫描" class="cbi-button cbi-button-save">
|
||||
</form>
|
||||
<div style="width: 100%;"></div>
|
||||
<button onclick="reloadPage();" class="cbi-button cbi-button-save">手动刷新扫描数据</button>
|
||||
</div>
|
||||
<br>
|
||||
<p id="quectelscanStatus" class="scan-status scanning">正在扫描基站中...</p>
|
||||
<br>
|
||||
<h3>基站列表</h3>
|
||||
<p>
|
||||
<table id="quectelResults" class="cbi-section-table">
|
||||
<tr>
|
||||
<th>网络制式</th>
|
||||
<th>运营商ISP</th>
|
||||
<th>频段 Band</th>
|
||||
<th>频点 EARFCN</th>
|
||||
<th>物理小区标识 PCI </th>
|
||||
<th>信号强度RSRP</th>
|
||||
<th>接收质量 RSRQ</th>
|
||||
<th>锁定它</th>
|
||||
</tr>
|
||||
<%
|
||||
local controller = require("luci.controller.fscan")
|
||||
local results = controller.parse_results_quectel() or {}
|
||||
if #results > 0 then
|
||||
for _, result in ipairs(results) do
|
||||
%>
|
||||
<tr>
|
||||
<td id="mode">
|
||||
<%= result.mode %>
|
||||
</td>
|
||||
<td id="operator">
|
||||
<%= result.operator %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.band %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.earfcn %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.pci %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.rsrp %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.rsrq %>
|
||||
</td>
|
||||
<td>
|
||||
<%= result.lockit %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end
|
||||
else
|
||||
%>
|
||||
<tr>
|
||||
<td id="mode">scaning...</td>
|
||||
<td id="operator"></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</table>
|
||||
</p>
|
||||
<p id="quectelscanStatus" class="scan-status"></p>
|
||||
</div>
|
||||
|
||||
<%+footer%>
|
||||
97
package/fish/luci-app-fscan/root/usr/share/fscan/fscan.sh
Executable file
97
package/fish/luci-app-fscan/root/usr/share/fscan/fscan.sh
Executable file
@ -0,0 +1,97 @@
|
||||
#!/bin/ash
|
||||
|
||||
PROGRAM="Fibocom"
|
||||
|
||||
lockfile=/tmp/cellscanlock
|
||||
|
||||
# 检查是否存在 /tmp/celltime 文件,以及文件中的时间戳
|
||||
if [ -e /tmp/celltime ]; then
|
||||
celltime=$(cat /tmp/celltime)
|
||||
current_time=$(date +%s)
|
||||
time_difference=$((current_time - celltime))
|
||||
|
||||
# 如果时间差小于20秒,则直接退出脚本
|
||||
if [ $time_difference -lt 60 ]; then
|
||||
echo "时间间隔小于20秒,使用缓存结果"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -e ${lockfile} ]; then
|
||||
if kill -9 $(cat ${lockfile}); then
|
||||
echo "Cell scanning is already Kill it."
|
||||
rm -f ${lockfile}
|
||||
else
|
||||
echo "Removing stale lock file."
|
||||
rm -f ${lockfile}
|
||||
fi
|
||||
fi
|
||||
|
||||
echo $$ >${lockfile}
|
||||
pid=$(cat ${lockfile})
|
||||
>/tmp/cellinfo
|
||||
>/tmp/tmpcellinfo
|
||||
echo "开始基站扫描..."
|
||||
# 获取当前时间的时间戳
|
||||
timestamp=$(date +%s)
|
||||
echo $timestamp > /tmp/celltime
|
||||
# echo -e 'at+GTCELLSCAN\r\n' >/dev/ttyUSB2
|
||||
sendat 2 'AT+GTCELLSCAN'
|
||||
|
||||
timeout 120s cat /dev/ttyUSB2 | while read line; do
|
||||
case "$line" in "+GTCELLSCAN"*)
|
||||
echo "$line" >> /tmp/tmpcellinfo
|
||||
;;
|
||||
esac
|
||||
case "$line" in *"OK"*)
|
||||
echo "<br>基站扫描完成"
|
||||
# 格式化输出基站信息供用户选择
|
||||
# awk '{print NR, $0}' /tmp/cellinfo
|
||||
# rm -f ${lockfile}
|
||||
# kill -9 $pid
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
while read line; do
|
||||
case "$line" in "+GTCELLSCAN"*)
|
||||
operatorCode=$(echo $line | awk -F ',' '{print $2$3}')
|
||||
case "$operatorCode" in
|
||||
"46000" | "46002" | "46004" | "46007" | "46008" | "46020")
|
||||
operator="中国移动"
|
||||
;;
|
||||
"46001" | "46006" | "46009")
|
||||
operator="中国联通"
|
||||
;;
|
||||
"46003" | "46005" | "46011")
|
||||
operator="中国电信"
|
||||
;;
|
||||
"46015")
|
||||
operator="中国广电"
|
||||
;;
|
||||
*)
|
||||
operator="未知运营商"
|
||||
;;
|
||||
esac
|
||||
earfcn=$(echo "$line" | awk -F ',' '{print $4}')
|
||||
first_field=$(echo "$line" | awk -F ',' '{print $1}')
|
||||
if [ "$first_field" = "+GTCELLSCAN: 4" ]; then
|
||||
lte="LTE"
|
||||
frequency_band="BAND$(echo $line | awk -F ',' '{print $10}')"
|
||||
elif [ "$first_field" = "+GTCELLSCAN: 5" ]; then
|
||||
lte="5G"
|
||||
frequency_band="N$(echo $line | awk -F ',' '{print $10}')"
|
||||
fi
|
||||
|
||||
# frequency_band=$(earfcn_to_band $earfcn)
|
||||
echo "$line" | awk -F ',' -v lte="$lte" -v operator="$operator" -v frequency_band="$frequency_band" -v earfcn="$earfcn" '{printf("%s,%s,%s,%s,%s,%s,%s,%s\n", lte, operator, frequency_band, earfcn, $5, $8, $9, $7)}' >> /tmp/cellinfo
|
||||
;;
|
||||
esac
|
||||
done < /tmp/tmpcellinfo
|
||||
echo "<br>数据处理完成"
|
||||
rm -f ${lockfile}
|
||||
# 获取当前时间的时间戳
|
||||
timestamp=$(date +%s)
|
||||
echo $timestamp > /tmp/celltime
|
||||
|
||||
rm -f ${lockfile}
|
||||
143
package/fish/luci-app-fscan/root/usr/share/fscan/yyfscan.sh
Executable file
143
package/fish/luci-app-fscan/root/usr/share/fscan/yyfscan.sh
Executable file
@ -0,0 +1,143 @@
|
||||
#!/bin/ash
|
||||
|
||||
PROGRAM="RM520N_CELLSCAN"
|
||||
|
||||
lockfile=/tmp/cellscanlock
|
||||
|
||||
earfcn_to_band() {
|
||||
local earfcn=$1
|
||||
local bands=""
|
||||
|
||||
# 4G LTE
|
||||
if [ $earfcn -ge 0 ] && [ $earfcn -le 41589 ]; then
|
||||
if [ $earfcn -ge 0 ] && [ $earfcn -le 599 ]; then
|
||||
bands="Band 1"
|
||||
elif [ $earfcn -ge 1200 ] && [ $earfcn -le 1949 ]; then
|
||||
bands="Band 3"
|
||||
elif [ $earfcn -ge 2400 ] && [ $earfcn -le 2649 ]; then
|
||||
bands="Band 5"
|
||||
elif [ $earfcn -ge 3450 ] && [ $earfcn -le 3799 ]; then
|
||||
bands="Band 8"
|
||||
elif [ $earfcn -ge 36200 ] && [ $earfcn -le 36349 ]; then
|
||||
bands="Band 34"
|
||||
elif [ $earfcn -ge 37750 ] && [ $earfcn -le 38249 ]; then
|
||||
bands="Band 38"
|
||||
elif [ $earfcn -ge 38250 ] && [ $earfcn -le 38649 ]; then
|
||||
bands="Band 39"
|
||||
elif [ $earfcn -ge 38650 ] && [ $earfcn -le 39649 ]; then
|
||||
bands="Band 40"
|
||||
elif [ $earfcn -ge 39650 ] && [ $earfcn -le 41589 ]; then
|
||||
bands="Band 41"
|
||||
fi
|
||||
# 以下是5G NR的
|
||||
elif [ $earfcn -ge 422000 ] && [ $earfcn -le 434000 ]; then
|
||||
bands="n1"
|
||||
elif [ $earfcn -ge 361000 ] && [ $earfcn -le 376000 ]; then
|
||||
bands="n3"
|
||||
elif [ $earfcn -ge 185000 ] && [ $earfcn -le 192000 ]; then
|
||||
bands="n8"
|
||||
elif [ $earfcn -ge 499200 ] && [ $earfcn -le 537999 ]; then
|
||||
bands="n41"
|
||||
elif [ $earfcn -ge 620000 ] && [ $earfcn -le 680000 ]; then
|
||||
bands="n78/n77"
|
||||
elif [ $earfcn -ge 693334 ] && [ $earfcn -le 733333 ]; then
|
||||
bands="n79"
|
||||
# 5G NR重复频段检查
|
||||
elif [ $earfcn -ge 158200 ] && [ $earfcn -le 164200 ]; then
|
||||
bands="n20"
|
||||
fi
|
||||
if [ $earfcn -ge 151600 ] && [ $earfcn -le 160600 ]; then
|
||||
[ -n "$bands" ] && bands="${bands}/"
|
||||
bands="${bands}n28"
|
||||
fi
|
||||
|
||||
if [ -z "$bands" ]; then
|
||||
bands="Unknown Band"
|
||||
fi
|
||||
|
||||
echo "$bands"
|
||||
}
|
||||
|
||||
|
||||
|
||||
# 检查是否存在 /tmp/celltime 文件,以及文件中的时间戳
|
||||
if [ -e /tmp/celltime ]; then
|
||||
celltime=$(cat /tmp/celltime)
|
||||
current_time=$(date +%s)
|
||||
time_difference=$((current_time - celltime))
|
||||
|
||||
# 如果时间差小于20秒,则直接退出脚本
|
||||
if [ $time_difference -lt 60 ]; then
|
||||
echo "时间间隔小于20秒,使用缓存结果"
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -e ${lockfile} ]; then
|
||||
if kill -9 $(cat ${lockfile}); then
|
||||
echo "Cell scanning is already Kill it."
|
||||
rm -f ${lockfile}
|
||||
else
|
||||
echo "Removing stale lock file."
|
||||
rm -f ${lockfile}
|
||||
fi
|
||||
fi
|
||||
|
||||
echo $$ >${lockfile}
|
||||
pid=$(cat ${lockfile})
|
||||
>/tmp/yycellinfo
|
||||
>/tmp/tmpcellinfo
|
||||
echo "开始基站扫描..."
|
||||
# 获取当前时间的时间戳
|
||||
timestamp=$(date +%s)
|
||||
echo $timestamp > /tmp/celltime
|
||||
echo -e 'at+qscan=3,0\r\n' >/dev/ttyUSB2
|
||||
|
||||
timeout 120s cat /dev/ttyUSB2 | while read line; do
|
||||
case "$line" in "+QSCAN"*)
|
||||
echo "$line" >> /tmp/tmpcellinfo
|
||||
;;
|
||||
esac
|
||||
case "$line" in *"OK"*)
|
||||
echo "<br>基站扫描完成"
|
||||
# 格式化输出基站信息供用户选择
|
||||
# awk '{print NR, $0}' /tmp/yycellinfo
|
||||
# rm -f ${lockfile}
|
||||
# kill -9 $pid
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
while read line; do
|
||||
case "$line" in "+QSCAN"*)
|
||||
operatorCode=$(echo $line | awk -F ',' '{print $2$3}')
|
||||
case "$operatorCode" in
|
||||
"46000" | "46002" | "46004" | "46007" | "46008" | "46020")
|
||||
operator="中国移动"
|
||||
;;
|
||||
"46001" | "46006" | "46009")
|
||||
operator="中国联通"
|
||||
;;
|
||||
"46003" | "46005" | "46011")
|
||||
operator="中国电信"
|
||||
;;
|
||||
"46015")
|
||||
operator="中国广电"
|
||||
;;
|
||||
*)
|
||||
operator="未知运营商"
|
||||
;;
|
||||
esac
|
||||
earfcn=$(echo "$line" | awk -F ',' '{print $4}')
|
||||
frequency_band=$(earfcn_to_band $earfcn)
|
||||
echo "$line" | awk -F ',' -v operator="$operator" -v frequency_band="$frequency_band" -v earfcn="$earfcn" '{printf("%s,%s,%s,%s,%s,%s,%s\n", $1, operator, frequency_band, earfcn, $5, $6, $7)}' >> /tmp/yycellinfo
|
||||
;;
|
||||
esac
|
||||
done < /tmp/tmpcellinfo
|
||||
echo "<br>数据处理完成"
|
||||
rm -f ${lockfile}
|
||||
# 获取当前时间的时间戳
|
||||
timestamp=$(date +%s)
|
||||
echo $timestamp > /tmp/celltime
|
||||
|
||||
rm -f ${lockfile}
|
||||
17
package/fish/luci-app-gobinetmodem/Makefile
Normal file
17
package/fish/luci-app-gobinetmodem/Makefile
Normal file
@ -0,0 +1,17 @@
|
||||
#
|
||||
# Copyright (C) 2015 OpenWrt.org
|
||||
#
|
||||
# This is free software, licensed under the GNU General Public License v2.
|
||||
# See /LICENSE for more information.
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
LUCI_TITLE:=Modem Server
|
||||
LUCI_DEPENDS:=+luci-compat +quectel-CM-5G +kmod-gobinet \
|
||||
+kmod-usb-net-cdc-ether +kmod-usb-net-qmi-wwan \
|
||||
+kmod-usb-net-rndis +kmod-usb-serial-option
|
||||
|
||||
include $(TOPDIR)/feeds/luci/luci.mk
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user