实验 121 USB鼠标驱动分析.docx
- 文档编号:28590027
- 上传时间:2023-07-19
- 格式:DOCX
- 页数:18
- 大小:339.88KB
实验 121 USB鼠标驱动分析.docx
《实验 121 USB鼠标驱动分析.docx》由会员分享,可在线阅读,更多相关《实验 121 USB鼠标驱动分析.docx(18页珍藏版)》请在冰豆网上搜索。
实验121USB鼠标驱动分析
实验12-1USB鼠标驱动分析实验
【实验目的】
Ø了解一下USB的协议。
Ø掌握USB鼠标的驱动架构。
【实验步骤】
第一步:
PXA270的OHCI初始化分析;
1、PXA270USB端口配置:
打开arch\arm\march-pxa\xsbase270.c文件,xsbase270_ohci_init函数完成对PXA270UHCR初始化配置。
staticintxsbase270_ohci_init(structdevice*dev)
{
/*setupPort1GPIOpin.*/
pxa_gpio_mode(88|GPIO_ALT_FN_1_IN);/*USBHPWR1*/
pxa_gpio_mode(89|GPIO_ALT_FN_2_OUT);/*USBHPEN1*/
/*SetthePowerControlPolarityLowandPowerSense
PolarityLowtoactivelow.*/
UHCHR=(UHCHR|UHCHR_PCPL|UHCHR_PSPL)&
~(UHCHR_SSEP1|UHCHR_SSEP2|UHCHR_SSEP3|UHCHR_SSE);
return0;
}
2、xsbase270_ohci_platform_data变量完成对基于PXA结构的OHCI数据结构体的配置。
staticstructpxaohci_platform_dataxsbase270_ohci_platform_data={
.port_mode=PMM_PERPORT_MODE,
.init=xsbase270_ohci_init,
};
3、系统启动时调用xsbase270_init(void)函数,用于完成对板级硬件的配置,其中pxa_set_ohci_info(&xsbase270_ohci_platform_data);函数实现添加PXA270的OHCI数据信息,该函数主要实现整个IntelPXA架构硬件初始化。
staticvoid__initxsbase270_init(void)
{
structrtc_timewtime;
wtime=get_rtc4513_time();
xtime.tv_sec=mktime(wtime.tm_year,wtime.tm_mon,wtime.tm_mday,wtime.tm_hour,wtime.tm_min,wtime.tm_sec);
ARB_CNTRL=ARB_CORE_PARK|0x234;
pxa_gpio_mode(GPIO45_SYSCLK_AC97_MD);
platform_add_devices(platform_devices,ARRAY_SIZE(platform_devices));
xsbase270_pxafb_info.modes=&lb064v02_mode;
set_pxa_fb_info(&xsbase270_pxafb_info);
pxa_set_ohci_info(&xsbase270_ohci_platform_data);
pxa_set_mci_info(&xsbase270_mci_platform_data);
}
4、打开linux-2.6.22.10\drivers\usb\Host\Ohci-pxa27x.c文件,该文件主要实现对PXA27x的OHCI的驱动,其中ohci_hcd_pxa27x_driver驱动结构体主要由驱动侦测(ohci_hcd_pxa27x_drv_probe)、驱动移除(ohci_hcd_pxa27x_drv_remove)和驱动关闭(usb_hcd_platform_shutdown)等几个成员变量组成,该结构体最终由linux-2.6.22.10\drivers\usb\Host\ohci-hdc.c文件中的平台伪总线驱动注册函数platform_driver_register(&PLATFORM_DRIVER)调用,以完成平台在初始化过程中实现注册加载OHCIUSB总线驱动,下图为系统驱动时加载ohci驱动的信息。
linux-2.6.22.10\drivers\usb\Host\Ohci-pxa27x.c
staticstructplatform_driverohci_hcd_pxa27x_driver={
.probe=ohci_hcd_pxa27x_drv_probe,
.remove=ohci_hcd_pxa27x_drv_remove,
.shutdown=usb_hcd_platform_shutdown,
#ifdefCONFIG_PM
.suspend=ohci_hcd_pxa27x_drv_suspend,
.resume=ohci_hcd_pxa27x_drv_resume,
#endif
.driver={
.name="pxa27x-ohci",
},
};
5、运行makemenuconfig内核配置命令,在DeviceDrivers-->USBSupport配置菜单中选中<*>OHCIHCDsubpport选项,使系统支持USB的OHCI驱动,系统启动后的输出信息如下图二。
【图12-1-1】
【图12-1-2】
第二步:
USB鼠标驱动分析
1、USB鼠标驱动的初始化:
staticint__initusb_mouse_init(void)
{
intretval=usb_register(&usb_mouse_driver);
if(retval==0)
info(DRIVER_VERSION":
"DRIVER_DESC);
returnretval;
}
USB鼠标初始函数调用USB注册函数usb_register(structusb_driver*driver)注册一个USB设备驱动,在该函数里它会分配一个usb_driver对象usb_mouse_driver,该结构体中定义了USB设备的ID列表(id_table)、USB设备的插入侦测函数(probe)和断开后的断开连接函数(disconnect)等成员变量。
staticstructusb_driverusb_mouse_driver={
.name="usbmouse",
.probe=usb_mouse_probe,
.disconnect=usb_mouse_disconnect,
.id_table=usb_mouse_id_table,
};
usb_mouse_driver驱动结构体中的id_table为USB鼠标的接口类的相关信息,由于USB鼠标和键盘都属于HID类,因此在usb_mouse_id_table中利用USB_INTERFACE_INFO宏来匹配一个定义的特殊接口类。
USB_INTERFACE_CLASS_HID为接口类的值,USB_INTERFACE_SUBCLASS_BOOT接口子类的值,USB_INTERFACE_PROTOCOL_MOUSE为接口所使用的协议。
在linux-2.6.22.10/include/linux/hid.h文件中定义。
staticstructusb_device_idusb_mouse_id_table[]={
{USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID,USB_INTERFACE_SUBCLASS_BOOT,
USB_INTERFACE_PROTOCOL_MOUSE)},
{}/*Terminatingentry*/
};
/*
*USBHIDinterfacesubclassandprotocolcodes
*/
#defineUSB_INTERFACE_SUBCLASS_BOOT1
#defineUSB_INTERFACE_PROTOCOL_KEYBOARD1
#defineUSB_INTERFACE_PROTOCOL_MOUSE2
2、USB鼠标的侦测过程:
当USB鼠标插入后,操作系统便调用USB鼠标驱动探测函数,usb_mouse_probe先调用interface_to_usbdev函数获取USB设备的配置描述descriptor、然后对配置interface以及端点endpoint等相关信息进行判断。
驱动利用usb_endpoint_is_int_in函数判断USB鼠标是否具有中断的方式收发数据,如果具备,便分配USB鼠标驱动所需的pipe和最大收发包。
Linux操作系统中,USBHID驱动属于input驱动设备,所以在USB鼠标驱动侦测函数中调用input_allocate_device函数定义分配一个input设备,并调用input_register_device函数注册成一个input类设备。
USB鼠标驱动侦测函数程序并利用usb_alloc_urb函数申请一个URB,并调用usb_fill_int_urb函数填充URB内容。
staticintusb_mouse_probe(structusb_interface*intf,conststructusb_device_id*id)
{
structusb_device*dev=interface_to_usbdev(intf);
structusb_host_interface*interface;
structusb_endpoint_descriptor*endpoint;
structusb_mouse*mouse;
structinput_dev*input_dev;
intpipe,maxp;
interror=-ENOMEM;
interface=intf->cur_altsetting;
if(interface->desc.bNumEndpoints!
=1)
return-ENODEV;
endpoint=&interface->endpoint[0].desc;
if(!
usb_endpoint_is_int_in(endpoint));//判断端点是否能进行中断传输
return-ENODEV;
pipe=usb_rcvintpipe(dev,endpoint->bEndpointAddress);//获取接收pipe
maxp=usb_maxpacket(dev,pipe,usb_pipeout(pipe));//获取最大的接收包
mouse=kzalloc(sizeof(structusb_mouse),GFP_KERNEL);
input_dev=input_allocate_device();//input设备定义
if(!
mouse||!
input_dev)
gotofail1;
mouse->data=usb_buffer_alloc(dev,8,GFP_ATOMIC,&mouse->data_dma);
//数据缓冲申请
if(!
mouse->data)
gotofail1;
mouse->irq=usb_alloc_urb(0,GFP_KERNEL);//分配一个URB
if(!
mouse->irq)
gotofail2;
mouse->usbdev=dev;
mouse->dev=input_dev;
if(dev->manufacturer)//获取USB鼠标制造商信息
strlcpy(mouse->name,dev->manufacturer,sizeof(mouse->name));
if(dev->product){
if(dev->manufacturer)
strlcat(mouse->name,"",sizeof(mouse->name));
strlcat(mouse->name,dev->product,sizeof(mouse->name));
}
if(!
strlen(mouse->name))
snprintf(mouse->name,sizeof(mouse->name),
"USBHIDBPMouse%04x:
%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
usb_make_path(dev,mouse->phys,sizeof(mouse->phys));
strlcat(mouse->phys,"/input0",sizeof(mouse->phys));
input_dev->name=mouse->name;
input_dev->phys=mouse->phys;
usb_to_input_id(dev,&input_dev->id);
input_dev->dev.parent=&intf->dev;
input_dev->evbit[0]=BIT(EV_KEY)|BIT(EV_REL);
input_dev->keybit[LONG(BTN_MOUSE)]=BIT(BTN_LEFT)|BIT(BTN_RIGHT)|BIT(BTN_MIDDLE);
input_dev->relbit[0]=BIT(REL_X)|BIT(REL_Y);
input_dev->keybit[LONG(BTN_MOUSE)]|=BIT(BTN_SIDE)|BIT(BTN_EXTRA);
input_dev->relbit[0]|=BIT(REL_WHEEL);
input_set_drvdata(input_dev,mouse);
input_dev->open=usb_mouse_open;
input_dev->close=usb_mouse_close;
usb_fill_int_urb(mouse->irq,dev,pipe,mouse->data,
(maxp>8?
8:
maxp),
usb_mouse_irq,mouse,endpoint->bInterval);
mouse->irq->transfer_dma=mouse->data_dma;
mouse->irq->transfer_flags|=URB_NO_TRANSFER_DMA_MAP;
error=input_register_device(mouse->dev);
if(error)
gotofail3;
usb_set_intfdata(intf,mouse);
return0;
fail3:
usb_free_urb(mouse->irq);
fail2:
usb_buffer_free(dev,8,mouse->data,mouse->data_dma);
fail1:
input_free_device(input_dev);
kfree(mouse);
returnerror;
}
3、USB鼠标的断开连接过程:
当USB鼠标断开连接时,Linux操作系统USB核便调用usb_mouse_disconnect函数进行USB设备断开时系统资源回收,但USB鼠标断开时,首先对URB包进行处理,然后调用input_unregister_device函数注销USB鼠标驱动。
分别调用相关资源回收函数回收驱动所占有的系统资源。
staticvoidusb_mouse_disconnect(structusb_interface*intf)
{
structusb_mouse*mouse=usb_get_intfdata(intf);
usb_set_intfdata(intf,NULL);
if(mouse){
usb_kill_urb(mouse->irq);
input_unregister_device(mouse->dev);
usb_free_urb(mouse->irq);
usb_buffer_free(interface_to_usbdev(intf),8,mouse->data,mouse->data_dma);
kfree(mouse);
}
}
4、
USB鼠标设备的打开:
当应用程序利用open函数打开视频USB鼠标设备时,Linux文件系统调用usb_mouse_open函数打开USB鼠标设备。
staticintusb_mouse_open(structinput_dev*dev)
{
structusb_mouse*mouse=input_get_drvdata(dev);
mouse->irq->dev=mouse->usbdev;
if(usb_submit_urb(mouse->irq,GFP_KERNEL))
return-EIO;
return0;
}
该函数先调用input_get_drvdata函数从input文件节点获取相关数据,由于USB鼠标采用中断进行数据的传送,所以在打开函数中调用usb_submit_urb函数提交一个URB请求。
5、USB数鼠标据的获取:
当鼠标进行操作时,便产生一个中断,分别调用input_report_key和input_report_rel函数提交鼠标的按键和飞梭操作,在这两个函数中,实际上调用了input_event函数产生一个事件操作(参考linux-2.6.22.10/drivers/input.c文件),然后再调用usb_submit_urb函数提交下一次数据的传输过程。
staticvoidusb_mouse_irq(structurb*urb)
{
structusb_mouse*mouse=urb->context;
signedchar*data=mouse->data;
structinput_dev*dev=mouse->dev;
intstatus;
……
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]);//鼠标飞梭
input_sync(dev);
resubmit:
status=usb_submit_urb(urb,GFP_ATOMIC);
if(status)
err("can'tresubmitintr,%s-%s/input0,status%d",
mouse->usbdev->bus->bus_name,
mouse->usbdev->devpath,status);
}
6、
设备的关闭:
当应用程序利用Close函数关闭USB鼠标设备时,操作系统调用usb_mouse_clos函数函数关闭USB鼠标设备。
该函数调用usb_kill_urb取消一个URB请求并等到请求结束。
staticvoidusb_mouse_close(structinput_dev*dev)
{
structusb_mouse*mouse=input_get_drvdata(dev);
usb_kill_urb(mouse->irq);
}
第三步:
USB鼠标驱动模块配置
1、运行makemenuconfig内核配置命令,在DeviceDrivers-->USBSupport配置菜单中选中<*>OHCIHCDsubpport选项,使系统支持USB的OHCI驱动。
【图12-1-3】
2、在DeviceDrivers-->HIDDevices配置菜单中选中<*>GenernicHIDsupport选项,使系统支持USB的input驱动
【图12-1-4】
3、由于实验将采用手动加载USB鼠标驱动,因此在内核配置命令中,需要去掉DeviceDrivers-->HIDdevices-->USBHIDBootProtocoldrivers配置菜单下的
<>USBHIDBPMouse(SimpleBoot)support
【图12-1-5】
第四步:
USB鼠标驱动模块的编译
1、将Linux-2.6.22.10/drivers/hid/Usbhid目录下的usbmouse.c复制到Linux下的一个工作目录中(如:
/root/work/usbmouse),利用vi工具新建一个用于编译usbmouse.c的Makefile文件。
其中KERNELDIR?
=/root/work/linux-2.6.22.10为内核位置。
#MakefilefortheUSBMouse.#
CFLAGS+=$(DEBFLAGS)-Wall
ifneq($(KERNELRELEASE),)
obj-m:
=usbmouse.o
else
KERNELDIR?
=/root/work/linux-2.6.22.10
PWD:
=$(shellpwd)
ALL:
$(MAKE)$(CFLAGS)-C$(KERNELDIR)M=$(PWD)modules
endif
clean:
rm-fr*.o*.ko*.symvers*~core.depend.*.cmd*.mod.c.tmp_versions
2、
利用ma
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 实验 121 USB鼠标驱动分析 USB 鼠标 驱动 分析