linux下编写usb驱动实例

DS小龙哥 DS小龙哥     2022-12-01     196

关键词:

1.1 Linux下USB驱动开发介绍​

USB 是连接计算机系统与外部设备的一种串口总线标准,也是一种输入输出接口的技术规范,被广泛地应用于个人电脑和移动设备等信息通讯产品,USB 就是简写,中文叫通用串行总线。我们知道总线是用来通信的,所以USB总线就是一个种通信协议,你的设备支持什么协议就得使用哪一种总线协议与之通信。比如: EEPROM支持IIC协议,那么我们就得使用IIC总线与之通信,而EEPROM设备在制造过程中也必须遵循IIC协议设计。

在学习驱动开发实例之前,先了解几个USB总线通信的问题:

  • 问题1: USB设备那么多,他们怎么分类的?USB设备按照传输类型分,主要分为4类: 控制传输,中断传输,等时传输,批量传输。
    其中控制传输时每个USB设备都必须支持的,通常用来获取设备描述符,设置设备的状态等。从USB设备插入到拔出的过程中一定为产生控制传输,不管当前设备是否被主机支持。
    中断传输的经典代表是USB鼠标和USB键盘,这里说的中断不是真正硬件发出的中断,而是一种轮询机制,
    USB设备驱动程序里可以设置轮询时间的间隔,也就是主机可以按照这个间隔时间来轮询设备。
    批量传输的经典代表是U盘,数据可靠,时间不可靠。
    等时传输的经典代表是摄像头,数据不可靠,时间可靠。
  • 问题2: 当USB设备插入系统时(USB主机),系统怎么知道这是什么设备?当USB设备插入系统之后,根据硬件设计的特性,会被USB主机控制器第一时间知道,然后主机控制器就会问当前插入的设备是什么设备。这里就引入了一个概念叫做描述符。
    描述符有很多种,最基本的有4种:设备描述符、配置描述符、接口描述符、端点描述符。一个∪SB设备必须同时支持这四大描述符,一般这些描述符都存放在USB设备的EEPROM里。设备描述符包含了设备遵循的 USB 的版本号、设备类、设备子类、制造商、产品编号等信息,主机会通过控制传输的方式获取这个设备描述符,通过这个设备描述符就能知道当前是什么设备了。

1.2 USB鼠标与键盘驱动编写实例

Linux内核默认是支持鼠标驱动的,想要自己重新编写鼠标驱动,需要先将内核自带的鼠标驱动先去除掉。

[root@wbyq linux-3.5]# make menuconfig


Device Drivers --->

HID support --->

USB HID support --->

< > USB HID transport layer //传输层

Linux内核里自带的鼠标驱动源码: \\drivers\\hid\\usbhid\\usbmouse.c

Linux内核里自带的键盘驱动:源码 \\drivers/usb/input/usbkbd.c

  • USB键盘和USB鼠标都属于HID人机交互类,都使用的是中断方式传输数据。代码区别只是匹配的类型不一样而已,其他处理代码通用。
  • Linux下编写USB驱动实例​_USB驱动

  • 下面是鼠标和键盘的模板:

#include <linux/init.h>

#include <linux/module.h>

#include <linux/usb.h>

#include <linux/usb/input.h>

#include <linux/hid.h>


/*

本程序为USB鼠标驱动程序,要安装本驱动,需要先将内核自带的USB驱动程序卸载掉

*/


//定义USB的IDTAB 24ae:2002

static const struct usb_device_id tiny4412_usb_id[] =

//148f:7601

USB_DEVICE(0x148f,0x7601),/*360WIFI的制造商ID和产品ID */

USB_DEVICE(0x1c4f,0x0051),/*当前鼠标的ID 1c4f:0051*/

,

;


//USB鼠标的ID

static struct usb_device_id usb_mouse_id[] =

USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_MOUSE) ,

/* 终止进入 */

;


//USB键盘的ID

static struct usb_device_id usb_kbd_id_table [] =

USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_KEYBOARD) ,

;


int size;

static unsigned char *buf =NULL;

static struct urb *myurb=NULL;

dma_addr_t buf_phy;


/*USB中断处理程序*/

static void usb_complete(struct urb *urb)

int i;

for(i=0;i<size;i++)

printk("0x%x ",buf[i]);

printk("\\n");


/* 重新提交异步请求*/

usb_submit_urb(myurb, GFP_KERNEL);


//USB设备信息与驱动端匹配成功的时候调用。

static int usb_probe(struct usb_interface *intf,const struct usb_device_id *id)

printk("USB驱动匹配成功! ID: 0x%X,0x%X\\n",id->idVendor,id->idProduct);

/*通过接口获取设备信息*/

struct usb_device *dev = interface_to_usbdev(intf);

/*获取当前接口设置*/

struct usb_host_interface *interface=intf->cur_altsetting;

/*获取端点描述符*/

struct usb_endpoint_descriptor *endpoint = &interface->endpoint[0].desc;

/*中断传输:创建输入管道*/

int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

/*从端点描述符中获取传输的数据大小 */

size = endpoint->wMaxPacketSize;

printk("设备传输数据包大小:%d\\n",size);

/*分配数据传输缓冲区*/

buf = usb_alloc_coherent(dev,size,GFP_ATOMIC,&buf_phy);

/*分配新的urb,urb是usb设备驱动中用来描述与usb设备通信所用的基本载体和核心数据结构*/

myurb = usb_alloc_urb(0,GFP_KERNEL);

/*中断方式初始化urb*/

usb_fill_int_urb(myurb,dev,pipe,buf,size,usb_complete,NULL,endpoint->bInterval);

myurb->transfer_dma = buf_phy;

myurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/*为端点提交异步传输请求*/

usb_submit_urb(myurb, GFP_KERNEL);

return 0;



//USB断开的时候调用

static void usb_disconnect(struct usb_interface *intf)

struct usb_device *dev = interface_to_usbdev(intf);

usb_kill_urb(myurb);

usb_free_urb(myurb);

usb_free_coherent(dev,size,buf, buf_phy);

printk("USB 设备释放成功!\\n");


//定义USB驱动结构体

static struct usb_driver tiny4412_usb_driver =

.name = "tiny4412_usb",

.id_table = usb_kbd_id_table,

.probe = usb_probe,

.disconnect = usb_disconnect

;


static int __init tiny4412_usb_init(void)

//注册USB设备驱动

usb_register(&tiny4412_usb_driver);

return 0;


static void __exit tiny4412_usb_exit(void)

注销USB设备驱动

usb_deregister(&tiny4412_usb_driver);


module_init(tiny4412_usb_init);

module_exit(tiny4412_usb_exit);

MODULE_AUTHOR("xiaolong");

MODULE_LICENSE("GPL");

1.3 USB电子扫码枪驱动编写实例

USB电子扫码枪的驱动与USB键盘驱动通用,只是数据包的大小是64字节,匹配的类型也是使用键盘的类型。

说明: USB电子扫码枪和USB键盘输出的数据都是以掩码的值输出。

//USB键盘的ID

static struct usb_device_id usb_kbd_id_table [] =

USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_KEYBOARD) ,

;

要测试电子扫码枪的驱动,也需要先将内核自带的USB键盘去掉先去掉在测试。

#include <linux/init.h>

#include <linux/module.h>

#include <linux/usb.h>

#include <linux/usb/input.h>

#include <linux/hid.h>


/*

本程序为USB鼠标驱动程序,要安装本驱动,需要先将内核自带的USB驱动程序卸载掉

*/


//定义USB的IDTAB 24ae:2002

static const struct usb_device_id tiny4412_usb_id[] =

//148f:7601

USB_DEVICE(0x148f,0x7601),/*360WIFI的制造商ID和产品ID */

USB_DEVICE(0x1c4f,0x0051),/*鼠标的ID 1c4f:0051*/

USB_DEVICE(0x0483,0x0011),/*电子扫描枪的ID 1c4f:0051*/

,

;


//USB鼠标的ID

static struct usb_device_id usb_mouse_id[] =

USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_MOUSE) ,

/* 终止进入 */

;


//USB键盘的ID

static struct usb_device_id usb_kbd_id_table [] =

USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,

USB_INTERFACE_PROTOCOL_KEYBOARD) ,

;


int size;

static unsigned char *buf =NULL;

static struct urb *myurb=NULL;

dma_addr_t buf_phy;


/*USB中断处理程序*/

static void usb_complete(struct urb *urb)

int i;

/*

for(i=0;i<size;i++)

if(buf[i]!=0)printk("%d,%d\\n",buf[i],i);

printk("\\n");

*/

//每包数据都是存放在buf[2]里,并且以掩码的形式存放,如果需要得到真实的

//按键值,需要根据键盘的规则找到对应的码值

if(buf[2]!=0)printk("0x%x\\n",buf[2]);

/* 重新提交异步请求*/

usb_submit_urb(myurb, GFP_KERNEL);


//USB设备信息与驱动端匹配成功的时候调用。

static int usb_probe(struct usb_interface *intf,const struct usb_device_id *id)

printk("USB驱动匹配成功! ID: 0x%X,0x%X\\n",id->idVendor,id->idProduct);

/*通过接口获取设备信息*/

struct usb_device *dev = interface_to_usbdev(intf);

/*获取当前接口设置*/

struct usb_host_interface *interface=intf->cur_altsetting;

/*获取端点描述符*/

struct usb_endpoint_descriptor *endpoint = &interface->endpoint[0].desc;

/*中断传输:创建输入管道*/

int pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);

/*从端点描述符中获取传输的数据大小 */

size = endpoint->wMaxPacketSize;

printk("设备传输数据包大小:%d\\n",size);

/*分配数据传输缓冲区*/

buf = usb_alloc_coherent(dev,size,GFP_ATOMIC,&buf_phy);

/*分配新的urb,urb是usb设备驱动中用来描述与usb设备通信所用的基本载体和核心数据结构*/

myurb = usb_alloc_urb(0,GFP_KERNEL);

/*中断方式初始化urb*/

usb_fill_int_urb(myurb,dev,pipe,buf,size,usb_complete,NULL,endpoint->bInterval);

myurb->transfer_dma = buf_phy;

myurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

/*为端点提交异步传输请求*/

usb_submit_urb(myurb, GFP_KERNEL);

return 0;



//USB断开的时候调用

static void usb_disconnect(struct usb_interface *intf)

struct usb_device *dev = interface_to_usbdev(intf);

usb_kill_urb(myurb);

usb_free_urb(myurb);

usb_free_coherent(dev,size,buf, buf_phy);

printk("USB 设备释放成功!\\n");


//定义USB驱动结构体

static struct usb_driver tiny4412_usb_driver =

.name = "tiny4412_usb",

.id_table =usb_kbd_id_table,//,

.probe = usb_probe,

.disconnect = usb_disconnect

;


static int __init tiny4412_usb_init(void)

//注册USB设备驱动

usb_register(&tiny4412_usb_driver);

return 0;


static void __exit tiny4412_usb_exit(void)

注销USB设备驱动

usb_deregister(&tiny4412_usb_driver);


module_init(tiny4412_usb_init);

module_exit(tiny4412_usb_exit);

MODULE_AUTHOR("xiaolong");

MODULE_LICENSE("GPL");

1.4 USB摄像头编写实例

要自己编写自己的UVC摄像头驱动,需要先将内核自带的驱动去掉。

Device Drivers --->
<*> Multimedia support --->

[*] Video capture adapters --->

[] V4L USB devices ---> //将*号去掉即可

  • 示例:


#include <linux/init.h>

#include <linux/module.h>

#include <linux/usb.h>

#include <linux/usb/input.h>

查看详情

怎样写linux下的usb设备驱动程序

  USB驱动程序基础在动手写USB驱动程序这前,让我们先看看写的USB驱动程序在内核中的结构,如下图: USB驱动程序存在于不同的内核子系统和USB硬件控制器之间,USB核心为USB驱动程序提供了一个用于访问和控制USB硬件的接口... 查看详情

请教:qt下如何调用linux下编译的驱动程序

在Windows上搭建一个qt的开发环境,将你在linux下面写的代码拿来从新编译,一般来说不需要修改就可以通过,注意的是:linux和windows上的qt版本要一致参考技术A界面的话可使用qt等夸平台的图形库算法部分尽可能使用C和c++的标准... 查看详情

怎样写linux下的usb设备驱动程序

你好,方法如下:写一个USB的驱动程序最基本的要做四件事:驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)驱动程序支持的设备:有一个结构体structusb_device_id,这个结构体提供了一列不同... 查看详情

怎样写linux下的usb设备驱动程序

写一个USB的驱动程序最基本的要做四件事:驱动程序要支持的设备、注册USB驱动程序、探测和断开、提交和控制urb(USB请求块)驱动程序支持的设备:有一个结构体structusb_device_id,这个结构体提供了一列不同类型的该驱动程序... 查看详情

usb的驱动应该怎么写?

麻烦高手解释下,USB驱动该怎么编写?在什么环境下,用什么语言,给点具体代码。或者你帮我写个接管鼠标的usb驱动显示出来鼠标传递了什么数据给你听说可以参考bushound?这个叫filterdriver???小弟初次涉及硬件驱动。想深... 查看详情

linux-usb驱动笔记

...4、USB总线4.1、USB2.04.2、USB3.05、USB控制器类型1、前言USB的驱动非常的复杂,一下子去看源码也是一头雾水,下面记录下学习USB驱动的过程,后续也会有几篇笔记连续起来。2、USB简介USB,是英文UniversalSerialBus(... 查看详情

linux如何写发送一个数据到usb的应用

就是把一个确定的数字(比如0)发送到USB上,USB的基本驱动什么的linux内核里都有了“然后通过USB发送到手机上来显示”USB是一个接口,不是设备。写数据到USB设备不难,关键是设备端也就是你的手机——有没有应用或底层在跑... 查看详情

linux驱动|从0写一个设备树节点实例(代码片段)

一、前言设备树是每一个Linux驱动工程师都必须掌握的一个知识点,有很多之前做单片机的朋友刚接触Linux驱动时,会一脸懵!其实设备树的使用并没有大家想像的那么复杂,对于大部分工程师来说,只要会修... 查看详情

windows下编写的脚本文件,放到linux中无法执行解决方法(代码片段)

在windows下编写的脚本文件,放到Linux中执行报错:shstartup.sh-mstandalone:commandnotfound:commandnotfound:commandnotfound:'tartup.sh:line19:syntaxerrornearunexpectedtoken`in'tartup.sh:line19:&# 查看详情

具有多个读取操作、ioctl 或 fops 的 Linux USB 驱动程序?

】具有多个读取操作、ioctl或fops的LinuxUSB驱动程序?【英文标题】:LinuxUSBdriverwithmultiplereadoperations,ioctlorfops?【发布时间】:2014-03-1223:26:07【问题描述】:我正在为具有三种不同读/写操作(闪存、EEPROM和I2C)的USB设备编写驱动程... 查看详情

linux下编写一个shell脚本,实现自动安装软件

安装的这个软件是一个确定的软件,不过可以自己选,也就是一个软件对应一个自动安装的shell脚本(有点绕,不知能否理解)。比如我们平时安装一个软件时,有些地方会问你yes或者no,有的时候要你读完协议再确定,有点地... 查看详情

如何在linux下编写代码(非常详细)(代码片段)

在linux系统中编程非常详细基础的教程,适合第一次在linux系统中编程的新手,一步一步图文教学。用到的linux命令:1、cd命令用来切换路径,打开目录或文件夹2、mkdir命令创建一个文件夹3、touch命令创建一个文件4... 查看详情

如何在linux下编写代码(非常详细)(代码片段)

在linux系统中编程非常详细基础的教程,适合第一次在linux系统中编程的新手,一步一步图文教学。用到的linux命令:1、cd命令用来切换路径,打开目录或文件夹2、mkdir命令创建一个文件夹3、touch命令创建一个文件4... 查看详情

debian下编译安装驱动模块

在Linux下,我们常有需要自己来编译安装驱动模块的情况,例如要安装显卡驱动,要安装无线驱动,有的时候某个程序的安装使用与需要安装相应的驱动模块。DebianLinux下的生活本已十分简单,使用apt可以处理一切。单就我们所... 查看详情

USB 驱动器检测 (Linux)

】USB驱动器检测(Linux)【英文标题】:USB-drivedetection(Linux)【发布时间】:2015-11-2109:35:42【问题描述】:在我的Python程序中,我需要不断检查是否有新的USB驱动器连接到我的设备,运行x86Linux(Ubuntu)。其他USB设备不应被误认为是USB驱... 查看详情

linux如何判断usb驱动是2.0

参考技术A看设备信息。lsusb可以看到系统中的usb设备信息。lsusb-v具体输出。里面的bcdUSB是usb的版本号。0x0110是usb1.10x0200是usb2.0在初始化过程中,除了F2812自身初始化外,还要完成对ISP1581各个端点使用的传输类型、传输包大小和... 查看详情

怎样编写linux设备驱动程序?

Linux是Unix操作系统的一种变种,在Linux下编写驱动程序的原理和思想完全类似于其他的Unix系统,但它dos或window环境下的驱动程序有很大的区别。在Linux环境下设计驱动程序,思想简洁,操作方便,功能也很强大,但是支持函数少... 查看详情