Linux Gadget的一点研究之U盘和USB虚拟串口


        Linux kernel2.6以上的版本中,USB设备驱动的接口改为了gadget,在kernel/driver/usb/gadget目录下主要包含了平台USB UDC驱动和gadget接口驱动。

        kernel/driver/usb/gadget目下的serial.c是一个常用的驱动文件,它可以配置为bulk传输驱动或CDC ACM驱动(USB转串口驱动)。配置的方式有两种,一可以在编译前手动更改驱动文件中的变量“use_acm"的默认值,现在默认值为”true“,对应为CDC ACM驱动,改为”false"后对应为bulk驱动;二可以将驱动编译成模块,然后在insmod时传递一个参数就行了。

       运行make menuconfig看一下:


         将“USB Gadget Support -->"选择编译为模块,方便动态加载驱动。

        进行“USB Gadget Support -->"配置子菜单:


        配置红色方框标注的模块。

      运行命令: make M=driver/usb/gagdet modules

      编译后在driver/usb/gagdet 下生产g_file_storage.ko和g_serial.ko,分别对应为U盘驱动和USB转串口驱动。

      笔者的嵌入式板上有个SD卡,linux驱动后挂载主目录是/dev/mmcblk0,分区目录是/dev/mmcblk0p1,/dev/mmcblk0p2,/dev/mmcblk0p3,有三个分区。

      执行:

root@rfODNCC:/mnt# insmod g_file_storage.ko file=/dev/mmcblk0 stall=0 removable=1
[   69.783477] g_file_storage gadget: No serial-number string provided!
[   69.798980] g_file_storage gadget: File-backed Storage Gadget, version: 1 September 2010
[   69.807495] g_file_storage gadget: Number of LUNs=1
[   69.812622] g_file_storage gadget-lun0: ro=0, nofua=0, file: /dev/mmcblk0
[   69.819763] musb-hdrc musb-hdrc.0: MUSB HDRC host driver
[   69.825622] musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 2
[   69.833801] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
[   69.840942] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[   69.848510] usb usb2: Product: MUSB HDRC host driver
[   69.853668] usb usb2: Manufacturer: Linux 2.6.37-05branch musb-hcd
[   69.860137] usb usb2: SerialNumber: musb-hdrc.0
[   69.872558] hub 2-0:1.0: USB hub found
[   69.876647] hub 2-0:1.0: 1 port detected
root@rfODNCC:/mnt# [   70.169555] g_file_storage gadget: high speed config #1

连接USB到PC,可以看到PC端出现SD卡的分区目录。

PS:insmod g_file_storage.ko file=/dev/mmcblk0 stall=0 removable=1 和 insmod g_file_storage.ko file=/dev/mmcblk0有点区别,后续可以查找理解stall 和 removable的具体作用。

接着制作一个嵌入式设备端fat32文件分区,然后挂载到PC上:

1.在主机ubuntu上建立fat32文件映像,大小为2M。

    #dd if=/dev/zero of=fat32.img bs=1k count=2048
    #mkfs.vfat fat32.img

2.向fat32.img中写入一些文件,以用来测试:
    #mkdir fat32
    #sudo mount -t vfat -o loop fat32.img fat32  
    #cd fat32
    #touch hello.txt
    #echo hello,wolrd>hello.txt
    #sync

3.把主机ubuntu上的fat32.img 拷贝到嵌入式设备的根文件系统中。

4.在嵌入式设备中加载g_file_storage驱动

  insmod g_file_storage.ko file=/opt/fat32.img stall=0 removable=1   //我将fat32.img放在/opt下

5.USB线连接设备和PC,弹出发现移动磁盘,打开盘,里面有个hello.txt文件。

6.在PC端打开U盘,增加一个文件系统,如text.txt,然后在设备端通过命令挂载映像,命令为:

mount -t vfat -o loop /opt/fat32.img /media      //挂载到media目录下

到media目录,cd /media

看到/media目下有两个文件hello.txt和test.txt,且内容和在PC端看到的一致。

注意:如果此时在PC端再次修改了文件。这设备端不能立即看到PC修改的结果。即PC和设备端不能同步。

此时可以在设备进行umount /media,然后重新mount一次就可以看到PC更改的结果。同样在设备端修改的文件,PC端也不能立即看到修改结果,需重新插拔USB线才能看到更新。至于原因,暂时不知道。

卸载g_file_storage

执行加载USB转串口命令

root@rfODNCC:/mnt# insmod g_serial.ko 
[  239.675933] g_serial gadget: Gadget Serial v2.4
[  239.680786] g_serial gadget: g_serial ready
[  239.685241] musb-hdrc musb-hdrc.0: MUSB HDRC host driver
[  239.691009] musb-hdrc musb-hdrc.0: new USB bus registered, assigned bus number 2
[  239.707153] usb usb2: New USB device found, idVendor=1d6b, idProduct=0002
[  239.714324] usb usb2: New USB device strings: Mfr=3, Product=2, SerialNumber=1
[  239.721893] usb usb2: Product: MUSB HDRC host driver
[  239.727111] usb usb2: Manufacturer: Linux 2.6.37-05branch musb-hcd
[  239.733581] usb usb2: SerialNumber: musb-hdrc.0
[  239.747467] hub 2-0:1.0: USB hub found
[  239.751434] hub 2-0:1.0: 1 port detected
root@rfODNCC:/mnt# [  240.044830] g_serial gadget: high speed config #2: CDC ACM config

PC端安装USB转串口驱动后,可以从PC设备管理器上看到多出了一个串口。

要使得设备端能与PC端通过USB转串口进行通信,设备端还需要手动创建设备文件节点,参考内核文档(Documents/usb/gagdet_serial.txt)中的部分内容:

This will also automatically load the underlying gadget peripheral
controller driver.  This must be done each time you reboot the gadget
side Linux system.  You can add this to the start up scripts, if


desired.


Your system should use mdev (from busybox) or udev to make the
device nodes.  After this gadget driver has been set up you should
then see a /dev/ttyGS0 node:


  # ls -l /dev/ttyGS0 | cat
  crw-rw----    1 root     root     253,   0 May  8 14:10 /dev/ttyGS0
  #


Note that the major number (253, above) is system-specific.  If
you need to create /dev nodes by hand, the right numbers to use
will be in the /sys/class/tty/ttyGS0/dev file.

作者创建设备节点为:先cat /sys/class/tty/ttyGS0/dev,得到主设备号后,mknod /dev/ttyGS0 c major_num 0

然后PC打开一个串口软件,打开对应的串口端口。

设备端执行 echo “hello” > /dev/ttyGS0,PC端串口软件收到相应数据。

PS:UDC(设备控制器)驱动主要是与硬件平台相关的,它会实现gadget功能驱动所需要的接口,一般的UDC仅支持注册一个gadget功能驱动,所以上面是在将g_file_storage驱动卸载后才能重新加载g_serial.ko。否则会出现失败。

看看UDC驱动代码中的注册gadget驱动函数usb_gadget_probe_driver中的部分程序:

	spin_lock_irqsave(&udc->lock, flags);
	if (udc->driver) {
		spin_unlock_irqrestore(&udc->lock, flags);
		return -EBUSY;
	}
可见第一次注册gadget驱动后udc->driver为true,在不卸载情况下再次注册gadget时出现无法注册的错误。

【以下为转载:http://blog.youkuaiyun.com/embededswordman/article/details/6689593】

Linux支持连接各种USB从设备,同时也支持自己作为设备插入到其他主机当中。最典型的例子就是Android OS的手机,插入电脑可以被识别为U盘之类的设备。

对于SOC来说,这部分直接对应了USB Device部分的操作。

为了避免与作为主机时支持的"设备驱动 (USB Device Driver)"一词混淆, Linux给这部分的实现取名为"Gadget",小玩具。内核源码的目录为\drivers\usb\gadget,里面包含了内核所支持的不同类型的USB Device Controller (UDC)驱动的实现,以及框架和不同gadget的实现。

以AT91 ARM9为例,最底层的驱动为at91_udc.c(对于支持高速USB 2.0的SOC是atmel_usba_udc.c),它实现了gadget.h定义的统一接口,然后上层的各种gadget driver(如serial.c等)调用这一套统一的接口去实现不同类型的功能,如USB串口、U盘、USB以太网等等。

Atmel USB串口的框架图:


USB串口的描述和使用方法在内核目录\Documentation\usb\gadget_serial.txt中有详细且清晰的描述,就不再这里重复。一旦加载模块后会自动在/dev/下创建设备文件,程序就可以open它并且write,即使USB线没有连接上。之前一直纠结在为什么g_serial没有向上层提供USB cable connect/disconnect的事件,后来想想在使用串口的时候也是一样的情况,打开一个即使没有连接线的串口,也可以发送数据,只是没有人会收到而已。不过与串口唯一的不同在于,如果通讯正在进行中拔掉USB线,那么再次连接USB线后需要重新open一次ttyGS0设备文件才可以重新发送,否则write不能向串口一样正常工作而返回出错。


参考部分:

官方Gadget框架的描述:http://www.linux-usb.org/gadget/

基于9263的配置过程:http://www.cublog.cn/u3/111925/showart_2278264.html

华清讲师刘洪涛的BLOG:http://blog.youkuaiyun.com/hongtao_liu/article/details/4555645




<think>好的,用户想了解如何使用libusb创建USB虚拟设备。首先,我需要回忆一下libusb的功能。libusb是一个跨平台的用户态USB库,允许开发者与USB设备通信,但它本身并不直接支持创建虚拟设备。不过,可以通过结合其他工具或内核模块来实现。 接下来,我应该检查用户提供的引用内容。引用1提到PyUSB的高层接口,引用23讨论了libusb的使用示例VC++实现,引用4涉及Python通过ctypes调用USB DLL。这些可能对解答有帮助,但用户的问题是关于创建虚拟设备,而不仅仅是通信。 可能需要提到使用内核模块如USB GadgetLinux)或第三方工具如USB/IP。比如,在Linux下,USB Gadget框架可以在设备端模拟USB设备。而libusb通常用于主机端通信,所以需要说明两者的区别。 然后,用户需要示例代码,但libusb本身不创建虚拟设备,所以应指导用户如何结合其他工具。例如,在Linux中使用g_mass_storage模块创建虚拟U,然后用libusb进行主机端访问。 另外,用户可能对虚拟设备的具体实现步骤感兴趣,比如配置描述符、端点设置等。需要分步骤说明,并确保代码示例正确,比如使用libusb初始化、打开设备、传输数据等。 还要注意引用中的资源,比如引用3中的VC++示例,可能适用于Windows环境,但创建虚拟设备通常需要内核驱动,这在用户态可能较难实现。因此,建议用户根据操作系统选择合适的方法,并参考相关文档示例。 最后,生成相关问题时要涵盖libusb的其他应用、调试工具、跨平台问题以及模拟设备的不同方法。确保回答结构清晰,步骤明确,引用相关资源帮助用户进一步学习。</think>### 使用libusb创建USB虚拟设备的方法 #### 1. 核心概念说明 libusb本身是一个用于与USB设备通信的用户态库,**不直接支持创建虚拟设备**。要实现USB虚拟设备,需结合操作系统级工具: - **Linux环境**:使用`USB Gadget`内核框架,通过配置FunctionFS或gadget模块模拟设备[^2] - **Windows环境**:需配合`WinUSB`或第三方虚拟总线驱动(如`libusb-win32`) #### 2. Linux实现步骤(以USB串口设备为例) ```c #include <libusb-1.0/libusb.h> // 配置设备描述符 const struct libusb_device_descriptor dev_desc = { .bLength = LIBUSB_DT_DEVICE_SIZE, .bDescriptorType = LIBUSB_DT_DEVICE, .bcdUSB = 0x0200, .bDeviceClass = LIBUSB_CLASS_COMM, .idVendor = 0x1234, .idProduct = 0x5678 }; int main() { libusb_init(NULL); libusb_device_handle *handle; // 创建虚拟设备上下文 int ret = libusb_control_transfer(handle, LIBUSB_REQUEST_TYPE_VENDOR, USB_REQ_SET_CONFIGURATION, 0, 0, NULL, 0, 1000); // 配置接口端点 struct libusb_config_descriptor *config; libusb_get_config_descriptor(handle, 0, &config); // 数据收发逻辑 unsigned char data[64]; int transferred; libusb_bulk_transfer(handle, 0x81, data, sizeof(data), &transferred, 0); } ``` #### 3. Windows实现要点(需驱动支持) 1. 安装`Zadig`工具绑定设备到`libusb-win32` 2. 使用`INF`文件定义虚拟设备 ```inf [Version] Signature="$Windows NT$" Class=USBDevice ClassGUID={36FC9E60-C465-11CF-8056-444553540000} [Device] DeviceDesc="Libusb Virtual Device" ``` #### 4. 调试工具建议 - `Wireshark`进行USB协议分析 - `usbmon`(Linux内核模块)实时监控总线 - `lsusb -v`查看设备树信息
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值