现象:把usb设备接入电脑

1.Windows发现设备

2.跳出一个对话框提示安装驱动程序

问1:既然没有驱动程序,为什么了够知道是什么驱动了??

答1:Windows里面已经有了usb总线驱动程序,接入usb设备后,是“总线驱动程序知道”是什么驱动。提示安装设备驱动程序

  usb总线驱动程序负责识别USB设备,给usb设备找到对应的驱动程序

问2.usb设备种类多,为什么接入电脑就能够识别出来了?

答2.PC和USB设备都的遵守一些规范。

  比如:USB接入电脑后PC机会发出,读取设备类型的命令(描述符)。然后USB设备就回答给PC机(描述符)。

问3.PC机上接有非常多的USB设备,怎么分辨?

答3.接在USB总线上的每个USB设备都有自己的编号(地址)PC机想访问某个USB设备的时候,发出的信息都有对方的编号(地址)

问4.USB设备刚接入PC的时候还没有编号,那么PC怎么把分配的编号告诉

答4.新接入的USB设备的默认编号为0,在没有分配新的编号前。PC使用0编号和USB通讯。

问5.为什么一接入USB设备,PC机就能发现USB设备

答5.PC的USB口内部。D-和D+接了下拉电阻,没有接入USB的时候为低电平,USB设备的USB口内部,D-或D+接了上啦电阻,接入时就有一个硬件的信号通知PC机有USB设备接入。  

其它概念:

1.USB是主从设备(主从结构)

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

  例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来读数据,只能被动的等待PC机来读取数据

2.USB的传输类型

a.控制传输:可靠,时间有保证,比如USB设备的识别过程

b.批量传输:可靠,时间没有保证,U盘

c.中断传输:可靠,实时,USB鼠标

d.实时传输:不可靠,实时,USB摄像头

3.USB传输的对象:端点(endpoint)

  读写U盘,可以细化为:把数据写到u盘的端点1,从u盘的端点2读出数据

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

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

4.每一个端点都有传输类型,传输方向。

5.术语里,程序里说的输入(IN)输出(OUT)。都是基于USB主机的立场说的。

  比如说对于鼠标,数据是从鼠标传输到PC机的。对应的端点称为“输出端点”

USB驱动

设备驱动:          1.知道数据的含义。

USB总线驱动程序(的作用)----> 1.识别设备

               2.找到并安装对应的USB设备驱动

               3.提供USB读写函数

硬件:    USB主机控制器

USB驱动程框架:

APP:

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

    USB设备驱动程序

内核--------------------------------------

    USB总线驱动程序

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

     USB主机控制器

  
硬件   ---------------------

      USB设备

/*****************************USB总线驱动程序****************************************/

USB设备驱动程序编写:

1.分配/设置usb_derver结构体

  .id_table  表示支持哪些usb设备

.probe

  .disconnect

2.注册

测试:

1.make munconfig 去掉内核中原来的usb鼠标驱动

-> Device Drivers

-> HID Devices

< > USB Human Interface Device (full HID) support

2.make uImage  并使用新的内核启动

使用新内核启动:nfs 30000000 192.168.1.102:/home/book/work/nfs_root/first_fs/uImage_nohid; 30000000

挂接根文件系统:mount -t nfs -o nolock,vers=2 192.168.1.102:/home/book/work/nfs_root/first_fs  /mut

3.insmod usbmonus_as_key.ko

实验1:

目的:通过控制台将数据数据移动按下数据打印出来。

步骤1:得到  usb_host_interface  结构体

interface = intf->cur_altsetting;//interface结构体

步骤2:获取端点描述符

endpoint = &interface->endpoint[0].desc;//端点描述符

步骤3://1.分配一个input_dev 结构体

uk_dev = input_allocate_device();

步骤4:设置uk_dev结构体

步骤5:注册input_dev结构体

步骤6:硬件相关的操作 (使用usb总线设备驱动来收发数据)

//数据传输的三要素: 源 、目的、长度
//源:USB的某个端点

代码分为:

usbmouse_as_key_probe函数(初始化需要操作鼠标的设置)

usbmouse_as_key_irq函数(当鼠标有数据变化时将调用这个函数)

usbmouse_as_key_disconnect函数(鼠标的断开处理函数)

usbmouse_as_key_probe代码如下:

static int usbmouse_as_key_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
/*打印厂家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;//interface结构体 endpoint = &interface->endpoint[].desc;//端点描述符
#if 0
struct usb_device *dev = interface_to_usbdev(intf);//通过 interface_to_usbdev接口函数得到 usb_device id
printk("bcd_USB = %x\n",dev->descriptor.bcdUSB);
printk("vid = 0x%x\n",dev->descriptor.idVendor);
printk("pid = 0x%x\n",dev->descriptor.idProduct);
printk("found usbmonuse!\n");
#endif //1.分配一个input_dev 结构体
uk_dev = input_allocate_device(); //2.设置分配的这个结构体
//2.1能产生那类事件
set_bit(EV_KEY, uk_dev->evbit);//设置能够产生按键类事件uk_dev->evbit是表示能够产生那类事件
set_bit(EV_REP, uk_dev->evbit);//设置能够产生重复类事件uk_dev->evbit是表示能够产生那类事件
//2.2能产生哪些事件
set_bit(KEY_L,uk_dev->keybit);//通过设置uk_dev->keybit 实现产生一个KEY_L的事件 (相当于按键按下 L 键)
set_bit(KEY_S,uk_dev->keybit);//通过设置uk_dev->keybit 实现产生一个KEY_S的事件 (相当于按键按下 S 键)
set_bit(KEY_ENTER,uk_dev->keybit);//通过设置uk_dev->keybit 实现产生一个KEY_ENTER的事件 (相当于按键按下 ENTER 键)
//3.注册input_dev结构体
input_register_device(uk_dev);
//4.硬件相关的操作 (使用usb总线设备驱动来收发数据)
//数据传输的三要素: 源 、目的、长度
//源:USB的某个端点
pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); //长度:
len =endpoint->wMaxPacketSize;//长度等于端点描述符的wMaxPacketSize(最大包大小) //目的:使用usb_buffer_alloc分配一个数据缓冲区
usb_buf=usb_buffer_alloc(dev, len, GFP_ATOMIC, &usb_buf_pyhs); //使用三要素 usb requset block
uk_urb = usb_alloc_urb(, GFP_KERNEL); //使用三要素 设置usb requset block
/* usb请求块, */
usb_fill_int_urb(uk_urb, dev, pipe, usb_buf, len, usbmouse_as_key_irq, NULL, endpoint->bInterval);
uk_urb->transfer_dma = usb_buf_pyhs;//设置usb传输的目的 的物理地址
uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;//设置标记 //使用urb
usb_submit_urb (uk_urb, GFP_KERNEL);//提交数据 提交urb
return ;
}

usbmouse_as_key_irq代码如下:(当鼠标数据发生变化时执行此函数)

static void usbmouse_as_key_irq(struct urb *urb)
{
int i;
static int cnt=;
/*将鼠标数据打印出来*/
printk("usb data %d: ",++cnt);
for(i=;i<len;i++)
{
printk("%02x ",usb_buf[i]);
}
printk("\n");
//重新提交urb
usb_submit_urb (uk_urb, GFP_KERNEL);//提交数据 提交urb
}

usbmouse_as_key_disconnect代码如下:其实就是usbmouse_as_key_probe的逆向操作

static void usbmouse_as_key_disconnect(struct usb_interface *intf)
{
struct usb_device *dev = interface_to_usbdev(intf); //printk("dsiconnect usbmonuse!\n");
usb_kill_urb (uk_urb);//清除urb
usb_free_urb(uk_urb);//释放urb
usb_buffer_free(dev,len,usb_buf,usb_buf_pyhs);//去除 usb_buf
input_unregister_device(uk_dev);
input_free_device(uk_dev);
}

测试步骤:

1、insmod usbmonus_as_key.ko  挂载驱动

2、ls /dev/event*        查看事件

3、移动或者按下鼠标

数据1:按键值

数据2:x方向位移 数据

数据3:y方向位移 数据

数据4:滚轮数据

实验2:

目的:使用鼠标上的按键实现  L  S 和ENTER 键值  在控制台上输出

通过实验一,已经将鼠标数据读了出来,所以要实现按键的话只关心第一个数据就可以了

所以只需要修改usbmouse_as_key_disconnect

static void usbmouse_as_key_irq(struct urb *urb)
{
static int pre_val;//用来保存上次的数据 #if 0
int i;
static int cnt=; /*将鼠标数据打印出来*/
printk("usb data %d: ",++cnt);
for(i=;i<len;i++)
{
printk("%02x ",usb_buf[i]);
}
printk("\n");
#endif /*
* USB鼠标数据含义
* data[0]:bit0-左键 1-按下 0-松开
* bit1-右键 1-按下 0-松开
* bit2-中键 1-按下 0-松开
*/
if((pre_val & (<<)) != (usb_buf[] & (<<)))
{
//左键发生了变化
input_event(uk_dev,EV_KEY,KEY_L,(usb_buf[] & (<<))? : );//使用input_event上报按键事件
input_sync(uk_dev);//同步信号
}
if((pre_val & (<<)) != (usb_buf[] & (<<)))
{
//右键发生了变化
input_event(uk_dev,EV_KEY,KEY_S,(usb_buf[] & (<<))? : );//使用input_event上报按键事件
input_sync(uk_dev);//同步信号
}
if((pre_val & (<<)) != (usb_buf[] & (<<)))
{
//中键发生了变化
input_event(uk_dev,EV_KEY,KEY_ENTER,(usb_buf[] & (<<))? : );//使用input_event上报按键事件
input_sync(uk_dev);//同步信号
}
pre_val = usb_buf[];
//重新提交urb
usb_submit_urb (uk_urb, GFP_KERNEL);//提交数据 提交urb
}

使用/dev/tty1 测试:

使用hexdump /dev/event1 测试:

liunx驱动----USB驱动的更多相关文章

  1. 【驱动】USB驱动实例·串口驱动·键盘驱动

    Preface   USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_driver结构描述.    对于不同类型的 USB设备,内核使用传统的设备驱动模型建立设备驱动 ...

  2. 【驱动】USB驱动实例·串口驱动·键盘驱动【转】

    转自:http://www.cnblogs.com/lcw/p/3159370.html Preface USB体系支持多种类型的设备. 在 Linux内核,所有的USB设备都使用 usb_drive ...

  3. usb驱动开发24之接口驱动

    从第一节我们已经知道,usb_generic_driver在自己的生命线里,以一己之力将设备的各个接口送给了linux的设备模型,让usb总线的match函数,也就是usb_device_match, ...

  4. Linux内核USB驱动【转】

    本文转载自:http://www.360doc.com/content/12/0321/14/8363527_196286673.shtml 注意,该文件是2.4的内核的驱动源文件,并不保证在2.6内 ...

  5. USB驱动开发大全【转】

    本文转载自:http://www.360doc.com/content/12/0504/19/8363527_208666082.shtml 编写USB驱动程序步骤:1所有usb驱动都必须创建主要结构 ...

  6. usb驱动开发15之设备生命线

    总算是进入了HCD的片儿区,既然来到一个片区,怎么都要去拜会一下山头几个大哥吧.,先回忆一些我们怎么到这里的?给你列举一个调用函数过程usb_control_msg->usb_internal_ ...

  7. usb驱动开发14之设备生命线

    直接看代码吧. /*-------------------------------------------------------------------*/ /** * usb_submit_urb ...

  8. usb驱动开发12之设备生命线

    函数usb_control_msg完成一些初始化后调用了usb_internal_control_msg之后就free urb.剩下的活,全部留给usb_internal_control_msg去做了 ...

  9. usb驱动开发10之usb_device_match

    在第五节我们说过会专门分析函数usb_device_match,以体现模型的重要性.同时,我们还是要守信用的. 再贴一遍代码,看代码就要不厌其烦. static int usb_device_matc ...

随机推荐

  1. react-native 打开设置界面

    iOS iOS打开设置还是比较简单的,使用Linking组件即可: Linking.openURL('app-settings:') .catch(err => console.log('err ...

  2. [LeetCode] All Paths From Source to Target 从起点到目标点到所有路径

    Given a directed, acyclic graph of N nodes.  Find all possible paths from node 0 to node N-1, and re ...

  3. JavaScript基础知识(Math的方法)

    Math的方法 Math : 对象数据类型 : Math: {} 是window下的一个键值对: 属性名叫Math,属性值是一个对象 var obj = {a:1}; console.log(obj. ...

  4. NIOS_UART

    1.Fifoed avalon UART带缓冲区,使用非常方便,google下载,google上有的技术资料,百度上找不到,以为没有这个事情: 2.两种UART如果想用操作寄存器的方式操作,需要在al ...

  5. Mac苹果电脑没有声音怎么办

    有时候 Mac 从睡眠状态恢复之后没有声音,这是 Mac OS X 系统的一个 Bug.这是因为 Mac OS X 的核心音频守护进程「coreaudiod」出了问题,虽然简单的重启电脑就能解决,但是 ...

  6. Autofac之生命周期和事件

    Autofac为注册的类型对象提供了一套生命周期事件,覆盖了一个类型从注册到最后“释放”的一套事件.有了这些事件,我们可以相对方便的在类型对象的各个阶段进行AOP操作. builder.Registe ...

  7. Python_tkinter(3)_grid布局

    Grid(网格)布局管理器,是Tkinter里面最灵活的几何管理布局器.注意:不要试图在一个主窗口中混合使用pack和grid. 1.简单的布局 from tkinter import * root ...

  8. vue 父组件给子组件传值,子组件给父组件传值

    父组件如何给子组件传值 使用props 举个例子: 子组件:fromTest.vue,父组件 app.vue fromTest.vue <template> <h2>{{tit ...

  9. React之ref

    作为响应式开发框架React,我们知道他是数据驱动的,但有时候避免不了还是得动用到DOM操作,这个时候我们就可以用到ref:用法如下: 然后这样做有个弊端,当一个 ul 下面的 li 是动态添加的时候 ...

  10. JDK1.8 LongAdder 空间换时间: 比AtomicLong还高效的无锁实现

    我们知道,AtomicLong的实现方式是内部有个value 变量,当多线程并发自增,自减时,均通过CAS 指令从机器指令级别操作保证并发的原子性. // setup to use Unsafe.co ...