11-Openwrtホットプラグシステム



11 Openwrt Hotplug System



linux hotplugはホットスワップ可能なシステムであり、ネットワークポートプラグ、USBのプラグ、キートリガーなどの多くのアプリケーションで使用されています...非常に幅広いアプリケーション、このプロセスを理解するための次のいくつかの例

1.gpio-button-hotplug(コアレイヤーはhotplug procdに送信します)

gpio-button-hotplugパッケージkernelは、見つかったパッケージ/ kernel / gpio-button-hotplug /です。



すべきCONFIG_PACKAGE_kmod-gpio-button-hotplug=yオプションを開く

1.1ドライバー

「Gpio-keys」と「gpio-keys-polled」は、次の2つのプラットフォームデバイスです。



static struct platform_driver gpio_keys_driver = { .probe = gpio_keys_probe, .remove = gpio_keys_remove, .driver = { .name = 'gpio-keys', .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_keys_of_match), }, } static struct platform_driver gpio_keys_polled_driver = { .probe = gpio_keys_polled_probe, .remove = gpio_keys_remove, .driver = { .name = 'gpio-keys-polled', .owner = THIS_MODULE, .of_match_table = of_match_ptr(gpio_keys_polled_of_match), }, } static int __init gpio_button_init(void) { int ret ret = platform_driver_register(&gpio_keys_driver) if (ret) return ret ret = platform_driver_register(&gpio_keys_polled_driver) if (ret) platform_driver_unregister(&gpio_keys_driver) return ret } static void __exit gpio_button_exit(void) { platform_driver_unregister(&gpio_keys_driver) platform_driver_unregister(&gpio_keys_polled_driver) } module_init(gpio_button_init) module_exit(gpio_button_exit)

以前のプラクティスと同様に、デバイスとドライバー、ドライバー側、デバイスの内側またはdtsのアーチが内側にあります。

DTSは構成の内部を調べます

gpio-keys-polled { compatible = 'gpio-keys-polled' #address-cells = #size-cells = poll-interval = <20> power { label = 'power' gpios = <&gpio0 24 1> //GPIO24 line is low, key is pressed linux,code = <116> //KEY_POWER } reset { label = 'reset' gpios = <&gpio1 11 1> //GPIO43 line is low, key is pressed linux,code = <0x198> //KEY_RESTART } }

これらのパラメータの上で、正しい形式を決定するために解析されるgpio_keys_get_devtree_pdata関数では、スタートアップ登録のエラーがエラーメッセージを表示します。



もう1つは内部のアーチに登録されています。
内部に登録インターフェースzkernel / 3.10.49 / arch / mips / mtk /dev-gpio-buttons.cを提供します。呼び出すことができます。

#define ZRMT7621_KEYS_POLL_INTERVAL 20 #define ZRMT7621_KEYS_DEBOUNCE_INTERVAL (3 * ZRMT7621_KEYS_POLL_INTERVAL) static struct gpio_keys_button zrmt7621_gpio_buttons[] __initdata = { { .desc = 'reset', .type = EV_KEY, .code = KEY_RESTART, .debounce_interval = ZRMT7621_KEYS_DEBOUNCE_INTERVAL, .gpio = ZRMT7621_GPIO_BUTTON_RESET, .active_low = 1, }, } ramips_register_gpio_buttons(-1, ZRMT7621_KEYS_POLL_INTERVAL, ARRAY_SIZE(zrmt7621_gpio_buttons), zrmt7621_gpio_buttons)

対応するタイプと適切なコードを定義するためのボタン内の上記の構造では、

ここでは、下位レベルの定義を確認できるように、意図的にlinux、値で記述された数値コードを示しています。gpio-button-hotplug.c次のように定義されています。

static struct bh_map button_map[] = { BH_MAP(BTN_0, 'BTN_0'), BH_MAP(BTN_1, 'BTN_1'), BH_MAP(BTN_2, 'BTN_2'), BH_MAP(BTN_3, 'BTN_3'), BH_MAP(BTN_4, 'BTN_4'), BH_MAP(BTN_5, 'BTN_5'), BH_MAP(BTN_6, 'BTN_6'), BH_MAP(BTN_7, 'BTN_7'), BH_MAP(BTN_8, 'BTN_8'), BH_MAP(BTN_9, 'BTN_9'), BH_MAP(KEY_BRIGHTNESS_ZERO, 'brightness_zero'), BH_MAP(KEY_CONFIG, 'config'), BH_MAP(KEY_COPY, 'copy'), BH_MAP(KEY_EJECTCD, 'eject'), BH_MAP(KEY_HELP, 'help'), BH_MAP(KEY_LIGHTS_TOGGLE, 'lights_toggle'), BH_MAP(KEY_PHONE, 'phone'), BH_MAP(KEY_POWER, 'power'), BH_MAP(KEY_RESTART, 'reset'), BH_MAP(KEY_RFKILL, 'rfkill'), BH_MAP(KEY_VIDEO, 'video'), BH_MAP(KEY_WIMAX, 'wwan'), BH_MAP(KEY_WLAN, 'wlan'), BH_MAP(KEY_WPS_BUTTON, 'wps'), }

in include/dt-bindings/input/linux-event-codes.h次のように定義されているので、最終的な値がわかります。

#define KEY_RESTART 0x198 #define KEY_INSERT 110 #define KEY_DELETE 111 #define KEY_MACRO 112 #define KEY_MUTE 113 #define KEY_VOLUMEDOWN 114 #define KEY_VOLUMEUP 115 #define KEY_POWER 116 /* SC System Power Down */ #define KEY_KPEQUAL 117 #define KEY_KPPLUSMINUS 118 #define KEY_PAUSE 119 #define KEY_SCALE 120 /* AL Compiz Scale (Expose) */

正常にロードされたドライバーには、次の情報が含まれます。

root@xxxxx:/sys/devices/platform/gpio-keys-polled# ls driver modalias subsystem uevent
1.2主要なアプリケーション層プロセス

ボタンがトリガーされたときbutton_hotplug_event関数(gpio-button-hotplug.c):call button_hotplug_create_event ueventイベントを生成し、call button_hotplug_fill_even Filledイベント(JSON形式)、最後に呼び出しbroadcast_ueventカーネルの後に発行されたUeventブロードキャスト情報netlink_broadcast関数(linux-3.10.49 / net / netlink / af_netlink.c)

主要なnetlinkは、このファイルの次の説明を参照し、ソケットからソケットへのブロードキャスト通信、コア、ソケットイベントをリッスンするだけでよい上位アプリケーション(procd)を発行できます。
https://blog.csdn.net/Swallow_he/article/details/84073545

ブロードキャストはprocdであると述べています。プロセスhotplug_handler(procd / plugin / hotplug.c)が受信され、JSONコンテンツの一致条件など/ hotplug.jsonが事前定義されているため、ポジショニング関数に対応して実行されます。

[ 'if', [ 'and', [ 'has', 'BUTTON' ], [ 'eq', 'SUBSYSTEM', 'button' ], ], [ 'exec', '/etc/rc.button/%BUTTON%' ] ],

ファイナルは、/ etc / rc.button /内部で同じ名前を実行します。reset/ powerなどの対応するスクリプト内のbutton_map構造を保持します。

root@xxxxx:/# cat etc/rc.button/power #!/bin/sh [ '${ACTION}' = 'released' ] || exit 0 exec /sbin/poweroff return 0 root@xxxxx:/# cat etc/rc.button/reset #!/bin/sh . /lib/functions.sh OVERLAY='$( grep ' /overlay ' /proc/mounts )' case '$ACTION' in pressed) [ -z '$OVERLAY' ] && return 0 return 5 timeout) . /etc/diag.sh set_state failsafe released) if [ '$SEEN' -lt 1 ] then echo 'REBOOT' > /dev/console sync reboot elif [ '$SEEN' -gt 5 -a -n '$OVERLAY' ] then echo 'FACTORY RESET' > /dev/console jffs2reset -y && reboot & fi esac return 0

ネットワークケーブルがポートに接続されているかどうか2.WAN検出(PHYコアの問題)

カーネルがWANポートの変更を検出するホットプラグメッセージ(broadcast_uevent)を作成し、procdに送信してから、対応するモジュールに転送します。

static void phy_hotplug_work(struct work_struct *work) { struct bh_event *event = container_of(work, struct bh_event, work) int ret = 0 event->skb = alloc_skb(BH_SKB_SIZE, GFP_KERNEL) if (!event->skb) goto out_free_event ret = bh_event_add_var(event, 0, '%root@xxxxx', event->action) if (ret) goto out_free_skb ret = phy_hotplug_fill_event(event) if (ret) goto out_free_skb if (event->type) { printk(KERN_NOTICE 'phy: port%u %s(irq) ', event->port_num, event->action) } else { printk(KERN_NOTICE 'phy: port%u %s(dev) ', event->port_num, event->action) } NETLINK_CB(event->skb).dst_group = 1 broadcast_uevent(event->skb, 0, 1, GFP_KERNEL) out_free_skb: if (ret) { kfree_skb(event->skb) } out_free_event: kfree(event) }

次のスクリプトは発行後にトリガーされます。スクリプトにコンテンツを追加する必要があります

/etc/hotplug.d/phy/00-wanに来ました

case '$wan_ifname' in 'eth'*) if [ '$wan_port' = '$PORTNUM' ] then logger -t 'phy' '$PORTNUM $ACTION' mkdir -p /tmp/status >/dev/null 2>&1 case '$ACTION' in 'linkup') echo '1' >/tmp/status/wan_port_status ubus call zboard set_wan '{'status':1,'port':$wan_port}' dhcp_handle_up 'wan' '$wan_ifname' 'linkdown') echo '0' >/tmp/status/wan_port_status ubus call zboard set_wan '{'status':0,'port':$wan_port}' dhcp_handle_down 'wan' '$wan_ifname' esac phy_hotplug 'wan' $ACTION fi *) if [ '$wan_port' = '$PORTNUM' ] then logger -t 'phy' '$PORTNUM $ACTION for wisp' mkdir -p /tmp/status >/dev/null 2>&1 case '$ACTION' in 'linkup') echo '1' >/tmp/status/wan_port_status ubus call zboard set_wan '{'status':1,'port':$wan_port}' 'linkdown') echo '0' >/tmp/status/wan_port_status ubus call zboard set_wan '{'status':0,'port':$wan_port}' esac fi esac

3.ネットワーク検出LEDの点滅を追加します(/ sbin / hotplug-call)

3.1zdetectネットワーク検出モジュール

zrouter / zpackages / zihome / utils / zdetect / src / zdetect.cでは、ネットワークが変更されたときに送信されるホットプラグイベント:

static void inet_hotplug(const char* action) { char *argv[3] int pid pid = fork() if (pid <0) { dbg_printf(MSG_INFO, 'hotplug_event fork failed!') return } else if (pid == 0) { setenv('ACTION', action, 1) argv[0] = HOTPLUG_PATH argv[1] = 'inet' argv[2] = NULL execvp(argv[0], argv) exit(127) } }
3.2ホットプラグメッセージ受信モジュールinet

14.07 / package / base-files / files / etc / hotplug.d / inet / 00-inet

#!/bin/sh case '$ACTION' in 'online') logger -t 'inet' 'detect online' zihome_led yellow on 'offline') logger -t 'inet' 'detect offline' zihome_led yellow 1000 1000 *) esac
3.3呼び出しはスクリプトを実行しました

14.07 / package / base-files / files / sbin / zihome_led

#!/bin/sh . /lib/functions/leds.sh led_path='zihome:''$1' led

4.iface(netifd)

すべてのスクリプトが/etc/hotplug.d/iface/ディレクトリでアルファベット順に実行されたら、各ネットワークインターフェイスを起動(上)またはオフ(下)します。不文律に従って、各スクリプトの前に正しい実行シーケンスを設定するために数値プレフィックスを追加します。これが、スクリプトの名前が次のような理由です:理由/etc/hotplug.d/iface/-。

変数名 説明
アクション 「ifup」または「ifdown」
インターフェース 'wan'などのネットワークインターフェイス名
端末 'br-lan'などの物理デバイスの名前

https://blog.csdn.net/vivianliulu/article/details/79629836

static void call_hotplug(void) static void run_cmd(const char *ifname, const char *device, enum interface_event event, enum interface_update_flags updated) { char *argv[3] int pid pid = fork() if (pid 0) { task.pid = pid uloop_process_add(&task) return } setenv('ACTION', eventnames[event], 1) setenv('INTERFACE', ifname, 1) if (device) setenv('DEVICE', device, 1) if (event == IFEV_UPDATE) { if (updated & IUF_ADDRESS) setenv('IFUPDATE_ADDRESSES', '1', 1) if (updated & IUF_ROUTE) setenv('IFUPDATE_ROUTES', '1', 1) if (updated & IUF_PREFIX) setenv('IFUPDATE_PREFIXES', '1', 1) if (updated & IUF_DATA) setenv('IFUPDATE_DATA', '1', 1) } argv[0] = hotplug_cmd_path argv[1] = 'iface' argv[2] = NULL execvp(argv[0], argv) exit(127) }