linux驱动学习(九) usb设备驱动的初步认知

《Linux驱动:USB设备驱动看这一篇就够了》 这一篇学习分析USB设备驱动程序,主要涉及到USB驱动基本概念,USB版本对比、USB主从结构、USB设备的传输类型、USB设备描述符关系、USB的数据传输对象;详细分析了USB总线驱动框架,USB Core、USB HCD、USB总线-设备-驱动模型;最后总结了USB驱动开发中的一般流程并模拟实现一个USB设备驱动程序。USB core注册了一个USB总线,并向USB总线中注册了三个驱动,分别是USB接口驱动、HUB驱动、USB设备驱动。...... 阅读详情

原文地址:http://blog.youkuaiyun.com/ghostyu/article/details/8114929

小小的概述

和i2c驱动类似,usb驱动架构中也有usb-core这样的框架,为上层设备驱动程序提供封装后的方便使用的api函数,为底层与硬件相关的代码封装提供总线接入功能。

撇开复杂的usb协议,我们先认知linux驱动中的usb框架,至于细节的实现,需要漫长的代码。在我们还不知道它长什么样的时候就去讨论内部的实现机制就毫无意义的。

usb驱动架构


图1

准确的说,图1是不完整的usb驱动架构,但是有助于对架构的理解。不光是i2c,linux均是以这样的架构呈现。

对于我们初学者来说,先接触一下usb协议的基本概念,然后在分析一个代表性的usb设备驱动,这样是一个有效的学习usb驱动的途径。

之后,在深入usb协议再分析usb-core。

usb-skeleton

linux内核源码中的/drivers/usb/usb-skeleton.c 文件为我们提供了一个最基础的usb驱动程序,即usb骨架程序,可以看做这是一个最简单的usb设备驱动实例,尽管具体的usb设备驱动千差万别,但其骨架则万变不离其宗。

我们的usb驱动开发也从他开始。

linux USB驱动程序需要做的第一件事件就是在linux usb子系统里注册,这个子系统就是usb-core,同事提供一些相关信息,例如这个驱动程序支持哪种设备,当被支持的设备从系统插入或者拔出时,会有哪些动作,所有这些信息都传送到usb子系统中,在usb-skeleton.c 中是这样表示的。

  1. static struct usb_driver skel_driver = {  
  2.     .name =     "skeleton",  
  3.     .probe =    skel_probe,  
  4.     .disconnect =   skel_disconnect,  
  5.     .id_table = skel_table,  
  6. };  
  7.   
  8. static int __init usb_skel_init(void)  
  9. {  
  10.     int result;  
  11.   
  12.     /* register this driver with the USB subsystem */  
  13.     result = usb_register(&skel_driver);  
  14.     if (result)  
  15.         err("usb_register failed. Error number %d", result);  
  16.   
  17.     return result;  
  18. }  
  19.   
  20. static void __exit usb_skel_exit(void)  
  21. {  
  22.     /* deregister this driver with the USB subsystem */  
  23.     usb_deregister(&skel_driver);  
  24. }  
  25.   
  26. module_init (usb_skel_init);  
  27. module_exit (usb_skel_exit);  

其实在2.4的内核中struct usb_driver skel_driver中还有file_operations的一个成员(现在被移到了usb_class_driver中),大多数usb驱动程序需要钩住另外一个驱动系统,usb驱动往往不是单独存在的,例如scsi、网络(usb网卡)、或者tty(usb转串口)子系统,这些驱动程序在其他驱动系统中注册,同事任何用户空间的交互操作(open、read、write、ioctl等)通过那些借口提供,比如我们把scsi设备驱动作为我们usb驱动钩住的另外一个驱动系统,那么我们此sub设备的read、write等操作,就相应按scsi设备的read、write函数进行访问。但如果没有一个匹配的驱动系统可以使用时,那我们就要自己处理与用户空间的read、write等交互函数,在usb_class_driver中提供注册file_operations的函数指针,这样就可以与用户空间实现方便的交互。

usb-skeleton驱动对应的device

当usb设备插入时,为了使hotplug系统自动装载驱动程序,还需要创建一个table,如下:

  1. /* table of devices that work with this driver */  
  2. static struct usb_device_id skel_table [] = {  
  3.     { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },  
  4.     { }                 /* Terminating entry */  
  5. };  
USB_SKEL_VENDOR_ID和USB_SKEL_PRODUCT_ID为厂商的ID和产品ID,为我么提供了一个设备的唯一标识,当系统插入一个id匹配的usb设备到usb总线时,驱动会在usb-core中注册,驱动程序的skel_probe函数也会被调用。
  1. static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)  
驱动程序需要确认插入的设备是否可以被接受,如果不接受,或者再初始化的过程中发生任何错误,skel_probe会返回一个错误,否则将使用usb-core的usb_register_dev注册设备。
  1. static int skel_probe(struct usb_interface *interface, const struct usb_device_id *id)  
  2. {  
  3.     ...  
  4.         /* save our data pointer in this interface device */  
  5.     usb_set_intfdata(interface, dev);  
  6.     ...  
  7.     /* we can register the device now, as it is ready */  
  8.     retval = usb_register_dev(interface, &skel_class);  
  9.     if (retval) {  
  10.         goto error;  
  11.     }  
  12.     ...  
  13. error:  
  14.     if (dev)  
  15.         kref_put(&dev->kref, skel_delete);  
  16.     return retval;  
  17. }  

skeleton的file_operations

此外,还将注册与应用程序交互的接口函数。如skel_class
  1. static struct file_operations skel_fops = {  
  2.     .owner =    THIS_MODULE,  
  3.     .read =     skel_read,  
  4.     .write =    skel_write,  
  5.     .open =     skel_open,  
  6.     .release =  skel_release,  
  7. };  
  8.   
  9. static struct usb_class_driver skel_class = {  
  10.     .name =     "skel%d",  
  11.     .fops =     &skel_fops,  
  12.     .minor_base =   USB_SKEL_MINOR_BASE,  
  13. };  
由于usb-skeleton没有钩住任何驱动子系统,因此这里实现自己的用户交互接口,在字符驱动中所数字的file_operations。

现在,usb-skeleton驱动就已经和设备绑定上了,任何用户态程序要操作此设备都可以通过file_operations结构所定义的函数进行了,

usb-skeleton的write和read函数

在skel_write中,有一个usb_fill_bulk_urb函数,实现urb系统callbak和我们自己的skel_write_bulk_callback回调函数。然后调用usb_submit_urb函数想目标端口提交写入的数据。

read函数与write函数稍有不同在于,read并没有用urb将数据从设备传送到驱动程序,而是用usb_bulk_msg函数代替,所以read能够不需要创建urbs和操作urb函数的情况下来读取设备数据到驱动程序,或者发送数据给设备。当对usb设备进行一次读或者写是,usb_bulk_msg函数是非常有用的,然后,当你需要连续的对设备进行读写是,最好自己建立自己的urbs。下面是代码展示。

  1. static ssize_t skel_read(struct file *file, char *buffer, size_t count, loff_t *ppos)  
  2. {  
  3.     ...  
  4.     retval = usb_bulk_msg(dev->udev,  
  5.                   usb_rcvbulkpipe(dev->udev, dev->bulk_in_endpointAddr),  
  6.                   dev->bulk_in_buffer,  
  7.                   min(dev->bulk_in_size, count),  
  8.                   &bytes_read, 10000);  
  9.     ...  
  10.     copy_to_user(buffer, dev->bulk_in_buffer, bytes_read);  
  11.     ...  
  12.     return retval;  
  13. }  
  1. static ssize_t skel_write(struct file *file, const char *user_buffer, size_t count, loff_t *ppos)  
  2. {  
  3.     ...  
  4.     usb_fill_bulk_urb(urb, dev->udev,  
  5.               usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),  
  6.               buf, writesize, skel_write_bulk_callback, dev);  
  7.     urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;  
  8.   
  9.     /* send the data out the bulk port */  
  10.     retval = usb_submit_urb(urb, GFP_KERNEL);  
  11.     ...  
  12.     return retval;  
  13. }  
写成功后的回调函数,用于释放空间
  1. static void skel_write_bulk_callback(struct urb *urb, struct pt_regs *regs)  
  2. {  
  3.     ...  
  4.     /* free up our allocated buffer */  
  5.     usb_buffer_free(urb->dev, urb->transfer_buffer_length,   
  6.             urb->transfer_buffer, urb->transfer_dma);  
  7.     up(&dev->limit_sem);  
  8. }  
usb骨架驱动程序,提供足够的例子来帮助初始人员在最短的时间里开发一个驱动程序。也是学习usb驱动的最佳开始。

进一步理解的usb驱动架构

有了上面的理解,usb驱动架构可以如图2所示


图2


Linux USB 驱动开发(三)—— 编写USB 驱动程序 Linux的设备驱动都遵循一个惯例——表征驱动程序(用driver更贴切一些,应该称为驱动器比较好吧)的结构体,结构体里面应该包含了驱动程序所需要的所有资源。用术语来说,就是这个驱动器对象所拥有的属性及成员。 一、usb-skeleton        下面先看一下Linux内核源码中的一个usb-skeleton(就是usb驱动的骨架咯),其定义的设备结构体就叫做usb-skel:s 阅读详情

相关推荐

[Linux驱动开发] USB驱动之usb_skel分析

在学习了这么些天的驱动之后,个人觉得驱动就是个架构的问题,只要把架构弄清楚了 然后往里面添砖加瓦就可以了,所以似乎看起来不是太困难,但也许是是我经验不足吧,这只能算是个人浅见了 这两天在学习USB驱动开发,奇怪的是老师居然不讲USB的代码,让人不理解,后来在网上找资料才发现原来内核已经给我们准备了一个usb_skel的代码向我们介绍几本的USB驱动的架构,于是自己分析了一下代码,画了一个我认为

Terry_Yuan的技术专栏 3905

Linux USB 驱动开发实例(七)—— 基于USB 总线的无线网卡浅析

回顾一下USB的相关知识 USB(Universal Serial Bus)总线又叫通用串行外部总线, 它是20世纪90年代发展起来的。USB接口现在得到了广泛的应用和普及,现在的PC机中都带有大量的USB接口。它最大的特点就是方便通用、支持热插拔并且可以在一个接口上插上多个设备。当设备用电量小的时候,它还可以充当电源。它的众多优点使得它得到了广泛的应用。 在PC机器内部有个USB中央控制器,这个...

|~~~热爱生活、努力学习的小伙汁~~~| 1365

Linux设备驱动probe过程(三)

本周把最后一个坑填上,看下热插拔设备驱动是如何probe的。这部分的代表设备有PCI和USB。鉴于USB流传度和通用性更广,本文选用USB作为分析示例。

zxcv788999的博客 2244

Linux设备驱动开发详解

Linux设备驱动开发详解Linux设备驱动开发详解Linux设备驱动开发Linux设备驱动开发详解1. linux设备驱动概述及开发环境搭建2. 驱动设计的硬件基础3. linux内核及内核编程4. linux内核模块5. linux文件系统与设备文件6. 字符设备驱动7. linux设备驱动中的并发控制8. linux设备驱动中的阻塞与非阻塞I/O9. linux设备驱动中的异步通知与异步I/O10. 中断与时钟11. 内存与I/O访问12. linux设备驱动的软件架构思想13. linux块设备驱.

tan1666的博客 2万+

usb-skeleton.c驱动详细分析

/*********注册usb驱动函数框架**********/ static struct usb_driver skel_driver={ .name = "skeletonNew",//指向驱动程序名字的指针 .probe = skel_probe,//探测usb .disconnect = skel_disconnect,//USB驱动程序中的断开处理函数 .id_table = skel_table, //指向ID设备表的指针 }; : //usb 入口(安装)(使用usb平台总线) static int __init usb_skel_init(void) { /* register this driver with the USB subsystem */ int result = usb_register(&skel_driver);//注册 if(result) printk("usb_register failed!\n"); else printk("usb_register successfull!\n"); return result; } //usb出口(卸载) static void __exit usb_skel_exit(void) { /* deregister this driver with the USB subsystem */ usb_deregister(&skel_driver);//取消注册 printk("usb_deregister successfull!\n"); } //驱动模块入口 module_init(usb_skel_init); //驱动模块出口 module_exit(usb_skel_exit); //遵循GPL MODULE_LICENSE("GPL");

STM32F103C8T6 驱动2位共阳数码管(基于 74HC595 和 PNP 三极管)

整体设计思路是通过 STM32F103C8T6 控制 74HC595 和 PNP 三极管,实现共阳数码管的显示功能。最初的电路设计中,三极管发射极接 5V 电源,这导致了数码管两位显示相同数字的问题。数码管能够稳定显示 0-99的数字。

qq_40289410的博客 2209

Linux USB 主机侧设备驱动匹配流程

Linux USB 主机侧设备驱动匹配流程如下: 1. usb 初始化,注册 hub 驱动与通用设备驱动。 2. usb 控制芯片与驱动匹配后,创建一个主机控制器设备(如 xhci)。 3. 主机控制器设备与驱动匹配后,创建一个 roothub 设备。 4. roothub 设备与 hub 驱动匹配后,设置中断。 5. usb 设备插入后,触发中断,初始化设备,读取设备描述符,根据设备描述符,选择、设置设备配置,匹配到具体设备驱动。 6. 在具体设备驱动中控制 usb 设备。

joyxysetu的博客 1292

RV1126开发板性能实测:网络、温度与功耗全解析

本文对RV1126开发板进行了全面的性能实测,重点分析了网络性能、温度表现与功耗特性。测试发现UDP带宽可达500Mbps,但TCP性能受限于协议栈;散热设计对持续性能至关重要,大板子在AI推理和视频推流中表现更稳定。为嵌入式开发者提供了真实的选型参考和优化建议。

d3e4f的博客 264

Linux设备驱动之usb设备驱动详解

1.Linux usb设备驱动框架USB是通用串行总线的总称,Linux内核几乎支持所有的usb设备,包括键盘,鼠标,打印机,modem,扫描仪。Linux的usb驱动分为主机驱动与gadget驱动。前者是设备连接到计算机上,通过主机驱动扫描usb设备,控制所连接的设备。而gadget驱动一般用于嵌入式设备,gadget驱动用于控制嵌入式设备。Linux的usb驱动两种类型图如下:左侧是usb的主机驱动,右侧是gadget驱动。下面着重介绍一下usb的主机驱动:(1)usb主机控制器-直接与硬件设备交互。(

1万+

Simulink仿真避坑指南:如何设置步长、powergui和模块采样时间才能让控制周期更稳定

本文深入解析Simulink仿真中步长、powergui和模块采样时间的协同配置方法,帮助工程师解决控制周期不稳定问题。通过实际案例和参数调优技巧,指导用户精准设置仿真参数,确保电机控制、电力电子系统等工业仿真结果的可靠性。

weixin_42524762的博客 418

基于PINN的一个简单的求解偏微分方程实例

本人是做化工模拟的一名学生,最近在学习PINN(Physics-Informed Neural Networks,物理信息神经网络)对管道动力学进行建模研究,PINN由于其对机理与数据的良好兼顾性非常热门,本文是作者对PINN入门研究过程的一个练手小题目,main code也是作者代码是基于pytorch2.6.0写的,发上来供各位参考,欢迎研究管道动力学和PINN的小伙伴一起讨论~

weixin_64491760的博客 1739

Linux驱动开发——USB设备驱动

Linux驱动开发——USB设备驱动

qq_52479948的博客 3775

银河飞腾FT6678实战指南:OpenMP多核并行编程优化技巧

本文详细介绍了在银河飞腾FT6678多核处理器上使用OpenMP进行并行编程的实战技巧与优化方法。从基础语法到环境配置,再到性能优化的五大核心技巧,包括循环并行化、并行粒度控制、reduction子句使用等,帮助开发者充分发挥FT6678的8核计算能力。通过实际案例展示如何将图像处理算法从200ms优化到28ms,并深入探讨了任务调度、内存访问优化等进阶主题。

weixin_29234423的博客 285

浅谈Linux USB设备驱动

1、USB基础介绍 1-1、USB硬件接口介绍 USB接口在硬件上总共有四根线组成VCC、D+、D-、GND,通过计算D+和D-的差值来确定数据。USB设备在传输速率上可以分为低速(1.5Mbps)、全速(12Mbps),高速(480Mbps)。在USB主机控制器端D+和D-都皆有一个下拉电阻,在USB设备端的D+或D-接了一个上拉电阻,USB设备插入后USB主机控制器的D+或D-会被拉高,这样USB主机控制器就能发现有设备接入。USB设备是主从式的设备,主机是在host端的主机控制器,从机就是如鼠标、

JJ1116的博客 6059

lp–mspm0g3507开发板进入低功耗模式怎么退出?烧程序烧着烧着就进来了,跳线帽没动过,且报错:Texas Instruments Debugger Error: DAP Co...如何解决?

🏆本文收录于 《全栈Bug调优(实战版)》 专栏,该专栏专注于分享我在真实项目开发中遇到的各类疑难Bug及其深层成因,并系统提供高效、可复现的解决思路和实操方案。无论你是刚入行的新手开发者,还是拥有多年项目经验的资深工程师,本专栏都将为你提供一条系统化、高质量的问题排查与优化路径,助力你加速成长,攻克技术壁垒,迈向技术价值最大化与职业发展的更高峰🚀!

**My Coding Family** 1568

Far planner代码系列(2)

graph_decoder系列(2) 承接上文 我们接着来看decoder_node.cpp的代码部分 void GraphDecoder::Init() { /* initialize subscriber and publisher */ //graph_sub_ 订阅节点/robot_vgraph 其类型是visibility_graph_msg/Graph的消息 graph_sub_ = nh.subscribe("/robot_vgrap...

博客 1533

USB鼠标设备驱动程序简单实现(一)

一、Linux下的USB驱动程序 分离和分层是Linux下驱动程序开发采用的最基本的形式,USB驱动开发在主机端主要涉及两个部分:主机控制器驱动和设备驱动。 主机控制器驱动主要是和具体的Soc相关的,它来识别USB设备,安装对应的设备驱动程序,提供对USB设备的读写函数。 设备驱动主要是根据具体的USB设备对USB主机驱动提供的读写函数获得的数据进行处理,实现这种USB设备特有的功能。具体的

TECH_PRO的博客 7906

Python 爬虫实战:全球渔业船舶捕捞记录数据采集与分析全攻略

通过本项目,我们实现了对全球渔业船舶捕捞记录数据的采集、处理和可视化,为渔业资源管理和海洋生态保护提供了数据支持。未来,可以进一步结合机器学习和深度学习技术,对捕捞行为进行预测和分类,提高对非法捕捞活动的识别能力。

2201_76125261的博客 557

Linux USB 设备侧设备驱动匹配流程

Linux USB 设备侧设备驱动匹配流程: 1. usb 初始化。 2. udc 设备与驱动匹配后,进行多种初始化,然后添加 udc 设备到 udc_list。 3. gadget 驱动加载后,在 udc_list 找到第一个没有绑定驱动的 udc 设备,进行绑定。 4. 启动 udc,然后使能 D+ 或者 D- 的上拉,让 host 可以检测到。

joyxysetu的博客 877

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

linux设备驱动之USB驱动-USB主机、设备与Gadget驱动

USB采用树形拓扑结构,主机侧和设备侧的USB控制器分别称为主机控制器(Host Controller)和USB设备控制器(UDC),每条总线上只用一个主机控制器,负责协调主机和设备之间的通信,而设备不能主动向主机发送任何消息。在linux系统中,USB主机控制器硬件,在其上运行的是USB主机控制器驱动,在主机控制器上的为USB核心层,再上层为USB设备驱动层(插入主机上的U盘、鼠标、USB转串口等设备驱动)。

weixin_48175016的博客 1168

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Linux内核USB设备驱动架构分析

一、总线速度及主机控制器一、总线速度及主机控制器1、USB系统架构USB通信协议采用主从结构,实现主机控制器和外围设备的通信。

m0_74186706的博客 1572

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

Linux USB 设备驱动框架简析

Linux,USB 设备驱动

JiMoKuangXiangQu的专栏 688

Linux-USB驱动笔记(六)--设备驱动框架

Linux-USB驱动笔记(六)--设备驱动框架1、前言2、USB设备驱动3、重要结构体3.1、usb_driver -- USB设备驱动3.2、usb_device_id -- 支持的USB设备信息3.3、urb -- USB请求块4、API函数5、URB发送流程 1、前言 Linux-USB驱动笔记一 Linux-USB驱动笔记二 Linux-USB驱动笔记三 Linux-USB驱动笔记(四)–USB整体框架 Linux-USB驱动笔记(五)–主机控制器驱动框架 2、USB设备驱动 这里的USB设备驱动

一只青木呀 3905

Linux USB总线驱动框架分析

1、USB驱动引入 USB(全称 Universal Serial Bus,通用串行总线),已经成为PC及嵌入式设备中最常用、最便捷的通信接口。Linux USB子系统较为庞大,本文主要对Linux系统下的USB总线驱动框架进行概述,重点的细节待后续文章展开。 首先来看一个现象,插入USB设备后linux系统打印如下日志: 拔出后提示:usb 1-1: USB disconnect...

boazheng的博客 4010
上一篇: linux驱动学习(八) i2c驱动架构(史上最全) davinc dm368 i2c驱动分析
下一篇: 关于XDC工具的文章
July_Yang
博客等级 码龄15年 46粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值