Linux usb驱动开发(基础)

最近想学几个基于linux的驱动开发:(想想还是从usb驱动开始记录,毕竟USB的驱动的开发的讲解比较多,学习比较快)

(做个笔记,忘了就进来看看)

参考文档:文档写的比较基础:

https://blog.csdn.net/zqixiao_09/article/details/50984074

https://www.cnblogs.com/general001/articles/2319552.html

基础知识:

USB体系:USB接口标准支持主机和外部设备之间的数据传输,主机预定了各种类型外部设备的总线带宽,,外部设备和主机正在运行时,可以添加,添加设置,使用外部设备。可以分为USB互联,USB主机,USB设备,USB互联是usb设备和USB主机之间的通信操作。USB系统中,有唯一的主机,USB和主机的接口称为主机控制器,,USB设备包括usb集线器和功能设备,usb集线器的作用向总线提供多个连接点。

USB工作流程:采用轮询方式控制,,主机控制设置初始化所有的数据传输,USB总线执行的传输动作最多传输3个数据包,每次传输开始:主机控制器发送一个描述符描述传输侗族偶尔的种类和方向,,这个数据包称为标志数据包,,usb设备收到数据包后,解析数据包。USB传输的方式:主机到设备,设备到主机,在一个数据传输开始,数据包标识传输方向,,发送端发送包含信息的数据,接收端发送一个握手数据标识是否传输成功。

USB主机控制器:提供OHCI,EHCI,UHCI总线接口,,usb核心部分连接了USB控制器和设备驱动,

两种类型的USB驱动:1:宿主上的驱动(host)2:设备上的驱动(device)

宿主USB是指:控制插入其中的USB设备,设备驱动:表示该设备作为一个USB设备和主机通信。

USB期间驱动“USB gadget drivers”

觉得该图像对USB设备的结构描述很适合,就借用过来了。

一:USB设备的基础知识

设备,配置,接口,端点。

我们从上往下看:(具体参数可查看上面链接)

1.设备描述符:一个usb只有一个设备描述符,说明usb的总体的信息,并指明配置的个数

结构体描述:struct usb_device_descriptor,

2.配置描述符:作用:接口本身被捆绑为配置,可以在配置之间切换改变设备的状态,主要用来说明配置特性和接口个数

结构体:struct usb_host_config

3.接口描述符:(相对比较重要)通俗的说是逻辑上的设备,eg:usb摄像头:就将各种不同的分辨率设置为不同的接口,

将最终的端点捆绑为接口,

结构体:usb_interface_descriptor

4.端点描述符:主机和设备之间的物理传输usb_endpoint_descriptor,usb中的每个端点都有唯一的端点号,传输方向也确定(或主机传输到设备,设备传输到主机,端点传输时单方向的)。设备地址,端点号,传输方向就可以传输一个地址,

在这里提出0端点,0端点比较特殊(不用配置就可以传输数据),只能用于传输控制单元,首先利用0端点与设备进行通信,得到usb的基本信息,配置其他的端点。

端点的传输方式:1:控制:用于配置设备,获取设备信息,发送命令到设备,usb协议保证有足够的带宽传输数据到设备,

2:中断:中断端点以一个固定的速录传输少量的数据,,3:批量:传输大量数据(可确保传输数据,不确保传输时间,eg:存储设备),4:等时:传输大量数据(确保传输时间,不确保传输内容,eg:摄像头)。

结构体:usb_endpoint_descriptor(该结构体由设备自己定义:具体内容,可参考文档。)

5.最后一个基本概念:管道:usb主机软件和usb设备之间的连接,,是在usb配置过程中建立,是usb主机和设备之间数据流的抽象,usb主机的数据缓冲区域usb设备的端点之间存在着逻辑数据传输,实际的数据传输由总线接口完成,管道中的数据都是相互独立的。

以上为最基础的结构体:

接下来我们要说的是比较上层的数据结构体:也就是包含以上的基础结构体,却有增加了新的比较重要的功能(优化后的结构体):(从端点道接口的主机配置描述符)

1:端点描述:usb_host_endpoint

其中有一个比较重要的结构体 :struct list_head urb_list //此端点表示urb队列

当usb设备调用usb_submit_urb提交urb请求时将此urb添加到该链表的末尾。

2:接口描述:struct usb_host_interface :主机端的接口包装器,用于解析接口设置描述符。用于描述接口本身的信息,一个接口由多个设置,以及所使用的端点

struct usb_interface 其中有个结构体usb_host_interface *cur_altsetting,用于表示当前的世界设置接口。

3:配置描述:struct usb_host_config:配置所有的接口以及接口缓存,配置描述符等参数。

4:通信描述符:struct usb_skeleton是一个局部的结构体:用于端点的通信。

其中包括设备信息,接口描述,块输入端点,块输出端点。

以上为基本配置参数,以下为基本设置函数:

1:struct usb_device(基于总线驱动设备描述符的:device)内核usb设备的表示

其中:struct usb_device *parent//表示设备从root hub开始一个个往外连,每个口连一个usb设备,一个hub可以有多个口,一级级的往下连。

其中发现有两处调用usb_device :usb_alloc_dev(usb.c分配一个dev usb_hcd主机控制器驱动)usb_set_configuaration(message.c设置一个特定设备为当前设备)

在hub.c的hub_thread。。hub_events。。hub_port_connect_change (处理物理逻辑和连接更改事件)。。时间中分配和创建一个dev结构体

2:struct usb_driver所有的usb驱动程序必须要创建的主结构体。,想usb户型代码描述了usb驱动程序,(一般我们开发填充修改的是这个结构体)

采用usb_register注册usb_driver结构体。

我们先谈该结构体的id_table

其中包含的结构体:struct usb_device_id结构体,包含了该驱动可以支持的所有不同类型的usb的设备,没有该变量,usb驱动程序的探测函数将不会被调用,(*****一个驱动usb_driver可以对应多个设备usb_device)热插拔脚本使用它来确定一个特定的设备插入到系统时该自动挂载那一个驱动程序。

初始化usb_device_id结构体的宏:USB_DEVICE(),和指定的制造商和ID匹配

USB_INTERFACE_INFO只和usb的制定类型相匹配,

使用初始化函数:MODULE_DEVICE_TABLE()容许用户空间的工具判断该驱动可以控制什么设备。

还用proble函数:usb驱动程序中的探测函数的指针,当usb核心认为有一个usb_interface可以由该驱动处理时,它将调用该函数,,usb核心用来判断的指向usb_device_id的指针也被传给该函数。(一个设备被安装而usb核心认为该驱动应该被处理)

disconnect函数:usb_interface被从系统中移除或者驱动程序从usb核心中卸载时被调用。(驱动程序因为某些原因不应该控制设备时)。

proble和disconnect(探测和断开的细节):

都是在USB集线器(usb_hub)内核线程的上下文被调用,其中的休眠合法(其中可以看hub.c的程序)(所以我们应该将探测函数时间减少),系统传递给探测函数两个结构体:1:usb_interface Usb的接口描述符,2:usb_device_id作为参数,

注意:USB驱动程序应该初始化任何用于控制USB设备的局部结构体,并把任何设备的相关信息保存到结构体中,:USB驱动程序需要探测设备的端点地址和缓冲区大小,根据这些然后建立与usb驱动的通信。(探测批量的IN和OUT端点)(eg:Usb_skeleton.c中的skel_probe函数中做了探测全部的IN和out端点的例程)

过程:1:循环访问改接口中的每个端点,赋予该端点局部指针,一遍稍后访问:结构体参数

struct usb_host_interface *iface_desc;

usb_interface *interface

    iface_desc = interface->cur_altsetting;
    for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
        endpoint = &iface_desc->endpoint[i].desc;

查看端点是输入还是输出:

        if (!dev->bulk_in_endpointAddr &&
            usb_endpoint_is_bulk_in(endpoint)) {}

        if (!dev->bulk_out_endpointAddr &&
            usb_endpoint_is_bulk_out(endpoint)) {

然后把该端点的相关信息保存到局部结构体中,以便稍后的端点通信。

把初始化的数据保存到接口设备中:usb_set_intfdata(interface,dev).用啦注册一个data,这个data的结构是任意的,这个程序向内核注册了一个usb_skel结构

得到设备中的接口信息:usb_get_intfdata()

基于上面的两个函数,以上为我们的接口函数,

还有一种注册usb设备的方法:usb_register_dev(interface,&skel_class)USB驱动程序没有和处理设备与用户交互的子系统,驱动程序可以使用USB主设备号,一遍用户空间使用传统的字符驱动接口,(具体查看上面的连接)。

猜你喜欢

转载自blog.csdn.net/zuodenghuakai/article/details/83892902