您的位置:首页 > 运维架构 > Linux

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

2017-11-23 19:35 2679 查看


一、硬件平台

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

/**

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

[cpp] view
plain copy

/**

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

[cpp] view
plain copy

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

#

#
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: