生活随笔
收集整理的這篇文章主要介紹了
Linux下自动检测USB热插拔
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
做嵌入式開發(fā),尤其在網(wǎng)關(guān)、路由器或者其他支持USB設(shè)備的終端上,為了提高用戶體驗(yàn),我們常常需要支持自動(dòng)識(shí)別并掛載USB設(shè)備功能。某些應(yīng)用程序,在使用USB設(shè)備的過程中,也希望能夠偵測(cè)到USB斷開事件,不至于某些工作因?yàn)閁SB已經(jīng)不存在而白做。在Linux下,我們主要有兩種辦法檢測(cè)USB熱插拔。 ? ?
第一種便是定時(shí)檢查/proc/scsi/scsi文件,該文件內(nèi)會(huì)按照標(biāo)準(zhǔn)格式保存著當(dāng)前設(shè)備內(nèi)掛載的存儲(chǔ)介質(zhì)基本信息,如果在PC端,除了硬盤(ATA)、光驅(qū)(CD-ROM)外,就是USB設(shè)備(Direct-Access)了,輪詢?cè)搒csi文件,檢查文件內(nèi)是否新增或減少數(shù)據(jù)便可實(shí)現(xiàn)自動(dòng)偵測(cè)USB熱插拔的效果。但是這種方法對(duì)于熱插拔(hotplug)設(shè)備,如U盤,效果就沒那么理想了,因?yàn)槲覀儾恢涝O(shè)備什么時(shí)候插上,又是什么時(shí)候被拔掉了,只能驗(yàn)證當(dāng)前是否已經(jīng)插上或者已經(jīng)拔除的事實(shí)。于是便有了另一種辦法,我們采用一種特殊類的的文件描述符(套結(jié)字)專門用于Linux內(nèi)核跟用戶空間之間的異步通信,這種技術(shù)通常被成為NETLINK。
由于NETLINK是Linux內(nèi)置功能,所以使用起來很簡(jiǎn)單:創(chuàng)建一個(gè)AF_NETLINK協(xié)議族下NETLINK_KOBJECT_UEVENT類型的特殊文件描述符(套結(jié)字)CppLive,然后利用setsocketopt允許該文件描述符(套結(jié)字)復(fù)用其他端口,再利用band函數(shù)將自身進(jìn)程綁定到特殊文件描述符(套結(jié)字)CppLive,最后利用select在while循環(huán)內(nèi)監(jiān)聽CppLive是否可讀,如果可讀則調(diào)用recv接收Linux系統(tǒng)內(nèi)核傳遞過來的數(shù)據(jù)并打印出來,這些輸出便是USB熱插拔信息。當(dāng)然你也可以個(gè)性化地處理來自內(nèi)核的熱插拔信息,讓程序變得更加智能以及人性化。
利用NETLINK檢測(cè)USB熱插拔的C語言實(shí)現(xiàn)代碼如下:
view plaincopy to clipboardprint?
#include?<stdio.h>?? #include?<stdlib.h>?? #include?<string.h>?? #include?<fcntl.h>?? #include?<sys/socket.h>?? #include?<linux/netlink.h>?? #define?UEVENT_BUFFER_SIZE?2048?? ?? int?main(void)?? {?? ????struct?sockaddr_nl?client;?? ????struct?timeval?tv;?? ????int?CppLive,?rcvlen,?ret;?? ????fd_set?fds;?? ????int?buffersize?=?1024;?? ????CppLive?=?socket(AF_NETLINK,?SOCK_RAW,?NETLINK_KOBJECT_UEVENT);?? ????memset(&client,?0,?sizeof(client));?? ????client.nl_family?=?AF_NETLINK;?? ????client.nl_pid?=?getpid();?? ????client.nl_groups?=?1;??? ????setsockopt(CppLive,?SOL_SOCKET,?SO_RCVBUF,?&buffersize,?sizeof(buffersize));?? ????bind(CppLive,?(struct?sockaddr*)&client,?sizeof(client));?? ????while?(1)?{?? ????????char?buf[UEVENT_BUFFER_SIZE]?=?{?0?};?? ????????FD_ZERO(&fds);?? ????????FD_SET(CppLive,?&fds);?? ????????tv.tv_sec?=?0;?? ????????tv.tv_usec?=?100?*?1000;?? ????????ret?=?select(CppLive?+?1,?&fds,?NULL,?NULL,?&tv);?? ????????if(ret?<?0)?? ????????????continue;?? ????????if(!(ret?>?0?&&?FD_ISSET(CppLive,?&fds)))?? ????????????continue;?? ?????????? ????????rcvlen?=?recv(CppLive,?&buf,?sizeof(buf),?0);?? ????????if?(rcvlen?>?0)?{?? ????????????printf("%s\n",?buf);?? ?????????????? ????????}?? ????}?? ????close(CppLive);?? ????return?0;?? }??
運(yùn)行程序,測(cè)試U盤插入/拔除,輸出如下:
view plaincopy to clipboardprint?
add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0?? add@/module/usb_storage?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6?? add@/bus/usb/drivers/usb-storage?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0?? change@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb?? add@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4?? add@/devices/virtual/bdi/8:16?? add@/module/fat?? add@/kernel/slab/fat_cache?? add@/kernel/slab/fat_inode_cache?? add@/module/vfat?? add@/module/nls_cp437?? add@/module/nls_iso8859_1?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/bsg/6:0:0:0?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_generic/sg2?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_device/6:0:0:0?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/scsi_disk/6:0:0:0?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb/sdb4?? remove@/devices/virtual/bdi/8:16?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0/block/sdb?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/target6:0:0/6:0:0:0?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6/scsi_host/host6?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0/host6?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1/2-1:1.0?? remove@/devices/pci0000:00/0000:00:1d.7/usb2/2-1?? remove@/host6/target6:0:0 ?
轉(zhuǎn)自http://www.cpplive.com/html/1355.html
總結(jié)
以上是生活随笔為你收集整理的Linux下自动检测USB热插拔的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。