5.USB驱动--四:USB 鼠标驱动

mac2024-01-27  35

目标: USB 鼠标用作按键:(相当于输入子系统) 左键 – L 右键 – S 中键 – Enter

直接在基础框架的probe函数中完善代码,使用input系统: 1.分配一个input_dev结构体*/ myusb_mouse_dev = input_allocate_device(); /2.设置input_dev结构体/

/*2.1能产生哪类事件*/ set_bit(EV_KEY, myusb_mouse_dev->evbit); set_bit(EV_REP,myusb_mouse_dev->evbit); /*2.2能产生这类事件下哪些事件*/ set_bit(KEY_L, myusb_mouse_dev->keybit); set_bit(KEY_S, myusb_mouse_dev->keybit); set_bit(KEY_ENTER, myusb_mouse_dev->keybit);

/3.注册input_dev结构体/ input_register_device(myusb_mouse_dev);

/4.硬件操作 /A数据传输三要素:源,目的,长度/ /*a.源:usb设备的某个端点pipe (int型) */

pipe =usb_rcvintpipe(dev, endpoint) //创建一个接收(rcv)中断(int)类型的端点管道(pipe),用来端点和数据缓冲区之间的连接,鼠标为接收中断型 dev: usb_device设备结构体 endpoint:为端点描述符的成员endpoint->bEndpointAddress //端点地址 对于控制类型的端点管道使用: usb_sndctrlpipe()/usb_rcvctrlpipe() 对于实时类型的端点管道使用: usb_sndisocpipe()/usb_sndisocpipe() 对于批量类型的端点管道使用: usb_sndbulkpipe()/usb_rcvbulkpipe()

端点地址位于: ;接口结构体->当前激活的接口结构体->这个端点结构体[0]->端点描述符下 即 usb_interface.cur_altsetting.endpoint[0].desc的成员内 这个宏“usb_rcvintpipe(dev,endpoint)”就包含了 USB 设备的地址,和哪一号端点(端点地址)。 “PIPE_INTERRUPT”中断类型端点。 “USB_DIR_IN”端点的方向。 “源-pipe”是个整数,这个整数里含有端点的类型-PIPE_INTERRUPT,和端点的方向–USB_DIR_IN。 “__create_pipe(dev,endpoint)”这里既含有设备地址,也含有端点地址。 “devnum”:就是 USB 设备的地址(USB 设备编号)。 “endpoint”:就是端点的地址(bEndpointAddress)也是端点的一个编号(也是整数)。

b.长度:一个端点的最大包大小(int型) 位于端点描述符内 len = usb_endpoint_descriptor->wMaxPacketSize

c.目的:从usb读取数据,读到一个缓冲区(为char型缓冲区虚拟地址) 分配一个缓冲区,不能用 kalloc 等 ,是用“usb_buffer_alloc()函数

void *usb_buffer_alloc( struct usb_device *dev, //usb_device设备结构体 size_t size, //配的缓冲区大小,即长度len gfp_t mem_flags, //分配内存的参数,这里填GFP_ATOMIC,表示从不睡眠 dma_addr_t *dma //缓冲区分配成功后,返回的DMA缓冲区物理地址 ) 函数功能:分配usb缓冲区,同时可以得到分配缓冲区的虚拟地址(char类型)和物理地址 (u32型) 返回值:缓冲区的虚拟地址(char类型)

B使用三要素:构建urb–usb请求块USB传输数据时,就是打包成urb结构体来传输 /1.分配一个urb结构体/ mouse_urb = usb_alloc_urb(iso_packets, mem_flags); /分配一个urb数据结构体, 分配成功返回一个urb结构体 urb全称为usb request block,USB传输数据时,就是打包成urb结构体来传输 iso_packets:表示iso类型的包个数,这里我们不是iso类型包,直接填0 mem_flags:分配内存的参数,这里填入GFP_KERNEL,正常分配/ 2,使用三要素前要设置 urb 。 a,Usb_fill_int_urb():fill(填充)中断类型的 urb。 inline void usb_fill_int_urb (struct urb *urb, struct usb_device *dev, unsigned int pipe, //三要素:源 void *transfer_buffer, //三要素:目的 int buffer_length, //三要素:长度 usb_complete_t complete_fn, //complete_fn 完成函数。 void *context, //给 complete_fn 使用 int interval) //中断方式是通过查询,查询有多频繁(interval)。 鼠标是中断传输,实际上 USB 设备(鼠标)并没有主动通知“USB 主机控制器”的能 力,即没有打断“USB 主机控制器”的能力。如何保证数据是“及时”的–用不断的查询。这个查询不是由 CPU 来查询,是由“USB 主机控制器”来不断查询,查询到数据后,USB 主机控制器发出中断(USB 主机控制器有中断 CPU 的能力)。USB 设备却没有中断“USB 主机控制器”的能力。USB 设备(USB 鼠标)所谓的“中断传输”指“USB 主机控制器”不断的查询“USB 设备”是否有数据过来。当“USB 主机控制器”得到数据后,“USB 总线驱动程序”就会调用“complete_fn–完成函数” “查询频率”:中断方式是通过查询,查询有多频繁(interval)。端点描述符中有个“interval–间隔、间隙”。 b,USB 主机控制器得到“USB 设备”的数据后,要往某个内存去写。它需要的是物理 地址。所以要告诉“USB 主机控制器”某个内存的物理地址。 c,设置某些标记(不知道其意思)。 //使用三要素: //6.4,分配一个 usb request block(USB 请求块) uk_urb = usb_alloc_urb(0, GFP_KERNEL); //6.5,使用三要素设置 urb //6.5.1,填充中断类型的 urb。 usb_fill_int_urb(uk_urb, dev, pipe, usb_buf,len,usbmouse_as_key_irq, NULL, endpoint->bInterval); //6.5.2,USB 主机控制收到 USB 设备数据要写到一个内存的物理地址. uk_urb->transfer_dma = usb_buf_phys; //6.5.3,设置某些标记 uk_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;

3,使用“urb”:提交 urb.usb_submit_urb() usb_submit_urb(mouse_urb, GFP_KERNEL); /初始化urb和中断函数退出时,都要重新提交一次,告诉内核初始化内存缓存等/

disconnect 函数 static void usbmouse_as_key_disconnect(struct usb_interface *intf) { struct usb_device *dev = interface_to_usbdev (intf); //从形参 intf 接口到 usb_device USB 设备结构体. //printk(“disconnect usbmouse!\n”); //1.4.1,提交过 urb ,这里杀掉 urb usb_kill_urb(uk_urb); //1.4.2,分配过 urb ,这里释放 urb usb_free_urb(uk_urb); //1.4.3,分配过主机控制器从 USB 设备读数据后存放的 buffer,这里释放 usb_buffer_free(dev, len, usb_buf, usb_buf_phys); //1.4.4,注册过 uk_dev ,这里卸载掉. input_unregister_device (uk_dev); //1.4.5,为 uk_dev 结构分配过空间,这里释放 input_free_device (uk_dev); }

最新回复(0)