USB Core二【转】

转自:http://blog.csdn.net/jacobywu/article/details/8819001

[cpp] view plaincopy

/**
 * usb_alloc_dev - usb device constructor (usbcore-internal)
 * @parent:   设备连接的那个hub
 * @bus: 设备连接的那条总线
 * @ port1 就是设备连接在hub 上的那个端口
 * Context: !in_interrupt()
 *
 * Only hub drivers (including virtual root hub drivers for host
 * controllers) should ever call this.
 *
 * This call may not be used in a non-sleeping context.
 */
struct usb_device *usb_alloc_dev(struct usb_device *parent,
                 struct usb_bus *bus, unsigned port1)
{
    struct usb_device *dev;
    struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
    unsigned root_hub = 0;  

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);
    if (!dev) //判断内存申请成功了没
        return NULL;
//一个主机控制器对应着一条usb总线
//函数bus_to_hcd是为了获得总线对应的主机控制器
//驱动,也就是struct usb_hcd结构对象,函数usb_get_hcd只是将得到的这个usb_hcd
//结构对象的引用计数加1
    if (!usb_get_hcd(bus_to_hcd(bus)))
        {
        kfree(dev);
        return NULL;
    }
    /* Root hubs aren‘t true devices, so don‘t allocate HCD resources */
    if (usb_hcd->driver->alloc_dev && parent &&
        !usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
        usb_put_hcd(bus_to_hcd(bus));
        kfree(dev);
        return NULL;
    }
//device_initialize 是设备模型里的函数,这里就是将struct usb_device 结构里
//嵌入的那个struct device 结构体初始化掉
    device_initialize(&dev->dev);
    dev->dev.bus = &usb_bus_type;//将设备所在的总线类型设置为usb_bus_type
    dev->dev.type = &usb_device_type;//将设备的设备类型初始化为usb_device_type
    dev->dev.groups = usb_device_groups;
    dev->dev.dma_mask = bus->controller->dma_mask;//dma_mask 被设置为host controller 的dma_mask
    set_dev_node(&dev->dev, dev_to_node(bus->controller));
    dev->state = USB_STATE_ATTACHED;//将usb 设备的状态设置为Attached,表示设备已经连接到usb 接口上了,是hub检测到设备时的初始状态
    atomic_set(&dev->urbnum, 0);  

    INIT_LIST_HEAD(&dev->ep0.urb_list);//,struct usb_device里直接就有这么一个成员ep0,这行就将ep0 的urb_list 给初始化掉
    dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;//初始化了端点0 的描述符长度
    dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;//初始化了端点0 的描述符类型
    /* ep0 maxpacket comes later, from device descriptor */
    //使struct usb_device 结构里的ep_in 和ep_out 指针数组的第一个成员指向ep0,ep_in[0]和ep_out[0]本来表示的就是端点0。
    usb_enable_endpoint(dev, &dev->ep0, false);
    dev->can_submit = 1;  

    /* Save readable and stable topology id, distinguishing devices
     * by location for diagnostics, tools, driver model, etc.  The
     * string is a path along hub ports, from the root.  Each device‘s
     * dev->devpath will be stable until USB is re-cabled, and hubs
     * are often labeled with these port numbers.  The name isn‘t
     * as stable:  bus->busnum changes easily from modprobe order,
     * cardbus or pci hotplugging, and so on.
     */
    /*
    unlikely(x)就是告诉编译器条件x 发生的
  可能性不大,那么这个条件块儿里语句的目标码可能就会被放在一个比较远的为止,以保证
    经常执行的目标码更紧凑。likely 则相反。
    */
    if (unlikely(!parent)) {
        dev->devpath[0] = ‘0‘;//首先判断你的设备是不是直接连到root hub 上的,如果是,将dev->devpath[0]赋值为‘0’,以示特
        dev->route = 0;  

        dev->dev.parent = bus->controller;
        dev_set_name(&dev->dev, "usb%d", bus->busnum);
        root_hub = 1;
    } else {
        /* match any labeling on the hubs; it‘s one-based */
        if (parent->devpath[0] == ‘0‘) {
            snprintf(dev->devpath, sizeof dev->devpath,
                "%d", port1);
            /* Root ports are not counted in route string */
            dev->route = 0;
        } else {
            snprintf(dev->devpath, sizeof dev->devpath,
                "%s.%d", parent->devpath, port1);
            /* Route string assumes hubs have less than 16 ports */
            if (port1 < 15)
                dev->route = parent->route +
                    (port1 << ((parent->level - 1)*4));
            else
                dev->route = parent->route +
                    (15 << ((parent->level - 1)*4));
        }  

        dev->dev.parent = &parent->dev;
        dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);  

        /* hub driver sets up TT records */
    }  

    dev->portnum = port1;
    dev->bus = bus;
    dev->parent = parent;
    INIT_LIST_HEAD(&dev->filelist);//初始化一个队列,usbfs 用的  

#ifdef  CONFIG_PM
    pm_runtime_set_autosuspend_delay(&dev->dev,
            usb_autosuspend_delay * 1000);
    dev->connect_time = jiffies;
    dev->active_duration = -jiffies;
#endif
    if (root_hub)   /* Root hub always ok [and always wired] */
        dev->authorized = 1;
    else {
        dev->authorized = usb_hcd->authorized_default;
        dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
    }
    return dev;
}  

起码能够知道端点0一次能够处理的最大数据长度啊,协议里说,对于高速设备,这个值为为64 字节,对于低
速设备为8 字节,而对于全速设备可能为8,16,32,64 其中的一个.

[cpp] view plaincopy

struct usb_ctrlrequest {
    __u8 bRequestType;//它的bit7 就表示了控制传输中DATA transaction 阶段的方向,
               //当然,如果有DATA 阶段的话。bit5~6 表示request 的类型,是标准的
    __u8 bRequest;//表示具体是哪个request
    __le16 wValue;//这个字段是request 的参数,request 不同,wValue 就不同。
    __le16 wIndex;//也是request 的参数,bRequestType 指明request 针对的是设备上的某个接口或端点的时候,wIndex 就用来指明是哪个接口或端点。
    __le16 wLength;//控制传输中DATA transaction 阶段的长度, 方向已经在
            //bRequestType 那儿指明了。如果这个值为0,就表示没有DATA transaction 阶段,bRequestType 的方向位也就无效了。
} __attribute__ ((packed));  

控制传输最少要有两个阶段的transaction,SETUP 和STATUS,SETUP 和STATUS 中间的那个DATA阶段是可有可无的.

SETUP transaction 一般来说也有三个阶段,就是主机向设备发送Setup Token 包、然后发送Data0 包,如果一切顺利,设备回应ACK
Handshake 包表示OK.

经过 SETUP、DATA、STATUS 这三个transaction 阶段,一个完整的控制传输完成了.

[cpp] view plaincopy

static int usb_internal_control_msg(struct usb_device *usb_dev,
                    unsigned int pipe,
                    struct usb_ctrlrequest *cmd,
                    void *data, int len, int timeout)
{
    struct urb *urb;
    int retv;
    int length;  

    urb = usb_alloc_urb(0, GFP_NOIO);  //:usb_alloc_urb函数,创建一个urb,struct urb结构体只能使用它来创建
    if (!urb)
        return -ENOMEM;  

    usb_fill_control_urb(urb, usb_dev, pipe, (unsigned char *)cmd, data,
                 len, usb_api_blocking_completion, NULL); //,初始化一个控制urb,urb被创建之后,使用之前必须要正确的初始化。  

    retv = usb_start_wait_urb(urb, timeout, &length);//将urb提交给咱们的usb core,以便分配给特定的主机控制器驱动进行处理
    if (retv < 0)
        return retv;
    else
        return length;
}
此函数可以概括为一个中心,三个基本点,以一个struct urb结构体为中心,

以usb_alloc_urb、usb_fill_control_urb、usb_start_wait_urb三个函数为基本点
时间: 2024-10-06 00:47:53

USB Core二【转】的相关文章

RabbitMQ与.net core(二)Producer与Exchange

原文:RabbitMQ与.net core(二)Producer与Exchange Producer:消息的生产者,也就是创建消息的对象 Exchange:消息的接受者,也就是用来接收消息的对象,Exchange接收到消息后将消息按照规则发送到与他绑定的Queue中.下面我们来定义一个Producer与Exchange. 1.新建.netcore console项目,并引入RabbitMQ.Client的Nuget包 2.创建Exchange using RabbitMQ.Client; nam

usb.core.NoBackendError: No backend available

使用pip install pyusb 安装pyusb后调用以下代码: import usb.core import usb.util dev =usb.core.find(find_all=True) print(dev) 最近一个案子是要用到USB信息交互,获取电脑连接的USB设备,但是遇到了报错:usb.core.NoBackendError No backend available , 我的操作系统是Windows10_64位. 首先,打开链:https://pan.baidu.com/

K8S+GitLab-自动化分布式部署ASP.NET Core(二) ASP.NET Core DevOps

一.介绍 前一篇,写的K8S部署环境的文章,下面正式开始部署ASP.NET Core 项目. 二.正式部署ASP.NET Core项目 GitHub地址: https://github.com/gyw1309631798/Deploy-API. 我创建了一个ASP.NET Core 2.1 WebAPI项目 里面包含了deploy.yaml,Dockerfile文件. 要在K8S上部署首先要添加regsecret ,不然从Harbor pull会失败. kubectl create namesp

.Net Core(二)EFCore

?EFCore与之前的EF基本类似,区别在于配置的时候有一些差异:也取消了DB First和Model First,仅保留广泛使用的Code First模式:也不再支持LazyLoad.这里就感受一下其基本使用. 一.EFCore的基本使用EFCore的Nuget包为Microsoft.EntityFrameworkCore,为了与Linux那边的Mysql连接还需安装provider,这里跟着安装了第三方的Pomelo.EntityFrameworkCore.Mysql.一开始不能用,后来发现

ASP.NET Core (二):入门

上一篇:ASP.NET Core(一):简介 下一篇:(待续) 英文原版:Getting Started 1. 安装 .NET Core 2. 创建 .NET Core 项目 在命令提示符窗口输入命令: mkdir aspnetcoreapp cd aspnetcoreapp dotnet new 3. 更新 project.json 文件,将 Kestrel HTTP 服务器程序包作为依赖添加到文件中 { "version": "1.0.0-*", "b

asp.net core 二 Nginx Supervisor 负载,监听

ASP.NET Core负载均衡集群搭建(CentOS7+Nginx+Supervisor+Kestrel) asp.net core在linux运行下,一但命令行退出,程序将停止,而且asp.net core的监听以及负载问题将在这里说明 参考连接:http://www.linuxidc.com/Linux/2016-11/136997.htm http://www.sohu.com/a/192683690_468635  https://www.cnblogs.com/ants/p/5732

Docker + .NET Core(二)

前言: 环境:centos7.5 64 位 正文: 首先我们在宿主机上安装 .NET Core SDK sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc sudo sh -c 'echo -e "[packages-microsoft-com-prod]\nname=packages-microsoft-com-prod \nbaseurl= https://packages.microsoft.com/yum

.Net Core(二) 下

接上面 http://www.cnblogs.com/xcodevs/p/5584218.html 在解决方案浏览器中,右击 Controllers 目录.选择添加>新建项.选择Web API控制器.命名为TodoController.点击添加. 将自动生成的代码替换为如下代码: 是不是很面熟?这个就是前面讲过的构造注入. 添加获取to-do项的方法到TodoController类中,代码如下: 在进行调试之前,还需要设置项目的启动Url.右击项目>属性.选择调试选项卡,将启动URL的值设置为

ARM开发板加载Realtek-8188CUS USB无线网卡(二)

平台参数: 内核: Linux 3.6 文件系统:Busybox-1.20.2 硬件参数:S3C2416 三.工具准备.知识准备 曾经一个山民说过,磨刀不误砍柴工.捣鼓WiFi,,那么WiFi相关的知识总要了解些吧,比如该无线网络的标准.涉及到的名词.加密术语等等,这些在附录里面提及. 现在要说的是,调试无线网卡需要的几个工具. 所有需要的工具都在源码包里,即wireless_tools/wireless_tools.30.rtl.tar.gz.解压之,修改Makefile: ## Compil