Linux USB U盘热插拔挂载和卸载

一、硬件平台

        1、  控制器:MT7620(A9内核)

        2、  RTC芯片:MCP7940

二、软件平台

       1、开发环境:Ubuntu12.04 

       2、SDK内核包:MT7620 SDK软件开发包(MediaTek_ApSoC_SDK_4320_20150414.tar.bz2)

       3、内核版本:linux-2.6.36.x

三、参考资料

      《MTK_APSoC_SDK_User_Manual.pdf》。

      下载链接:http://download.csdn.net/detail/xhoufei2010/9478004

四、USB U盘驱动简介

        USB Mass Storage是一类USB存储设备,这些设备包括USB磁盘、USB硬盘、USB磁带机、USB光驱、U盘、记忆棒、智能卡和一些USB摄像头等,这类设备由USB协议支持。

       对于USB的U盘驱动,已经非常完善,大家只需要简单地配置一下内核,开启U盘的功能即可。

五、U盘配置

       5.1 取消内核自动挂载功能

        由于Linux 内核包默认会自动挂载,且内核初始化的过程中,挂载出现在创建USB节点之前,经常出现自动挂载导致内核崩溃,故取消内核挂载,自己监听USB的热插拔,然后挂载。

        1.开启设置busybox

        进入到内核开发包目录 cd /home/kernel/source

        输入命令 make menuconfig

        Kernel/Library/Defaults Selection  --->Customize Busybox Settings ,选中该选项,如图5-1所示,设置完成之后,保存退出。

        

                                                          图5-1 设置Busybox

       2. 取消USB自动挂载/卸载功能

       在图5-1保存设置之后,会自动跳转到busybox的设置界面,在界面中,进入Linux System Utilities,取消掉Support command execution at device addition/removal 选项,如图5-2所示。


                                                       图5-2 取消USB的自动挂载/卸载

       5.2 开启U盘功能

        在linux-2.6.36.x中,输入命令make menuconfig,进入配置

        Linux Kernel Configuration ---> Device Drivers  ---> USB support ,在配置中,选中USB Mass Storage support,如图5-3所示。


                                                         图5-3 开启USB U盘支持

六、监听USB热插拔程序

       6.1 说明

        对于USB的热插拔,实际就是建立一个socket,采用socket监听USB的插拔信息。

        当监听到USB插入信息,且发现在 /dev目录下,存在 sda1或者sdb1分区(有时候分区节点为其他名称,根据实际分区修改分区的名称判断条件)的时候,就挂载USB分区到 /tmp/usb目录下。

        当监听到USB拔出信息,则卸载 /tmp/usb目录。

        6.2 usb控制器头文件,UsbController.h。

[cpp]  view plain  copy
  1. /** 
  2.  * @addtogroup module_genericGateway 
  3.  * @{ 
  4.  */  
  5.   
  6. /** 
  7.  * @file 
  8.  * @brief USB控制器,管理USB插拔及挂载。 
  9.  * @details  
  10.  * @version 1.0.0 
  11.  * @author sky.houfei 
  12.  * @date 2016-3-18 
  13.  */  
  14.   
  15.   
  16. #ifndef _USB_USBCONTROLLER_H_  
  17. #define _USB_USBCONTROLLER_H_  
  18.   
  19.   
  20. #ifdef __cplusplus  
  21. extern "C" {  
  22. #endif  
  23.   
  24. //******************************************************************************  
  25. #include <stdbool.h>  
  26.   
  27.   
  28. //******************************************************************************  
  29. /**  
  30.  * @brief USB控制器初始化,准备USB的监听服务。  
  31.  * @return ret, int,如果初始化成功,则返回0,否则为-1.  
  32.  */  
  33. int UsbController_Init(void);  
  34.   
  35.   
  36. /** 
  37.  * @brief USB设备挂载监听。 
  38.  * @details 如果USB之前没有挂载且当前可以挂载,则挂载。 
  39.  * \n 如果USB之前挂载成功,此时设备已经被拔出,则卸载。 
  40.  */  
  41. void UsbController_MountMonitor(void);  
  42.   
  43.   
  44. /** 
  45. * @brief 是否已经挂载成功。 
  46. * @return bool s_isMounted, USB设备挂载成功,则返回 true, 否则返回false。 
  47. */  
  48. bool UsbController_IsMounted(void);  
  49.   
  50.   
  51. #ifdef __cplusplus  
  52. }  
  53. #endif  
  54.   
  55.   
  56. #endif  // _USB_USBCONTROLLER_H_  
  57.   
  58. /** @} */  

       6.3 usb控制器监听热插拔c文件, UsbController.c

[cpp]  view plain  copy
  1. /** 
  2.  * @addtogroup module_genericGateway 
  3.  * @{ 
  4.  */  
  5.   
  6. /** 
  7.  * @file 
  8.  * @brief USB控制器,管理USB插拔及挂载。 
  9.  * @details  
  10.  * @version 1.0.0 
  11.  * @author sky.houfei 
  12.  * @date 2016-3-18 
  13.  */  
  14.   
  15. //******************************************************  
  16. #include <stdio.h>   
  17. #include <stdlib.h>   
  18. #include <string.h>   
  19. #include <ctype.h>   
  20. #include <sys/un.h>   
  21. #include <sys/ioctl.h>   
  22. #include <sys/socket.h>   
  23. #include <linux/types.h>   
  24. #include <linux/netlink.h>   
  25. #include <errno.h>   
  26. #include <unistd.h>   
  27. #include <arpa/inet.h>   
  28. #include <netinet/in.h>   
  29. #include "UsbController.h"  
  30. #include "GenericGateway.h"  
  31.   
  32. //******************************************************  
  33. #define UEVENT_BUFFER_SIZE 2048   
  34.   
  35. //******************************************************  
  36. static bool isUsbConnected = false;  
  37. static int s_hotplugSock = 0;  
  38. static bool s_isMounted = false;  
  39.   
  40.  //******************************************************  
  41. static void* UsbController_HotPlugMonitor(void);  // USB监听,监听USB的插拔事件,并进行挂载和卸载USB设备。  
  42.   
  43.   
  44. //******************************************************  
  45. static int UsbController_HotplugSockInit(void)   
  46. {   
  47.     const int buffersize = 1024;   
  48.     int ret;   
  49.   
  50.     struct sockaddr_nl snl;   
  51.     bzero(&snl, sizeof(struct sockaddr_nl));   
  52.     snl.nl_family = AF_NETLINK;   
  53.     snl.nl_pid = getpid();   
  54.     snl.nl_groups = 1;   
  55.   
  56.     int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);   
  57.     if (s == -1)    
  58.     {   
  59.         perror("socket");   
  60.         return -1;   
  61.     }   
  62.     setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));   
  63.   
  64.     ret = bind(s, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));   
  65.     if (ret < 0)    
  66.     {   
  67.         perror("bind");   
  68.         close(s);   
  69.         return -1;   
  70.     }   
  71.   
  72.     return s;   
  73. }   
  74.   
  75.   
  76. /**  
  77.  * @brief USB控制器初始化,准备USB的监听服务。  
  78.  * @return ret, int,如果初始化成功,则返回0,否则为-1.  
  79.  */  
  80. int UsbController_Init(void)  
  81. {  
  82.     const int buffersize = 1024;   
  83.     int ret;   
  84.     pthread_t id;  
  85.   
  86.     struct sockaddr_nl snl;   
  87.     bzero(&snl, sizeof(struct sockaddr_nl));   
  88.     snl.nl_family = AF_NETLINK;   
  89.     snl.nl_pid = getpid();   
  90.     snl.nl_groups = 1;   
  91.   
  92.     if (access("/dev/sda1", 0) == 0)  
  93.     {  
  94.         // USB已经连接成功  
  95.         isUsbConnected = true;  
  96.     }  
  97.   
  98.   
  99.     UsbController_MountMonitor();   // 首次检查USB是否挂载  
  100.     s_hotplugSock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);   
  101.     if (s_hotplugSock == -1)    
  102.     {   
  103.         perror("socket error");   
  104.         return -1;   
  105.     }   
  106.     setsockopt(s_hotplugSock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize));   
  107.   
  108.     ret = bind(s_hotplugSock, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl));   
  109.     if (ret < 0)    
  110.     {   
  111.         perror("bind error");   
  112.         close(s_hotplugSock);   
  113.         return -1;   
  114.     }   
  115.   
  116.     ret = pthread_create(&id, NULL, UsbController_HotPlugMonitor, NULL);    
  117.     if (ret != 0)     
  118.     {    
  119.         printf("pthread_create error = %d\n", ret);    
  120.     }    
  121.   
  122.     return 0;  
  123. }  
  124.   
  125.   
  126. /** 
  127.  * @brief USB监听热插拔,监听USB的插拔事件,并进行挂载和卸载USB设备。 
  128.  */  
  129. static void* UsbController_HotPlugMonitor(void)  
  130. {   
  131.     pthread_detach(pthread_self());  
  132.     char *result = NULL;  
  133.     char buf[UEVENT_BUFFER_SIZE * 2] = {0};     //  Netlink message buffer    
  134.       
  135.     while (1)  
  136.     {  
  137.         recv(s_hotplugSock, &buf, sizeof(buf), 0); // 获取 USB 设备的插拔会出现字符信息,  
  138.         result = strtok(buf, "@");                // 查看 USB的插入还是拔出信息  
  139.         if (result != NULL)  
  140.         {  
  141.             if ((strcmp(result, "add") == 0))  
  142.             {  
  143.                 if (isUsbConnected == false)  
  144.                 {  
  145.                     isUsbConnected = true;  
  146.                 }  
  147.   
  148.             }  
  149.             else if ((strcmp(result, "remove") == 0))  
  150.             {  
  151.                 if (isUsbConnected == true)  
  152.                 {  
  153.                     isUsbConnected = false;  
  154.                 }  
  155.             }  
  156.         }  
  157.         memset(buf, 0, UEVENT_BUFFER_SIZE * 2);  
  158.     }  
  159. }  
  160.   
  161.   
  162. /** 
  163. * @brief 是否连接成功。 
  164. * @return bool isConnnected, USB设备连接成功,则返回 true, 否则返回false。 
  165. */  
  166. static bool UsbController_IsConnected(void)  
  167. {  
  168.     return isUsbConnected;  
  169. }  
  170.   
  171.   
  172. /** 
  173.  * @brief 挂载文件系统。 
  174.  * @details 创建文件夹 /tmp/usb,将USB设备挂在在该目录下。尝试挂在 sda1和sdb1,如果都挂在失败,则认为挂载失败。 
  175.  * @return 如果挂载成功,则返回0,否则为-1。 
  176.  */  
  177. static int UsbController_MountFileSystem(void)  
  178. {  
  179.     const char directory[] = "/tmp/usb";  
  180.     int ret = 0;  
  181.   
  182.     printf("Try to mount the usb device\n");  
  183.     // 检测是否存在文件夹  
  184.     if (access(directory, 0) == -1)  
  185.     {  
  186.         // 文件夹不存在  
  187.         if (mkdir(directory, 0777)) // 创建文件夹  
  188.         {  
  189.             printf("creat directory(%s) failed!!!", directory);  
  190.             return -1;  
  191.         }  
  192.     }  
  193.   
  194.     if (system("mount -t vfat /dev/sda1  /tmp/usb") < 0)  // 挂载USB的文件系统  
  195.     {  
  196.         if (system("mount -t vfat /dev/sdb1  /tmp/usb") < 0)  
  197.         {  
  198.             return -1;  
  199.         }  
  200.     }  
  201.   
  202.     return 0;  
  203. }  
  204.   
  205.   
  206. /** 
  207.  * @brief 卸载文件系统。 
  208.  * @return 如果挂载成功,则返回0,否则为-1。 
  209.  */  
  210. static int UsbController_UnmountFileSystem(void)  
  211. {  
  212.     int ret = 0;  
  213.   
  214.     if (system("umount /tmp/usb") < 0)  // 挂载USB的文件系统  
  215.     {  
  216.         printf("Umount the usb device failed\n");  
  217.         ret =  -1;  
  218.     }  
  219.   
  220.     printf("Umount the usb device success\n");  
  221.     return ret;  
  222. }  
  223.   
  224.   
  225. /** 
  226.  * @brief USB设备是否可以挂载。 
  227.  * @details 设备处于连接状态,且在/dev/目录下创建了sda1或者sdb1节点,则视为可以挂载。 
  228.  * @return 如果可以挂在,则返回true,否则为false。 
  229.  */  
  230. static bool UsbController_IsMountable(void)  
  231. {  
  232.     bool isMountable = false;  
  233.     bool isPartitionExist = false;  
  234.   
  235.     if (access("/dev/sda1", 0) == 0 || access("/dev/sdb1", 0) == 0)  
  236.     {  
  237.         // 存在分区 /dev/sda1 或者 /dev/sdb1  
  238.         isPartitionExist = true;  
  239.     }  
  240.   
  241.     if (isUsbConnected == true && isPartitionExist == true)  
  242.     {  
  243.         isMountable = true;  
  244.     }  
  245.   
  246.     return isMountable;  
  247. }  
  248.   
  249.   
  250. /** 
  251.  * @brief USB设备挂载监听。 
  252.  * @details 如果USB之前没有挂载且当前可以挂载,则挂载。 
  253.  * \n 如果USB之前挂载成功,此时设备已经被拔出,则卸载。 
  254.  */  
  255. void UsbController_MountMonitor(void)  
  256. {  
  257.     if (s_isMounted == false && UsbController_IsMountable() == true)  
  258.     {  
  259.         // 之前没有挂载且当前可以挂载,挂载文件系统  
  260.         if (0 == UsbController_MountFileSystem())  
  261.         {  
  262.             printf("Mount success\n");  
  263.             s_isMounted = true;  
  264.             GenericGateway_SetUsbMounted(s_isMounted);  
  265.         }  
  266.     }  
  267.     else if (s_isMounted == true && UsbController_IsConnected() == false)  
  268.     {  
  269.         // 之前挂载成功,此时设备已经被拔出,卸载设备  
  270.         if (0 == UsbController_UnmountFileSystem())  
  271.         {  
  272.             s_isMounted = false;  
  273.             GenericGateway_SetUsbMounted(s_isMounted);  
  274.         }  
  275.     }  
  276. }  
  277.   
  278.   
  279. /** 
  280. * @brief 是否已经挂载成功。 
  281. * @return bool s_isMounted, USB设备挂载成功,则返回 true, 否则返回false。 
  282. */  
  283. bool UsbController_IsMounted(void)  
  284. {  
  285.     return s_isMounted;  
  286. }  
  287.   
  288.   
  289. /** @} */  

       6.4 主函数 main.c

[cpp]  view plain  copy
  1. #include <stdio.h>  
  2. #include "usb/UsbController.h"  
  3.   
  4. int main(int argc, char** argv)  
  5. {  
  6.     int secondCount = 0;  
  7.     UsbController_Init();  
  8.       
  9.       
  10.     while (1)  
  11.     {  
  12.         sleep(1);  
  13.         secondCount++;  
  14.         if (secondCount >= 5)  
  15.         {  
  16.             secondCount = 0;  
  17.             UsbController_MountMonitor();  
  18.         }  
  19.     }  
  20. }  

    6.5 测试结果

    6.5.1 USB 插入

     1. 查看USB设备

     # ls /dev/sd*
     /dev/sda1  /dev/sda

     2. 插入设备打印信息

# [  226.340000] usb 1-1: new high speed USB device using rt3xxx-ehci and address 6
[  226.490000] scsi4 : usb-storage 1-1:1.0
[  227.520000] scsi 4:0:0:0: Direct-Access     Kingston DataTraveler 2.0 1.00 PQ: 0 ANSI: 4
[  227.540000] sd 4:0:0:0: [sda] 30310400 512-byte logical blocks: (15.5 GB/14.4 GiB)
[  227.550000] sd 4:0:0:0: [sda] Write Protect is off
[  227.560000] sd 4:0:0:0: [sda] Assuming drive cache: write through
[  227.570000] sd 4:0:0:0: [sda] Assuming drive cache: write through
[  227.580000]  sda: sda1
[  227.590000] sd 4:0:0:0: [sda] Assuming drive cache: write through
[  227.590000] sd 4:0:0:0: [sda] Attached SCSI removable disk
Try to mount the usb device
[  232.110000] FAT: utf8 is not a recommended IO charset for FAT filesystems, filesystem will be case sensitive!
Mount success

     3. 查看USB挂载后的文件系统

     查看之后,可以正常获取到U盘的内容。

     # ls /tmp/usb/
test       software   computime

         6.5.2 USB 拔出

      1. USB拔出之后,打印信息:

      # [  789.230000] usb 1-1: USB disconnect, address 6
      Umount the usb device success

      2. 查看文件系统

      查看,发现/tmp/usb目录的内容已经被卸载,正常卸载。

      # ls /tmp/usb/
      # 
      # 

猜你喜欢

转载自blog.csdn.net/liuqingsongmsdn2014/article/details/78618235