USB在接入系统的时候,以0的设备ID和主机通信,然后由主机为其分配新的ID。

在主机端,D+和D-都是下拉接地的。而设备端的D-接上拉时,表明此设备为高速设备:12M/s。 D+接上拉时则是全速设备:480M/S。

PC的USB口中的D+D-有15K的下拉电阻,未接USB设备时,皆为低电平。

而设备中的D+D-则是1.5K的上拉电阻。一旦接入PC中,电脑就会知道有设备接入。

USB是主从结构。所有的传输都是由主机发起的,即USB设备没有主动通知USB主机的能力。

USB的传输类型:

    控制传输。 可靠,时间有保证。 例如:USB设备的识别。

      批量传输。 可靠,但时间没有保证。 例如:U盘。

    中断传输。 可靠,实时传输。  例如:USB鼠标。

    实时传输。 不可靠。实时传输。  例如:USB摄像头。

USB传输的对象为端点。比如读U盘和写U盘,可以形容为从端点1读数据,从端点2写数据。

    除了端点0以外,每个端点只支持一个方向的数据传输。

    端点0用于控制传输,既能输出也能输入。

每一个端点都有传输类型和方向。

程序和术语中说的输入输出 都是基于USB主机的立场说的。

  比如鼠标是数据从鼠标传输到PC机的,鼠标对应的端点称为输入端点。

USB总线驱动程序的作用: 1.识别设备  2. 查找并安装对应的设备驱动程序  3.提供USB读写函数。

USB驱动程序框架:

app:

--------------------------------------------------------------------

          USB设备驱动程序  (拿到数据处理,驱动开发人员编写)

--------------------------------------------------------------------

            USB总线驱动程序  //1.识别  2.找到匹配的设备驱动  3.提供读写函数(不知数据含义)

--------------------------------------------------------------------

          主机控制器

         UHCI  OHCI  EHCI

--------------------------------------------------------------------

          USB设备

UHCI  intel 适用于低速和全速

OHCI  Microsoft 适用于低速和全速

EHCI   高速

1.识别设备

1.1分配地址,并告诉USB设备(set address)。

1.2 发出命令获取描述符

2. 查找并安装对应的设备驱动程序

3.提供USB读写函数。

把USB设备接到开发板上,看输出信息:

usb -: new full speed USB device using s3c2410-ohci and address            
usb -: configuration # chosen from choice

scsi0 : SCSI emulation for USB Mass Storage devices
  scsi 0:0:0:0: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: 0 ANSI: 6
  sd 0:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB)
  sd 0:0:0:0: [sda] Write Protect is off
  sd 0:0:0:0: [sda] Assuming drive cache: write through
  sd 0:0:0:0: [sda] 30277632 512-byte hardware sectors (15502 MB)
  sd 0:0:0:0: [sda] Write Protect is off
  sd 0:0:0:0: [sda] Assuming drive cache: write through
  sda: sda1
  sd 0:0:0:0: [sda] Attached SCSI removable disk

断开USB设备

usb -: USB disconnect, address 

再接上:

usb -: new full speed USB device using s3c2410-ohci and address
usb -: configuration # chosen from choice
scsi1 : SCSI emulation for USB Mass Storage devices
scsi :::: Direct-Access Kingston DataTraveler 3.0 PMAP PQ: ANSI:
sd :::: [sda] -byte hardware sectors ( MB)
sd :::: [sda] Write Protect is off
sd :::: [sda] Assuming drive cache: write through
sd :::: [sda] -byte hardware sectors ( MB)
sd :::: [sda] Write Protect is off
sd :::: [sda] Assuming drive cache: write through
sda: sda1
sd :::: [sda] Attached SCSI removable disk

然后在内核中搜索USB device using这个字符。最后发现在 drivers/usb/core/hub.c(+2186)中的hub_port_init 函数中。

逆推则发现如下调用关系:

hub_irq()

  -->> kick_khubd()

    -->> hub_thread()

      -->> hub_events()

        -->> hub_port_connect_change()

          -->>choose_address()   //分配新的USB地址

          -->> hub_port_init()

            -->> hub_set_address()  //把地址告诉USB设备

             -->> usb_get_device_descriptor()   //获取USB设备描述符

            -->> usb_get_device_descriptor()   //再获取一次USB设备描述符

            -->> usb_new_device()     

              -->> usb_get_configuration()   //读取所有的设备描述符并解析     

               -->> device_add()        //把设备放入总线的dev链表,从总线的driver链表中取出driver一一比较。

                                //usb_interface和usb_driver的id_table比较。

                                //如果匹配上了,则调用对应driver的probe函数。

    -->> 进入USB总线驱动

usb驱动测试程序:

/*************************************************************************
> File Name: usb_mouse_as_key.c
> Author:
> Mail:
> Created Time: 2016年11月04日 星期五 22时55分15秒
************************************************************************/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/usb/input.h>
#include <linux/hid.h> struct input_dev *input_dev;
signed char *usb_buff;
static dma_addr_t usb_buf_phys;
struct urb *uk_urb;
int len; static void usbmouse_as_key_irq(struct urb *urb)
{
int i;
static int cnt = ;
#if 0

static int pr_lb,pr_rb,pr_mb;
// printk("data cnt %d:",++cnt);
// for( i=0;i<len;i++ )
// {
// printk("%2.2x ",usb_buff[i]);
// }
// printk("\n");
// printk("lb:%01x rb:%01x mb:%01x\n",(usb_buff[1])&0x01,(usb_buff[1]>>1)&0x01,(usb_buff[1]>>2)&0x01);
// printk("move x:%04d y:%04d\n",(usb_buff[2]),(usb_buff[3]>>4));
if( (usb_buff[1]&0x01) != pr_lb )
{
  input_event(input_dev,EV_KEY,KEY_L,!pr_lb); /* 有事件产生时上报事件 */
  input_sync(input_dev);
}

if( ((usb_buff[1]>>1)&0x01) != pr_rb )
{
  input_event(input_dev,EV_KEY,KEY_S,!pr_rb); /* 有事件产生时上报事件 */
  input_sync(input_dev);
}


if( ((usb_buff[1]>>2)&0x01) != pr_mb )
{
  input_event(input_dev,EV_KEY,KEY_ENTER,!pr_mb); /* 有事件产生时上报事件 */
  input_sync(input_dev);
}

pr_lb = usb_buff[1]&0x01;
pr_rb = (usb_buff[1]>>1)&0x01;
pr_mb = (usb_buff[1]>>2)&0x01;

#else
printk("data cnt %d:",++cnt);
for( i=;i<len;i++ )
{
printk("%02x",usb_buff[i]);
}
printk("\n");
#endif
usb_submit_urb(uk_urb,GFP_KERNEL);
} static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
int pipe; interface = intf->cur_altsetting;
endpoint = &interface->endpoint[].desc; printk("found usbmouse_as_key\n");
printk("bcdUSB = %x\n",dev->descriptor.bcdUSB);
printk("VID = 0X%x\n",dev->descriptor.idVendor);
printk("PID = 0X%x\n",dev->descriptor.idProduct); /* 分配一个input_dev结构体 */
input_dev = input_allocate_device(); /* 设置 */
/* 能产生哪类事件 */
set_bit(EV_KEY,input_dev->evbit);
set_bit(EV_REP,input_dev->evbit); //重复类事件 /* 能产生哪些事件 */
set_bit(KEY_L,input_dev->keybit);
set_bit(KEY_S,input_dev->keybit);
set_bit(KEY_ENTER,input_dev->keybit); /* 注册 */
input_register_device(input_dev); /* 硬件相关操作 */
/* 数据传输3要素: 源、目的、长度 */
/* 源: USB设备的某个节点 */
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); /* 长度 */
len = endpoint->wMaxPacketSize; /* 目的: */
usb_buff = usb_buffer_alloc(dev, , GFP_ATOMIC, &usb_buf_phys); /* 使用3要素 */
/* USB request block */
uk_urb = usb_alloc_urb(, GFP_KERNEL);
/* 设置URB */
usb_fill_int_urb(uk_urb, dev, pipe, usb_buff,
len, usbmouse_as_key_irq, NULL, endpoint->bInterval); //bInterval 查询频率
uk_urb->transfer_dma = usb_buf_phys;
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* 使用urb */
usb_submit_urb(uk_urb,GFP_KERNEL); return ;
} static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf); printk("disconnect usbmouse_as_key\n");
usb_kill_urb(uk_urb);
usb_free_urb(uk_urb); usb_buffer_free(dev, len, usb_buff,usb_buf_phys);
input_unregister_device(input_dev);
input_free_device(input_dev);
} static struct usb_device_id usbmouse_as_key_id_table[] = {
{ USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,USB_INTERFACE_PROTOCOL_MOUSE) },
{ }/* Terminating entry */
}; /* 分配 设置 */
static struct usb_driver usbmouse_as_key_driver = {
.name= "usbmouse",
.probe= usbmouse_as_key_probe,
.disconnect= usbmouse_as_key_disconnect,
.id_table= usbmouse_as_key_id_table, }; static int mouse_init(void)
{
/* 注册 */
usb_register(&usbmouse_as_key_driver); return ;
} static void mouse_exit(void)
{
usb_deregister(&usbmouse_as_key_driver);
} module_init(mouse_init);
module_exit(mouse_exit);
MODULE_LICENSE("GPL");

卸载掉内核中的鼠标usb驱动程序。

安装我们的驱动程序,接入鼠标。

按下鼠标按键,将会在控制台看到相应的信息。

将打印信息的地方改成上报信息,即可

sd

嵌入式Linux驱动学习之路(二十)USB设备驱动的更多相关文章

  1. Linux USB驱动学习总结(二)---- USB设备驱动

    USB 设备驱动: 一.USB 描述符:(存在于USB 的E2PROM里面) 1.  设备描述符:struct usb_device_descriptor 2.  配置描述符:struct usb_c ...

  2. 嵌入式Linux驱动学习之路(二十七)字符设备驱动的另一种写法

    之前讲的字符设备驱动程序,只要有一个主设备号,那么次设备号无论是什么都会和同一个 struct file_operations 结构体对应. 而本节课讲的是如何在设备号相同的情况下,让不同的次设备号对 ...

  3. 嵌入式Linux驱动学习之路(二十五)虚拟网卡驱动程序

    一.协议栈层次对比 设备无关层到驱动层的体系结构 1).网络协议接口层向网络层协议提供提供统一的数据包收发接口,不论上层协议为ARP还是IP,都通过dev_queue_xmit()函数发送数据,并通过 ...

  4. 嵌入式Linux驱动学习之路(二十四)Nor Flash驱动程序

    Nor Flash和Nand Flash的不同: 类型 NOR Flash  Nand Flash  接口 RAM-like,引脚多 引脚少 容量 小(1M.2M...) 大(512M.1G) 读 简 ...

  5. 嵌入式Linux驱动学习之路(二十一)字符设备驱动程序总结和块设备驱动程序的引入

    字符设备驱动程序 应用程序是调用C库中的open read write等函数.而为了操作硬件,所以引入了驱动模块. 构建一个简单的驱动,有一下步骤. 1. 创建file_operations 2. 申 ...

  6. 嵌入式Linux驱动学习之路(二十二)用内存模拟磁盘

    安装驱动后,可在/dev/目录下发现已经生成了相应的设备文件. 格式化设备:mkdosfs /dev/ramblock. 挂载设备. 读写设备 . 驱动程序代码: /***************** ...

  7. 嵌入式Linux驱动学习之路(二十六)DM9000C网卡驱动程序

    基于DM9000C的原厂代码修改dm9000c的驱动程序. 首先确认内存的基地址 iobase. 确定中断号码. 打开模块的初始化函数定义. 配置内存控制器的相应时序(结合DM9000C.C的手册). ...

  8. 嵌入式linux的学习之路[转]

    我认为的一条学习嵌入式Linux的路: 1)学习 Linux系统安装. 常用命令.应用程序安装. 2) 学习 Linux 下的 C 编程.这本书必学<UNIX 环境高级编程>.<UN ...

  9. Linux内核驱动学习(三)字符型设备驱动之初体验

    Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...

随机推荐

  1. Windows下安装Nginx+php+mysql环境

    系统:Windows 7 64位系统 安装之前,首先下载软件: Nginx: http://nginx.org/en/download.html PHP Stable PHP 5.6.26: http ...

  2. 《Ext JS模板与组件基本知识框架图----模板》

    最近在整理Ext JS的模板和组件,在参考<Ext JS权威指南>,<Ext JS Web应用程序开发指南>,<Ext JS API>等相关书籍后才写下这篇< ...

  3. tomcat 自定义classpath(亲自测试)

    因为一直以来使用tomcat和weblogic作为应用服务器为主,最近在升级新中间件的过程中遇到一个问题,我们的web前端应用现在升级是进行全量包升级的,因为现在的系统架构为前端和后端通过rpc框架交 ...

  4. 使用HBaseShellPro操作Hadoop 2系列发行版CDH4.4

    前言 对于hadoop,hbase由于项目紧张原因好几个月没有时间认真的来总结下了,最近有一些空,就来继续的把项目中用到的一些技术实际的写出来,动动手,好久没有写东西了,都生疏了,说起hadoop,公 ...

  5. gulp压缩css文件跟js文件

    越到最后啊 就越发现,真的很理解那句话 就是自己多学一点一点知识,就少一句问别人的东西 这是多么痛苦的领悟 今天需要压缩css跟js文件 然后不懂啊 就问别人啊 就问啊问啊 然后再上网了解啊了解啊 用 ...

  6. [deviceone开发]-多种样式下拉菜单demo

    一.简介 该demo主要展示了3种下拉菜单. 一.仿QQ弹出菜单 主要实现原理是通过add一个ui,然后通过点击事件控制其visible属性来显示或者隐藏. 二.组合下拉菜单 主要用到的控件是do_A ...

  7. 屌丝giser成长记-研一篇(上)

    2011年本科毕业之后,我选择了保研GIS研究生,继续了我的GIS研究生涯,读研的童鞋们注意了,读研选择什么样的导师很重要,因为不同的导师有不同的人脉,从浅一点的来说,导师手头的开发项目多的话,你自己 ...

  8. 关于ArcGIS的Web 3D GIS问答

    以下问答基于ArcGIS 10.4版本,涉及的软件有 ArcGIS for Server ArcGIS for Desktop ArcGIS Pro 1.3 Esri Drone2Map 1 支持B/ ...

  9. Docker 从零开始制作基础镜像[centos]

    http://www.oschina.net/news/62897/docker-hub-contains-high-risk-vulnerabilities 这里有个统计,docker官方和个人发布 ...

  10. 自定义控件之圆形的image

    需要添加点击事件的的时候在自定义的控件中覆写OnTouchEvent():方法进行点击事件的分发 package com.example.administrator.mvp.ui.widget; im ...