ARM上的linux如何实现无线网卡的冷插拔和热插拔

2022-12-23,,,,

ARM上的linux如何实现无线网卡的冷插拔热插拔

fulinux 凌云实验室

1. 冷插拔

如果在系统上电之前就将RT2070/RT3070芯片的无线网卡(以下简称wlan)插上,即冷插拔。我们通过分析系统启动流程过程中的运行的脚本,将启动wlan的脚本加入其中,就可以实现自动运行wlan.。

系统启动后的第一个进程/sbin/init。init进程最主要的功能就是准备软件执行的环境,包括系统的主机名、网络配置、语系处理、文件系统格式以及其他服务的启动等。而所有的操作都会通过init的配置文件,即/etc/inittab来规划。

在inittab文件中有很多如下格式的语句:

label:runlevel:action:process

但是我们这里只关注下面这条语句:

# now run any rc scripts

null::wait:/etc/init.d/rcS

即运行所有的rc 脚本,这里是运行rcS脚本,rcS脚本内容如下:

~ >: cat /etc/init.d/rcS

#!/bin/sh

# Copyright (C) 2011 GuoWenxue <guowenxue@gmail.com QQ:281143292>

# Start all init scripts in /etc/init.d

# executing them in numerical order.

#

for i in /etc/init.d/S??* ;do

$i

done

~ >:

很简单的一个脚本,即运行/etc/init.d/目录下以S开头,两个?匹配任意两个字符

*匹配0或多个字符。该目录下有一个文件S01_network,内容如下:

注:绿色为注释
~ >: cat etc/init.d/S01_network

#!/bin/sh

# FILE:/etc/init.d/S01_network

# Copyright (C) 2012 GuoWenxue <guowenxue@gmail.com QQ:281143292>

# This file used to configure the network from the configure files

#network_cfg_dir变量是否为空,如果是将/apps/etc/network赋值给network_cfg_dir。

if [ -z "$network_cfg_dir" ] ; then

export network_cfg_dir=/apps/etc/network

Fi

#进入/apps/etc/network目录

cd $network_cfg_dir

#~ >: cd apps/etc/network/

/apps/etc/network >: ls

bakifcfg-wlan0       ifcfg-eth0           resolv.conf

gatewayD.conf        ifcfg-ppp10          wpa_supplicant.conf

hostapd.conf         ifcfg-wlan0

/apps/etc/network >:

#上面这个正则表达式的目的是提取出网卡名,例如eth0、wlan0,其中wlan0为我们所需要的。

interfaces=$( ls ifcfg* | \

sed -e '/ifcfg-[A-Za-z0-9\._-]\+$/ { s/^ifcfg-//g;s/[0-9]/ &/}' | \

sort -k 1,1 -k 2n | \

sed 's/ //')

#如果网卡还没有配置好,那么运行:#ifconfig 系统只会输出以lo 为首的部分。lo 是look-back网络接口,从IP地址127.0.0.1就可以看出,它代表本机。无论系统是否接入网络,这个设备总是存在的,除非你在内核编译的时候禁止了网络支持,这是一个称为回送设备的特殊设备,它自动由Linux配置以提供网络的自身连接。IP地址127.0.0.1是一个特殊的回送地址(即默认的本机地址),可以在自己的系统上用telnet对IP地址127.0.0.1进行测试。如果有inetd进程在运行的话您会从自己的机器上获得登录提示符。Linux可以利用这个特征在进程与仿真网络之间进行通信。(您有兴趣的话还可以试试本机的实际IP地址,如这里的机器就是210.34.6.89,或者试试"localhost",或者"127.0.0.1",同样可以模拟网络通信。这可是Linux一个非常突出的优点!)

ifconfig lo 127.0.0.1

# No interface configure, then use the default IP address

如果/apps/etc/network目录下没有带网卡名的文件,这时interface变量为空,配置eth0网卡,之后退出。

if [ -z "$interfaces" ] ; then

ifconfig eth0 192.168.1.223 up

exit

fi

# Set up all the interface

设置所有网卡接口

for i in $interfaces; do

#unset删除变量或函数

unset DEVICE TYPE

#如果这时候$i为wlan0,则下面的目的是提取出ifcfg-wlan0文件中的DEVICE、TYPE等号后面的内容。ifcfg-wlan0在该脚本下面。

eval $(fgrep "DEVICE=" ifcfg-$i)

eval $(fgrep "TYPE=" ifcfg-$i)

#如果$DEVICE为空,着将$i的值赋给它。

if [ -z "$DEVICE" ] ; then DEVICE="$i"; fi

#如果ifcfg-wlan0文件中的ONBOOT不为no,时执行下面的语句。

if ! egrep -L "^ONBOOT=['\"]?[Nn][Oo]['\"]?" ifcfg-$i > /dev/null ; then

#下面是根据各自的TYPE值,执行相应的脚本

if [ "$TYPE" = "Ethernet" ] ; then

echo "Bring up $TYPE interface $i"

/usr/sbin/ifup-eth $i

elif [ "$TYPE" = "PPP" ] ; then

echo "Bring up $TYPE interface $i"

elif [ "$TYPE" = "WLAN" ] ; then

# Just bring up the wiFi module here. Configure it in the followed shell scripts

#如果是WLAN,存在目录/sys/class/net/wlan0/就会运行下面的命令,其中/apps/tools/ifup-wlan是一个脚本。在ifcfg-wlan0配置文件下面。

if [ -d /sys/class/net/$DEVICE/ ] ; then

/apps/tools/ifup-wlan $i

fi

else

echo "Bring up $TYPE interface $i"

fi

fi

# for循环结束

done

#结束

~ >:

1.1. ifcfg-wlan0配置文件

/apps/etc/network/ifcfg-wlan0配置文件中的内容如下:

/apps/etc/network >: cat ifcfg-wlan0

#Wireless Network adapter RT3070(wlan0) device configure file

#FILE:/apps/etc/network/ifcfg-wlan0

# Copyright (C) 2012 GuoWenxue <guowenxue@gmail.com QQ:281143292>

DEVICE=wlan0

ONBOOT=yes

NAME="RT3070"

TYPE=WLAN

#The WiFi Module should work on AP or STA mode

#AP mode 是类似于一个不带有限接口lan的无线路由,即市面上的迷你无线路由,STA  mode是无线上网终端一般所用的模式。我们要向无线上网就必须使用STA mode

WORKMODE=STA

#WORKMODE=AP

#BOOTPROT should be static or dhcp, it will only take effact

#when the NIC work on STA mode

#可以说静态分配ip,也可以使用DHCP动态分配ip.这里使用静态,静态建立连接到速度快。

BOOTPROTO=static

#这是AP模式要使用的配置

#Work on AP mode IP address

IPADDR_AP=192.168.5.1

NETMASK_AP=255.255.255.0

#Work on STA mode IP address

IPADDR_STA=192.168.1.166

NETMASK_STA=255.255.255.0

#Gateway Settings

GATEWAY=192.168.1.1

DEFROUTE=yes

#DHCP Server configuration, only take effact when the NIC work on AP mode

#这是AP模式要使用的配置

DHCP_SERVER=yes

DHCP_START_IP=192.168.5.10

DHCP_END_IP=192.168.5.100

DHCP_NETMASK=255.255.255.0

DHCP_GATEWAY=192.168.5.1

DHCP_DNS1=4.2.2.2

DHCP_DNS2=8.8.8.8

DHCP_LEASE=18800

1.2. ifup-wlan脚本

#ifup-wlan脚本解析

/apps/etc/init.d >: vim /apps/tools/ifup-wlan

#!/bin/sh

# FILE:/usr/sbin/ifup-wlan0

# Copyright (C) 2011 GuoWenxue <guowenxue@gmail.com QQ:281143292>

# This file used to configure the specified network interface device

source /etc/profile

#判断目录是否存在,如果不存在,则赋值为/apps/etc/network目录。

if [ -z "$network_cfg_dir" ];  then

export network_cfg_dir=/apps/etc/network

fi

#将传入的参数赋值给DEVICE ,$1和${1}的区别,例如:

val=10

test=${val}ue  这种情况下,是获取val变量的值,则test=10ue

text=$value    这种情况下,是获取value变量的值,这里value未定义

这两个是不一样的:

带括号的话,所以{}使用来标识哪一部分是变量名

/*****************************转载声明****************************/

DEVICE=${1}

#下面这个是一个很巧妙的语句,关键是&&,”[]”这个也具有判断的功能,一般执行与判断时,如果第一个判断语句是假,则不必往下执行,如果为真就会判断下一个语句。这里如果传进来的参数有不为空,即为真时,就会执行与后面的语句打印信息,并退出脚本。

[ -z "${DEVICE}" ] && {

echo $"Usage: $0 <device name>" >&2

exit 1

}

#下面的判断语句中-o是或的意思,查看man test

( EXPRESSION )

EXPRESSION is true  真判定

! EXPRESSION

EXPRESSION is false 否判定

EXPRESSION1 -a EXPRESSION2

both EXPRESSION1 and EXPRESSION2 are true 与判定

EXPRESSION1 -o EXPRESSION2

either EXPRESSION1 or EXPRESSION2 is true 或判定

-d  FILE

FILE exists and is a directory

-f  FILE

FILE exists and is a regular file

if [ ! -d $network_cfg_dir -o ! -f "$network_cfg_dir/ifcfg-${DEVICE}" ]; then

echo "$0: configuration<$network_cfg_dir/ifcfg-${DEVICE}> not found." >&2

echo "Usage: $0 <device name>" >&2

exit 1

fi

#判断/sys/class/net/wlan0是否存在,说明没有wlan0适配器退出

if [ ! -d /sys/class/net/$DEVICE/ ] ; then

echo  "Wireless network adapter $DEVICE dosn't exist, exit now..."

exit

fi

#其中有个“。”相当于source命令。查看

[lingyun@vmlinux fulinux]$ man source

.  filename [arguments]

这里是使能ifcfg-wlan0配置文件。

使能了这些文件后上面的一些参数就成为系统中的全局参数,比如说我在下面加入如下代码时,

cd $network_cfg_dir

. ifcfg-${DEVICE}

echo "print wifi workmode is $WORKMODE"

会打印如信息

/apps/tools >: sh ifup-wlan wlan0

print wifi workmode is STA

因为是在脚本中使能了这个文件,所以相当于创建了一个子进程,如果退出这个脚本后出来运行echo $WORKMODE不会有什么显示。

cd $network_cfg_dir

. ifcfg-${DEVICE}

#由于配置文件中的WORKMODE的选项很肯使用小写的sta或是ap,也有可能是Sta和Ap书写方法,通过下面的第一个语句就可以将这些选项统统装化为大写模式,toupper()是一个转换为大写的函数。如果不是STA(station)模式,就赋值为AP模式。

WORKMODE=$(echo $WORKMODE | awk '{ print toupper($0) }')

if [ $WORKMODE != "STA" ] ; then

WORKMODE="AP"

fi

echo "Enable network interface $DEVICE[$NAME] work on $WORKMODE mode." >&2

#下面主要的是理解eval命令,可以通过在shell中拆解来理解,如下

/apps/etc/network >: export WORKMODE=STA

/apps/etc/network >: export IPADDR_STA=192.168.1.166

/apps/etc/network >: echo $WORKMODE

STA

/apps/etc/network >: echo \$IPADDR_$WORKMODE

$IPADDR_STA

/apps/etc/network >: eval "echo \$IPADDR_$WORKMODE"

192.168.1.166

/apps/etc/network >:

也就是把192.168.1.166赋值给ipaddr,同理netmask=255.255.255.0

parser_ip()

{

unset ipaddr netmask

ipaddr=$(eval "echo \$IPADDR_$WORKMODE")

netmask=$(eval "echo \$NETMASK_$WORKMODE")

}

#下面这一个是关掉wifi适配器的函数。

stop_wifi_worker()

{

#stop DHCP work on this NIC

#分解运行分析如下:

/apps/etc/network >: ps | grep dhcp

5385 root      1332 S    udhcpc -i eth0

10678 root      1324 S    udhcpc -i wlan0

11598 root      1316 S    grep dhcp

/apps/etc/network >: ps | grep dhcp | grep -v grep

5385 root      1332 S    udhcpc -i eth0

10678 root      1324 S    udhcpc -i wlan0

/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan

10678 root      1324 S    udhcpc -i wlan0

/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan | awk '{print $1}'

/apps/etc/network >: ps | grep dhcp | grep -v grep | grep wlan | awk '{print $2}'

root 这样可以获得udhcpc -i wlan0的进程id,并将其杀死。下同。

dhcp_pid=`ps | grep -v grep | grep "dhcp" | grep $DEVICE | awk '{print $1;}'`

if [ -n "$dhcp_pid" ] ; then

kill $dhcp_pid

fi

ifconfig $DEVICE 0.0.0.0

#Stop wpa_supplicant work on STA mode

pid=`ps | grep -v grep | grep "wpa_supplicant" | grep $DEVICE | awk '{print $1;}'`

if [ -n "$pid" ] ; then

kill $pid

sleep 1

fi

if [ -d /var/run/wpa_supplicant ] ; then

rm -rf /var/run/wpa_supplicant

fi

#Stop hostapd work on AP mode

pid=`ps | grep -v grep | grep "hostapd" | awk '{print $1;}'`

if [ -n "$pid" ] ; then

kill $pid

sleep 1

fi

if [ -d /var/run/hostapd ] ; then

rm -rf /var/run/hostapd

fi

}

#配置wifi为station模式。

configure_wifi_sta()

{

parser_ip

#If enable DHCP configure or IP address not configured, then use DHCP get IP address and exit

#man test 可以查看下面判断选项的意思

-n STRING

the length of STRING is nonzero

字符串的长度不为0为真

STRING equivalent to -n STRING

-z STRING

the length of STRING is zero

字符串的长度为0为真

-o选项是或运算

if [ -n "$BOOTPROTO" -o -z "$ipaddr" ]; then

BOOTPROTO=$(echo $BOOTPROTO | awk '{ print toupper($0) }')

if [ "$BOOTPROTO" = "DHCP" ] ; then

ifconfig $DEVICE up

#Start wpa_supplicant to work now

#连接路由命令,这里使用的配置文件是apps/etc/network/目录下的wpa_supplicant.conf

/apps/tools/wpa_supplicant -B -Dwext -i$DEVICE -c${network_cfg_dir}/wpa_supplicant.conf

#再为我们的wifi动态分配ip地址,并且是后台运行。

udhcpc -i $DEVICE &

exit

fi

fi

# Calculate the network configuration value

#如果没有上面的动态分配且不存在子网掩码,就需要分配一个

if [ -z "${netmask}" ] ; then

eval $(/bin/ipcalc --netmask ${ipaddr})

fi

#Configure for the WiFi interface IP address and bring up it

#静态分配ip地址和掩码。

ifconfig $DEVICE $ipaddr netmask $netmask up

#Set the default route

#把DEFROUTE选项都转化为大写。

DEFROUTE=$(echo $DEFROUTE | awk '{ print toupper($0) }')

且DEFROUTE选项为YES时,

if [ -n "$GATEWAY" -a "$DEFROUTE" = "YES" ]; then

#ip route add  ${NETWORK}/${PREFIX} via $GATEWAY > /dev/null 2>&1

ip route replace default via $GATEWAY

fi

#Start wpa_supplicant to work now

mkdir -p /var/run/wpa_supplicant

/apps/tools/wpa_supplicant -B -Dwext -i$DEVICE -c${network_cfg_dir}/wpa_supplicant.conf

}

#通过将rt2070/rt3070配置为AP模式后,我们的笔记本和手机就能连接到wlan0上来,再通过netfilter/iptables构建的防火墙,使eth0接有线连接到internet上,我们的笔记本和手机就能通过它上网 -_-||

configure_wifi_ap()

{

parser_ip

#Configure for the WiFi interface IP address and bring up it

,就静态分配ipaddr

if [ -z "$ipaddr" ] ; then

ipaddr=192.168.1.166

netmask=255.255.255.0

fi

ifconfig $DEVICE $ipaddr netmask $netmask up

#Enable DHCP server

#使能DHCP服务功能,这样我们就不用为每台连接到开发板上的电脑和手机静态分配ip地址,而是通过开发板上的DHCP服务为每一台连接的终端设备动态分配地址。

DHCP_SERVER=$(echo $DHCP_SERVER | awk '{ print toupper($0) }')

#如果$DHCP_SERVER 长度不为空,且$DHCP_SERVER为YES时才为真。

if [ -n "$DHCP_SERVER" -a "$DHCP_SERVER" = "YES" ]; then

#定义一些配置文件:/tmp/dhcpd_wlan0.config , /tmp/dhcpd_wlan0.leases , /var/run/dhcpd_wlan0.pid

conf_file="/tmp/dhcpd_${DEVICE}.conf"

lease_file="/tmp/dhcpd_${DEVICE}.leases"

pid_file="/var/run/dhcpd_${DEVICE}.pid"

#[lingyun@localhost ~]$ ipcalc -h

ipcalc: ip address expected

Usage: ipcalc [OPTION...]

-c, --check         Validate IP address for specified address family

-4, --ipv4          IPv4 address family (default)

-6, --ipv6          IPv6 address family

-b, --broadcast Display calculated broadcast address(显示指定ip和子网掩码的广播地址)
 -h, --hostname Show hostname determined via DNS(显示指定ip的主机名)
 -m, --netmask Display default netmask for IP (class A, B, or C)(显示指定ip的子网掩码--特指默认,实际未必是)
 -n, --network Display network address(显示指定ip的网络地址)
 -p, --prefix Display network prefix(显示网络前缀)
 -s, --silent Don't ever display error messages (不显示错误信息)

Help options:

-?, --help          Show this help message

--usage             Display brief usage message

#[lingyun@localhost ~]$ipcalc -p 192.168.1.1 255.255.255.0
PREFIX=24
#[lingyun@localhost ~]$ipcalc -n 192.168.1.1 255.255.255.0
NETWORK=192.168.1.0
#[lingyun@localhost ~]$ipcalc -h 192.168.1.1
HOSTNAME=dbrg-2
#[lingyun@localhost ~]$ipcalc -m 192.168.1.1
NETMASK=255.255.255.0
#[lingyun@localhost ~]$ipcalc -pnbm 192.168.1.1 255.255.255.0
NETMASK=255.255.255.0
PREFIX=24
BROADCAST=192.168.1.255
NETWORK=192.168.1.0
#[lingyun@localhost ~]$

所以下面的意图是取得子网的网络地址。例如

[lingyun@localhost ~]$ ipcalc -n 192.168.5.1 255.255.255.0

NETWORK=192.168.5.0

[lingyun@localhost ~]$ ipcalc -n 192.168.5.1 255.255.255.0 | awk -F "=" '{print $2}'

192.168.5.0

[lingyun@localhost ~]$

DHCP_SUBNET=`ipcalc -n $DHCP_START_IP $DHCP_NETMASK | awk -F "=" '{print $ 2}`

#下面是将子网的网络地址、子网掩码、动态分配的起止地址、域名解析、网关、租约时间(IP默认失效时间)等写到/tmp/dhcpd_wlan0.config文件中,其中“>”和“>>”是重定向:

1、shell遇到”>”操作符,会判断右边文件是否存在,如果存在就先删除,并且创建新文件。不存在直接创建。 无论左边命令执行是否成功。右边文件都会变为空。

2、“>>”操作符,判断右边文件,如果不存在,先创建。以添加方式打开文件,会分配一个文件描述符[不特别指定,默认为1,2]然后,与左边的标准输出

形成下面类似的结构:

段内的ip*/
            default-lease-time 21600;                                                                                  /*默认地址租期,单位为s*/
            max-lease-time 43200;                                                                                     /*最长地址租期,单位为s*/

}

echo "subnet $DHCP_SUBNET netmask $DHCP_NETMASK { " > $conf_file

echo "  range $DHCP_START_IP $DHCP_END_IP;" >> $conf_file

echo "  option domain-name-servers $DHCP_DNS1, $DHCP_DNS2;" >> $conf_file

echo "  option routers $DHCP_GATEWAY;" >> $conf_file

echo "  default-lease-time $DHCP_LEASE;" >> $conf_file

echo "  max-lease-time 72000;" >> $conf_file

echo "  authoritative;" >> $conf_file

echo "}" >> $conf_file

#大多数情况下,DHCP 的安装不创建一个 dhcpd.leases 文件,在你启动 DHCP 服务器之前,你必须创建空文件 dhcpd.leases:

touch $lease_file

dhcpd -q -pf $pid_file -cf $conf_file -lf $lease_file $DEVICE

fi

#下面启动AP模式

# Start hostapd to server on AP mode

mkdir -p /var/run/hostapd

/apps/tools/hostapd -B ${network_cfg_dir}/hostapd.conf

}

#真正的主题在这,上面相当于C函数,而这里相当于main函数。判断是不是STA模式,如果是就先关闭wifi,再启动STA模式,AP模式亦然

if [ $WORKMODE == "STA" ]; then

stop_wifi_worker

configure_wifi_sta

else

stop_wifi_worker

configure_wifi_ap

fi

#结束

AP  mode我们暂时不用考虑。到这里差不多可以实现启动自动运行wlan0 的目的了,有线的eth0可以拔出。

运行结果如下:

~ >: ifconfig wlan0

wlan0     Link encap:Ethernet  HWaddr 00:0C:43:30:72:81

inet addr:192.168.1.166  Bcast:192.168.1.255  Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:136 errors:0 dropped:15 overruns:0 frame:0

TX packets:4 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:14849 (14.5 KiB)  TX bytes:548 (548.0 B)

~ >: iwconfig wlan0

wlan0     IEEE 802.11bgn  ESSID:"Router_LingYun"

Mode:Managed  Frequency:2.437 GHz  Access Point: D8:5D:4C:18:04:7A

Bit Rate=1 Mb/s   Tx-Power=20 dBm

Retry  long limit:7   RTS thr:off   Fragment thr:off

Encryption key:off

Power Management:on

Link Quality=49/70  Signal level=-61 dBm

Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0

Tx excessive retries:0  Invalid misc:4   Missed beacon:0

~ >: ping www.baidu.com

PING www.baidu.com (115.239.210.26): 56 data bytes

64 bytes from 115.239.210.26: seq=0 ttl=55 time=58.396 ms

64 bytes from 115.239.210.26: seq=1 ttl=55 time=95.457 ms

64 bytes from 115.239.210.26: seq=2 ttl=55 time=97.314 ms

64 bytes from 115.239.210.26: seq=3 ttl=55 time=99.431 ms

64 bytes from 115.239.210.26: seq=4 ttl=55 time=97.498 ms

--- www.baidu.com ping statistics ---

5 packets transmitted, 5 packets received, 0% packet loss

round-trip min/avg/max = 58.396/89.619/99.431 ms

~ >:

表明已经连接上了网络。

2. 热插拔

2.1. hotplug

要实现热插拔首先内核要支持hotplug,配置如下:

Device Drivers  --->

Generic Driver Options  --->

(/sbin/hotplug) path to uevent helper

[ ] Maintain a devtmpfs filesystem to mount at /dev

[ ] Select only drivers that don't need compile-time external firmware

[ ] Prevent firmware from being built

Linux系统处理热插拔的机制是这样的

l 将可移动设备连入系统时,系统的后台中会依次发生如下事件:


内核检测到新硬件插入,然后分别通知hotplug和udev。前者用来装入相应的内核模块(如usb-storage),而后者用来在/dev中创建相应的设备节点(如/dev/sda1)。


udev创建了相应的设备节点之后,会将这一消息通知hal的守护程序(hald)。当然udev还得保证新创建的设备节点可以被普通用户访问。


hotplug装入了相应的内核模块之后,会把这一消息通知给hald。


hald在受到hotplug和udev发出的消息之后,认为新硬件已经正式被系统认可了。此时它会通过一系列精心编写的规则文件(就是传说中的xxx-policy.fdi),把发现新硬件的消息通过dbus发送出去,同时还会调用update-fstab或fstab-sync来更新/etc/fstab,为相应的设备节点创建适合的挂载点。


卷管理器会监听dbus中发现新硬件的消息。根据所插入的硬件(区分U盘和数码相机等)不同,卷管理器会先将相应的设备节点挂载到hald创建的挂载点上,然后再打开不同的应用程序。

l 当然,如果是在CDROM中插入光盘,过程可能比较简单。因为CDROM本身就是一个固定的硬件,无需hotplug和udev的协助:


hald会自己监视CDROM,并且将光盘托架开合的消息通过dbus发出去。


卷管理器负责检查CDROM中的盘片内容,进行挂载,并调用合适的应用程序。

l 要注意,hald的工作是从上游得到硬件就绪的消息,然后将这个消息转发到dbus中。尽管它会调用程序来更新fstab,但实际上它自己并不执行挂载的工作。

l 下面是上面的过程中涉及的模块和工具:


hotplug

l hotplug 包和内核里的hotplug模块不是一回事,2.6内核里的pci_hotplug.ko是一个内核模块,而hotplug包是用来处理内核产生的hotplug事件。这个软件包还在引导时检测现存的硬件并在运行的内核中加载相关模块。

l 不但有热插拔,还有冷插拔(cold pluging)。热插拔在内核启动之后发生,而“cold pluging”发生在内核启动的过程中。

l /etc/hotplug/*.rc 这些脚本用于冷插拔(检测和激活在系统启动时已经存在的硬件)。它们被 hotplug 初始化脚本调用。*.rc 脚本会尝试恢复系统引导时丢失的热插拔事件,举例来说,内核没有挂载根文件系统。

l /etc/hotplug/*.agent这些脚本将被 hotplug调用以响应内核产生的各种不同的热插拔事件,导致插入相应的内核模块和调用用户预定义的脚本。

l /sbin/hotplug内核默认情况下将在内核态的某些事情发生变化时(如硬件的插入和拔出)调用此脚本。

l 发送热插拔事件的子系统(subsystem)包括总线驱动(USB、PCI等)和一些设备的抽象层(网络接口、磁盘分区等)。它们通过/sbin/hotplug的第一个参数来识别。

l 对于设备驱动来说,需要在代码里设置MODULE_DEVICE_TABLE,指向驱动程序感兴趣的设备的设备ID列表。
udev

l 在2.6内核里,使用了udev来取代hotplug。据udev的作者Greg K.H说,之所以废弃了hotplug原因是sysfs的出现,这个东西会产生非常多的hotplug事件,远远超过了2.4的内核(只要实现了了kobject模型的设备驱动都回产生该事件)。所以hotplug变得复杂,而且因为hotplug都是bash所写,所以开始变得没有效率。于是出现了一个名叫hotplug-ng的项目,就是为了解决这个过于复杂以及缺乏效率的问题,ng应该是next generation的意思。但这个项目目前为止还不能胜任角色,所以udev挺身而出,充当了救火队员。

l 2.6.15之后,/proc/sys/kernel/hotplug会成空的,因为内核通知用户空间的接口变成了netlink,所以最新的udev也采用了netlink接口去写,废弃了/sbin/hotplug或者/sbin/udevsend。udev在2.6.15以后的内核上可以直接通过netlink接听设备事件,sysfs提供了uevent文件,对该文件的“写”可以送出设备事件!

l udev 完全在用户态 (userspace) 工作,利用设备加入或移除时内核所发送的hotplug 事件 (event) 来工作。关于设备的详细信息是由内核输出 (export) 到位于 /sys 的 sysfs 文件系统的。所有的设备命名策略、权限控制和事件处理都是在用户态下完成的。与此相反,devfs 是作为内核的一部分工作的。

l 传统上一般 Linux 系统使用创建静态设备的方法,因此在 /dev 目录下创建了大量的设备节点(有时会有数千个节点),而不管对应的硬件设备实际上是否存在。这通常是由 MAKEDEV 脚本完成的,这个脚本包含许多调用 mknod 程序的命令,为这个世界上可能存在的每个设备创建相应的主设备号和次设备号。而使用 udev 方式的时候,只有被内核检测到的设备才为其创建设备节点。因为每次系统启动的时候都要重新创建这些设备节点,所以它们被存储在 tmpfs 文件系统上,设备节点不需要很多磁盘空间,所占用的内存可以忽略不计。

l udev 初始化脚本负责在 Linux 启动的时候创建设备节点,该脚本首先将 /sbin/udevsend 注册为热插拔事件处理程序。热插拔事件(随后将讨论)本不应该在这个阶段发生,注册 udev 只是为了以防万一。然后 udevstart 遍历 /sys 文件系统,并在 /dev 目录下创建符合描述的设备。例如,/sys/class/tty/vcs/dev 里含有"7:0"字符串,udevstart 就根据这个字符串创建主设备号为 7 、次设备号为 0 的 /dev/vcs 设备。udevstart 创建的每个设备的名字和权限由 /etc/udev/rules.d/ 目录下的文件指定的规则来设置。如果 udev 找不到所创建设备的权限文件,就将其权限设置为缺省的 660 ,所有者为 root:root 。上面的步骤完成后,那些已经存在并且已经内建驱动的设备就可以使用了。

l 对于以模块驱动的设备,当内核检测到一个新设备连接时,内核会产生一个热插拔事件,并在 /proc/sys/kernel/hotplug 文件里查找处理设备连接的用户空间程序(新的内核通知接口改变,/proc/sys/kernel/hotplug为空了)。udev
初始化脚本将 udevsend注册为该处理程序。当产生热插拔事件的时候,内核让 udev 在 /sys 文件系统里检测与新设备的有关信息,并为新设备在 /dev 里创建项目。

l 所有在 sysfs 中显示的设备都可以由 udev 来创建节点。如果内核中增加了其它设备的支持,udev 也就自动地可以为它们工作了。

l 大多数 Linux 发行版通过 /etc/modules.conf 配置文件来处理模块加载,对某个设备节点的访问导致相应的内核模块被加载。对 udev 这个方法就行不通,因为在模块加载前,设备节点根本不存在。Linux 的设计是在设备被发现的时候加载模块,而不是当它被访问的时候。通过在 /etc/sysconfig/modules文件里添加模块名,就可以在系统启动的时候加载这些模块,这样 udev就可以检测到设备,并创建相应的设备节点了。

l 如何写udev规则。通过udevinfo程序来找到那些可以作为规则文件里的匹配项的项目。分为两种情况:第一种情况是,当你把设备插入系统后,系统为设备产生了设备名(如/dev/sda)。那样的话,你先用udevinfo -q path -n /dev/sda,命令会产生一个该设备名对应的在sysfs下的路径,如/block/sda。然后,你再用udevinfo -a -p /sys/block/sda,这个命令会显示一堆信息,信息分成很多块。这些信息实际来自于操作系统维护的sysfs链表,不同的块对应不同的路径。你就可以用这些信息来作为udev规则文件中的匹配项。但需要注意的是,同一个规则只能使用同一块中显示的信息,不能跨块书写规则;第二种情况是,不知道系统产生的设备名,那就只有到/sys目录下去逐个目录查找了,反复用udevinfo -a -p /sys/path...这个命令看信息,如果对应的信息是这个设备的,那就恭喜你。否则就再换个目录。当然,在这种情况下,成功的可能性比较小。

HAL

l HAL位于设备驱动程序和应用程序之间。

D-BUS

l D-BUS 是一个大有前途的消息总线和活动系统,正开始深入地渗透到 Linux 桌面之中。D-BUS 本质上是进程间通信(inter-process communication)(IPC)的一个实现,设计用于桌面应用程序和OS 通信。

l 典型的 D-BUS 设置将由几个总线构成。一个持久的系统总线(system bus),它在引导时就会启动。这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序不能欺骗系统事件。还将有很多会话总线(session buses),这些总线当用户登录后启动,属于那个用户私有。

l 一个更为有趣但很不实用的例子是 Jamboree 和 Ringaling 的结合。Jamboree 是一个简单的音乐播放器,它具有 D-BUS 接口,以使得它可以被告知播放、到下一首歌、改变音量等等。Ringaling 是一个小程序,它打开 /dev/ttyS0(一个串行端口)并观察接收到的内容。当 Ringaling 发现文本“RING”时,就通过 D-BUS 告知 Jamboree 减小音量。最终的结果是,如果您的计算机上插入了一个调制解调器,而且电话铃响,则音乐音量就会为您减小。
这正是计算机所追求的!

一些查看硬件信息的工具

l lspci
列出所有PCI 设备。有两个参数是比较常用,-b 和-v,lspci也会把usb接口列出来。

l lshal 列出系统硬件设备。

l Usbmodules
列出可用于已插入usb设备的驱动模块。

Hot Plug Greg Kroah-Hartman

Hot-pluggable devices have been created to solve a number of user needs. On laptop computers, PCMCIA devices were designed to allow the user to swap cards while the computer was still running. This allowed people to change network adaptors, memory cards and even disk drives without shutting down the machine.
The success of this led to the creation of the USB and IEEE1394 (FireWire) buses. These designs allow for peripherals to be attached and removed at any point. They also were created to try to move systems away from the ISA bus to a full Plug-and-Play-type system.
From the operating system's point of view, there are many problems with hot plugging devices. In the past, the operating system only had to search for the various devices connected to it on power-up, and once seen, the device would never go away. From the view of the device driver, it never expects to have the hardware that it is trying to control disappear. But with hot-pluggable devices, all of this changes.
Now the operating system has to have a mechanism that constantly detects if a new device appears. This usually is done by a bus-specific manager. This manager handles the scanning for new devices and recognizes this disappearance. It must be able to create system resources for the new device and pass control off to a specific driver. The device driver for a hot-pluggable device has to be able to recover gracefully when the hardware is removed and be able to bind itself to new hardware at any moment. Not only does the kernel need to know when devices are removed or added, but the user also should be notified when this happens. Other kinds of kernel events, such as the creation of network devices or the insertion of a laptop into a docking station, also would be useful for the user to know about.
This article describes the new framework in the Linux kernel for supporting USB and other hot-pluggable devices. It covers how the past implementation of PCMCIA loaded its drivers and the problems of that system. It presents the current method of loading USB and PCI drivers, and how this same framework can handle other kinds of user configuration issues easily.

The Past
Linux has had support for PCMCIA since 1995. In order for the PCMCIA core to be able to load drivers when a new device was inserted, it had a user-space program called cardmgr. The cardmgr program would receive notification from the kernel's PCMCIA core when a device had been inserted or removed and use that information to load or unload the proper driver for that card. It used a configuration file located at /etc/pcmcia/config to determine which driver should be used for which card. This configuration file needed to be kept up to date with which driver supported which card, or ranges of cards, and has grown to be over 1,500 lines long. Whenever a driver author added support for a new device, they had to modify two different files to enable the device to work properly.
As the USB core code became mature, the group realized that it also needed something like the PCMCIA system to be able to load and unload drivers dynamically when devices were inserted and removed. The group also noted that since USB and PCMCIA both needed this system, and that other kernel hot-plug subsystems also would use such a system, a generic hot-plug core would be useful. David Brownell posted an initial patch to the kernel (marc.theaimsgroup.com/?l=linux-usb-devel&m=96334011602320), enabling it to call out to a user-space program called /sbin/hotplug. This patch eventually was accepted, and other subsystems were modified to take advantage of it.

Let the Computer Do It Itself
All USB and PCI devices contain an identifier that describes either what kind of functions they support (like a USB audio or USB mass storage device), or if they do not support a class specification, they contain a unique vendor and product identifier. PCMCIA devices also contain these same kind of identifiers.
These identifiers are known by the PCI and USB kernel drivers, as they need to know which kind of devices they work properly for. The USB and PCI kernel drivers register with the kernel a list of the different types of devices that they support. This list is used to determine which driver will control which devices.
The kernel knows when and what kind of devices are inserted or removed from the system through the device bus core code (USB, FireWire, PCI, etc.). It can send this information to the user.
Taking these three pieces together (devices tell the computer what they are, drivers know what devices they support and the kernel knows what is going on) provides us with a solution to let the computer automatically load the proper driver whenever a new device is inserted.

/sbin/hotplug
The kernel hot-plug core provides a method for the kernel to notify user space that something has happened. The CONFIG_HOTPLUG configuration item needs to be selected for this code to be enabled. The notification happens when the kernel calls the executable listed in the global variable hotplug_path. When the kernel starts, hotplug_path is set to /sbin/hotplug, but the user can modify the value at /proc/sys/kernel/hotplug to change this. The kernel function call_usermodehelper() executes /sbin/hotplug.
As of kernel 2.4.14, the /sbin/hotplug method is being used by the PCI, USB, IEEE1394 and Network core subsystems. As time goes on, more subsystems will be converted to use it. Patches are available for the PnP-BIOS (notification when a laptop is inserted and removed from a docking station), Hot-Plug CPU, SCSI and IDE kernel subsystems. These are expected to be merged into the main kernel over time.
When /sbin/hotplug is called, different environment variables are set, depending on what action has just occurred.

PCI
PCI devices call /sbin/hotplug with the following arguments:
argv [0] = hotplug_pathargv [1] = "pci"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binPCI_CLASS=class_codePCI_ID=vendor:devicePCI_SUBSYS_ID=subsystem_vendor:subsystem_devicePCI_SLOT_NAME=slot_nameACTION=actionThe action setting is ``add'' or ``remove'' depending on whether the device is being inserted or removed from the system. The class_code, vendor, subsystem_vendor, subsystem_device and slot_name environment settings represent the numerical values for the PCI device's information.

USB
USB devices call /sbin/hotplug with the following arguments:
argv [0] = hotplug_pathargv [1] = "usb"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binACTION=actionPRODUCT=idVendor/idProduct/bcdDeviceTYPE=device_class/device_subclass/device_protocolThe action setting is ``add'' or ``remove'' depending on whether the device is being inserted or removed from the system, and idVendor, idProduct, bcdDevice, device_class, device_subclass and device_protocol are filled in with the information from the USB device's descriptors.

If the USB device's deviceClass is 0 then the environment variable INTERFACE is set to:
INTERFACE=class/subclass/protocolThis is because USB has a much more complex model for device configuration than PCI does.
If the USB subsystem is compiled with the usbdevfs filesystem enabled, the following environment variables also are set:
DEVFS=/proc/bus/usbDEVICE=/proc/bus/usb/bus_number/device_numberwhere bus_number and device_number are set to the bus number and device number that this specific USB device is assigned.

Network
The network core code calls /sbin/hotplug whenever a network device is registered or unregistered with the network subsystem, and /sbin/hotplug is called with the following arguments when called from the network core:
argv [0] = hotplug_pathargv [1] = "net"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binINTERFACE=interfaceACTION=actionThe action setting is ``register'' or ``unregister'' depending on what happened in the network core, and interface is the name of the interface that just had the action applied to itself.

CPU
The Hot-Plug CPU patch (available at sourceforge.net/projects/lhcs) calls /sbin/hotplug after a CPU is removed or added to the system, and /sbin/hotplug is called with the following arguments:
argv [0] = hotplug_pathargv [1] = "cpu"argv [2] = 0and the system environment is set to the following:
HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binCPU=cpu_numberACTION=actionThe action setting is ``add'' or ``remove'' depending on what happened to the CPU, and cpu_number is the number of the CPU that just had the action applied to itself.

Examples
The /sbin/hotplug script can be a very simple script if you only want it to control a small number of devices. For example, if you have a USB mouse and wish to load and unload the kernel driver whenever the mouse is inserted or removed, the following script, located at /sbin/hotplug, would be sufficient:
#!/bin/shif [ "$1" = "usb" ]; then    if [ "$INTERFACE" = "3/1/2" ]; then        if [ "$ACTION" = "add" ]; then            modprobe usbmouse        else            rmmod usbmouse        fi    fifiOr if you want to run ColdSync (<FONT color="#44440a" href="http://www.ooblick.com/software/coldsync" target="_blank" [url=]www.ooblick.com/software/coldsync[/url]) automatically when you connect your USB HandSpring Visor to the computer, the following script located at /sbin/hotplug would work well:
#!/bin/shUSER=gregkhif [ "$1" = "usb" ]; then    if [ "$PRODUCT" = "82d/100/0" ]; then        if [ "$ACTION" = "add" ]; then            modprobe visor            su $USER - -c "/usr/bin/coldsync"        else            rmmod visor        fi    fifiIf you want to make sure that your network devices always come up connected to the proper Ethernet card, the following /sbin/hotplug script, contributed by Sukadev Bhattiprolu, can do this: #!/bin/shif [ "$1" = "network" ]; then    if [ "$ACTION" = "register" ]; then        nameif -r $INTERFACE -c /etc/mactab    fifiListing 1 shows a more complex example that can handle automatically loading and unloading modules for three different USB devices.

Listing 1. Script to Load and Unload Modules Automatically for Three Different USB Devices

Need for Automation
The previous small example shows the limitations of being forced to enter in all of the different device IDs manually, product IDs and such in order to keep a /sbin/hotplug script up to date with all of the different devices that the kernel knows about. Instead, it would be better for the kernel itself to specify the different types of devices that it supports in such a way that any user-space tools could read them. Thus was born a macro called MODULE_DEVICE_TABLE() that is used by all USB and PCI drivers. This macro describes which devices each specific driver can support. At compilation time, the build process extracts this information out of the driver and builds a table. The table is called modules.pcimap and modules.usbmap for all PCI and USB devices, respectively, and exists in the directory /lib/modules/kernel_version/.
For example, the following code snippet from drivers/net/eepro100.c:
static struct pci_device_id eepro100_pci_tbl[]__devinitdata = {    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,      PCI_ANY_ID, PCI_ANY_ID, },    { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82562ET,      PCI_ANY_ID, PCI_ANY_ID, },        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _82559ER, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _ID1029, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _ID1030, PCI_ANY_ID, PCI_ANY_ID,},        { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL          _82801BA_7, PCI_ANY_ID, PCI_ANY_ID,},        { 0,}    };    MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl);causes these lines to be added to the modules.pcimap file:
eepro100 0x00008086 0x00001229 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001031 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001209 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001029 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00001030 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000eepro100 0x00008086 0x00002449 0xffffffff 0xffffffff0x00000000 0x00000000 0x00000000As the example shows, a PCI device can be specified by any of the same parameters that are passed to the /sbin/hotplug program.

A USB device can specify that it can accept only specific devices such as this example from drivers/usb/mdc800.c:
static struct usb_device_id  mdc800_table [] = {   { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },   { } /* Terminating entry */};MODULE_DEVICE_TABLE(usb, mdc800_table);which causes the following line to be added to the modules.usbmap file:
mdc800 0x0003 0x055f 0xa800 0x0000 0x0000 0x00 0x000x00 0x00 0x00 0x00 0x00000000Or it can specify that it accepts any device that matches a specific USB class code, as in this example from drivers/usb/printer.c: static struct usb_device_id usblp_ids [] = {  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 1) },  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 2) },  { USB_INTERFACE_INFO(USB_CLASS_PRINTER, 1, 3) },  { }    /* Terminating entry */};MODULE_DEVICE_TABLE(usb, usblp_ids);which causes the following lines to be added to the modules.usbmap file: printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x01 0x00000000printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x02 0x00000000printer 0x0380 0x0000 0x0000 0x0000 0x0000 0x00 0x000x00 0x07 0x01 0x03 0x00000000Again these USB examples show that the information in the modules.usbmap file matches the information provided to /sbin/hotplug by the kernel, enabling /sbin/hotplug to determine which driver to load without relying on a hand-generated table, as PCMCIA does.

Preprocessor Abuse
The macro MODULE_DEVICE_TABLE automatically creates two variables. For the example: MODULE_DEVICE_TABLE (usb, usblp_ids); the variables __module_usb_device_size and __module_usb_device_table are created and placed into the read-only data section and the initialized data section of the module, respectively. The variable __module_usb_device_size contains the value of the size of the struct usb_id structure, and __module_usb_device_table points to the usblp_ids structure. The usblp_ids variable is an array of usb_id structures with a terminating NULL structure at the end of the list.
When the depmod program is run, as part of the kernel installation process, it goes through every module looking for the symbol __module_usb_device_size to be present in the compiled module. If it finds it, it copies the data pointed to by the __module_usb_device_table symbol into a structure, extracts all of the information and writes it out to the modules.usbmap file, which is located in the module root directory. It does the same thing while looking for the __module_pci_device_size in creating the modules.pcimap file.
With the kernel module information exported to the files modules.usbmap and modules.pcimap, our version of /sbin/hotplug can look like Listing 2 [available at ftp.ssc.com/pub/lj/listings/issue96/5604.tgz]. This example only tests for a match of the USB product ID and vendor IDs. The Linux-Hotplug Project has created a set of scripts that covers all of the different subsystems that can call /sbin/hotplug. This enables drivers to be loaded automatically when new devices are inserted into the systems. It also starts up network services when network devices are seen. These scripts are released under the GPL and are available at linux-hotplug.sourceforge.net. Almost all major Linux distributions are currently shipping this package, so it is probably already on your machine.

The Future
The current /sbin/hotplug subsystem needs to be incorporated into other kernel systems, as they develop hot-plug capability. SCSI, IDE and other systems all have hot-plug patches available for kernel support but need to have script support, kernel macro support and modutils depmod support added in order to provide the user with a consistent experience.
As the kernel boots, and discovers new devices, it tries to spawn /sbin/hotplug, but since user space has not been initialized yet, it cannot run. This means that any USB or PCI devices that are needed at boot time need to be compiled into the kernel or exist in an initrd RAM disk image as a module. Sometime during the 2.5 development process, the initrd RAM disk image will be converted to contain an entire small user-space tree. This will allow /sbin/hotplug to be run during the boot process and load modules dynamically. Some links describing this disk image idea are:lwn.net/2001/0712/kernel.php3, marc.theaimsgroup.com/?l=acpi4linux&m=99705696732868, marc.theaimsgroup.com/?l=linux-kernel&m=99436439232254 and marc.theaimsgroup.com/?l=linux-kernel&m=99436253707952.
Because of the small space requirements of this RAM disk image, the dietHotplug program has been written. It is an implementation of the Linux-Hotplug bash scripts in C and does not require modules.*map files when the program runs. The executable size of the entire dietHotplug program is one-fifth of the size of the original modules.*map files themselves. The small size is due to the use of dietLibc (found at www.fefe.de/dietlibc) and other space-saving techniques. dietHotplug will undergo more development as the 2.5 kernel requirements are more fully known. dietHotplug can be downloaded from the Linux-Hotplug site.

Acknowledgements
I would like to thank David Brownell who wrote the original /sbin/hotplug kernel patch and most of the Linux Hotplug scripts. Without his persistence, Linux would not have this user-friendly feature. I also would like to acknowledge the entire Linux USB development team, who have provided a solid kernel subsystem in a relatively short amount of time.
Keith Owens wrote the supporting code in the depmod utility and has endured constant changes to the format of the MODULE_DEVICE_TABLE() USB structure.
The other developers on the linux-hotplug-devel mailing list who have helped with their patches and feedback on the hot-plug scripts also deserve recognition, along with the wonderful Linux distribution-specific support that Debian, Red Hat and Mandrake have provided.
This article was based upon a paper and presentation that I gave at the 2001 Ottawa Linux Symposium.

Greg Kroah-Hartman is currently the Linux USB and PCI Hotplug kernel maintainer. He works for IBM, doing various LInux kernel-related things and can be reached at greg@kroah.com.

2.2. mdev.conf文件

参考 mdev的使用以及mdev.conf的规则配置

/etc >: cat mdev.conf

sd[a-h]*[0-9]     0:0 0660        *(/usr/sbin/hotplug /media/usb)

sd[a-h]           0:0 0660        *(/usr/sbin/hotplug /media/usb)

ub[a-h]*[0-9]     0:0 0660        *(/usr/sbin/hotplug /media/usb)

ub[a-h]           0:0 0660        *(/usr/sbin/hotplug /media/usb)

mmcblk[0-9]p[0-9] 0:0 0660        @(/bin/mount /dev/$MDEV /media/mmc)

mmcblk[0-9]       0:0 0660        $(/bin/umount /media/mmc)

wlan[0-9]         0:0 0660        @(/apps/tools/ifup-wlan $INTERFACE)

/etc >:

如果我们在apps/tools/ifup-wlan文件的开头加入下面红色的一行:

~ >: cat apps/tools/ifup-wlan

#!/bin/sh

# FILE:/usr/sbin/ifup-wlan0

# Copyright (C) 2011 GuoWenxue <guowenxue@gmail.com QQ:281143292>

# This file used to configure the specified network interface device

source /etc/profile

export > /tmp/hotplug.log

if [ -z "$network_cfg_dir" ];  then

export network_cfg_dir=/apps/etc/network

fi

。 。 。 。

/*****************************转载声明****************************/

保存后退出。

重新插入无线网卡:
~ >: usb 1-1.1: new full speed USB device number 4 using s3c2410-ohci

usb 1-1.1: New USB device found, idVendor=148f, idProduct=3070

usb 1-1.1: New USB device strings: Mfr=1, Product=2, SerialNumber=3

usb 1-1.1: Product: 802.11 n WLAN

usb 1-1.1: Manufacturer: Ralink

usb 1-1.1: SerialNumber: 1.0

~ >:

在hotplug.log文件中记录了热插拔过程中传过来的一下变量,红色所示。

~ >: cat /tmp/hotplug.log

export ACTION='add'

export DEVPATH='/devices/platform/s3c2410-ohci/usb1/1-1/1-1.1/1-1.1:1.0/net/wlan0'

export DEVTYPE='wlan'

export EDITOR='/bin/vi'

export HISTFILESIZE='500'

export HISTSIZE='500'

export HOME='/'

export HOSTNAME='fulinux'

export IFINDEX='4'

export INPUTRC='/etc/inputrc'

export INTERFACE='wlan0'

export LD_LIBRARY_PATH='/lib:/usr/lib:/apps/lib'

export LOGNAME='root'

export MDEV='wlan0'

export PAGER='/bin/more '

export PATH='/bin:/sbin:/usr/bin:/usr/sbin:/apps/tools'

export PS1='\w >: '

export PWD='/dev'

export SEQNUM='493'

export SUBSYSTEM='net'

export USER='root'

export network_cfg_dir='/apps/etc/network'

~ >:

如果是在命令行中使用export命令,结果如下:

~ >: export

export EDITOR='/bin/vi'

export HISTFILESIZE='500'

export HISTSIZE='500'

export HOME='/'

export HOSTNAME='fulinux'

export INPUTRC='/etc/inputrc'

export LD_LIBRARY_PATH='/lib:/usr/lib:/apps/lib'

export LOGNAME='root'

export PAGER='/bin/more '

export PATH='/bin:/sbin:/usr/bin:/usr/sbin:/apps/tools'

export PS1='\w >: '

export PWD='/'

export SHELL='/bin/sh'

export TERM='vt100'

export USER='root'

export network_cfg_dir='/apps/etc/network'

~ >:

最后运行的结果:

~ >: ifconfig wlan0

wlan0     Link encap:Ethernet  HWaddr 00:0C:43:30:72:81

inet addr:192.168.1.166  Bcast:192.168.1.255  Mask:255.255.255.0

UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1

RX packets:136 errors:0 dropped:15 overruns:0 frame:0

TX packets:4 errors:0 dropped:0 overruns:0 carrier:0

collisions:0 txqueuelen:1000

RX bytes:14849 (14.5 KiB)  TX bytes:548 (548.0 B)

~ >: iwconfig wlan0

wlan0     IEEE 802.11bgn  ESSID:"Router_LingYun"

Mode:Managed  Frequency:2.437 GHz  Access Point: D8:5D:4C:18:04:7A

Bit Rate=1 Mb/s   Tx-Power=20 dBm

Retry  long limit:7   RTS thr:off   Fragment thr:off

Encryption key:off

Power Management:on

Link Quality=49/70  Signal level=-61 dBm

Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0

Tx excessive retries:0  Invalid misc:4   Missed beacon:0

~ >: ping www.baidu.com

PING www.baidu.com (115.239.210.26): 56 data bytes

64 bytes from 115.239.210.26: seq=0 ttl=55 time=58.396 ms

64 bytes from 115.239.210.26: seq=1 ttl=55 time=95.457 ms

64 bytes from 115.239.210.26: seq=2 ttl=55 time=97.314 ms

64 bytes from 115.239.210.26: seq=3 ttl=55 time=99.431 ms

64 bytes from 115.239.210.26: seq=4 ttl=55 time=97.498 ms

--- www.baidu.com ping statistics ---

5 packets transmitted, 5 packets received, 0% packet loss

round-trip min/avg/max = 58.396/89.619/99.431 ms

~ >:

表明wlan0已成功运行。

ARM上的linux如何实现无线网卡的冷插拔和热插拔的相关教程结束。

《ARM上的linux如何实现无线网卡的冷插拔和热插拔.doc》

下载本文的Word格式文档,以方便收藏与打印。