精华内容
下载资源
问答
  • 目录第1篇 Linux那些事儿之我是USB Core1.引子22.它从哪里来23.PK34.漫漫辛酸路35.我型我秀46.我是一棵树57.我是谁98.好戏开始了119.不一样的Core1310.从这里开始1711.面纱2012.模型,又见模型2213....

    目录

    第1篇  Linux那些事儿之我是USB Core

    1.引子 2

    2.它从哪里来 2

    3.PK 3

    4.漫漫辛酸路 3

    5.我型我秀 4

    6.我是一棵树 5

    7.我是谁 9

    8.好戏开始了 11

    9.不一样的Core 13

    10.从这里开始 17

    11.面纱 20

    12.模型,又见模型 22

    13.繁华落尽 26

    14.接口是设备的接口 28

    15.设置是接口的设置 32

    16.端点 35

    17.设备 37

    18.配置 45

    19.向左走,向右走 48

    20.设备的生命线(一) 53

    21.设备的生命线(二) 56

    22.设备的生命线(三) 61

    23.设备的生命线(四) 67

    24.设备的生命线(五) 73

    25.设备的生命线(六) 80

    26.设备的生命线(七) 88

    27.设备的生命线(八) 94

    28.设备的生命线(九) 100

    29.设备的生命线(十) 104

    30.设备的生命线(十一) 109

    31.驱动的生命线(一) 122

    32.驱动的生命线(二) 127

    33.驱动的生命线(三) 131

    34.驱动的生命线(四) 135

    35.字符串描述符 138

    36.接口的驱动 147

    37.还是那个match 150

    38.结束语 155

    第2篇  Linux那些事儿之我是HUB

    1.引子 157

    2.跟我走吧,现在就出发 157

    3.特别的爱给特别的Root Hub 158

    4.一样的精灵不一样的API 160

    5.那些队列,那些队列操作函数 164

    6.等待,只因曾经承诺 169

    7.最熟悉的陌生人--probe 171

    8.蝴蝶效应 174

    9.While You Were Sleeping(一) 178

    10.While You Were Sleeping(二) 183

    11.While You Were Sleeping(三) 185

    12.While You Were Sleeping(四) 191

    13.再向虎山行 194

    14.树,是什么样的树 198

    15.没完没了的判断 201

    16.一个都不能少 206

    17.盖茨家对Linux代码的影响 215

    18.八大重量级函数闪亮登场(一) 220

    19.八大重量级函数闪亮登场(二) 223

    20.八大重量级函数闪亮登场(三) 225

    21.八大重量级函数闪亮登场(四) 237

    22.八大重量级函数闪亮登场(五) 241

    23.是月亮惹的祸还是spec的错 249

    24.所谓的热插拔 251

    第3篇  Linux那些事儿之我是UHCI

    1.引子 256

    2.开户和销户 258

    3.PCI,我们来了! 262

    4.I/O内存和I/O端口 270

    5.传说中的DMA 275

    6.来来,我是一条总线,线线线线线线 281

    7.主机控制器的初始化 285

    8.有一种资源,叫中断 293

    9.一个函数引发的故事(一) 295

    10.一个函数引发的故事(二) 298

    11.一个函数引发的故事(三) 303

    12.一个函数引发的故事(四) 309

    13.一个函数引发的故事(五) 311

    14.寂寞在唱歌 313

    15.Root Hub的控制传输(一) 321

    16.Root Hub的控制传输(二) 327

    17.非Root Hub的批量传输 339

    18.传说中的中断服务程序(ISR) 345

    19.Root Hub的中断传输 362

    20.非Root Hub的中断传输 364

    21.等时传输 375

    22."脱"就一个字 381

    第4篇  Linux那些事儿之我是U盘

    1.小城故事 388

    2.Makefile 389

    3.变态的模块机制 390

    4.想到达明天现在就要启程 392

    5.外面的世界很精彩 394

    6.未曾开始却似结束 395

    7.狂欢是一群人的孤单 396

    8.总线、设备和驱动(上) 397

    9.总线、设备和驱动(下) 398

    10.我是谁的他 400

    11.从协议中来,到协议中去(上) 401

    12.从协议中来,到协议中去(中) 403

    13.从协议中来,到协议中去(下) 405

    14.梦开始的地方 406

    15.设备花名册 411

    16.冰冻三尺非一日之寒 412

    17.冬天来了,春天还会远吗?(一) 416

    18.冬天来了,春天还会远吗?(二) 422

    19.冬天来了,春天还会远吗?(三) 425

    20.冬天来了,春天还会远吗?(四) 427

    21.冬天来了,春天还会远吗?(五) 431

    22.通往春天的管道 436

    23.传说中的URB 440

    24.彼岸花的传说(一) 443

    25.彼岸花的传说(二) 445

    26.彼岸花的传说(三) 448

    27.彼岸花的传说(四) 451

    28.彼岸花的传说(五) 453

    29.彼岸花的传说(六) 457

    30.彼岸花的传说(七) 460

    31.彼岸花的传说(八) 463

    32.彼岸花的传说(The End) 467

    33.SCSI命令之我型我秀 468

    34.迷雾重重的批量传输(一) 472

    35.迷雾重重的批量传输(二) 476

    36.迷雾重重的批量传输(三) 479

    37.迷雾重重的批量传输(四) 484

    38.迷雾重重的批量传输(五) 489

    39.迷雾重重的批量传输(六) 493

    40.迷雾重重的批量传输(七) 495

    41.跟着感觉走(一) 500

    42.跟着感觉走(二) 503

    43.有多少爱可以胡来?(一) 509

    44.有多少爱可以胡来?(二) 513

    45.当梦醒了天晴了 518

    46.其实世上本有路,走的人多了,也便没了路 522

    附录  Linux那些事儿之我是sysfs

    1.sysfs初探 526

    2.设备模型 527

    2.1  设备底层模型 528

    2.1.1  kobject 528

    2.1.2  kset 530

    2.1.3  kobj_type 531

    2.2  设备模型上层容器 532

    2.3  示例一:usb子系统 535

    2.4  示例二:usb storage驱动 540

    3.sysfs文件系统 546

    3.1  文件系统 547

    3.1.1  dentry & inode 548

    3.1.2  一起散散步path_walk 551

    3.1.3  super_block与vfsmount 552

    3.2  sysfs 553

    3.2.1  sysfs_dirent 553

    3.2.2  sysfs_create_dir() 554

    3.2.3  sysfs_create_file() 556

    3.3  file_oprations 557

    3.3.1  示例一:读入sysfs目录的

    内容 558

    3.3.2  示例二:读入sysfs普通

    文件的内容 560

    【责任编辑:云霞 TEL:(010)68476606】

    点赞 0

    展开全文
  • usb驱动程序分析

    2021-05-22 14:28:33
    usb驱动是linux内核中比较复杂的驱动之一,因此,大多数usb教程建议从usb-skeleton开始学习usb驱动。个人认为这是相当正确的,usb-sekelton提供了一个usb驱动开发的模板,而且代码量较少,很适合初学者的学习。记住...

    usb驱动是linux内核中比较复杂的驱动之一,因此,大多数usb教程建议从usb-skeleton开始学习usb驱动。个人认为这是相当正确的,usb-sekelton提供了一个usb驱动开发的模板,而且代码量较少,很适合初学者的学习。

    记住,对于c语言的程序设计说,数据结构是整个程序的灵魂。因此,分析别人编写的代码的简洁的入口点就是高清代码中主要数据结构之间的关系。分析以usb-skeleton为例的完整的usb驱动框架,我们就从主要的几个数据结构入手。

    一、usb驱动框架的主要数据结构

    usb驱动框架主要包括设备,配置,接口和端点几个组成部分,相对应的数据结构为:

    struct usb_device;                //usb设备

    struct usb_host_config;//usb配置

    struct usb_host_interface;//usb接口

    struct usb_host_endpoit;          //usb端口

    它们之间的关系可以形象的表示为图1。

    184d9ab4cbe5f39dac7744fb664a399b.png

    上图描述的usb各组成部分的关系可以描述为:

    (1)一个usb设备可以有多个usb配置,多个配置之间可以相互切换,某个时刻只能对应一个配置;

    (2)一个usb配置可以有多个usb接口,一个usb接口代表了一个基本功能,对以一个usb客户端驱动程序;

    (3)一个usb接口可以有多个usb端点;

    就像我们平时程序设计经常使用的方法一样,一个对象由一个结构体来表示,但还会再用来一个结构体来描述这个对象的一些属性。usb驱动框架也采用了这样的设计思想,usb框架中每一个组成部分都用两个结构体来描述:一个结构体表示成员组成,另一个结构体表示属性组成。Linux-USB核心定义了4个usb描述符。

    struct usb_device_descriptor; struct usb_device;

    struct usb_host_config; struct usb_config_descriptor;

    struct usb_host_interface; struct usb_interface_descriptor;

    struct usb_host_endpoint; struct usb_endpoint_descriptor;

    另外,还有一个比较特殊的数据结构是URB(USB Request Block),被USB协议栈使用,是USB数据传输机制的核心数据结构,具体的URB的类型,URB的使用步骤等读者可以参考《Linux设备驱动程序》一书,本文不做详细介绍。

    二、USB设备的枚举过程

    USB设备是一种典型的热插拔设备,与PCI设备类似,当总线检测到有设备插入的时候,总线驱动程序就会去遍历总线上已经挂载的所有的设备驱动程序,查看有没有驱动程序与刚插入的设备匹配,如果匹配成功,则去执行驱动程序中的probe函数。这是Linux内核中经典的驱动和设备挂钩的方式之一。

    三、分析代码的执行过程

    要理解代码的含义,最关键的是理清代码的执行路径,即代码中函数的调用关系。光靠source insight或eclipse代码分析工具有时候略显不够,对于那些没有直接调用关系的函数这些静态代码分析工具爱莫能助。最好方法是能看到代码一步一步的执行流程,那么,单步调试就是比较好的选择了。本文采用KVM+GDB的方式对usb-skeleton模块进行了单步调试。Linux内核调试环境的搭建参考文章《qemu+eclipse内核调试》,这里仅需要创建一个Makefile文件,编译usb-skeleton.c即可。KVM中usb设备的使用参考文章《KVM中使用usb设备》。需要注意的是,Linux内中默认的usb存储设备的驱动模块名称为usb-storage,在调试前,先卸载该模块。

    四、usb-skeleton主要代码分析(Linux-2.6.35)

    1 skel_probe函数

    static int skel_probe(struct usb_interface *interface,

    const struct usb_device_id *id)

    {

    struct usb_skel *dev;

    struct usb_host_interface *iface_desc;

    struct usb_endpoint_descriptor *endpoint;

    size_t buffer_size;

    int i;

    int retval = -ENOMEM;

    /* allocate memory for our device state and initialize it */

    dev = kzalloc(sizeof(*dev), GFP_KERNEL);

    if (!dev) {

    err("Out of memory");

    goto error;

    }

    kref_init(&dev->kref);

    sema_init(&dev->limit_sem, WRITES_IN_FLIGHT);

    mutex_init(&dev->io_mutex);/IO操作互斥锁,在进行IO操作时,不允许进行其他操作,如数据拷贝,后面会提到/

    spin_lock_init(&dev->err_lock);

    init_usb_anchor(&dev->submitted);

    init_completion(&dev->bulk_in_completion);/*comletion同步机制,即IO操作和数据拷贝的同步*/

    /*数据结构之间的转换,这里是usb_skel和usb_host_interface两个结构体之间的转换,相当于container_of宏*/

    dev->udev = usb_get_dev(interface_to_usbdev(interface));

    dev->interface = interface;

    /* set up the endpoint information */

    /* use only the first bulk-in and bulk-out endpoints */

    /* 初始化dev设备的bulk-in和bulk-out相关的数据成员,两种数据类型只初始化一个*/

    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)) {

    /* we found a bulk in endpoint */

    buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);

    dev->bulk_in_size = buffer_size;

    dev->bulk_in_endpointAddr = endpoint->bEndpointAddress;

    dev->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);

    if (!dev->bulk_in_buffer) {

    err("Could not allocate bulk_in_buffer");

    goto error;

    }

    dev->bulk_in_urb = usb_alloc_urb(0, GFP_KERNEL);

    if (!dev->bulk_in_urb) {

    err("Could not allocate bulk_in_urb");

    goto error;

    }

    }

    if (!dev->bulk_out_endpointAddr &&

    usb_endpoint_is_bulk_out(endpoint)) {

    /* we found a bulk out endpoint */

    dev->bulk_out_endpointAddr = endpoint->bEndpointAddress;

    }

    }

    if (!(dev->bulk_in_endpointAddr && dev->bulk_out_endpointAddr)) {

    err("Could not find both bulk-in and bulk-out endpoints");

    goto error;

    }

    /* save our data pointer in this interface device */

    /*不同上下文之间结构体传递的一种方式,在probe和open等其他函数之间通过usb_set_intfdata和usb_get_intfdata两个函数来保存和获取局部变量de*/

    usb_set_intfdata(interface, dev);

    /* we can register the device now, as it is ready */

    /*执行完usb_register_dev之后,接口interface就会对应一个此设备号,至此与该接口对应的驱动注册完成,其他一些操作将会等到open时再进行*/

    retval = usb_register_dev(interface, &skel_class);

    if (retval) {

    /* something prevented us from registering this driver */

    err("Not able to get a minor for this device.");

    usb_set_intfdata(interface, NULL);

    goto error;

    }

    /* let the user know what node this device is now attached to */

    dev_info(&interface->dev,

    "USB Skeleton device now attached to USBSkel-%d",

    interface->minor);

    return 0;

    error:

    if (dev)

    /* this frees allocated memory */

    kref_put(&dev->kref, skel_delete);

    return retval;

    }

    此函数主要完成usb用户态驱动的注册即usb_class_driver的注册,即skel_class结构体的注册。另外,需要注意的是在驱动程序设计中probe()和open()两个函数的区别,即它们各自应该实现什么功能?个人认为主要理解以下几点:

    (1)对每个驱动来讲probe函数只会执行一次,执行时机为驱动加载或设备枚举的时候,用来实现设备和驱动的匹配。从这方面来讲,probe函数的执行函数应该尽可能的短,因此,操作越少越好。

    (2)open()函数是每次打开某设备时都要执行的函数,如果系统中有多个进程都在使用某个设备,那么,open()函数就有可能执行多次,从这个角度来讲,open()函数主要应该坐与可冲入相关的操作,即让每个进程看来都是像第一次打开设备一样,其他进程对设备的某些值的修改不应该被其他进程看到。即相当于每次都虚拟了一个实际的硬件设备。

    从这两方面将,如果不考虑probe的执行时间,如果不会存在多个使用同一设备的进程,完全可以将probe和open合并。

    2 skel_open()函数

    static int skel_open(struct inode *inode, struct file *file)

    {

    struct usb_skel *dev;

    struct usb_interface *interface;

    int subminor;

    int retval = 0;

    subminor = iminor(inode);

    /*通过驱动和此设备号去查找对应的设备,类此pci设备,根据驱动结构体,在总线的device链表上查找这个驱动对应的设备,在usb驱动架构中即指对应的借口。*/

    interface = usb_find_interface(&skel_driver, subminor);

    if (!interface) {

    err("%s - error, can't find device for minor %d",

    __func__, subminor);

    retval = -ENODEV;

    goto exit;

    }

    /*获得在probe函数中保存的局部变量usb_skel dev*/

    dev = usb_get_intfdata(interface);

    if (!dev) {

    retval = -ENODEV;

    goto exit;

    }

    /* increment our usage count for the device */

    kref_get(&dev->kref);

    /* lock the device to allow correctly handling errors

    * in resumption */

    mutex_lock(&dev->io_mutex);

    if (!dev->open_count++) {/*与电源管理相关的代码,可以暂时不去分析*/

    retval = usb_autopm_get_interface(interface);

    if (retval) {

    dev->open_count--;

    mutex_unlock(&dev->io_mutex);

    kref_put(&dev->kref, skel_delete);

    goto exit;

    }

    } /* else { //uncomment this block if you want exclusive open

    retval = -EBUSY;

    dev->open_count--;

    mutex_unlock(&dev->io_mutex);

    kref_put(&dev->kref, skel_delete);

    goto exit;

    } */

    /* prevent the device from being autosuspended */

    /* save our object in the file's private structure */

    /*这里需要注意,前面讲过在probe和open等函数之间传递私有数据用的是两个函数usb_set_intfdata()和usb_get_intfdata, 那么,在open函数和其他函数如read/write之间传递私有数据就是通过file->private_data变量来实现的*/

    file->private_data = dev;

    mutex_unlock(&dev->io_mutex);

    exit:

    return retval;

    }

    从上面的代码我们可以发现,open函数归根结底其实只做了一件事情:保存了私有变量usb_skel dev,是的其他文件操作函数可用。

    3.skel_read()函数

    static ssize_t skel_read(struct file *file, char *buffer, size_t count,

    loff_t *ppos)

    {

    struct usb_skel *dev;

    int rv;

    bool ongoing_io;

    dev = (struct usb_skel *)file->private_data;

    /* if we cannot read at all, return EOF */

    if (!dev->bulk_in_urb || !count)

    return 0;

    /* no concurrent readers */

    /*I/O操作的互斥锁,每次读操作前先去获得此锁,防止读操作和IO之间的并发进行。即如果读操作获得了此锁,IO操作就不能进行,同样的,如果该锁已经被IO操作获得,则当前执行流程睡眠,直到IO操作完成,释放此锁*/

    rv = mutex_lock_interruptible(&dev->io_mutex);

    if (rv < 0)

    return rv;

    if (!dev->interface) { /* disconnect() was called */

    rv = -ENODEV;

    goto exit;

    }

    /* if IO is under way, we must not touch things */

    retry:

    spin_lock_irq(&dev->err_lock);

    ongoing_io = dev->ongoing_read;/*获得当前的IO状态*/

    spin_unlock_irq(&dev->err_lock);

    if (ongoing_io) {/*如果usb的I/O操作正在进行中,要等待I/O操作执行完成*/

    /* nonblocking IO shall not wait */

    if (file->f_flags & O_NONBLOCK) {

    rv = -EAGAIN;

    goto exit;

    }

    /*

    * IO may take forever

    * hence wait in an interruptible state

    */

    /*睡眠等待IO操作完成*/

    rv = wait_for_completion_interruptible(&dev->bulk_in_completion);

    if (rv < 0)

    goto exit;

    /*

    * by waiting we also semiprocessed the urb

    * we must finish now

    */

    dev->bulk_in_copied = 0;/*如果正在进行IO操作,说明当前URB对应的缓冲区没有数据可用了,所以copied=0*/

    dev->processed_urb = 1;/*z执行到这的时候IO操作已经完成了,这里要标记下开始处理URB了*/

    }

    if (!dev->processed_urb) {/*等于0时,说明这个URB还没被处理过,即第一次读取这个URB*/

    /*

    * the URB hasn't been processed

    * do it now

    */

    /*这里为什么还要等待,什么情况下需要等待?????*/

    wait_for_completion(&dev->bulk_in_completion);

    dev->bulk_in_copied = 0;

    dev->processed_urb = 1;

    }

    /* errors must be reported */

    rv = dev->errors;

    if (rv < 0) {

    /* any error is reported once */

    dev->errors = 0;

    /* to preserve notifications about reset */

    rv = (rv == -EPIPE) ? rv : -EIO;

    /* no data to deliver */

    dev->bulk_in_filled = 0;

    /* report it */

    goto exit;

    }

    /*

    * if the buffer is filled we may satisfy the read

    * else we need to start IO

    */

    if (dev->bulk_in_filled) {/*不是第一次读,当前缓冲区中的数据的字节数*/

    /* we had read data */

    size_t available = dev->bulk_in_filled - dev->bulk_in_copied;/*当前URB还有多少数据没有拷贝*/

    size_t chunk = min(available, count);

    if (!available) {/*当前URB对应的缓冲区中没有数据了,要执行IO操作读入*/

    /*

    * all data has been used

    * actual IO needs to be done

    */

    /*执行IO操作,主要包括初始化一个URB和向usb core提交这个URB两个操作,真正的IO操作是由usb core驱动代码来完成的*/

    rv = skel_do_read_io(dev, count);

    if (rv < 0)

    goto exit;

    else

    goto retry;

    }

    /*

    * data is available

    * chunk tells us how much shall be copied

    */

    /*从当前URB对应的缓冲区中拷贝chunk字节数据到用户空间*/

    if (copy_to_user(buffer,

    dev->bulk_in_buffer + dev->bulk_in_copied,

    chunk))

    rv = -EFAULT;

    else

    rv = chunk;

    dev->bulk_in_copied += chunk; /*增加已拷贝数据的字节数*/

    /*

    * if we are asked for more than we have,

    * we start IO but don't wait

    */

    /*当前缓冲区拷贝完成后,还没有完成用户指定的数据拷贝量,要继续执行I/O操作,填充URB*/

    if (available < count)

    skel_do_read_io(dev, count - chunk);

    } else {

    /* no data in the buffer */

    /*当前缓冲区已经没有数据了,要执行I/O操作来填充URB对应的缓冲区*/

    rv = skel_do_read_io(dev, count);

    if (rv < 0)

    goto exit;

    else if (!(file->f_flags & O_NONBLOCK))

    goto retry;

    rv = -EAGAIN;

    }

    exit:

    mutex_unlock(&dev->io_mutex);

    return rv;

    }/*执行完I/O操作后,要去唤醒usb用户驱动中正在睡眠等待的读拷贝操作过程*/

    static void skel_read_bulk_callback(struct urb *urb)

    {

    struct usb_skel *dev;

    dev = urb->context;

    spin_lock(&dev->err_lock);

    /* sync/async unlink faults aren't errors */

    if (urb->status) {

    if (!(urb->status == -ENOENT ||

    urb->status == -ECONNRESET ||

    urb->status == -ESHUTDOWN))

    err("%s - nonzero write bulk status received: %d",

    __func__, urb->status);

    dev->errors = urb->status;

    } else {

    dev->bulk_in_filled = urb->actual_length;

    }

    dev->ongoing_read = 0; /*执行完IO操作通知usb客户端驱动*/

    spin_unlock(&dev->err_lock);

    /*执行唤醒操作*/

    complete(&dev->bulk_in_completion);

    }

    static int skel_do_read_io(struct usb_skel *dev, size_t count)

    {

    int rv;

    /* prepare a read */

    /*在执行I/O操作前,先准备号一个URB*/

    usb_fill_bulk_urb(dev->bulk_in_urb,

    dev->udev,

    usb_rcvbulkpipe(dev->udev,

    dev->bulk_in_endpointAddr),

    dev->bulk_in_buffer,

    min(dev->bulk_in_size, count),

    skel_read_bulk_callback,

    dev);

    /* tell everybody to leave the URB alone */

    spin_lock_irq(&dev->err_lock);

    dev->ongoing_read = 1; /*标记现在要进行I/O操作了*/

    spin_unlock_irq(&dev->err_lock);

    /* do it */

    /*交由usb core模块去执行真正的IO操作*/

    rv = usb_submit_urb(dev->bulk_in_urb, GFP_KERNEL);

    if (rv < 0) {

    err("%s - failed submitting read urb, error %d",

    __func__, rv);

    dev->bulk_in_filled = 0;

    rv = (rv == -ENOMEM) ? rv : -EIO;

    spin_lock_irq(&dev->err_lock);

    dev->ongoing_read = 0;

    spin_unlock_irq(&dev->err_lock);

    }

    return rv;

    }

    该函数比较容易理解,就是一个从usb设备读数据到用户程序的过程,这里涉及到一个主要的数据结构URB,对于usb客户驱动来讲,只需调用usb core提供的API即可,因此,usb驱动开发者只需了解这个API的功能和如何使用即可。详见代码注释。

    4 skel_write()操作

    static ssize_t skel_write(struct file *file, const char *user_buffer,

    size_t count, loff_t *ppos)

    {

    struct usb_skel *dev;

    int retval = 0;

    struct urb *urb = NULL;

    char *buf = NULL;

    /*确定每次写操作可以写的数据量,最大值为PAGE_SIZE - 512 字节*/

    size_t writesize = min(count, (size_t)MAX_TRANSFER);

    dev = (struct usb_skel *)file->private_data;

    /* verify that we actually have some data to write */

    if (count == 0)

    goto exit;

    /*

    * limit the number of URBs in flight to stop a user from using up all

    * RAM

    */

    if (!(file->f_flags & O_NONBLOCK)) {

    if (down_interruptible(&dev->limit_sem)) {

    retval = -ERESTARTSYS;

    goto exit;

    }

    } else {

    if (down_trylock(&dev->limit_sem)) {

    retval = -EAGAIN;

    goto exit;

    }

    }

    spin_lock_irq(&dev->err_lock);

    retval = dev->errors;

    if (retval < 0) {

    /* any error is reported once */

    dev->errors = 0;

    /* to preserve notifications about reset */

    retval = (retval == -EPIPE) ? retval : -EIO;

    }

    spin_unlock_irq(&dev->err_lock);

    if (retval < 0)

    goto error;

    /* create a urb, and a buffer for it, and copy the data to the urb */

    /*在usb用户驱动的读程序中,并没有URB的分配,因为在usb_skel中包含了一个URB数据成员*/

    urb = usb_alloc_urb(0, GFP_KERNEL);

    if (!urb) {

    retval = -ENOMEM;

    goto error;

    }

    /*因为这里是由usb用户驱动负责分配的URB,因此,也应负责分配URB的成员指向的内存*/

    buf = usb_alloc_coherent(dev->udev, writesize, GFP_KERNEL,

    &urb->transfer_dma);

    if (!buf) {

    retval = -ENOMEM;

    goto error;

    }

    /*把用户空间的数据拷贝到URB对应的DMA内存中*/

    if (copy_from_user(buf, user_buffer, writesize)) {

    retval = -EFAULT;

    goto error;

    }

    /* this lock makes sure we don't submit URBs to gone devices */

    /*在URB没有准备好之前,不允许进行实际的I/O操作*/

    mutex_lock(&dev->io_mutex);

    if (!dev->interface) { /* disconnect() was called */

    mutex_unlock(&dev->io_mutex);

    retval = -ENODEV;

    goto error;

    }

    /* initialize the urb properly */

    usb_fill_bulk_urb(urb, dev->udev,

    usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),

    buf, writesize, skel_write_bulk_callback, dev);

    urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

    /*把urb添加到另外一条链表上,以便在其他地方对其进行访问*/

    usb_anchor_urb(urb, &dev->submitted);

    /* send the data out the bulk port */

    retval = usb_submit_urb(urb, GFP_KERNEL);

    mutex_unlock(&dev->io_mutex);

    if (retval) {

    err("%s - failed submitting write urb, error %d", __func__,

    retval);

    goto error_unanchor;

    }

    /*

    * release our reference to this urb, the USB core will eventually free

    * it entirely

    */

    usb_free_urb(urb);

    return writesize;

    }

    在函数与skel_read非常类似,唯一不同的是在写操作过程中需要usb客户驱动程序来显示的分配和初始化用于写操作的URB,之所以在读操作过程中看不到这个过程,是因为,在struct usb_skel dev中已经为写操作内嵌了一个数据成员:

    /* Structure to hold all of our device specific stuff */

    struct usb_skel {

    struct usb_device    *udev;            /* the usb device for this device */

    struct usb_interface    *interface;        /* the interface for this device */

    struct semaphore    limit_sem;        /* limiting the number of writes in progress */

    struct usb_anchor    submitted;        /* in case we need to retract our submissions */

    struct urb        *bulk_in_urb;       /* the urb to read data with */

    unsigned char *bulk_in_buffer;    /* the buffer to receive data */

    size_t            bulk_in_size;        /* the size of the receive buffer */

    size_t            bulk_in_filled;        /* number of bytes in the buffer */

    size_t            bulk_in_copied;        /* already copied to user space */

    __u8            bulk_in_endpointAddr;    /* the address of the bulk in endpoint */

    __u8            bulk_out_endpointAddr;    /* the address of the bulk out endpoint */

    int            errors;            /* the last request tanked */

    int            open_count;        /* count the number of openers */

    bool            ongoing_read;        /* a read is going on */

    bool            processed_urb;        /* indicates we haven't processed the urb */

    spinlock_t        err_lock;        /* lock for errors */

    struct kref        kref;

    struct mutex        io_mutex;        /* synchronize I/O with disconnect */

    struct completion    bulk_in_completion;    /* to wait for an ongoing read */

    };

    而且这个结构体的很多数据成员都与读操作有关,具体为什么这么设计,暂时还没有搞明白,希望大家指教!

    总结:

    1. usb客户驱动还是比较简单的,主要是因为很多功能都由usb core驱动程序事先完成了,usb客户端驱动程序仅仅是调用一些API即可。

    2. usb客户驱动程序的开发比较固定,直接套用usb-skeleton的代码基本就可以完成用户自定义驱动的编写

    展开全文
  • 一、使用STM32CubeMX生成USB驱动程序 打开STM32CubeMX软件,选择Start My project formMCU,点ACCESS TO MCU SELECTOR。 选择相应的芯片信号,点击Start Project 配置RCC的High Speed Clock为图中所示,...

    以STM32CubeMX生成USB驱动为例,其步骤如下:

    一、使用STM32CubeMX生成USB驱动程序

    打开STM32CubeMX软件,选择Start My project formMCU,点ACCESS TO MCU SELECTOR。

    选择相应的芯片信号,点击Start Project

    配置RCC的High Speed Clock为图中所示,位置为外部时钟。

    选择SYS的Debug为Serial Wire,开启调试,否则下载程序后无法再次下载。具体解决方法参考链接:

    ST-LINK无法下载程序的解决方法

    在Connectivety下选择USB,勾选Device(FS),配置NVIC的中断,打上对勾,开启中断。

    在USB_DEVICE中的mode,选择Communication Device Class配置,在Device Descriptor中配置USB的信息,根据图片自行修改。

    在Clock configuration中,选择HES外部晶振,选择PLLCLK。在HCLK(MHz)下,填入72,点回车,等待系统自动配置时钟,配置完成后,USB时钟为48MHz,注意USB必须为48MHz。

    在Project Manager中,一次填写工程名称,路径,IDE选择MDK-ARM,Minimum Heap Size改为0x400或者0x800,否则可能出现USB在调用USBD_malloc() 申请内存是失败,导致数据无法接收的情况。点击右上角GENERATE CODE。

    打开工程文件,编译后下载到板子上,会在设备管理器看到这个设备

    测试中出现电脑上检测不到USB设备的情况,经过查阅资料,USB的DP引脚必须上拉1.5K欧的电阻,才能检测到,否则电脑上检测不到。

    电脑检测到USB的设备后,还需要安装相应的驱动。使用inf-wizard工具生成USB驱动。

    打开后,选择对应的设备,一路NEXT下去,等一会就会生成对应的驱动,安装该驱动,设备就能被电脑识别。

    工程文件和USB驱动生成工具稍后附上链接。

    下载链接:

    STM32F103的USB工程及USB驱动生成工具

    展开全文
  • Android USB 驱动分析

    2021-05-27 03:57:40
    一、USB驱动代码架构和使用1、代码简介USB驱动代码在/drivers/usb/gadget下,有三个文件:android.c,f_adb.c,f_mass_storage.c;g_android.ko 是由这三个文件编译而来,其中android.c 依赖于f_adb.c和 f_mass_...

    一、USB驱动代码架构和使用

    1、代码简介

    USB驱动代码在/drivers/usb/gadget下,有三个文件:android.c,f_adb.c,

    f_mass_storage.c;g_android.ko 是由这三个文件编译而来,其中android.c 依赖于

    f_adb.c 和 f_mass_storage.c(这两个文件之间无依赖关系)。

    可在android.c中看到:

    static int __init android_bind_config(struct usb_configuration *c)

    {

    struct android_dev *dev = _android_dev;

    int ret;

    printk(KERN_DEBUG "android_bind_config\n");

    ret = mass_storage_function_add(dev->cdev, c, dev->nluns);

    if (ret)

    return ret;

    return adb_function_add(dev->cdev, c);

    }

    2、驱动使用

    要使USB mass storage连接到主机:

    打开/sys/devices/platform/usb_mass_storage/lun0/file文件,向file文件写入一个存储

    设备的路径,例如/dev/block/vold/179:0 (major:minor)路径;

    这里的usb_mass_storage根据实际应用可以改的,由platform_device_register函数的参数决

    定。

    例如:

    static struct platform_device fsg_platform_device =

    {

    .name = "usb_mass_storage",

    .id   = -1,

    };

    static void __init tegra_machine_init(void)

    {

    ....

    (void) platform_device_register(&fsg_platform_device);

    ....

    }

    能够连接的设备数,由驱动中的nluns变量来控制,最多支持8个。

    二、USB插入检测

    三、USB代码分析

    1、USB初始化

    在android.c中分别注册adb和mass storage:

    static int __init android_bind_config(struct usb_configuration *c)

    {

    struct android_dev *dev = _android_dev;

    int ret;

    printk(KERN_DEBUG "android_bind_config\n");

    ret = mass_storage_function_add(dev->cdev, c, dev->nluns);

    if (ret)

    return ret;

    return adb_function_add(dev->cdev, c);

    }

    2、往驱动写入lun信息

    在驱动中有static DEVICE_ATTR(file, 0444, show_file, store_file);这是负责读

    (cat/read)或直写(echo/write)设备属性文件的宏。

    3、USB连接到主机

    echo /dev/block/vold/179:0 > /sys/devices/platform/usb_mass_storage/lun0/file

    4、USB从主机断开

    echo "" > /sys/devices/platform/usb_mass_storage/lun0/file

    展开全文
  • 就不得不需要一个合适的USB驱动。为了方便大家,我们特意收集并整理了比较大众的安卓手机机型USB驱动的下载链接(所有链接均来自官方网站)。有些链接是直接提供USB驱动下载,也有一些没有直接提供下载。但是您可以...
  • 一、USB 1、概述 USB(Universal Serial Bus)即“通用外部总线”,在各种场所已经大量使用。它的接口简单(只有5v电源和地、两根数据线D+和D-),可以外接硬盘、键盘、鼠标、打印机等多种设备。 USB总线规范有...
  • linux驱动路径

    2021-05-12 02:03:53
    1. 按键驱动\drivers\input\keyboard\utu2440_buttons.c2. LED驱动\drivers\char\utu2440-led.c3. DM9000网卡驱动\drivers\net\DM9000.c4. 串口(包含三个串口驱动0,1,2,对应设备名,/dev/s3c2410_serial0,/dev/s3c...
  • Linux USB驱动-鼠标驱动

    2021-03-18 21:28:36
    USB总线采用拓扑结构,USB主机和USB设备的连接构成了一颗树,树的结点为USB节点或USB集线器(HUB),USB集线器(HUB)用于扩展设备接口,一个集线器(HUB)可接多个USB设备或多个集线器。主机侧的USB节点为根节点,...
  • Win7原镜像注入USB驱动
  • 驱动编译:目前的kernel中都是自带了usbtouchscreen驱动的,我的版本3.1.10源码位于:/kernel/drivers/input/touchscreen/usbtouchscreen.c从这个路径可以看出所属驱动分支,我这边平台本身是没放开的,并没有编译进...
  • linux 内核 usb驱动分析

    2021-05-14 22:42:13
    简单分析 USB 主机控制器驱动 根 Hub 的注册过程,以及 USB设备的枚举过程,并不涉及USB协议,单纯分析驱动框架流程。无论是hub还是普通的usb设备,它们注册到 usb_bus_type 都会经历两次 Match ,因为第一次注册...
  • USB转RS232串口驱动》主要用于USB转RS232串口线,用上了USB转RS232串口线后就要装usb转232驱动才可以正常使用,特别是好多笔记本电脑都没有232接口了,可以用USB转RS232串口线来解决,特此本站发布这个兼容性驱动...
  • 电脑无法正常使用U盘的情况很多,并不都是操作系统的问题,很多单位处于电脑安全和信息保密的需要,常常通过注册表禁用USB接口、注册表禁用U盘、屏蔽USB接口的使用等;或者通过专门的电脑USB端口管理软件——如...
  • 在许多情况下,计算机无法正常使用USB闪存驱动器,并且这并不总是操作系统的问题. 许多单位需要计算机安全性和信息保密性. 他们通常通过注册表禁用USB接口,通过注册表禁用USB闪存驱动器,并屏蔽USB接口. 使用等;或...
  • 最近需要往TV上装一个触摸屏设备,现在比较常见的...驱动编译:目前的kernel中都是自带了usbtouchscreen驱动的,我的版本3.1.10源码位于:/kernel/drivers/input/touchscreen/usbtouchscreen.c从这个路径可以看出...
  • 嵌入式Linux下基于libusb的USB驱动开发

    千次阅读 2018-01-06 16:39:53
    由于usb设备的普遍性及其多样性,大量的usb设备的驱动开发也就成为开发者做的最多的事情。Linux平台上,内核驱动的开发由于内核的复杂和版本问题,初学者难以入手,驱动程序也不易升级和维护。本文主要介绍Linux平台...
  • linux USB host驱动

    2021-05-16 10:38:14
    8种机械键盘轴体对比本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?介绍USB系统框架,只关注框架部分,不涉及细节USB设备注册过程usb_add_hcd ->...usb_device_match(驱动匹配) -> generic_probe -...
  • 驱动程序原理介绍USB大存储设备(Mass Storage)是以文件为单位进行存储的从设备(Gadget)。在主设备主机(任何操作系统)上它以U盘的形式出现,在有Linux操作系统的从设备主机上,它以Gadget驱动程序形式出现,实现从...
  • quartusII 9.1 USB blaster驱动安装 USB blaster的驱动在安装好quartus软件后就有了,只不过还没有安装而已。默认存放路径为你quartus安装目录下的drivers 我的路径为C:\altera\91\quartus\drivers 安装驱动需要把...
  • Android平台Wifi的基本代码路径1.Wpa_supplicant源码部分external/wpa_supplicant_6/生成库libwpa_client.so和守护进程wpa_supplicant2.Wifi的HAL层代码位于hardware/libhardware_legary/wifi/3.Wifi的JNI部分位于...
  • WinCE系列全站仪usb驱动程序是一款WinCE系列全站仪连接USB驱动同步软件,适合全系列Windows操作系统,支持早期的WIN9X和当前主流操作系统XP/WIN7,支持WINSERVER2K3/2K8系统,用于WINDOWS/LINUX/MAC操作平台。...
  • 1. 复制google_latest_usb_driver_windows-master.zip到电脑终端,解压; 2. 在计算机管理总找到对应连接的Android手机设备,设备管理器中找到设备的连接位置(带黄色感叹号的Android设备标志),右键->属性,-&...
  • http://blog.csdn.net/jiang_dlut/article/details/5832237: 这个...usbhub发现新设备的插入时, 先用device来进行dvice_add(见usb_alloc_dev, 其中dev->dev.type = &usb_device_type; 这个表示是整个usb de...
  • 文件路径为kernel/driver/usb/usb_skelton.c该文件是usb驱动的一个框架,很多usb的驱动都可以在这个文件的基础上进行修改得到.下面就是该源文件,中文部分是我的注释,如有错误的地方,欢迎指出./** USB Skeleton driver...
  • #KVER:= 2.6.24.7_$(ARCH)本文引用地址:http://www.eepw.com.cn/article/201808/385301.htm修改第96行,指定2.6.12内核路径:KSRC:= /test/yle...下载8712u.ko驱动到目标板。2.5 安装wirelesstools[3]无线网卡配置...
  • 获取已加载的驱动列表 lsmod 加载驱动文件 参数为驱动完整路径 insmod /lib/modules/ax88179_178a.ko ifconfig eth1 up 卸载驱动 参数为lsmod获取到的驱动名称,而不是路径 rmmod ax88179_178a
  • ------------------------------------------本文系本站原创,欢迎转载!转载请注明出处:...在usb2.0规范中,将其定义成了一个分层模型.linux中的代码也是按照这个分层模型来设计的.具体的分...
  • Windows Usb驱动打印

    2021-02-26 21:31:24
    PID_0100#0001B0000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}USB小票打印解决办法一、需要驱动,无需更改程序安装USB打印驱动,然后共享打印机,通过 “\\计算机\打印机名”的形式,按端口方式写。1二、直接写USB...
  • 在眺望电子TW-IMX6DL-EVM开发板上出厂内核镜像默认未配置USB摄像头驱动,需要在内核中添加UVC驱动。。 编译环境及开发包: 主机:ubuntu18.04 交叉编译器:arm-linux-gnueabihf-gcc 开发板:TW-IMX6DL-EVM Linux:...
  • 本发明涉及QNX软件技术领域,尤其涉及一种QNX系统的USB驱动加载方法。背景技术:QNX系统是由加拿大QSSL公司(QNX Software System Ltd.)开发的分布式实时操作系统,以其稳定著称,因此非常适合作用对稳定性要求较高的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 32,178
精华内容 12,871
关键字:

usb驱动路径