Linux USB 鼠标驱动程序详解Word文件下载.docx
- 文档编号:16242250
- 上传时间:2022-11-21
- 格式:DOCX
- 页数:14
- 大小:22.07KB
Linux USB 鼠标驱动程序详解Word文件下载.docx
《Linux USB 鼠标驱动程序详解Word文件下载.docx》由会员分享,可在线阅读,更多相关《Linux USB 鼠标驱动程序详解Word文件下载.docx(14页珍藏版)》请在冰豆网上搜索。
/*
*$Id:
usbmouse.c,v1.152001/12/2710:
37:
41vojtechExp$
*
*Copyright(c)1999-2001VojtechPavlik
*USBHIDBPMousesupport
*/
#include<
linux/kernel.h>
linux/slab.h>
linux/module.h>
linux/init.h>
linux/usb/input.h>
linux/hid.h>
*VersionInformation
#defineDRIVER_VERSION"
v1.6"
#defineDRIVER_AUTHOR"
VojtechPavlik<
vojtech@ucw.cz>
"
#defineDRIVER_DESC"
USBHIDBootProtocolmousedriver"
#defineDRIVER_LICENSE"
GPL"
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
*鼠标结构体,用于描述鼠标设备。
structusb_mouse
{
/*鼠标设备的名称,包括生产厂商、产品类别、产品等信息*/
charname[128];
/*设备节点名称*/
charphys[64];
/*USB鼠标是一种USB设备,需要内嵌一个USB设备结构体来描述其USB属性*/
structusb_device*usbdev;
/*USB鼠标同时又是一种输入设备,需要内嵌一个输入设备结构体来描述其输入设备的属性*/
structinput_dev*dev;
/*URB请求包结构体,用于传送数据*/
structurb*irq;
/*普通传输用的地址*/
signedchar*data;
/*dma传输用的地址*/
dma_addr_tdata_dma;
};
*urb回调函数,在完成提交urb后,urb回调函数将被调用。
*此函数作为usb_fill_int_urb函数的形参,为构建的urb制定的回调函数。
staticvoidusb_mouse_irq(structurb*urb)
/*
*urb中的context指针用于为USB驱动程序保存一些数据。
比如在这个回调函数的形参没有传递在probe
*中为mouse结构体分配的那块内存的地址指针,而又需要用到那块内存区域中的数据,context指针则帮了
*大忙了!
*在填充urb时将context指针指向mouse结构体数据区,在这又创建一个局部mouse指针指向在probe
*函数中为mouse申请的那块内存,那块内存保存着非常重要数据。
*当urb通过USBcore提交给hc之后,如果结果正常,mouse->
data指向的内存区域将保存着鼠标的按键
*和移动坐标信息,系统则依靠这些信息对鼠标的行为作出反应。
*mouse中内嵌的dev指针,指向input_dev所属于的内存区域。
structusb_mouse*mouse=urb->
context;
signedchar*data=mouse->
data;
structinput_dev*dev=mouse->
dev;
intstatus;
*status值为0表示urb成功返回,直接跳出循环把鼠标事件报告给输入子系统。
*ECONNRESET出错信息表示urb被usb_unlink_urb函数给unlink了,ENOENT出错信息表示urb被
*usb_kill_urb函数给kill了。
usb_kill_urb表示彻底结束urb的生命周期,而usb_unlink_urb则
*是停止urb,这个函数不等urb完全终止就会返回给回调函数。
这在运行中断处理程序时或者等待某自旋锁
*时非常有用,在这两种情况下是不能睡眠的,而等待一个urb完全停止很可能会出现睡眠的情况。
*ESHUTDOWN这种错误表示USB主控制器驱动程序发生了严重的错误,或者提交完urb的一瞬间设备被拔出。
*遇见除了以上三种错误以外的错误,将申请重传urb。
switch(urb->
status)
{
case0:
/*success*/
break;
case-ECONNRESET:
/*unlink*/
case-ENOENT:
case-ESHUTDOWN:
return;
/*-EPIPE:
shouldclearthehalt*/
default:
/*error*/
gotoresubmit;
}
*向输入子系统汇报鼠标事件情况,以便作出反应。
*data数组的第0个字节:
bit0、1、2、3、4分别代表左、右、中、SIDE、EXTRA键的按下情况;
*data数组的第1个字节:
表示鼠标的水平位移;
*data数组的第2个字节:
表示鼠标的垂直位移;
*data数组的第3个字节:
REL_WHEEL位移。
input_report_key(dev,BTN_LEFT,data[0]&
0x01);
input_report_key(dev,BTN_RIGHT,data[0]&
0x02);
input_report_key(dev,BTN_MIDDLE,data[0]&
0x04);
input_report_key(dev,BTN_SIDE,data[0]&
0x08);
input_report_key(dev,BTN_EXTRA,data[0]&
0x10);
input_report_rel(dev,REL_X,data[1]);
input_report_rel(dev,REL_Y,data[2]);
input_report_rel(dev,REL_WHEEL,data[3]);
*这里是用于事件同步。
上面几行是一次完整的鼠标事件,包括按键信息、绝对坐标信息和滚轮信息,输入子
*系统正是通过这个同步信号来在多个完整事件报告中区分每一次完整事件报告。
示意如下:
*按键信息坐标位移信息滚轮信息EV_SYC|按键信息坐标位移信息滚轮信息EV_SYC...
input_sync(dev);
*系统需要周期性不断地获取鼠标的事件信息,因此在urb回调函数的末尾再次提交urb请求块,这样又会
*调用新的回调函数,周而复始。
*在回调函数中提交urb一定只能是GFP_ATOMIC优先级的,因为urb回调函数运行于中断上下文中,在提
*交urb过程中可能会需要申请内存、保持信号量,这些操作或许会导致USBcore睡眠,一切导致睡眠的行
*为都是不允许的。
resubmit:
status=usb_submit_urb(urb,GFP_ATOMIC);
if(status)
err("
can'
tresubmitintr,%s-%s/input0,status%d"
mouse->
usbdev->
bus->
bus_name,
devpath,status);
}
*打开鼠标设备时,开始提交在probe函数中构建的urb,进入urb周期。
staticintusb_mouse_open(structinput_dev*dev)
structusb_mouse*mouse=dev->
private;
irq->
dev=mouse->
usbdev;
if(usb_submit_urb(mouse->
irq,GFP_KERNEL))
return-EIO;
return0;
*关闭鼠标设备时,结束urb生命周期。
staticvoidusb_mouse_close(structinput_dev*dev)
usb_kill_urb(mouse->
irq);
*驱动程序的探测函数
staticintusb_mouse_probe(structusb_interface*intf,conststructusb_device_id*id)
/*
*接口结构体包含于设备结构体中,interface_to_usbdev是通过接口结构体获得它的设备结构体。
*usb_host_interface是用于描述接口设置的结构体,内嵌在接口结构体usb_interface中。
*usb_endpoint_descriptor是端点描述符结构体,内嵌在端点结构体usb_host_endpoint中,而端点
*结构体内嵌在接口设置结构体中。
structusb_device*dev=interface_to_usbdev(intf);
structusb_host_interface*interface;
structusb_endpoint_descriptor*endpoint;
structusb_mouse*mouse;
structinput_dev*input_dev;
intpipe,maxp;
interface=intf->
cur_altsetting;
/*鼠标仅有一个interrupt类型的in端点,不满足此要求的设备均报错*/
if(interface->
desc.bNumEndpoints!
=1)
return-ENODEV;
endpoint=&
interface->
endpoint[0].desc;
if(!
usb_endpoint_is_int_in(endpoint))
*返回对应端点能够传输的最大的数据包,鼠标的返回的最大数据包为4个字节,数据包具体内容在urb
*回调函数中有详细说明。
pipe=usb_rcvintpipe(dev,endpoint->
bEndpointAddress);
maxp=usb_maxpacket(dev,pipe,usb_pipeout(pipe));
/*为mouse设备结构体分配内存*/
mouse=kzalloc(sizeof(structusb_mouse),GFP_KERNEL);
/*input_dev*/
input_dev=input_allocate_device();
mouse||!
input_dev)
gotofail1;
*申请内存空间用于数据传输,data为指向该空间的地址,data_dma则是这块内存空间的dma映射,
*即这块内存空间对应的dma地址。
在使用dma传输的情况下,则使用data_dma指向的dma区域,
*否则使用data指向的普通内存区域进行传输。
*GFP_ATOMIC表示不等待,GFP_KERNEL是普通的优先级,可以睡眠等待,由于鼠标使用中断传输方式,
*不允许睡眠状态,data又是周期性获取鼠标事件的存储区,因此使用GFP_ATOMIC优先级,如果不能
*分配到内存则立即返回0。
data=usb_buffer_alloc(dev,8,GFP_ATOMIC,&
mouse->
data_dma);
data)
*为urb结构体申请内存空间,第一个参数表示等时传输时需要传送包的数量,其它传输方式则为0。
*申请的内存将通过下面即将见到的usb_fill_int_urb函数进行填充。
irq=usb_alloc_urb(0,GFP_KERNEL);
irq)
gotofail2;
/*填充usb设备结构体和输入设备结构体*/
usbdev=dev;
dev=input_dev;
/*获取鼠标设备的名称*/
if(dev->
manufacturer)
strlcpy(mouse->
name,dev->
manufacturer,sizeof(mouse->
name));
product)
strlcat(mouse->
name,"
"
sizeof(mouse->
product,sizeof(mouse->
strlen(mouse->
name))
snprintf(mouse->
name,sizeof(mouse->
name),
USBHIDBPMouse%04x:
%04x"
le16_to_cpu(dev->
descriptor.idVendor),
descriptor.idProduct));
*填充鼠标设备结构体中的节点名。
usb_make_path用来获取USB设备在Sysfs中的路径,格式
*为:
usb-usb总线号-路径名。
usb_make_path(dev,mouse->
phys,sizeof(mouse->
phys));
phys,"
/input0"
/*将鼠标设备的名称赋给鼠标设备内嵌的输入子系统结构体*/
input_dev->
name=mouse->
name;
/*将鼠标设备的设备节点名赋给鼠标设备内嵌的输入子系统结构体*/
phys=mouse->
phys;
*input_dev中的input_id结构体,用来存储厂商、设备类型和设备的编号,这个函数是将设备描述符
*中的编号赋给内嵌的输入子系统结构体
usb_to_input_id(dev,&
input_dev->
id);
/*cdev是设备所属类别(classdevice)*/
cdev.dev=&
intf->
/*evbit用来描述事件,EV_KEY是按键事件,EV_REL是相对坐标事件*/
evbit[0]=BIT(EV_KEY)|BIT(EV_REL);
/*keybit表示键值,包括左键、右键和中键*/
keybit[LONG(BTN_MOUSE)]=BIT(BTN_LEFT)|BIT(BTN_RIGHT)|BIT(BTN_MIDDLE);
/*relbit用于表示相对坐标值*/
relbit[0]=BIT(REL_X)|BIT(REL_Y);
/*有的鼠标还有其它按键*/
keybit[LONG(BTN_MOUSE)]|=BIT(BTN_SIDE)|BIT(BTN_EXTRA);
/*中键滚轮的滚动值*/
relbit[0]|=BIT(REL_WHEEL);
/*input_dev的private数据项用于表示当前输入设备的种类,这里将鼠标结构体对象赋给它*/
private=mouse;
/*填充输入设备打开函数指针*/
open=usb_mouse_open;
/*填充输入设备关闭函数指针*/
close=usb_mouse_close;
*填充构建urb,将刚才填充好的mouse结构体的数据填充进urb结构体中,在open中递交urb。
*当urb包含一个即将传输的DMA缓冲区时应该设置URB_NO_TRANSFER_DMA_MAP。
USB核心使用
*transfer_dma变量所指向的缓冲区,而不是transfer_buffer变量所指向的。
*URB_NO_SETUP_DMA_MAP用于Setup包,URB_NO_TRANSFER_DMA_MAP用于所有Data包。
usb_fill_int_urb(mouse->
irq,dev,pipe,mouse->
data,
(maxp>
8?
8:
maxp),
usb_mouse_irq,mouse,endpoint->
bInterval);
transfer_dma=mouse->
data_dma;
transfer_flags|=URB_NO_TRANSFER_DMA_MAP;
/*向系统注册输入设备*/
input_register_device(mouse->
dev);
*一般在probe函数中,都需要将设备相关信息保存在一个usb_interface结构体中,以便以后通过
*usb_get_intfdata获取使用。
这里鼠标设备结构体信息将保存在intf接口结构体内嵌的设备结构体中
*的driver_data数据成员中,即intf->
dev->
dirver_data=mouse。
usb_set_intfdata(intf,mouse);
fail2:
usb_buffer_free(dev,8,mouse->
data,mouse->
da
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Linux USB 鼠标驱动程序详解 鼠标 驱动程序 详解