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。

/**
 * @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/

#

#

时间: 2024-12-15 01:40:41

Linux USB U盘热插拔挂载和卸载的相关文章

Linux下U盘的挂载,卸载

1, 插入U盘后,在Linux下输入fdisk -l命令,如下所示 表明该设备已经被识别,并且该设备的名称为sdb1. 2, 建立一个挂载usb的挂载目录,(可以自定义目录) #mkdir /mnt/usb 3,   将U盘挂载在到/mnt/usb目录下 mount命令格式:mount [-参数] [设备名称] [挂载点] [其他参数]                            mount -t vfat /dev/sdb1/ /mnt/usb -o iocharset=gb2312

Linux基础之磁盘的挂载与卸载

在linux系统中,挂载是指将一个设备(通常是存储设备)挂接到一个已存在的目录上.我们要访问存储设备中的文件,必须将文件所在的分区挂载到一个已存在的目录上,然后通过访问这个目录来访问存储设备.比如访问光盘,u盘,磁盘分区都需要通过挂载的方式才可以正常访问和使用. 在挂载之前需要确定的有: 单一文件系统不应该被重复挂载在不同的挂载点中 单一目录不应该重复挂载多个文件系统 作为挂载点的目录理论上应该都是空目录才行 mount命令 mount可将指定设备中的指定的文件系统加载到linux目录下.可将经

Linux下磁盘分区、挂载、卸载操作记录

Linux下磁盘分区.挂载.卸载操作记录. 操作环境:CentOS release 6.5 (Final) Last login: Wed Oct 26 17:25:27 2016 from 118.230.194.76 [[email protected] ~]# [[email protected] ~]# fdisk -l Disk /dev/sda: 536.9 GB, 536870912000 bytes 255 heads, 63 sectors/track, 65270 cylin

嵌入式linux 实现mdev SD卡和U盘自动挂载和卸载的方法 mdev.conf

首先先参考这些博客做一些了解:http://linux.chinaunix.net/techdoc/install/2009/11/18/1144936.shtml http://www.cnblogs.com/leaven/archive/2010/09/17/1828896.html,也可百度mdev.conf查看其他文章. 内核务必要支持mdev和hotplug功能. etc目录下要有这个文件mdev.conf,内容如下(其他的类似): sd[a-z][0-9] 0:0 666 @/etc

最小LINUX系统下U盘的挂载及卸载

U盘挂载命令U盘插入的时候会显示启动信息,启动信息中sda: sda1指U盘的设备名为sda1dev设备目录下有一个sda1设备文件,此设备文件就是我们插入的U盘,我们将这个设备文件挂载到Linux系统的/mnt/udisk1这个目录下,这样我们即可以通过访问/mnt/udisk1目录来读写U盘,挂载用mount命令[[email protected] /]# mount /dev/sda1 /mnt/udisk1精简写法为mntud1,功能与mount /dev/sda1 /mnt/udisk

Linux基础01-u盘的挂载

检测设备的名称: sudo fdisk -l Disk /dev/sda: 238.5 GiB, 256060514304 bytes, 500118192 sectors Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt D

讯为开发板的最小LINUX系统烧写及U盘的挂载及卸载

fdisk -c 0 fatformat mmc 0:1ext3format mmc 0:2ext3format mmc 0:3ext3format mmc 0:4 fastboot fastboot.exe flash kernel zImage fastboot.exe flash ramdisk ramdisk-uboot.imgfastboot.exe flash system system.img fastboot -w fastboot reboot 挂载U盘,在根目录下操作moun

linux下U盘的挂载经历

参考资料:http://space.itpub.net/4227/viewspace-625987 环境说明: 1)系统安装在虚拟机中,没有办法上网 2)系统没有安装虚拟工具 U盘挂载在Linux系统 1)将U盘插入U盘插槽 2)检测到U盘,连接到虚拟机中 3)使用指令: # fdisk -l 内容如下: Disk /dev/sda:21.5GB ........... Disk /dev/sdb:7862MB Device Boot  Start  End Blocks Id System /

白话kali linux USB启动盘的制作(快捷版)

以前装系统没有正确方法,基本上是胡乱安装. 制作启动盘,网上有很多的教程,各种软件非常的多,但是基本没有使用过,因为一定程度的不信任. 在知乎上看到一个据说非常良心的软件,既可以安装windows也可以安装linux,关注官网,才发现可以安装的其实更多. 这个软件的名字叫rufus: 中文网址:http://rufus.akeo.ie/?locale=zh_CN 英文网址:http://rufus.akeo.ie/ github网址:https://github.com/pbatard/rufu