Android基于USB_BUIK触摸驱动

更新时间:2023-05-07 22:45:24 阅读: 评论:0

Android基于USB_BUIK触摸驱动
1、概述
Android 和PC系统本⾝是⽀持 usb hid输⼊设备的。不过由于业务的发展,需要采⽤⾼精度触摸框。重新设计框架,改变原来  串⼝+usb_hid的⽅式。采⽤俩路usb,⼀路usb_buik+⼀路usb_hid⽅式。具体架构如下图:
2、触摸驱动
该驱动是基于Android 8.0 内核 4.9版本上调试的。驱动主要从俩个⽅⾯去分析:1) USB 驱动框架  2)input 驱动
2.1 USB驱动框架
USB驱动基于Linux USB总线完成的。主要注册USB 设备和填充USB设备结构体相关信息。
static int __init usb_touch_init(void)
{
int retval = usb_register(&XX_driver); //注册usb driver到系统中
printk(KERN_ALERT "usb touch init\r\n");
if(retval)
printk(KERN_ALERT "usb touch init error %d\r\n",retval);
return retval;
}
static void __exit usb_touch_exit(void)
{
printk(KERN_ALERT "usb touch exit");
usb_deregister(&XX_driver);
}
module_init(usb_touch_init);
module_exit(usb_touch_exit);
Linux 内核驱动都是从init函数开始执⾏,相当于应⽤程序⾥⾯的main函数。在init函数中主要做了usb_register(),注册usb driver到
系统中。usb_register() 参数为struct usb_driver 结构。
static struct usb_driver XX_driver = {
.name      = "XXXXXX", //usb driver name
.probe    = XX_probe, //usb 匹配后执⾏probe
.disconnect  = XX_disconnect, //usb 设备断开
.id_table    = XX_id_table,  // ⽤于usb 匹配信息
};
在usb_driver结构中重要的⼏个参数为 .probe 该函数⽤于usb 设备匹配正确后执⾏的。匹配规则后⾯会讲到 ,.disconnect该函数⽤于
usb设备断开后执⾏的,主要做⼀些资源的释放。id_table ⽤于usb设备匹配信息,下⾯会讲。.name ⽤于usb driver name
static struct usb_device_id XX_id_table [] ={
{
.match_flags =  USB_DEVICE_ID_MATCH_VENDOR,//匹配规则,根据vid pid 去匹配设备
.idVendor = XXXX,
.idProduct = XXXXX,
},
{
.match_flags =  USB_DEVICE_ID_MATCH_VENDOR, //可以匹配多个usb设备
.idVendor = XXXXX,
.idProduct = XXXXX,
},
//{ USB_DEVICE(USB_TOUCH_VENDOR_ID, USB_TOUCH_PRODUCT_ID) },
{}
};
MODULE_DEVICE_TABLE (usb, XX_id_table );
usb _device_id 写明usb 设备与驱动匹配的规则,这⾥采⽤的 是根据vid pid去匹配。每个usb设备的pid vid都是唯⼀的,当然也可以根据
class Subclass (设备描述符)去匹配usb 设备.同时⼀个usb 驱动可以匹配多个usb 设备。MODULE_DEVICE_TABLE 宏将你写好的匹配
规则带⼊到系统中.
注意 usb_device_id XX_id_table 要与 usb_driver 中的.id_table 关联起来,系统才可以识别相关的usb 设备。
static int usb_touch_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
//获取usb_device 通过结构体成员指针获取结构体⾸地址
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint_in=NULL,*endpoint_out;
//将接⼝描述符赋为当前接⼝
interface = intf->cur_alttting;
//获取端点个数
endpoint_num=interface->desc.bNumEndpoints;
//申请touch 结构体空间
touch = kzalloc(sizeof(struct usb_touch), GFP_KERNEL);
//查找端点的属性,In端点还是Out端点
for(i=0;i<interface->desc.bNumEndpoints;i++){
if(!touch->input_ep &&  usb_endpoint_dir_in(&interface->endpoint[i].desc)){
endpoint_in=&interface->endpoint[i].desc;
touch->input_ep = interface->endpoint[i].desc.bEndpointAddress;
maxp= usb_maxpacket(dev, touch->input_ep, usb_pipeout(touch->input_ep));
printk(KERN_ALERT "In  bDescriptorType -> %x bEndpointAddress -> %x                                                        bmAttributes -> %x  wMaxPacketSize  ->%x\r\n",    endpoint_in->bDescriptorType,endpoint_in->bEndpointAddress,endpoint_in->bmAttributes,endpoint_in->wMaxPacketSize);
}
if(!touch->output_ep &&  usb_endpoint_dir_out(&interface->endpoint[i].desc)){
endpoint_out=&interface->endpoint[i].desc;
touch->output_ep = interface->endpoint[i].desc.bEndpointAddress;
maxp= usb_maxpacket(dev, touch->output_ep, usb_pipeout(touch->output_ep));
printk(KERN_ALERT "Out  bDescriptorType -> %x bEndpointAddress -> %x  bmAttributes -> %x  wMaxPacketSize  ->%x\r\n",
endpoint_out->bDescriptorType,endpoint_out->bEndpointAddress,endpoint_out->bmAttributes,endpoint_out->wMaxPacketSize);
}
}
//申请data空间和buff空间
touch->data = usb_alloc_coherent(dev,512*20,GFP_KERNEL,&touch->data_dma);
touch->buff = kmalloc(512*20, GFP_ATOMIC);
touch->buff = kmalloc(512*20, GFP_ATOMIC);
if(!touch->data || !touch->buff)
goto fail1;
/*
* 为 urb 结构体申请内存空间,第⼀个参数表⽰等时传输时需要传送包的数量,其它传输⽅式则为0。
* 申请的内存将通过下⾯即将见到的 usb_fill_int_urb 函数进⾏填充。
*/
touch->irq = usb_alloc_urb(0,GFP_KERNEL);
if(!touch->irq)
goto fail2;
/* 填充 usb 设备结构体和输⼊设备结构体 */
touch->usbdev=dev;
touch->usb_touch_input_dev=input_dev;
/* 获取Usb_hid设备的名称 */
printk(KERN_ALERT "usb touch probe manufacturer %s\r\n",dev->manufacturer);
if(dev->manufacturer)
strlcpy(touch->name, dev->manufacturer, sizeof(touch->name));
printk(KERN_ALERT "usb touch probe touch->name %s\r\n",touch->name);
printk(KERN_ALERT "usb touch probe product %s\r\n",dev->product);
if (dev->product) {
if (dev->manufacturer)
strlcat(touch->name, " ", sizeof(touch->name));
strlcat(touch->name, dev->product, sizeof(touch->name));
printk(KERN_ALERT "usb touch probe touch->name22 %s\r\n",touch->name);
}
if (!strlen(touch->name))
snprintf(touch->name, sizeof(touch->name),
"XXXX touch %04x:%04x",
le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
printk(KERN_ALERT "usb touch probe touch->name333 %s\r\n",touch->name);
//初始化⼀个buik_urb块⽤于异步传输数据
usb_fill_bulk_urb(touch->irq, dev, usb_rcvbulkpipe(dev, touch->input_ep), touch->data,
512*20,
usb_touch_irq, touch);
touch->irq->transfer_dma = touch->data_dma;//dma数据缓冲区指向设备的data_dma成员
touch->irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;// DMA 有效
//提交urb到系统中
retval = usb_submit_urb(touch->irq,GFP_KERNEL);
if (retval) {
printk(KERN_ALERT "retval %d\r\n",retval);
}
}
在probe函数主要是⼀些初始化,⾸先通过interface_to_usbdev函数获取到usb_dev.这种⼿法在内核中很常⽤。申请相关的结构体的空间,判断usb设备端点的属性和初始化⼀个urb⽤于传输数据。在初始化urb时 usb_fill_bulk_urb() 第六个参数是⼀个回调函数,当有数据是系统会调⽤这个函数。类似于中断函数。第五个参数是参数数据的buff。
static void usb_touch_irq(struct urb* urb)
{
//根据上下⽂可获取到usb_touch 结构体 urb的私有成员。不过在这⾥设置usb_touch为全局变量,
//struct usb_touch *touch = urb->context;
int status=0;
//判断urb 块传输数据的状态
switch (urb->status) {
ca 0:
/*success */
break;
ca -ECONNRESET: /* unlink */
ca -ENOENT:
ca -ESHUTDOWN:
printk(KERN_ALERT "ESHUTDOWN\r\n");
return;
/
* -EPIPE:  should clear the halt */
default:  /* error */
goto resubmit;
}
//接收数据的长度
urb->actual_length;
//touch->data 接收的数据。
//urb 状态未知时,再次提交urb到系统中
resubmit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
printk(KERN_ALERT "can't resubmit intr, %s-%s/input0, status %d",
touch->usbdev->bus->bus_name,
touch->usbdev->devpath, status);
}
在irq⾥判断urb的状态,然后就可以读到数据和数据的长度。
static void usb_touch_disconnect(struct usb_interface *intf)
{
struct usb_touch *touch = usb_get_intfdata (intf);
usb_t_intfdata(intf, NULL);
if (touch) {
usb_kill_urb(touch->irq);
usb_free_urb(touch->irq);
usb_free_coherent(interface_to_usbdev(intf), 512, touch->data, touch->data_dma);
kfree(touch);
}
}
在disconnect 中释放之前申请的资源。
2.2 input 部分
Input部分相对来讲会简单⼀些,在probe函数⾥⾯做相关初始化,在disconnect⾥⾯释放相关资源。然后再irq函数中拿到数据后上报数据给系统即可。Android系统本事的input⼦系统会识别相关的event 事件,触摸正常。
static int usb_touch_probe(struct usb_interface *intf,const struct usb_device_id *id)
{
struct input_dev *input_dev;
input_dev = input_allocate_device();//为input设备申请空间
/*
* 填充usb设备结构体中的节点名。usb_make_path ⽤来获取 USB 设备在 Sysfs 中的路径,格式
* 为:usb-usb 总线号-路径名。
*/
usb_make_path(dev, touch->phys, sizeof(touch->phys));
input_dev->name = touch->name;
input_dev->phys=touch->phys;
usb_to_input_id(dev, &input_dev->id);//设置输⼊设备的bustype,vendor,product,version
input_dev->dev.parent = &intf->dev;//usb接⼝设备为输⼊设备的⽗设备
/
/设备⽀持X Y ID 事件
//⽀持同步事件
t_bit(EV_SYN, input_dev->evbit);
//设置绝对坐标,触摸屏采⽤绝对坐标,⿏标采⽤相对坐标
t_bit(EV_ABS, input_dev->evbit);
//设置点击事件
t_bit(BTN_TOUCH, input_dev->keybit);
//设置压⼒
t_bit(ABS_MT_PRESSURE, input_dev->absbit);
//点的ID ,多钱根据ID区分
t_bit(ABS_MT_TRACKING_ID, input_dev->keybit);
/
/设置X 事件
t_bit(ABS_MT_POSITION_X, input_dev->absbit);
//设置Y事件
t_bit(ABS_MT_POSITION_Y, input_dev->absbit);
//设置触摸笔的类型,粗细笔
t_bit(ABS_MT_TOOL_TYPE, input_dev->absbit);
//设置触摸屏设备
t_bit(INPUT_PROP_DIRECT, input_dev->propbit);
//设置压⼒的范围
input_t_abs_params(input_dev, ABS_MT_PRESSURE,0,255,0,0);
//设置X Y坐标的范围
input_t_abs_params(input_dev, ABS_MT_POSITION_X, 0, 0x7fff, 0, 0);
input_t_abs_params(input_dev, ABS_MT_POSITION_Y, 0, 0x7fff, 0, 0);
//设置多点的ID个数 10点
input_t_abs_params(input_dev, ABS_MT_TRACKING_ID, 0, 10, 0, 0);
//设置⾯积的长宽
input_t_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_t_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
//设置粗细笔个数
input_t_abs_params(input_dev, ABS_MT_TOOL_TYPE,0, 3, 0, 0);
//关联input_dev与touch设备
input_t_drvdata(input_dev, touch);
/
/注册input驱动
input_register_device(touch->usb_touch_input_dev);
}
在probe中做相关的初始化,到此input相关已经初始化完成,在irq函数中直接上报函数即可。

本文发布于:2023-05-07 22:45:24,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/fan/89/867276.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:设备   函数   数据   结构   设置   驱动   匹配
相关文章
留言与评论(共有 0 条评论)
   
验证码:
推荐文章
排行榜
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图