ARM上的linux如何实现无线网卡的冷插拔和热插拔
fulinux
1.冷插拔
如果在系统上电之前就将RT2070/RT3070芯片的无线网卡(以下简称wlan)插上,即冷插拔。我们通过分析系统启动流程过程中的运行的脚本,将启动wlan的脚本加入其中,就可以实现自动运行wlan.。
系统启动后的第一个进程/sbin/init。init进程最主要的功能就是准备软件执行的环境,包括系统的主机名、网络配置、语系处理、文件系统格式以及其他服务的启动等。而所有的操作都会通过init的配置文件,即/etc/inittab来规划。
在inittab文件中有很多如下格式的语句:
label:runlevel:action:process
但是我们这里只关注下面这条语句:
#nowrunanyrcscripts
null::wait:/etc/init.d/rcS
即运行所有的rc脚本,这里是运行rcS脚本,rcS脚本内容如下:
~>:cat/etc/init.d/rcS
#!/bin/sh
#Copyright(C)2011GuoWenxue<guowenxue@gmail.comQQ:281143292>
#Startallinitscriptsin/etc/init.d
#executingtheminnumericalorder.
#
foriin/etc/init.d/S??*;do
$i
done
~>:
很简单的一个脚本,即运行/etc/init.d/目录下以S开头,两个?匹配任意两个字符
*匹配0或多个字符。该目录下有一个文件S01_network,内容如下:
注:绿色为注释~>:catetc/init.d/S01_network
#!/bin/sh
#FILE:/etc/init.d/S01_network
#Copyright(C)2012GuoWenxue<guowenxue@gmail.comQQ:281143292>
#Thisfileusedtoconfigurethenetworkfromtheconfigurefiles
#network_cfg_dir变量是否为空,如果是将/apps/etc/network赋值给network_cfg_dir。
if[-z"$network_cfg_dir"];then
exportnetwork_cfg_dir=/apps/etc/network
Fi
#进入/apps/etc/network目录
cd$network_cfg_dir
#~>:cdapps/etc/network/
/apps/etc/network>:ls
bakifcfg-wlan0ifcfg-eth0resolv.conf
gatewayD.confifcfg-ppp10wpa_supplicant.conf
hostapd.confifcfg-wlan0
/apps/etc/network>:
#上面这个正则表达式的目的是提取出网卡名,例如eth0、wlan0,其中wlan0为我们所需要的。
interfaces=$(lsifcfg*|\
sed-e’/ifcfg-[A-Za-z0-9\._-]\&;$/{s/^ifcfg-//g;s/[0-9]/&/}’|\
sort-k1,1-k2n|\
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一个非常突出的优点!)
ifconfiglo127.0.0.1
#Nointerfaceconfigure,thenusethedefaultIPaddress
如果/apps/etc/network目录下没有带网卡名的文件,这时interface变量为空,配置eth0网卡,之后退出。
if[-z"$interfaces"];then
ifconfigeth0192.168.1.223up
exit
fi
#Setupalltheinterface
设置所有网卡接口
foriin$interfaces;do
#unset删除变量或函数
unsetDEVICETYPE
#如果这时候$i为wlan0,则下面的目的是提取出ifcfg-wlan0文件中的DEVICE、TYPE等号后面的内容。ifcfg-wlan0在该脚本下面。
eval$(fgrep"DEVICE="ifcfg-$i)
eval$(fgrep"TYPE="ifcfg-$i)
#如果$DEVICE为空,着将$i的值赋给它。
if[-z"$DEVICE"];thenDEVICE="$i";fi
#如果ifcfg-wlan0文件中的ONBOOT不为no,时执行下面的语句。
if!egrep-L"^ONBOOT=[‘\&;]?[Nn][Oo][‘\&;]?"ifcfg-$i>/dev/null;then
#下面是根据各自的TYPE值,执行相应的脚本
if["$TYPE"="Ethernet"];then
echo"Bringup$TYPEinterface$i"
/usr/sbin/ifup-eth$i
elif["$TYPE"="PPP"];then
echo"Bringup$TYPEinterface$i"
elif["$TYPE"="WLAN"];then
#JustbringupthewiFimodulehere.Configureitinthefollowedshellscripts
#如果是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"Bringup$TYPEinterface$i"
fi
fi
#for循环结束
done
#结束
~>:
1.1.ifcfg-wlan0配置文件
/apps/etc/network/ifcfg-wlan0配置文件中的内容如下:
/apps/etc/network>:catifcfg-wlan0
#WirelessNetworkadapterRT3070(wlan0)deviceconfigurefile
#FILE:/apps/etc/network/ifcfg-wlan0
#Copyright(C)2012GuoWenxue<guowenxue@gmail.comQQ:281143292>
DEVICE=wlan0
ONBOOT=yes
NAME="RT3070"
TYPE=WLAN
#TheWiFiModuleshouldworkonAPorSTAmode
#APmode是类似于一个不带有限接口lan的无线路由,即市面上的迷你无线路由,STAmode是无线上网终端一般所用的模式。我们要向无线上网就必须使用STAmode
WORKMODE=STA
#WORKMODE=AP
#BOOTPROTshouldbestaticordhcp,itwillonlytakeeffact
#whentheNICworkonSTAmode
#可以说静态分配ip,也可以使用DHCP动态分配ip.这里使用静态,静态建立连接到速度快。
BOOTPROTO=static
#这是AP模式要使用的配置
#WorkonAPmodeIPaddress
IPADDR_AP=192.168.5.1
NETMASK_AP=255.255.255.0
#WorkonSTAmodeIPaddress
IPADDR_STA=192.168.1.166
NETMASK_STA=255.255.255.0
#GatewaySettings
GATEWAY=192.168.1.1
DEFROUTE=yes
#DHCPServerconfiguration,onlytakeeffactwhentheNICworkonAPmode
#这是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)2011GuoWenxue<guowenxue@gmail.comQQ:281143292>
#Thisfileusedtoconfigurethespecifiednetworkinterfacedevice
source/etc/profile
#判断目录是否存在,如果不存在,则赋值为/apps/etc/network目录。
if[-z"$network_cfg_dir"];then
exportnetwork_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<devicename>">&2
exit1
}
#下面的判断语句中-o是或的意思,查看mantest
(EXPRESSION)
EXPRESSIONistrue真判定
!EXPRESSION
EXPRESSIONisfalse否判定
EXPRESSION1-aEXPRESSION2
bothEXPRESSION1andEXPRESSION2aretrue与判定
EXPRESSION1-oEXPRESSION2
eitherEXPRESSION1orEXPRESSION2istrue或判定
-dFILE
FILEexistsandisadirectory
-fFILE
FILEexistsandisaregularfile
if[!-d$network_cfg_dir-o!-f"$network_cfg_dir/ifcfg-${DEVICE}"];then
echo"$0:configuration<$network_cfg_dir/ifcfg-${DEVICE}>notfound.">&2
echo"Usage:$0<devicename>">&2
exit1
fi
#判断/sys/class/net/wlan0是否存在,说明没有wlan0适配器退出
if[!-d/sys/class/net/$DEVICE/];then
echo"Wirelessnetworkadapter$DEVICEdosn’texist,exitnow…"
exit
fi
#其中有个“。”相当于source命令。查看
[lingyun@vmlinuxfulinux]$mansource
.filename[arguments]
这里是使能ifcfg-wlan0配置文件。
使能了这些文件后上面的一些参数就成为系统中的全局参数,比如说我在下面加入如下代码时,
cd$network_cfg_dir
.ifcfg-${DEVICE}
echo"printwifiworkmodeis$WORKMODE"
会打印如信息
/apps/tools>:shifup-wlanwlan0
printwifiworkmodeisSTA
因为是在脚本中使能了这个文件,所以相当于创建了一个子进程,如果退出这个脚本后出来运行echo$WORKMODE不会有什么显示。
cd$network_cfg_dir
.ifcfg-${DEVICE}
#由于配置文件中的WORKMODE的选项很肯使用小写的sta或是ap,也有可能是Sta和Ap书写方法,通过下面的第一个语句就可以将这些选项统统装化为大写模式,toupper()是一个转换为大写的函数。如果不是STA(station)模式,就赋值为AP模式。
WORKMODE=$(echo$WORKMODE|awk'{printtoupper($0)}’)
if[$WORKMODE!="STA"];then
WORKMODE="AP"
fi
echo"Enablenetworkinterface$DEVICE[$NAME]workon$WORKMODEmode.">&2
#下面主要的是理解eval命令,可以通过在shell中拆解来理解,如下
/apps/etc/network>:exportWORKMODE=STA
/apps/etc/network>:exportIPADDR_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()
{
unsetipaddrnetmask
ipaddr=$(eval"echo\$IPADDR_$WORKMODE")
netmask=$(eval"echo\$NETMASK_$WORKMODE")
}
#下面这一个是关掉wifi适配器的函数。
stop_wifi_worker()
{
#stopDHCPworkonthisNIC
#分解运行分析如下:
/apps/etc/network>:ps|grepdhcp
5385root1332Sudhcpc-ieth0
10678root1324Sudhcpc-iwlan0
11598root1316Sgrepdhcp
/apps/etc/network>:ps|grepdhcp|grep-vgrep
5385root1332Sudhcpc-ieth0
10678root1324Sudhcpc-iwlan0
/apps/etc/network>:ps|grepdhcp|grep-vgrep|grepwlan
10678root1324Sudhcpc-iwlan0
/apps/etc/network>:ps|grepdhcp|grep-vgrep|grepwlan|awk'{print$1}’
10678
/apps/etc/network>:ps|grepdhcp|grep-vgrep|grepwlan|awk'{print$2}’
root这样可以获得udhcpc-iwlan0的进程id,并将其杀死。下同。
dhcp_pid=`ps|grep-vgrep|grep"dhcp"|grep$DEVICE|awk'{print$1;}’`
if[-n"$dhcp_pid"];then
kill$dhcp_pid
fi
ifconfig$DEVICE0.0.0.0
#Stopwpa_supplicantworkonSTAmode
pid=`ps|grep-vgrep|grep"wpa_supplicant"|grep$DEVICE|awk'{print$1;}’`
if[-n"$pid"];then
kill$pid
sleep1
fi
if[-d/var/run/wpa_supplicant];then
rm-rf/var/run/wpa_supplicant
fi
#StophostapdworkonAPmode
pid=`ps|grep-vgrep|grep"hostapd"|awk'{print$1;}’`
if[-n"$pid"];then
kill$pid
sleep1
fi
if[-d/var/run/hostapd];then
rm-rf/var/run/hostapd
fi
}
#配置wifi为station模式。
configure_wifi_sta()
{
parser_ip
#IfenableDHCPconfigureorIPaddressnotconfigured,thenuseDHCPgetIPaddressandexit
#mantest可以查看下面判断选项的意思
-nSTRING
thelengthofSTRINGisnonzero
字符串的长度不为0为真
STRINGequivalentto-nSTRING
-zSTRING
thelengthofSTRINGiszero
字符串的长度为0为真
-o选项是或运算
if[-n"$BOOTPROTO"-o-z"$ipaddr"];then
BOOTPROTO=$(echo$BOOTPROTO|awk'{printtoupper($0)}’)
if["$BOOTPROTO"="DHCP"];then
ifconfig$DEVICEup
#Startwpa_supplicanttoworknow
#连接路由命令,这里使用的配置文件是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
#Calculatethenetworkconfigurationvalue
#如果没有上面的动态分配且不存在子网掩码,就需要分配一个
if[-z"${netmask}"];then
eval$(/bin/ipcalc–netmask${ipaddr})
fi
#ConfigurefortheWiFiinterfaceIPaddressandbringupit
#静态分配ip地址和掩码。
ifconfig$DEVICE$ipaddrnetmask$netmaskup
#Setthedefaultroute
#把DEFROUTE选项都转化为大写。
DEFROUTE=$(echo$DEFROUTE|awk'{printtoupper($0)}’)
#如果GATEWAY字符长度不为0且DEFROUTE选项为YES时,
if[-n"$GATEWAY"-a"$DEFROUTE"="YES"];then
#iprouteadd${NETWORK}/${PREFIX}via$GATEWAY>/dev/null2>&1
iproutereplacedefaultvia$GATEWAY
fi
#Startwpa_supplicanttoworknow
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
#ConfigurefortheWiFiinterfaceIPaddressandbringupit
#如果ipaddr长度为0,就静态分配ipaddr
if[-z"$ipaddr"];then
ipaddr=192.168.1.166
netmask=255.255.255.0
fi
ifconfig$DEVICE$ipaddrnetmask$netmaskup
#EnableDHCPserver
#使能DHCP服务功能,这样我们就不用为每台连接到开发板上的电脑和手机静态分配ip地址,而是通过开发板上的DHCP服务为每一台连接的终端设备动态分配地址。
DHCP_SERVER=$(echo$DHCP_SERVER|awk'{printtoupper($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:ipaddressexpected
Usage:ipcalc[OPTION…]
-c,–checkValidateIPaddressforspecifiedaddressfamily
-4,–ipv4IPv4addressfamily(default)
-6,–ipv6IPv6addressfamily
-b,–broadcastDisplaycalculatedbroadcastaddress(显示指定ip和子网掩码的广播地址)-h,–hostnameShowhostnamedeterminedviaDNS(显示指定ip的主机名)-m,–netmaskDisplaydefaultnetmaskforIP(classA,B,orC)(显示指定ip的子网掩码–特指默认,实际未必是)-n,–networkDisplaynetworkaddress(显示指定ip的网络地址)-p,–prefixDisplaynetworkprefix(显示网络前缀)-s,–silentDon’teverdisplayerrormessages(不显示错误信息)
Helpoptions:
-?,–helpShowthishelpmessage
–usageDisplaybriefusagemessage
#[lingyun@localhost~]$ipcalc-p192.168.1.1255.255.255.0PREFIX=24#[lingyun@localhost~]$ipcalc-n192.168.1.1255.255.255.0NETWORK=192.168.1.0#[lingyun@localhost~]$ipcalc-h192.168.1.1HOSTNAME=dbrg-2#[lingyun@localhost~]$ipcalc-m192.168.1.1NETMASK=255.255.255.0#[lingyun@localhost~]$ipcalc-pnbm192.168.1.1255.255.255.0NETMASK=255.255.255.0PREFIX=24BROADCAST=192.168.1.255NETWORK=192.168.1.0#[lingyun@localhost~]$
所以下面的意图是取得子网的网络地址。例如
[lingyun@localhost~]$ipcalc-n192.168.5.1255.255.255.0
NETWORK=192.168.5.0
[lingyun@localhost~]$ipcalc-n192.168.5.1255.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]然后,与左边的标准输出
形成下面类似的结构:
[root@localhostetc]#catdhcpd.confddns-update-styleinterim;ignoreclient-updates;subnet192.168.1.0netmask255.255.255.0{#—defaultgatewayoptionrouters192.168.1.1;/*默认路由器地址*/optionsubnet-mask255.255.255.0;/*默认子网掩码*/optionnis-domain"510.home";/*为客户机设置nis域*/optiondomain-name"510.home";/*客户机所属DNS域的域名*/optiondomain-name-servers192.168.1.1;/*DNS服务器地址*/optiontime-offset-18000;/*为客户设置与格林威治时间的偏移时间*/optionhost-name"myDhcpServer";/*设置主机名*/rangedynamic-bootp192.168.1.2192.168.1.128;/*服务器将为客户分配192.168.1.2-128段内的ip*/default-lease-time21600;/*默认地址租期,单位为s*/max-lease-time43200;/*最长地址租期,单位为s*/}
echo"subnet$DHCP_SUBNETnetmask$DHCP_NETMASK{">$conf_file
echo"range$DHCP_START_IP$DHCP_END_IP;">>$conf_file
echo"optiondomain-name-servers$DHCP_DNS1,$DHCP_DNS2;">>$conf_file
echo"optionrouters$DHCP_GATEWAY;">>$conf_file
echo"default-lease-time$DHCP_LEASE;">>$conf_file
echo"max-lease-time72000;">>$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模式
#StarthostapdtoserveronAPmode
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
#结束
APmode我们暂时不用考虑。到这里差不多可以实现启动自动运行wlan0的目的了,有线的eth0可以拔出。
运行结果如下:
~>:ifconfigwlan0
wlan0Linkencap:EthernetHWaddr00:0C:43:30:72:81
inetaddr:192.168.1.166Bcast:192.168.1.255Mask:255.255.255.0
UPBROADCASTRUNNINGMULTICASTMTU:1500Metric:1
RXpackets:136errors:0dropped:15overruns:0frame:0
TXpackets:4errors:0dropped:0overruns:0carrier:0
collisions:0txqueuelen:1000
RXbytes:14849(14.5KiB)TXbytes:548(548.0B)
~>:iwconfigwlan0
wlan0IEEE802.11bgnESSID:"Router_LingYun"
Mode:ManagedFrequency:2.437GHzAccessPoint:D8:5D:4C:18:04:7A
BitRate=1Mb/sTx-Power=20dBm
Retrylonglimit:7RTSthr:offFragmentthr:off
Encryptionkey:off
PowerManagement:on
LinkQuality=49/70Signallevel=-61dBm
Rxinvalidnwid:0Rxinvalidcrypt:0Rxinvalidfrag:0
Txexcessiveretries:0Invalidmisc:4Missedbeacon:0
~>:pingwww.baidu.com
PINGwww.baidu.com(115.239.210.26):56databytes
64bytesfrom115.239.210.26:seq=0ttl=55time=58.396ms
64bytesfrom115.239.210.26:seq=1ttl=55time=95.457ms
64bytesfrom115.239.210.26:seq=2ttl=55time=97.314ms
64bytesfrom115.239.210.26:seq=3ttl=55time=99.431ms
64bytesfrom115.239.210.26:seq=4ttl=55time=97.498ms

—www.baidu.compingstatistics—
5packetstransmitted,5packetsreceived,0%packetloss
round-tripmin/avg/max=58.396/89.619/99.431ms
~>:
表明已经连接上了网络。
2.热插拔2.1.hotplug
要实现热插拔首先内核要支持hotplug,配置如下:
DeviceDrivers—>
GenericDriverOptions—>
(/sbin/hotplug)pathtoueventhelper
[]Maintainadevtmpfsfilesystemtomountat/dev
[]Selectonlydriversthatdon’tneedcompile-timeexternalfirmware
[]Preventfirmwarefrombeingbuilt
Linux系统处理热插拔的机制是这样的
l将可移动设备连入系统时,系统的后台中会依次发生如下事件:
l内核检测到新硬件插入,然后分别通知hotplug和udev。前者用来装入相应的内核模块(如usb-storage),而后者用来在/dev中创建相应的设备节点(如/dev/sda1)。
ludev创建了相应的设备节点之后,会将这一消息通知hal的守护程序(hald)。当然udev还得保证新创建的设备节点可以被普通用户访问。
lhotplug装入了相应的内核模块之后,会把这一消息通知给hald。
lhald在受到hotplug和udev发出的消息之后,认为新硬件已经正式被系统认可了。此时它会通过一系列精心编写的规则文件(就是传说中的xxx-policy.fdi),把发现新硬件的消息通过dbus发送出去,同时还会调用update-fstab或fstab-sync来更新/etc/fstab,为相应的设备节点创建适合的挂载点。
l卷管理器会监听dbus中发现新硬件的消息。根据所插入的硬件(区分U盘和数码相机等)不同,卷管理器会先将相应的设备节点挂载到hald创建的挂载点上,然后再打开不同的应用程序。
l当然,如果是在CDROM中插入光盘,过程可能比较简单。因为CDROM本身就是一个固定的硬件,无需hotplug和udev的协助:
lhald会自己监视CDROM,并且将光盘托架开合的消息通过dbus发出去。
l卷管理器负责检查CDROM中的盘片内容,进行挂载,并调用合适的应用程序。
l要注意,hald的工作是从上游得到硬件就绪的消息,然后将这个消息转发到dbus中。尽管它会调用程序来更新fstab,但实际上它自己并不执行挂载的工作。
l下面是上面的过程中涉及的模块和工具:
lhotplug
lhotplug包和内核里的hotplug模块不是一回事,2.6内核里的pci_hotplug.ko是一个内核模块,而hotplug包是用来处理内核产生的hotplug事件。这个软件包还在引导时检测现存的硬件并在运行的内核中加载相关模块。
l不但有热插拔,还有冷插拔(coldpluging)。热插拔在内核启动之后发生,而“coldpluging”发生在内核启动的过程中。
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的作者GregK.H说,之所以废弃了hotplug原因是sysfs的出现,这个东西会产生非常多的hotplug事件,远远超过了2.4的内核(只要实现了了kobject模型的设备驱动都回产生该事件)。所以hotplug变得复杂,而且因为hotplug都是bash所写,所以开始变得没有效率。于是出现了一个名叫hotplug-ng的项目,就是为了解决这个过于复杂以及缺乏效率的问题,ng应该是nextgeneration的意思。但这个项目目前为止还不能胜任角色,所以udev挺身而出,充当了救火队员。
l2.6.15之后,/proc/sys/kernel/hotplug会成空的,因为内核通知用户空间的接口变成了netlink,所以最新的udev也采用了netlink接口去写,废弃了/sbin/hotplug或者/sbin/udevsend。udev在2.6.15以后的内核上可以直接通过netlink接听设备事件,sysfs提供了uevent文件,对该文件的“写”可以送出设备事件!
ludev完全在用户态(userspace)工作,利用设备加入或移除时内核所发送的hotplug事件(event)来工作。关于设备的详细信息是由内核输出(export)到位于/sys的sysfs文件系统的。所有的设备命名策略、权限控制和事件处理都是在用户态下完成的。与此相反,devfs是作为内核的一部分工作的。
l传统上一般Linux系统使用创建静态设备的方法,因此在/dev目录下创建了大量的设备节点(有时会有数千个节点),而不管对应的硬件设备实际上是否存在。这通常是由MAKEDEV脚本完成的,这个脚本包含许多调用mknod程序的命令,为这个世界上可能存在的每个设备创建相应的主设备号和次设备号。而使用udev方式的时候,只有被内核检测到的设备才为其创建设备节点。因为每次系统启动的时候都要重新创建这些设备节点,所以它们被存储在tmpfs文件系统上,设备节点不需要很多磁盘空间,所占用的内存可以忽略不计。
ludev初始化脚本负责在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-qpath-n/dev/sda,命令会产生一个该设备名对应的在sysfs下的路径,如/block/sda。然后,你再用udevinfo-a-p/sys/block/sda,这个命令会显示一堆信息,信息分成很多块。这些信息实际来自于操作系统维护的sysfs链表,不同的块对应不同的路径。你就可以用这些信息来作为udev规则文件中的匹配项。但需要注意的是,同一个规则只能使用同一块中显示的信息,不能跨块书写规则;第二种情况是,不知道系统产生的设备名,那就只有到/sys目录下去逐个目录查找了,反复用udevinfo-a-p/sys/path…这个命令看信息,如果对应的信息是这个设备的,那就恭喜你。否则就再换个目录。当然,在这种情况下,成功的可能性比较小。
HAL
lHAL位于设备驱动程序和应用程序之间。
D-BUS
lD-BUS是一个大有前途的消息总线和活动系统,正开始深入地渗透到Linux桌面之中。D-BUS本质上是进程间通信(inter-processcommunication)(IPC)的一个实现,设计用于桌面应用程序和OS通信。
l典型的D-BUS设置将由几个总线构成。一个持久的系统总线(systembus),它在引导时就会启动。这个总线由操作系统和后台进程使用,安全性非常好,以使得任意的应用程序不能欺骗系统事件。还将有很多会话总线(sessionbuses),这些总线当用户登录后启动,属于那个用户私有。
l一个更为有趣但很不实用的例子是Jamboree和Ringaling的结合。Jamboree是一个简单的音乐播放器,它具有D-BUS接口,以使得它可以被告知播放、到下一首歌、改变音量等等。Ringaling是一个小程序,它打开/dev/ttyS0(一个串行端口)并观察接收到的内容。当Ringaling发现文本“RING”时,就通过D-BUS告知Jamboree减小音量。最终的结果是,如果您的计算机上插入了一个调制解调器,而且电话铃响,则音乐音量就会为您减小。这正是计算机所追求的!
一些查看硬件信息的工具
llspci列出所有PCI设备。有两个参数是比较常用,-b和-v,lspci也会把usb接口列出来。
llshal列出系统硬件设备。
lUsbmodules列出可用于已插入usb设备的驱动模块。
HotPlugGregKroah-HartmanHot-pluggabledeviceshavebeencreatedtosolveanumberofuserneeds.Onlaptopcomputers,PCMCIAdevicesweredesignedtoallowtheusertoswapcardswhilethecomputerwasstillrunning.Thisallowedpeopletochangenetworkadaptors,memorycardsandevendiskdriveswithoutshuttingdownthemachine.ThesuccessofthisledtothecreationoftheUSBandIEEE1394(FireWire)buses.Thesedesignsallowforperipheralstobeattachedandremovedatanypoint.TheyalsowerecreatedtotrytomovesystemsawayfromtheISAbustoafullPlug-and-Play-typesystem.Fromtheoperatingsystem’spointofview,therearemanyproblemswithhotpluggingdevices.Inthepast,theoperatingsystemonlyhadtosearchforthevariousdevicesconnectedtoitonpower-up,andonceseen,thedevicewouldnevergoaway.Fromtheviewofthedevicedriver,itneverexpectstohavethehardwarethatitistryingtocontroldisappear.Butwithhot-pluggabledevices,allofthischanges.Nowtheoperatingsystemhastohaveamechanismthatconstantlydetectsifanewdeviceappears.Thisusuallyisdonebyabus-specificmanager.Thismanagerhandlesthescanningfornewdevicesandrecognizesthisdisappearance.Itmustbeabletocreatesystemresourcesforthenewdeviceandpasscontrolofftoaspecificdriver.Thedevicedriverforahot-pluggabledevicehastobeabletorecovergracefullywhenthehardwareisremovedandbeabletobinditselftonewhardwareatanymoment.Notonlydoesthekernelneedtoknowwhendevicesareremovedoradded,buttheuseralsoshouldbenotifiedwhenthishappens.Otherkindsofkernelevents,suchasthecreationofnetworkdevicesortheinsertionofalaptopintoadockingstation,alsowouldbeusefulfortheusertoknowabout.ThisarticledescribesthenewframeworkintheLinuxkernelforsupportingUSBandotherhot-pluggabledevices.ItcovershowthepastimplementationofPCMCIAloadeditsdriversandtheproblemsofthatsystem.ItpresentsthecurrentmethodofloadingUSBandPCIdrivers,andhowthissameframeworkcanhandleotherkindsofuserconfigurationissueseasily.ThePastLinuxhashadsupportforPCMCIAsince1995.InorderforthePCMCIAcoretobeabletoloaddriverswhenanewdevicewasinserted,ithadauser-spaceprogramcalledcardmgr.Thecardmgrprogramwouldreceivenotificationfromthekernel’sPCMCIAcorewhenadevicehadbeeninsertedorremovedandusethatinformationtoloadorunloadtheproperdriverforthatcard.Itusedaconfigurationfilelocatedat/etc/pcmcia/configtodeterminewhichdrivershouldbeusedforwhichcard.Thisconfigurationfileneededtobekeptuptodatewithwhichdriversupportedwhichcard,orrangesofcards,andhasgrowntobeover1,500lineslong.Wheneveradriverauthoraddedsupportforanewdevice,theyhadtomodifytwodifferentfilestoenablethedevicetoworkproperly.AstheUSBcorecodebecamemature,thegrouprealizedthatitalsoneededsomethinglikethePCMCIAsystemtobeabletoloadandunloaddriversdynamicallywhendeviceswereinsertedandremoved.ThegroupalsonotedthatsinceUSBandPCMCIAbothneededthissystem,andthatotherkernelhot-plugsubsystemsalsowouldusesuchasystem,agenerichot-plugcorewouldbeuseful.DavidBrownellpostedaninitialpatchtothekernel(marc.theaimsgroup.com/?l=linux-usb-devel&m=96334011602320),enablingittocallouttoauser-spaceprogramcalled/sbin/hotplug.Thispatcheventuallywasaccepted,andothersubsystemsweremodifiedtotakeadvantageofit.LettheComputerDoItItselfAllUSBandPCIdevicescontainanidentifierthatdescribeseitherwhatkindoffunctionstheysupport(likeaUSBaudioorUSBmassstoragedevice),oriftheydonotsupportaclassspecification,theycontainauniquevendorandproductidentifier.PCMCIAdevicesalsocontainthesesamekindofidentifiers.TheseidentifiersareknownbythePCIandUSBkerneldrivers,astheyneedtoknowwhichkindofdevicestheyworkproperlyfor.TheUSBandPCIkerneldriversregisterwiththekernelalistofthedifferenttypesofdevicesthattheysupport.Thislistisusedtodeterminewhichdriverwillcontrolwhichdevices.Thekernelknowswhenandwhatkindofdevicesareinsertedorremovedfromthesystemthroughthedevicebuscorecode(USB,FireWire,PCI,etc.).Itcansendthisinformationtotheuser.Takingthesethreepiecestogether(devicestellthecomputerwhattheyare,driversknowwhatdevicestheysupportandthekernelknowswhatisgoingon)providesuswithasolutiontoletthecomputerautomaticallyloadtheproperdriverwheneveranewdeviceisinserted./sbin/hotplugThekernelhot-plugcoreprovidesamethodforthekerneltonotifyuserspacethatsomethinghashappened.TheCONFIG_HOTPLUGconfigurationitemneedstobeselectedforthiscodetobeenabled.Thenotificationhappenswhenthekernelcallstheexecutablelistedintheglobalvariablehotplug_path.Whenthekernelstarts,hotplug_pathissetto/sbin/hotplug,buttheusercanmodifythevalueat/proc/sys/kernel/hotplugtochangethis.Thekernelfunctioncall_usermodehelper()executes/sbin/hotplug.Asofkernel2.4.14,the/sbin/hotplugmethodisbeingusedbythePCI,USB,IEEE1394andNetworkcoresubsystems.Astimegoeson,moresubsystemswillbeconvertedtouseit.PatchesareavailableforthePnP-BIOS(notificationwhenalaptopisinsertedandremovedfromadockingstation),Hot-PlugCPU,SCSIandIDEkernelsubsystems.Theseareexpectedtobemergedintothemainkernelovertime.When/sbin/hotplugiscalled,differentenvironmentvariablesareset,dependingonwhatactionhasjustoccurred.PCIPCIdevicescall/sbin/hotplugwiththefollowingarguments:argv[0]=hotplug_pathargv[1]="pci"argv[2]=0andthesystemenvironmentissettothefollowing:HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binPCI_CLASS=class_codePCI_ID=vendor:devicePCI_SUBSYS_ID=subsystem_vendor:subsystem_devicePCI_SLOT_NAME=slot_nameACTION=actionTheactionsettingis“add”or“remove”dependingonwhetherthedeviceisbeinginsertedorremovedfromthesystem.Theclass_code,vendor,subsystem_vendor,subsystem_deviceandslot_nameenvironmentsettingsrepresentthenumericalvaluesforthePCIdevice’sinformation.USBUSBdevicescall/sbin/hotplugwiththefollowingarguments:argv[0]=hotplug_pathargv[1]="usb"argv[2]=0andthesystemenvironmentissettothefollowing:HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binACTION=actionPRODUCT=idVendor/idProduct/bcdDeviceTYPE=device_class/device_subclass/device_protocolTheactionsettingis“add”or“remove”dependingonwhetherthedeviceisbeinginsertedorremovedfromthesystem,andidVendor,idProduct,bcdDevice,device_class,device_subclassanddevice_protocolarefilledinwiththeinformationfromtheUSBdevice’sdescriptors.IftheUSBdevice’sdeviceClassis0thentheenvironmentvariableINTERFACEissetto:INTERFACE=class/subclass/protocolThisisbecauseUSBhasamuchmorecomplexmodelfordeviceconfigurationthanPCIdoes.IftheUSBsubsystemiscompiledwiththeusbdevfsfilesystemenabled,thefollowingenvironmentvariablesalsoareset:DEVFS=/proc/bus/usbDEVICE=/proc/bus/usb/bus_number/device_numberwherebus_numberanddevice_numberaresettothebusnumberanddevicenumberthatthisspecificUSBdeviceisassigned.NetworkThenetworkcorecodecalls/sbin/hotplugwheneveranetworkdeviceisregisteredorunregisteredwiththenetworksubsystem,and/sbin/hotplugiscalledwiththefollowingargumentswhencalledfromthenetworkcore:argv[0]=hotplug_pathargv[1]="net"argv[2]=0andthesystemenvironmentissettothefollowing:HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binINTERFACE=interfaceACTION=actionTheactionsettingis“register”or“unregister”dependingonwhathappenedinthenetworkcore,andinterfaceisthenameoftheinterfacethatjusthadtheactionappliedtoitself.CPUTheHot-PlugCPUpatch(availableatsourceforge.net/projects/lhcs)calls/sbin/hotplugafteraCPUisremovedoraddedtothesystem,and/sbin/hotplugiscalledwiththefollowingarguments:argv[0]=hotplug_pathargv[1]="cpu"argv[2]=0andthesystemenvironmentissettothefollowing:HOME=/PATH=/sbin:/bin:/usr/sbin:/usr/binCPU=cpu_numberACTION=actionTheactionsettingis“add”or“remove”dependingonwhathappenedtotheCPU,andcpu_numberisthenumberoftheCPUthatjusthadtheactionappliedtoitself.ExamplesThe/sbin/hotplugscriptcanbeaverysimplescriptifyouonlywantittocontrolasmallnumberofdevices.Forexample,ifyouhaveaUSBmouseandwishtoloadandunloadthekerneldriverwheneverthemouseisinsertedorremoved,thefollowingscript,locatedat/sbin/hotplug,wouldbesufficient:#!/bin/shif["$1"="usb"];thenif["$INTERFACE"="3/1/2"];thenif["$ACTION"="add"];thenmodprobeusbmouseelsermmodusbmousefififiOrifyouwanttorunColdSync(<FONTcolor="#44440a"href="http://www.ooblick.com/software/coldsync"target="_blank"[url=]www.ooblick.com/software/coldsync[/url])automaticallywhenyouconnectyourUSBHandSpringVisortothecomputer,thefollowingscriptlocatedat/sbin/hotplugwouldworkwell:#!/bin/shUSER=gregkhif["$1"="usb"];thenif["$PRODUCT"="82d/100/0"];thenif["$ACTION"="add"];thenmodprobevisorsu$USER–c"/usr/bin/coldsync"elsermmodvisorfififiIfyouwanttomakesurethatyournetworkdevicesalwayscomeupconnectedtotheproperEthernetcard,thefollowing/sbin/hotplugscript,contributedbySukadevBhattiprolu,candothis:#!/bin/shif["$1"="network"];thenif["$ACTION"="register"];thennameif-r$INTERFACE-c/etc/mactabfifiListing1showsamorecomplexexamplethatcanhandleautomaticallyloadingandunloadingmodulesforthreedifferentUSBdevices.Listing1.ScripttoLoadandUnloadModulesAutomaticallyforThreeDifferentUSBDevicesNeedforAutomationTheprevioussmallexampleshowsthelimitationsofbeingforcedtoenterinallofthedifferentdeviceIDsmanually,productIDsandsuchinordertokeepa/sbin/hotplugscriptuptodatewithallofthedifferentdevicesthatthekernelknowsabout.Instead,itwouldbebetterforthekernelitselftospecifythedifferenttypesofdevicesthatitsupportsinsuchawaythatanyuser-spacetoolscouldreadthem.ThuswasbornamacrocalledMODULE_DEVICE_TABLE()thatisusedbyallUSBandPCIdrivers.Thismacrodescribeswhichdeviceseachspecificdrivercansupport.Atcompilationtime,thebuildprocessextractsthisinformationoutofthedriverandbuildsatable.Thetableiscalledmodules.pcimapandmodules.usbmapforallPCIandUSBdevices,respectively,andexistsinthedirectory/lib/modules/kernel_version/.Forexample,thefollowingcodesnippetfromdrivers/net/eepro100.c:staticstructpci_device_ideepro100_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);causestheselinestobeaddedtothemodules.pcimapfile:eepro1000x000080860x000012290xffffffff0xffffffff0x000000000x000000000x00000000eepro1000x000080860x000010310xffffffff0xffffffff0x000000000x000000000x00000000eepro1000x000080860x000012090xffffffff0xffffffff0x000000000x000000000x00000000eepro1000x000080860x000010290xffffffff0xffffffff0x000000000x000000000x00000000eepro1000x000080860x000010300xffffffff0xffffffff0x000000000x000000000x00000000eepro1000x000080860x000024490xffffffff0xffffffff0x000000000x000000000x00000000Astheexampleshows,aPCIdevicecanbespecifiedbyanyofthesameparametersthatarepassedtothe/sbin/hotplugprogram.AUSBdevicecanspecifythatitcanacceptonlyspecificdevicessuchasthisexamplefromdrivers/usb/mdc800.c:staticstructusb_device_idmdc800_table[]={{USB_DEVICE(MDC800_VENDOR_ID,MDC800_PRODUCT_ID)},{}/*Terminatingentry*/};MODULE_DEVICE_TABLE(usb,mdc800_table);whichcausesthefollowinglinetobeaddedtothemodules.usbmapfile:mdc8000x00030x055f0xa8000x00000x00000x000x000x000x000x000x000x00000000OritcanspecifythatitacceptsanydevicethatmatchesaspecificUSBclasscode,asinthisexamplefromdrivers/usb/printer.c:staticstructusb_device_idusblp_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)},{}/*Terminatingentry*/};MODULE_DEVICE_TABLE(usb,usblp_ids);whichcausesthefollowinglinestobeaddedtothemodules.usbmapfile:printer0x03800x00000x00000x00000x00000x000x000x000x070x010x010x00000000printer0x03800x00000x00000x00000x00000x000x000x000x070x010x020x00000000printer0x03800x00000x00000x00000x00000x000x000x000x070x010x030x00000000AgaintheseUSBexamplesshowthattheinformationinthemodules.usbmapfilematchestheinformationprovidedto/sbin/hotplugbythekernel,enabling/sbin/hotplugtodeterminewhichdrivertoloadwithoutrelyingonahand-generatedtable,asPCMCIAdoes.PreprocessorAbuseThemacroMODULE_DEVICE_TABLEautomaticallycreatestwovariables.Fortheexample:MODULE_DEVICE_TABLE(usb,usblp_ids);thevariables__module_usb_device_sizeand__module_usb_device_tablearecreatedandplacedintotheread-onlydatadivandtheinitializeddatadivofthemodule,respectively.Thevariable__module_usb_device_sizecontainsthevalueofthesizeofthestructusb_idstructure,and__module_usb_device_tablepointstotheusblp_idsstructure.Theusblp_idsvariableisanarrayofusb_idstructureswithaterminatingNULLstructureattheendofthelist.Whenthedepmodprogramisrun,aspartofthekernelinstallationprocess,itgoesthrougheverymodulelookingforthesymbol__module_usb_device_sizetobepresentinthecompiledmodule.Ifitfindsit,itcopiesthedatapointedtobythe__module_usb_device_tablesymbolintoastructure,extractsalloftheinformationandwritesitouttothemodules.usbmapfile,whichislocatedinthemodulerootdirectory.Itdoesthesamethingwhilelookingforthe__module_pci_device_sizeincreatingthemodules.pcimapfile.Withthekernelmoduleinformationexportedtothefilesmodules.usbmapandmodules.pcimap,ourversionof/sbin/hotplugcanlooklikeListing2[availableatftp.ssc.com/pub/lj/listings/issue96/5604.tgz].ThisexampleonlytestsforamatchoftheUSBproductIDandvendorIDs.TheLinux-HotplugProjecthascreatedasetofscriptsthatcoversallofthedifferentsubsystemsthatcancall/sbin/hotplug.Thisenablesdriverstobeloadedautomaticallywhennewdevicesareinsertedintothesystems.Italsostartsupnetworkserviceswhennetworkdevicesareseen.ThesescriptsarereleasedundertheGPLandareavailableatlinux-hotplug.sourceforge.net.AlmostallmajorLinuxdistributionsarecurrentlyshippingthispackage,soitisprobablyalreadyonyourmachine.TheFutureThecurrent/sbin/hotplugsubsystemneedstobeincorporatedintootherkernelsystems,astheydevelophot-plugcapability.SCSI,IDEandothersystemsallhavehot-plugpatchesavailableforkernelsupportbutneedtohavescriptsupport,kernelmacrosupportandmodutilsdepmodsupportaddedinordertoprovidetheuserwithaconsistentexperience.Asthekernelboots,anddiscoversnewdevices,ittriestospawn/sbin/hotplug,butsinceuserspacehasnotbeeninitializedyet,itcannotrun.ThismeansthatanyUSBorPCIdevicesthatareneededatboottimeneedtobecompiledintothekernelorexistinaninitrdRAMdiskimageasamodule.Sometimeduringthe2.5developmentprocess,theinitrdRAMdiskimagewillbeconvertedtocontainanentiresmalluser-spacetree.Thiswillallow/sbin/hotplugtoberunduringthebootprocessandloadmodulesdynamically.Somelinksdescribingthisdiskimageideaare:lwn.net/2001/0712/kernel.php3,marc.theaimsgroup.com/?l=acpi4linux&m=99705696732868,marc.theaimsgroup.com/?l=linux-kernel&m=99436439232254andmarc.theaimsgroup.com/?l=linux-kernel&m=99436253707952.BecauseofthesmallspacerequirementsofthisRAMdiskimage,thedietHotplugprogramhasbeenwritten.ItisanimplementationoftheLinux-HotplugbashscriptsinCanddoesnotrequiremodules.*mapfileswhentheprogramruns.TheexecutablesizeoftheentiredietHotplugprogramisone-fifthofthesizeoftheoriginalmodules.*mapfilesthemselves.ThesmallsizeisduetotheuseofdietLibc(foundatwww.fefe.de/dietlibc)andotherspace-savingtechniques.dietHotplugwillundergomoredevelopmentasthe2.5kernelrequirementsaremorefullyknown.dietHotplugcanbedownloadedfromtheLinux-Hotplugsite.AcknowledgementsIwouldliketothankDavidBrownellwhowrotetheoriginal/sbin/hotplugkernelpatchandmostoftheLinuxHotplugscripts.Withouthispersistence,Linuxwouldnothavethisuser-friendlyfeature.IalsowouldliketoacknowledgetheentireLinuxUSBdevelopmentteam,whohaveprovidedasolidkernelsubsysteminarelativelyshortamountoftime.KeithOwenswrotethesupportingcodeinthedepmodutilityandhasenduredconstantchangestotheformatoftheMODULE_DEVICE_TABLE()USBstructure.Theotherdevelopersonthelinux-hotplug-develmailinglistwhohavehelpedwiththeirpatchesandfeedbackonthehot-plugscriptsalsodeserverecognition,alongwiththewonderfulLinuxdistribution-specificsupportthatDebian,RedHatandMandrakehaveprovided.ThisarticlewasbaseduponapaperandpresentationthatIgaveatthe2001OttawaLinuxSymposium.
GregKroah-HartmaniscurrentlytheLinuxUSBandPCIHotplugkernelmaintainer.HeworksforIBM,doingvariousLInuxkernel-relatedthingsandcanbereachedatgreg@kroah.com.
2.2.mdev.conf文件
参考mdev的使用以及mdev.conf的规则配置
/etc>:catmdev.conf
sd[a-h]*[0-9]0:00660*(/usr/sbin/hotplug/media/usb)
sd[a-h]0:00660*(/usr/sbin/hotplug/media/usb)
ub[a-h]*[0-9]0:00660*(/usr/sbin/hotplug/media/usb)
ub[a-h]0:00660*(/usr/sbin/hotplug/media/usb)
mmcblk[0-9]p[0-9]0:00660@(/bin/mount/dev/$MDEV/media/mmc)
mmcblk[0-9]0:00660$(/bin/umount/media/mmc)
wlan[0-9]0:00660@(/apps/tools/ifup-wlan$INTERFACE)
/etc>:
如果我们在apps/tools/ifup-wlan文件的开头加入下面红色的一行:
~>:catapps/tools/ifup-wlan
#!/bin/sh
#FILE:/usr/sbin/ifup-wlan0
#Copyright(C)2011GuoWenxue<guowenxue@gmail.comQQ:281143292>
#Thisfileusedtoconfigurethespecifiednetworkinterfacedevice
source/etc/profile
export>/tmp/hotplug.log
if[-z"$network_cfg_dir"];then
exportnetwork_cfg_dir=/apps/etc/network
fi
。。。。
/*********************************************************/
保存后退出。
重新插入无线网卡:~>:usb1-1.1:newfullspeedUSBdevicenumber4usings3c2410-ohci
usb1-1.1:NewUSBdevicefound,idVendor=148f,idProduct=3070
usb1-1.1:NewUSBdevicestrings:Mfr=1,Product=2,SerialNumber=3
usb1-1.1:Product:802.11nWLAN
usb1-1.1:Manufacturer:Ralink
usb1-1.1:SerialNumber:1.0
~>:
在hotplug.log文件中记录了热插拔过程中传过来的一下变量,红色所示。
~>:cat/tmp/hotplug.log
exportACTION=’add’
exportDEVPATH=’/devices/platform/s3c2410-ohci/usb1/1-1/1-1.1/1-1.1:1.0/net/wlan0′
exportDEVTYPE=’wlan’
exportEDITOR=’/bin/vi’
exportHISTFILESIZE=’500′
exportHISTSIZE=’500′
exportHOME=’/’
exportHOSTNAME=’fulinux’
exportIFINDEX=’4′
exportINPUTRC=’/etc/inputrc’
exportINTERFACE=’wlan0′
exportLD_LIBRARY_PATH=’/lib:/usr/lib:/apps/lib’
exportLOGNAME=’root’
exportMDEV=’wlan0′
exportPAGER=’/bin/more’
exportPATH=’/bin:/sbin:/usr/bin:/usr/sbin:/apps/tools’
exportPS1=’\w>:’
exportPWD=’/dev’
exportSEQNUM=’493′
exportSUBSYSTEM=’net’
exportUSER=’root’
exportnetwork_cfg_dir=’/apps/etc/network’
~>:
如果是在命令行中使用export命令,结果如下:
~>:export
exportEDITOR=’/bin/vi’
exportHISTFILESIZE=’500′
exportHISTSIZE=’500′
exportHOME=’/’
exportHOSTNAME=’fulinux’
exportINPUTRC=’/etc/inputrc’
exportLD_LIBRARY_PATH=’/lib:/usr/lib:/apps/lib’
exportLOGNAME=’root’
exportPAGER=’/bin/more’
exportPATH=’/bin:/sbin:/usr/bin:/usr/sbin:/apps/tools’
exportPS1=’\w>:’
exportPWD=’/’
exportSHELL=’/bin/sh’
exportTERM=’vt100′
exportUSER=’root’
exportnetwork_cfg_dir=’/apps/etc/network’
~>:
最后运行的结果:
~>:ifconfigwlan0
wlan0Linkencap:EthernetHWaddr00:0C:43:30:72:81
inetaddr:192.168.1.166Bcast:192.168.1.255Mask:255.255.255.0
UPBROADCASTRUNNINGMULTICASTMTU:1500Metric:1
RXpackets:136errors:0dropped:15overruns:0frame:0
TXpackets:4errors:0dropped:0overruns:0carrier:0
collisions:0txqueuelen:1000
RXbytes:14849(14.5KiB)TXbytes:548(548.0B)
~>:iwconfigwlan0
wlan0IEEE802.11bgnESSID:"Router_LingYun"
Mode:ManagedFrequency:2.437GHzAccessPoint:D8:5D:4C:18:04:7A
BitRate=1Mb/sTx-Power=20dBm
Retrylonglimit:7RTSthr:offFragmentthr:off
Encryptionkey:off
PowerManagement:on
LinkQuality=49/70Signallevel=-61dBm
Rxinvalidnwid:0Rxinvalidcrypt:0Rxinvalidfrag:0
Txexcessiveretries:0Invalidmisc:4Missedbeacon:0
~>:pingwww.baidu.com
PINGwww.baidu.com(115.239.210.26):56databytes
64bytesfrom115.239.210.26:seq=0ttl=55time=58.396ms
64bytesfrom115.239.210.26:seq=1ttl=55time=95.457ms
64bytesfrom115.239.210.26:seq=2ttl=55time=97.314ms
64bytesfrom115.239.210.26:seq=3ttl=55time=99.431ms
64bytesfrom115.239.210.26:seq=4ttl=55time=97.498ms

—www.baidu.compingstatistics—
5packetstransmitted,5packetsreceived,0%packetloss
round-tripmin/avg/max=58.396/89.619/99.431ms
~>:
表明wlan0已成功运行。
每年的同一天和他庆祝生日,每年的情人节、圣诞节、除夕,