软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 开发杂谈 -> LinuxUSBU盘热插拔挂载和卸载 -> 正文阅读

[开发杂谈]LinuxUSBU盘热插拔挂载和卸载


一、硬件平台


        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所示,设置完成之后,保存退出。
        [img]http://img.blog.csdn.net/20160331154746972?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center
                                                          图5-1 设置Busybox

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


       在图5-1保存设置之后,会自动跳转到busybox的设置界面,在界面中,进入Linux System Utilities,取消掉Support command execution at device addition/removal 选项,如图5-2所示。
[img]http://img.blog.csdn.net/20160331155237052?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

                                                       图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所示。
[img]http://img.blog.csdn.net/20160331161114434?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center

                                                         图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。



/**
 * @addtogroup module_genericGateway
 * @{
 */

/**
 * @file
 * @brief USB控制器,管理USB插拔及挂载。
 * @details 
 * @version 1.0.0
 * @author sky.houfei
 * @date 2016-3-18
 */


#ifndef _USB_USBCONTROLLER_H_
#define _USB_USBCONTROLLER_H_


#ifdef __cplusplus
extern "C" {
#endif

//******************************************************************************
#include <stdbool.h>


//******************************************************************************
/**
 * @brief USB控制器初始化,准备USB的监听服务。
 * @return ret, int,如果初始化成功,则返回0,否则为-1.
 */
int UsbController_Init(void);


/**
 * @brief USB设备挂载监听。
 * @details 如果USB之前没有挂载且当前可以挂载,则挂载。
 * \n 如果USB之前挂载成功,此时设备已经被拔出,则卸载。
 */
void UsbController_MountMonitor(void);


/**
* @brief 是否已经挂载成功。
* @return bool s_isMounted, USB设备挂载成功,则返回 true, 否则返回false。
*/
bool UsbController_IsMounted(void);


#ifdef __cplusplus
}
#endif


#endif  // _USB_USBCONTROLLER_H_

/** @} */

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



/**
 * @addtogroup module_genericGateway
 * @{
 */

/**
 * @file
 * @brief USB控制器,管理USB插拔及挂载。
 * @details 
 * @version 1.0.0
 * @author sky.houfei
 * @date 2016-3-18
 */

//******************************************************
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 
#include <sys/un.h> 
#include <sys/ioctl.h> 
#include <sys/socket.h> 
#include <linux/types.h> 
#include <linux/netlink.h> 
#include <errno.h> 
#include <unistd.h> 
#include <arpa/inet.h> 
#include <netinet/in.h> 
#include "UsbController.h"
#include "GenericGateway.h"

//******************************************************
#define UEVENT_BUFFER_SIZE 2048 

//******************************************************
static bool isUsbConnected = false;
static int s_hotplugSock = 0;
static bool s_isMounted = false;

 //******************************************************
static void* UsbController_HotPlugMonitor(void);  // USB监听,监听USB的插拔事件,并进行挂载和卸载USB设备。


//******************************************************
static int UsbController_HotplugSockInit(void) 
{ 
    const int buffersize = 1024; 
    int ret; 

    struct sockaddr_nl snl; 
    bzero(&snl, sizeof(struct sockaddr_nl)); 
    snl.nl_family = AF_NETLINK; 
    snl.nl_pid = getpid(); 
    snl.nl_groups = 1; 

    int s = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
    if (s == -1)  
    { 
        perror("socket"); 
        return -1; 
    } 
    setsockopt(s, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize)); 

    ret = bind(s, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)); 
    if (ret < 0)  
    { 
        perror("bind"); 
        close(s); 
        return -1; 
    } 

    return s; 
} 


/**
 * @brief USB控制器初始化,准备USB的监听服务。
 * @return ret, int,如果初始化成功,则返回0,否则为-1.
 */
int UsbController_Init(void)
{
	const int buffersize = 1024; 
    int ret; 
	pthread_t id;

    struct sockaddr_nl snl; 
    bzero(&snl, sizeof(struct sockaddr_nl)); 
    snl.nl_family = AF_NETLINK; 
    snl.nl_pid = getpid(); 
    snl.nl_groups = 1; 

	if (access("/dev/sda1", 0) == 0)
	{
		// USB已经连接成功
		isUsbConnected = true;
	}


	UsbController_MountMonitor();	// 首次检查USB是否挂载
    s_hotplugSock = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); 
    if (s_hotplugSock == -1)  
    { 
        perror("socket error"); 
        return -1; 
    } 
    setsockopt(s_hotplugSock, SOL_SOCKET, SO_RCVBUF, &buffersize, sizeof(buffersize)); 

    ret = bind(s_hotplugSock, (struct sockaddr *)&snl, sizeof(struct sockaddr_nl)); 
    if (ret < 0)  
    { 
        perror("bind error"); 
        close(s_hotplugSock); 
        return -1; 
    } 

	ret = pthread_create(&id, NULL, UsbController_HotPlugMonitor, NULL);  
    if (ret != 0)   
    {  
        printf("pthread_create error = %d\n", ret);  
    }  

	return 0;
}


/**
 * @brief USB监听热插拔,监听USB的插拔事件,并进行挂载和卸载USB设备。
 */
static void* UsbController_HotPlugMonitor(void)
{ 
	pthread_detach(pthread_self());
	char *result = NULL;
    char buf[UEVENT_BUFFER_SIZE * 2] = {0};     //  Netlink message buffer  
	
	while (1)
	{
	    recv(s_hotplugSock, &buf, sizeof(buf), 0); // 获取 USB 设备的插拔会出现字符信息,
		result = strtok(buf, "@");                // 查看 USB的插入还是拔出信息
		if (result != NULL)
		{
			if ((strcmp(result, "add") == 0))
			{
				if (isUsbConnected == false)
				{
					isUsbConnected = true;
				}

			}
			else if ((strcmp(result, "remove") == 0))
			{
				if (isUsbConnected == true)
				{
					isUsbConnected = false;
				}
			}
		}
		memset(buf, 0, UEVENT_BUFFER_SIZE * 2);
	}
}


/**
* @brief 是否连接成功。
* @return bool isConnnected, USB设备连接成功,则返回 true, 否则返回false。
*/
static bool UsbController_IsConnected(void)
{
	return isUsbConnected;
}


/**
 * @brief 挂载文件系统。
 * @details 创建文件夹 /tmp/usb,将USB设备挂在在该目录下。尝试挂在 sda1和sdb1,如果都挂在失败,则认为挂载失败。
 * @return 如果挂载成功,则返回0,否则为-1。
 */
static int UsbController_MountFileSystem(void)
{
	const char directory[] = "/tmp/usb";
	int ret = 0;

	printf("Try to mount the usb device\n");
	// 检测是否存在文件夹
	if (access(directory, 0) == -1)
	{
		// 文件夹不存在
		if (mkdir(directory, 0777)) // 创建文件夹
        {
            printf("creat directory(%s) failed!!!", directory);
			return -1;
        }
	}

	if (system("mount -t vfat /dev/sda1  /tmp/usb") < 0)  // 挂载USB的文件系统
	{
		if (system("mount -t vfat /dev/sdb1  /tmp/usb") < 0)
		{
			return -1;
		}
	}

	return 0;
}


/**
 * @brief 卸载文件系统。
 * @return 如果挂载成功,则返回0,否则为-1。
 */
static int UsbController_UnmountFileSystem(void)
{
	int ret = 0;

	if (system("umount /tmp/usb") < 0)  // 挂载USB的文件系统
	{
		printf("Umount the usb device failed\n");
		ret =  -1;
	}

	printf("Umount the usb device success\n");
	return ret;
}


/**
 * @brief USB设备是否可以挂载。
 * @details 设备处于连接状态,且在/dev/目录下创建了sda1或者sdb1节点,则视为可以挂载。
 * @return 如果可以挂在,则返回true,否则为false。
 */
static bool UsbController_IsMountable(void)
{
	bool isMountable = false;
	bool isPartitionExist = false;

	if (access("/dev/sda1", 0) == 0 || access("/dev/sdb1", 0) == 0)
	{
		// 存在分区 /dev/sda1 或者 /dev/sdb1
		isPartitionExist = true;
	}

	if (isUsbConnected == true && isPartitionExist == true)
	{
		isMountable = true;
	}

	return isMountable;
}


/**
 * @brief USB设备挂载监听。
 * @details 如果USB之前没有挂载且当前可以挂载,则挂载。
 * \n 如果USB之前挂载成功,此时设备已经被拔出,则卸载。
 */
void UsbController_MountMonitor(void)
{
	if (s_isMounted == false && UsbController_IsMountable() == true)
	{
		// 之前没有挂载且当前可以挂载,挂载文件系统
		if (0 == UsbController_MountFileSystem())
		{
			printf("Mount success\n");
			s_isMounted = true;
			GenericGateway_SetUsbMounted(s_isMounted);
		}
	}
	else if (s_isMounted == true && UsbController_IsConnected() == false)
	{
		// 之前挂载成功,此时设备已经被拔出,卸载设备
		if (0 == UsbController_UnmountFileSystem())
		{
			s_isMounted = false;
			GenericGateway_SetUsbMounted(s_isMounted);
		}
	}
}


/**
* @brief 是否已经挂载成功。
* @return bool s_isMounted, USB设备挂载成功,则返回 true, 否则返回false。
*/
bool UsbController_IsMounted(void)
{
	return s_isMounted;
}


/** @} */

       6.4 主函数 main.c



#include <stdio.h>
#include "usb/UsbController.h"

int main(int argc, char** argv)
{
	int secondCount = 0;
	UsbController_Init();
	
	
	while (1)
	{
		sleep(1);
		secondCount++;
		if (secondCount >= 5)
		{
			secondCount = 0;
			UsbController_MountMonitor();
		}
	}
}

    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/
      # 
      # 

......显示全文...
    点击查看全文


上一篇文章      下一篇文章      查看所有文章
2016-04-02 21:01:37  
开发杂谈 最新文章
BloomFilter
大学四年编程之历程
内核分析
造人论坛——意识的本质和一个人工脑模型
OFDM信号[matlab描述]
人类还会进化吗?
HDUACM1035RobotMotion简单模拟题
树、二叉树(二)
iisphpweb.config处理404,500等,跳转友好
DatabaseAsaFortress
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年1日历
2018-1-17 14:56:35
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --