alt+鼠标左键 linux
2012-04-20 10:38:15 yaotinging 阅读数 566

USB 总线引出两个重要的链表!
一个 USB 总线引出两个重要的链表,一个为 USB 设备链表,一个为 USB 驱动链表。设备链表包含各种系统中的 USB 设备以及这些设备的所有接口,驱动链表包含 USB 设备驱动程序(usb device driver)和 USB 驱动程序(usb driver)。

 

USB 设备驱动程序(usb device driver)和 USB 驱动程序(usb driver)的区别是什么?
USB 设备驱动程序包含 USB 设备的一些通用特性,将与所有 USB 设备相匹配。在 USB core 定义了:struct usb_device_driver usb_generic_driver。usb_generic_driver 是 USB 子系统中唯一的一个设备驱动程序对象。而 USB 驱动程序则是与接口相匹配,接口是一个完成特定功能的端点的集合。

 

设备是如何添加到设备链表上去的?
在设备插入 USB 控制器之后,USB core 即会将设备在系统中注册,添加到 USB 设备链表上去。

 

USB 设备驱动程序(usb device driver)是如何添加到驱动链表上去的?
在系统启动注册 USB core 时,USB 设备驱动程序即将被注册,也就添加到驱动链表上去了。

 

接口是如何添加到设备链表上去的?
在 USB 设备驱动程序和 USB 设备的匹配之后,USB core 会对设备进行配置,分析设备的结构之后会将设备所有接口都添加到设备链表上去。比如鼠标设备中有一个接口,USB core 对鼠标设备配置后,会将这个接口添加到设备链表上去。

 

USB 驱动程序(usb driver)是如何添加到驱动链表上去的?
在每个 USB 驱动程序的被注册时,USB 驱动程序即会添加到驱动链表上去。比如鼠标驱动程序,usb_mouse_init 函数将通过 usb_register(&usb_mouse_driver) 将鼠标驱动程序注册到 USB core 中,然后就添加到驱动链表中去了。其中 usb_mouse_driver 是描述鼠标驱动程序的结构体。

 

已配置状态(configured status)之后话
当鼠标的设备、接口都添加到设备链表,并且鼠标驱动程序也添加到驱动链表上去了,系统就进入一种叫做已配置(configured)的状态。要达到已配置状态,将经历复杂的过程,USB core 为 USB 设备奉献着无怨无悔。在这个过程中,系统将会建立起该设备的的设备、配置、接口、设置、端点的描述信息,它们分别被 usb_device、usb_configuration、usb_interface、usb_host_interface、usb_host_endpoint 结构体描述。
设备达到已配置状态后,首先当然就要进行 USB 驱动程序和相应接口的配对,对于鼠标设备来说则是鼠标驱动程序和鼠标中的接口的配对。USB core 会调用 usb_device_match 函数,通过比较设备中的接口信息和 USB 驱动程序中的 id_table,来初步决定该 USB 驱动程序是不是跟相应接口相匹配。通过这一道关卡后,USB core 会认为这个设备应该由这个驱动程序负责。
然而,仅仅这一步是不够的,接着,将会调用 USB 驱动程序中的 probe 函数对相应接口进行进一步检查。如果该驱动程序确实适合设备接口,对设备做一些初始化工作,分配 urb 准备数据传输。
当鼠标设备在用户空间打开时,将提交 probe 函数构建的 urb 请求块,urb 将开始为传送数据而忙碌了。urb 请求块就像一个装东西的“袋子”,USB 驱动程序把“空袋子”提交给 USB core,然后再交给主控制器,主控制器把数据放入这个“袋子”后再将装满数据的“袋子”通过 USB core 交还给 USB 驱动程序,这样一次数据传输就完成了。

/*
 * $Id: usbmouse.c,v 1.15 2001/12/27 10:37:41 vojtech Exp $
 *
 *  Copyright (c) 1999-2001 Vojtech Pavlik
 *
 *  USB HIDBP Mouse support
 */


#include <linux/kernel.h> 
#include <linux/slab.h> 
#include <linux/module.h> 
#include <linux/init.h> 
#include <linux/usb/input.h> 
#include <linux/hid.h> 


/*
 * Version Information
 */
#define DRIVER_VERSION "v1.6" 
#define DRIVER_AUTHOR "Vojtech Pavlik <vojtech@ucw.cz>" 
#define DRIVER_DESC "USB HID Boot Protocol mouse driver" 
#define DRIVER_LICENSE "GPL" 


MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);


/*
 * 鼠标结构体,用于描述鼠标设备。
 */
struct usb_mouse 
{
    /* 鼠标设备的名称,包括生产厂商、产品类别、产品等信息 */
    char name[128]; 
    /* 设备节点名称 */
    char phys[64];  
    /* USB 鼠标是一种 USB 设备,需要内嵌一个 USB 设备结构体来描述其 USB 属性 */
    struct usb_device *usbdev;
    /* USB 鼠标同时又是一种输入设备,需要内嵌一个输入设备结构体来描述其输入设备的属性 */
    struct input_dev *dev;  
    /* URB 请求包结构体,用于传送数据 */
    struct urb *irq;
    /* 普通传输用的地址 */
    signed char *data;
    /* dma 传输用的地址 */
    dma_addr_t data_dma;        
};


/*
 * urb 回调函数,在完成提交 urb 后,urb 回调函数将被调用。
 * 此函数作为 usb_fill_int_urb 函数的形参,为构建的 urb 制定的回调函数。
 */
static void usb_mouse_irq(struct urb *urb)
{
    /*
     * urb 中的 context 指针用于为 USB 驱动程序保存一些数据。比如在这个回调函数的形参没有传递在 probe
     * 中为 mouse 结构体分配的那块内存的地址指针,而又需要用到那块内存区域中的数据,context 指针则帮了
     * 大忙了!
     * 在填充 urb 时将 context 指针指向 mouse 结构体数据区,在这又创建一个局部 mouse 指针指向在 probe
     * 函数中为 mouse 申请的那块内存,那块内存保存着非常重要数据。
     * 当 urb 通过 USB core 提交给 hc 之后,如果结果正常,mouse->data 指向的内存区域将保存着鼠标的按键
     * 和移动坐标信息,系统则依靠这些信息对鼠标的行为作出反应。 
     * mouse 中内嵌的 dev 指针,指向 input_dev 所属于的内存区域。
     */
    struct usb_mouse *mouse = urb->context;
    signed char *data = mouse->data;
    struct input_dev *dev = mouse->dev;
    int status;


    /*
     * 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)
    {
    case 0:     /* success */
        break;
    case -ECONNRESET:   /* unlink */
    case -ENOENT:
    case -ESHUTDOWN:
        return;
    /* -EPIPE:  should clear the halt */
    default:        /* error */
        goto resubmit;
    }


    /*
     * 向输入子系统汇报鼠标事件情况,以便作出反应。
     * data 数组的第0个字节:bit 0、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 过程中可能会需要申请内存、保持信号量,这些操作或许会导致 USB core 睡眠,一切导致睡眠的行
     * 为都是不允许的。
     */
resubmit:
    status = usb_submit_urb (urb, GFP_ATOMIC);
    if (status)
        err ("can't resubmit intr, %s-%s/input0, status %d",
                mouse->usbdev->bus->bus_name,
                mouse->usbdev->devpath, status);
}


/*
 * 打开鼠标设备时,开始提交在 probe 函数中构建的 urb,进入 urb 周期。
 */
static int usb_mouse_open(struct input_dev *dev)
{
    struct usb_mouse *mouse = dev->private;


    mouse->irq->dev = mouse->usbdev;
    if (usb_submit_urb(mouse->irq, GFP_KERNEL))
        return -EIO;


    return 0;
}


/*
 * 关闭鼠标设备时,结束 urb 生命周期。
 */
static void usb_mouse_close(struct input_dev *dev)
{
    struct usb_mouse *mouse = dev->private;


    usb_kill_urb(mouse->irq);
}


/*
 * 驱动程序的探测函数
 */
static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
    /* 
     * 接口结构体包含于设备结构体中,interface_to_usbdev 是通过接口结构体获得它的设备结构体。
     * usb_host_interface 是用于描述接口设置的结构体,内嵌在接口结构体 usb_interface 中。
     * usb_endpoint_descriptor 是端点描述符结构体,内嵌在端点结构体 usb_host_endpoint 中,而端点
     * 结构体内嵌在接口设置结构体中。
     */
    struct usb_device *dev = interface_to_usbdev(intf);
    struct usb_host_interface *interface;
    struct usb_endpoint_descriptor *endpoint;
    struct usb_mouse *mouse;
    struct input_dev *input_dev;
    int pipe, 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))
        return -ENODEV;


    /*
     * 返回对应端点能够传输的最大的数据包,鼠标的返回的最大数据包为4个字节,数据包具体内容在 urb
     * 回调函数中有详细说明。
     */
    pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
    maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));


    /* 为 mouse 设备结构体分配内存 */
    mouse = kzalloc(sizeof(struct usb_mouse), GFP_KERNEL);
    /* input_dev */
    input_dev = input_allocate_device();
    if (!mouse || !input_dev)
        goto fail1;


    /*
     * 申请内存空间用于数据传输,data 为指向该空间的地址,data_dma 则是这块内存空间的 dma 映射,
     * 即这块内存空间对应的 dma 地址。在使用 dma 传输的情况下,则使用 data_dma 指向的 dma 区域,
     * 否则使用 data 指向的普通内存区域进行传输。
     * GFP_ATOMIC 表示不等待,GFP_KERNEL 是普通的优先级,可以睡眠等待,由于鼠标使用中断传输方式,
     * 不允许睡眠状态,data 又是周期性获取鼠标事件的存储区,因此使用 GFP_ATOMIC 优先级,如果不能
     * 分配到内存则立即返回 0。
     */
    mouse->data = usb_buffer_alloc(dev, 8, GFP_ATOMIC, &mouse->data_dma);
    if (!mouse->data)
        goto fail1;


    /*
     * 为 urb 结构体申请内存空间,第一个参数表示等时传输时需要传送包的数量,其它传输方式则为0。
     * 申请的内存将通过下面即将见到的 usb_fill_int_urb 函数进行填充。 
     */
    mouse->irq = usb_alloc_urb(0, GFP_KERNEL);
    if (!mouse->irq)
        goto fail2;


    /* 填充 usb 设备结构体和输入设备结构体 */
    mouse->usbdev = dev;
    mouse->dev = input_dev;


    /* 获取鼠标设备的名称 */
    if (dev->manufacturer)
        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),
             "USB HIDBP Mouse %04x:%04x",
             le16_to_cpu(dev->descriptor.idVendor),
             le16_to_cpu(dev->descriptor.idProduct));


    /*
     * 填充鼠标设备结构体中的节点名。usb_make_path 用来获取 USB 设备在 Sysfs 中的路径,格式
     * 为:usb-usb 总线号-路径名。
     */
    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;
    /*
     * input_dev 中的 input_id 结构体,用来存储厂商、设备类型和设备的编号,这个函数是将设备描述符
     * 中的编号赋给内嵌的输入子系统结构体
     */
    usb_to_input_id(dev, &input_dev->id);
    /* cdev 是设备所属类别(class device) */
    input_dev->cdev.dev = &intf->dev;


    /* evbit 用来描述事件,EV_KEY 是按键事件,EV_REL 是相对坐标事件 */
    input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
    /* keybit 表示键值,包括左键、右键和中键 */
    input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
    /* relbit 用于表示相对坐标值 */
    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_dev 的 private 数据项用于表示当前输入设备的种类,这里将鼠标结构体对象赋给它 */
    input_dev->private = mouse;
    /* 填充输入设备打开函数指针 */
    input_dev->open = usb_mouse_open;
    /* 填充输入设备关闭函数指针 */
    input_dev->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);
    mouse->irq->transfer_dma = mouse->data_dma;
    mouse->irq->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);
    return 0;


fail2:  usb_buffer_free(dev, 8, mouse->data, mouse->data_dma);
fail1:  input_free_device(input_dev);
    kfree(mouse);
    return -ENOMEM;
}


/*
 * 鼠标设备拔出时的处理函数
 */
static void usb_mouse_disconnect(struct usb_interface *intf)
{
    /* 获取鼠标设备结构体 */
    struct usb_mouse *mouse = usb_get_intfdata (intf);


    /* intf->dev->dirver_data = NULL,将接口结构体中的鼠标设备指针置空。*/
    usb_set_intfdata(intf, NULL);
    if (mouse)
    {
        /* 结束 urb 生命周期 */
        usb_kill_urb(mouse->irq);
        /* 将鼠标设备从输入子系统中注销 */
        input_unregister_device(mouse->dev);
        /* 释放 urb 存储空间 */
        usb_free_urb(mouse->irq);
        /* 释放存放鼠标事件的 data 存储空间 */
        usb_buffer_free(interface_to_usbdev(intf), 8, mouse->data, mouse->data_dma);
        /* 释放存放鼠标结构体的存储空间 */
        kfree(mouse);
    }
}


/*
 * usb_device_id 结构体用于表示该驱动程序所支持的设备,USB_INTERFACE_INFO 可以用来匹配特定类型的接口,
 * 这个宏的参数意思为 (类别, 子类别, 协议)。
 * USB_INTERFACE_CLASS_HID 表示是一种 HID (Human Interface Device),即人机交互设备类别;
 * USB_INTERFACE_SUBCLASS_BOOT 是子类别,表示是一种 boot 阶段使用的 HID;
 * USB_INTERFACE_PROTOCOL_MOUSE 表示是鼠标设备,遵循鼠标的协议。
 */
static struct usb_device_id usb_mouse_id_table [] = {
    { USB_INTERFACE_INFO(USB_INTERFACE_CLASS_HID, USB_INTERFACE_SUBCLASS_BOOT,
        USB_INTERFACE_PROTOCOL_MOUSE) },
    { } /* Terminating entry */
};


/*
 * 这个宏用来让运行在用户空间的程序知道这个驱动程序能够支持的设备,对于 USB 驱动程序来说,第一个参数必须
 * 是 usb。
 */
MODULE_DEVICE_TABLE (usb, usb_mouse_id_table);


/*
 * 鼠标驱动程序结构体
 */
static struct usb_driver usb_mouse_driver = {
    .name       = "usbmouse",
    .probe      = usb_mouse_probe,
    .disconnect = usb_mouse_disconnect,
    .id_table   = usb_mouse_id_table,
};


/*
 * 驱动程序生命周期的开始点,向 USB core 注册这个鼠标驱动程序。
 */
static int __init usb_mouse_init(void)
{
    int retval = usb_register(&usb_mouse_driver);
    if (retval == 0)
        info(DRIVER_VERSION ":" DRIVER_DESC);
    return retval;
}


/*
 * 驱动程序生命周期的结束点,向 USB core 注销这个鼠标驱动程序。
 */
static void __exit usb_mouse_exit(void)
{
    usb_deregister(&usb_mouse_driver);
}


module_init(usb_mouse_init);
module_exit(usb_mouse_exit);



 

2019-01-08 02:46:24 weixin_34318272 阅读数 13
 
 
 
4.2.1 usb_endpoint_is_int_in
判断端点是否为中断in类型
static inline int usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
{
 return (usb_endpoint_xfer_int(epd) && usb_endpoint_dir_in(epd));
}
static inline int usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
{
 return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==USB_ENDPOINT_XFER_INT); 
}
端点描述符中bmAttributes的低两位用于标示端点传输类型,分为四种:
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
#define USB_ENDPOINT_XFER_CONTROL 0     --控制传输
#define USB_ENDPOINT_XFER_ISOC  1     --等时传输
#define USB_ENDPOINT_XFER_BULK  2     --块传输
#define USB_ENDPOINT_XFER_INT    3     --中断传输  
static inline int usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
{
 return ((epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN);
}
对于bEndpointAddress的最高位用于标示传输方向,以host定位,in只device to host ,而out指host to device。而低四位用于标示设备地址。所以每一个hub上最多
挂31个器件。
同时对于其他端点类型的检测类似,如检测端点是否为块in类型:usb_endpoint_is_bulk_in。
4.2.2 usb_rcvintpipe
设置端点信息,其实pipe是一个int类型的数据。urb所发送的特定目标struct usb_device的端点信息。
#define usb_rcvintpipe(dev,endpoint) ((PIPE_INTERRUPT << 30) | __create_pipe(dev, endpoint) | USB_DIR_IN)
static inline unsigned int __create_pipe(struct usb_device *dev,unsigned int endpoint)
{
 return (dev->devnum << 8) | (endpoint << 15);
}
pipe由四个部分组成,最高2位用于标示PIPE类型,第15到23的bit位用于标示endpoint->bEndpointaddress信息,而第8到第15位用于标示设备的number号,第7bit位
用于标示数据流方向。
个人以为这里的endpoint极容易引起误解,如果写成endpointaddress会较好理解,这样在看到该API时直接就知道传入参数是什么。
创建各种管道:
#define usb_sndctrlpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个控制OUT端点
#define usb_rcvctrlpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个控制IN端点
#define usb_sndisocpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个等时OUT端点
#define usb_rcvisocpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个等时IN端点
#define usb_sndbulkpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个块OUT端点
#define usb_rcvbulkpipe(dev,endpoint)   --把指定usb设备的指定端口设置为一个块IN端点
#define usb_sndintpipe(dev,endpoint)    --把指定usb设备的指定端口设置为一个中断OUT端点
#define usb_rcvintpipe(dev,endpoint)    --把指定usb设备的指定端口设置为一个中断IN端点
pipe的含义就很好理解了,其就是将指定usb设备的指定端口设置为某一类型的端口,即是将端点的信息保存。
4.2.3 usb_maxpacket
取得端点所支持的最大数据数
static inline __u16 usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
{
 struct usb_host_endpoint *ep;
 unsigned   epnum = usb_pipeendpoint(pipe);    --获取设备number (pipe>>15)&&0x0F
 
 if (is_out) {
  WARN_ON(usb_pipein(pipe));
  ep = udev->ep_out[epnum];           --获取端点
 } else {
  WARN_ON(usb_pipeout(pipe));
  ep = udev->ep_in[epnum];
 }
 if (!ep)
  return 0;
 /* NOTE:  only 0x07ff bits are for packet size... */
 return le16_to_cpu(ep->desc.wMaxPacketSize);    --获取端点信息
}
4.2.4 usb_buffer_alloc
从字面含义去理解开辟一段缓冲区。参数很好理解,一般的mem_flags为GFP_KERNEL,不过在中断上下文中不能阻塞,设置为GFP_ATOMIC
void *usb_buffer_alloc(struct usb_device *dev, size_t size, gfp_t mem_flags, dma_addr_t *dma)
{
 if (!dev || !dev->bus)
  return NULL;
 return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
}
void *hcd_buffer_alloc(struct usb_bus *bus,size_t size,gfp_t mem_flags,dma_addr_t *dma)
{
 struct usb_hcd  *hcd = bus_to_hcd(bus);
 int    i;
 /* some USB hosts just use PIO */
 if (!bus->controller->dma_mask &&!(hcd->driver->flags & HCD_LOCAL_MEM)) {
  *dma = ~(dma_addr_t) 0;
  return kmalloc(size, mem_flags);
 }
 for (i = 0; i < HCD_BUFFER_POOLS; i++) {
  if (size <= pool_max [i])           --当size在HCD_BUFFER_POOLS之内时,直接在pool中分配
   return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
 }
 return dma_alloc_coherent(hcd->self.controller, size, dma, 0);   --分配DMA空间
}
4.2.5 usb_alloc_urb
在usb系统中urb很重要,其内核通过urb与usb设备通信。这个类型一个联络官一样,将驱动和设备连接。
urb是一个很巨大的结构体,不过对于驱动工程师而言,需要理解下面几个成员:
struct usb_device *dev;   urb所发送的目标usb device的指针。
unsigned int pipe;        这个就不多说了,这个就是所发送特定目标的特定端点信息。至于pipe怎么设置在上面讲过。
unsigned int transfer_flags; 传输标识符
     URB_SHORT_NOT_OK         --对任何可能发生的对IN端点的读取都应该是err
   URB_ISO_ASAP           --如果urb是等时的,这个在以后等时urb时再看
     URB_NO_TRANSFER_DMA_MAP --当urb包含一个即将传输DMA缓冲区时应该设置该位,usb core使用transfer_dma指向的缓冲区,而不是transfer_buffer指向地址
     URB_NO_SETUP_DMA_MAP     --类似于上面。usb core使用setup_dma变量指向的缓冲区,而非setup_packet.s
     URB_NO_FSBR  
     URB_ZERO_PACKET  
     URB_NO_INTERRUPT 
void *transfer_buffer 指向用于发送数据到设备(OUT urb)或者从设备接收数据(IN urb)的缓冲区的指针。该缓冲区必须要使用kmalloc来创建,而非在栈中或静态内存中。
dma_addr_t transfer_dma 用于以DMA方式传输数据到usb设备的缓冲区。
int transfer_buffer_length 上述两个参数指向的缓冲区的大小
unsigned char *setup_packet 指向控制urb的设置数据包的指针
dma_addr_t setup_dma
usb_complete_t complete  结束处理函数指针,当urb完全传输或发生错误时调用。
void *context  类似于一个urb的私有数据
int actual_length urb结束后,urb所发送或接收的实际长度。
int status urb结束或被调用时的状态
int start_frame 设置或返回初始的帧数量。
int interval urb被轮询的时间间隔
上面几个成员比较重要。
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)
{
 struct urb *urb;
 urb = kmalloc(sizeof(struct urb) +iso_packets * sizeof(struct usb_iso_packet_descriptor),mem_flags);
 if (!urb) {
  printk(KERN_ERR "alloc_urb: kmalloc failed\n");
  return NULL;
 }
 usb_init_urb(urb);
 return urb;
}
void usb_init_urb(struct urb *urb)
{
 if (urb) {
  memset(urb, 0, sizeof(*urb));
  kref_init(&urb->kref);
  INIT_LIST_HEAD(&urb->anchor_list);
 }
}
4.2.6 usb_fill_int_urb
在urb申请后,需要对urb的参数进行赋值。对于中断,控制,以及批量urb都有对urb的初始化函数。
以usb_fill_int_urb为例:
static 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,void *context,int interval)
{
 urb->dev = dev;
 urb->pipe = pipe;
 urb->transfer_buffer = transfer_buffer;
 urb->transfer_buffer_length = buffer_length;
 urb->complete = complete_fn;
 urb->context = context;
 if (dev->speed == USB_SPEED_HIGH)
  urb->interval = 1 << (interval - 1);
 else
  urb->interval = interval;
 urb->start_frame = -1;
}
对于控制urb和批量urb都有类似的初始化函数
static inline void usb_fill_bulk_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,void *transfer_buffer,int buffer_length,usb_complete_t complete_fn,void *context) 
static inline void usb_fill_control_urb(struct urb *urb,struct usb_device *dev,unsigned int pipe,unsigned char *setup_packet,void *transfer_buffer,int buffer_length,usb_complete_t complete_fn,void *context)
对于urb的填充均是对urb的部分成员进行赋值。
4.2.7 usb_submit_urb
int usb_submit_urb(struct urb *urb, gfp_t mem_flags) 
参数 urb 就是前面的urb
mem_flags 有三种值可以使用
GFP_ATOMIC
   调用者在一个urb结束处理函数中,中断处理函数,底半部。tasklet或定时器的回调函数中。
   调用者正持有一个自旋锁或读写锁
   其实所白了这个标识符的设置其实是避免睡眠。
GFP_NOIO
   驱动程序处于块IO路径中应使用该值
GFP_KERNEL
   在上述情况之外使用
五.总结
对于linux的usb设备的驱动,一般是针对设备的某一接口做的驱动。在其中主要是urb的申请和提交。
2011-12-26 11:46:28 wu_zf 阅读数 9093

以下命令打开鼠标:

  :set mouse=a

否则 Vim 不会在所有模式下识别鼠标 (见 'mouse')。

 

目前,鼠标只有在 Unix 的 xterm 窗口、Linux 终端 (带 GPM |gpm-mouse|)、MS-DOS

和 Windows 终端上才支持。鼠标键击可以用来定位光标,设置区域并粘贴。

 

'mouse' 选项的字符决定 Vim 在什么场合下会使用鼠标:

  n 普通模式

  v 可视模式

  i 插入模式

  c 命令行模式

  h 在帮助文件里,以上所有的模式

  a 以上所有的模式

  r 跳过 |hit-enter| 提示

 

'mouse' 的缺省值为空,即不使用鼠标。通常你会用:

  :set mouse=a

来开始使用鼠标 (这等价于设置 'mouse' 为 "nvich")。如果你只想在若干模式下或者在

某两个任务上使用鼠标,你需要专注于那些模式对应的字母。例如:

  :set mouse=nv

会使得鼠标在普通模式和可视模式下工作。

  :set mouse=h

会使得鼠标只有在帮助文件里工作 (这样,可以用 "g<LeftMouse>" 来进行标签跳转)。

 

鼠标能否在可视模式或者选择模式下开始选择,决定于 "selectmode" 选项包不包括

"mouse"。

 

在 xterm 终端里,在 'mouse' 选项包含当前激活的模式的前提下,普通的鼠标键击归

Vim 使用,而带 shift 或者 ctrl 键的鼠标键击由 xterm 控制。如果 'mouse' 不包括

当前激活的模式,则所有的鼠标键击由 xterm 控制。

 

  *xterm-clipboard*

Athena 和 Motif GUI 版本上,如果在终端运行但是可以访问 X-server (设置了

DISPLAY),那么复制和粘贴和 GUI 上的行为相似。如果不是,那么鼠标中键会插入无名

寄存器。这种情况下,这里是如何复制和粘贴一段文本的方法:

 

用鼠标和可视模式复制/粘贴 ('mouse' 选项必须设置,见上):

1. 在文本的第一个字符上按鼠标左键,移动鼠标到文本的最后一个字母,然后释放左

  键。这会启动可视模式并高亮选择区域。

2. 按 "y" 抽出可视文本到无名寄存器里。

3. 在要插入的位置上按鼠标左键。

4. 按鼠标中键。

 

快捷方式: 如果插入位置和可视文本同时出现在屏幕上,你可以一次做 2、3 和 4: 在要

插入的位置直接按鼠标中键。

 

注意: 如果使用 |-X| 命令行参数,Vim 不会连接到 X 服务器,所以复制/粘贴到 X 剪

贴板 (选择区) 不会工作。使用带 shift 键的鼠标键来让 xterm 完成选择。

 

  *xterm-command-server*

如果 X-服务器的剪贴板可用,|x11-clientserver| 的命令服务器可以在命令行用

--servername 打开。

 

  *xterm-copy-paste*

注意: 在有些 (较老的) xterm 版本里,光标不能移动超过第 95 列。这是 xterm 的问

题,不是 Vim 的。用新一点的 xterm 吧 |color-xterm|。

 

使用 xterm 粘贴/复制 (当前模式_不_包括在 'mouse' 里):

1. 在文本的第一个字符上按鼠标左键,移动鼠标到文本的最后一个字母,然后释放。

2. 使用普通的 Vim 命令把光标移动到待插入的位置。

3. 按 "a" 开始插入模式。

4. 按鼠标中键。

5. 按 ESC 退出插入模式。

(对包含在 'mouse' 里的模式,这里的操作同样可以完成,只要你在使用鼠标的时候按住

shift 键就行了。)

 

注意: 如果你在粘贴的时候丢失了第 8 位 (特殊字符被翻译成其他字符),你需要在启动

Vim 之前在外壳上执行 "stty cs8 -istrip -parenb"。

 

这样,在 xterm 上 shift 和 ctrl 键不能和鼠标一起使用。需要 CTRL 修饰符的鼠标命

令可以在使用鼠标前按 "g" 键模拟:

  "g<LeftMouse>" 是 "<C-LeftMouse> (跳转到鼠标点击的标签上)

  "g<RightMouse>" 是 "<C-RightMouse> ("CTRL-T")

 

  *mouse-mode-table* *mouse-overview*

如果 'mousemodel' 是 "extend" ,鼠标按钮的功能的概述在此:

 

普通模式:

事件 移动光标 选择 改变窗口 行动  

<LeftMouse> 是 结束 是

<C-LeftMouse> 是 结束 是 "CTRL-]" (2)

<S-LeftMouse> 是 不改变 是 "*" (2) *<S-LeftMouse>*

<LeftDrag> 是 开始或者扩展 (1) 否 *<LeftDrag>*

<LeftRelease> 是 开始或者扩展 (1) 否

<MiddleMouse> 是 如果没有激活 否 放置

<MiddleMouse> 是 如果激活 否 抽出和放置

<RightMouse> 是 开始或者扩展 是

<A-RightMouse> 是 开始或者扩展列块 是 *<A-RightMouse>*

<S-RightMouse> 是 不改变 是 "#" (2) *<S-RightMouse>*

<C-RightMouse> 否 不改变 否 "CTRL-T"

<RightDrag> 是 扩展 否 *<RightDrag>*

<RightRelease> 是 扩展 否 *<RightRelease>*

 

 

 

插入或替换模式:

事件 移动光标 选择 改变窗口 行动  

<LeftMouse> 是 (不能激活) 是

<C-LeftMouse> 是 (不能激活) 是 "CTRL-O^]" (2)

<S-LeftMouse> 是 (不能激活) 是 "CTRL-O*" (2)

<LeftDrag> 是 开始或者扩展 (1) 否 类似于 CTRL-O (1)

<LeftRelease> 是 开始或者扩展 (1) 否 类似于 CTRL-O (1)

<MiddleMouse> 否 (不能激活) 否 放置寄存器内容

<RightMouse> 是 开始或者扩展 是 类似于 CTRL-O

<A-RightMouse> 是 开始或者扩展列块 是

<S-RightMouse> 是 (不能激活) 是 "CTRL-O#" (2)

<C-RightMouse> 否 (不能激活) 否 "CTRL-O CTRL-T"

 

在帮助窗口里:

事件 移动光标 选择 改变窗口 行动  

<2-LeftMouse> 是 (不能激活) 否 "^]" (帮助标签跳转)

 

当 'mousemodel' 为 "popup" 时,下面这些有所差异:

 

普通模式:

事件 移动光标 选择 改变窗口 行动  

<S-LeftMouse> 是 开始或者扩展 (1) 否

<A-LeftMouse> 是 开始或者扩展列块 否 *<A-LeftMouse>*

<RightMouse> 否 弹出菜单 否

 

插入或替换模式:

事件 移动光标 选择 改变窗口 行动  

<S-LeftMouse> 是 开始或者扩展 (1) 否 类似于 CTRL-O (1)

<A-LeftMouse> 是 开始或者扩展列块 否

<RightMouse> 否 弹出菜单 否

 

(1) 只有当鼠标在按键后发生移动

(2) 只有当点击发生在同一缓冲区时

 

点击鼠标左键改变光标的位置。如果点击发生在另一个窗口,那么那个窗口成为活动窗

口。在编辑命令行时,光标只能定位在命令行上。在插入模式下,Vim 仍然保持在插入模

式。如果设置了 'scrolloff',而光标定位在窗口边界 'scrolloff' 行范围内,则文本

被滚动。

 

在第一个字符上按鼠标左键,移动鼠标到最后一个字符,然后释放,可以进行选择。直到

你释放鼠标键,你不一定总能看到选择的区域。只有一些版本能够 (GUI、MS-DOS、

WIN32) 使得拖动立即显示。注意 如果 'scrolloff' 非零,你可以在窗口的首/ 末行移

动鼠标至少一个字符位置使文本滚动。

 

在普通、可视和选择模式下,单击鼠标右键使得可视区域被扩展。如果 'mousemodel' 为

'popup',必须使用按住 shift 键的鼠标左键。如果在编辑另外一个缓冲区时点击一个窗

口,可视和选择模式被终止。

 

在普通、可视和选择模式下,按下 Alt 键同时单击鼠标右键,可使选择区域成为面向列

块。当 'mousemodel' 被设置为 "popup",鼠标左键必须和 Alt 键一起使用。注意在某

些系统中失效,那些系统中的窗口管理器在按下 Alt 键时会吃掉鼠标事件 (可能会移动

窗口)。

 

  *double-click*

双击、三击和四击在 GUI 激活时、MS-DOS 和 Win32,以及 xterm (如果有

gettimeofday() 函数) 上得到支持。对于文本选择,附加的点击会扩展选择区:

  点击 选择  

  两次 单词或者 % 匹配 *<2-LeftMouse>*

  三次 行 *<3-LeftMouse>*

  四次 矩形区域 *<4-LeftMouse>*

特例: 在帮助窗口上,双击跳到点击的单词对应的帮助。

双击单词选择该单词。'iskeyword' 用来指定单词可以包括哪些字符。双击一个有匹配的

字符选择直到该匹配的区域 (类似于 "v%")。如果匹配是 #if/#else/#endif 块,选择变

为面向行。

MS-DOS 和 xterm 上,双击相隔的时间可以通过 'mousetime' 选项设置。其他系统上,

该值只能在 Vim 之外定义。

一个使用双击跳转到光标所在的标签的例子:

  :map <2-LeftMouse> :exe "tag ". expand("<cword>")<CR>

 

使用双击拖动鼠标 (按下按钮、抬起按钮、按下按钮、然后拖动) 会导致完整的多个单词

被选择,直到按钮被释放为止。这时选择重新以字符为单位。

 

  *gpm-mouse*

GPM 鼠标只有在编译时打开 |+mouse_gpm| 特性才有效。GPM 鼠标驱动 (Linux 终端) 不

支持四击。

 

插入模式下,但选择开始时,Vim 暂时回到普通模式。在可视或者选择模式结束时,又回

到插入模式。这类似于在插入模式下使用 CTRL-O 的情形。选择模式在 'selectmode' 选

项包含 "mouse" 时被使用。

 

  *drag-status-line*

如果有多个窗口一起工作,窗口的大小可以用通过鼠标拖动状态行来改变。把鼠标点在状

态行上,按左键,移动鼠标把状态行带到新的位置,再释放左键。只是用鼠标点击状态行

而不移动鼠标使得那个窗口成为当前窗口。如果选择了一个窗口会改变状态行的位置或大

小,状态行的拖动看起来很奇怪,但还是会工作的 (试试吧)。

 

  *<MiddleRelease>* *<MiddleDrag>*

鼠标点击可以映射。鼠标点击的代码是:

  代码 鼠标按钮 一般的行动   

 <LeftMouse> 按住左键 设置光标位置

 <LeftDrag> 按住并移动左键 扩展选择区

 <LeftRelease> 释放左键 结束选择区

 <MiddleMouse> 按住中键 在光标所在的位置上粘贴

 <MiddleDrag> 按住并移动中键 -

 <MiddleRelease> 释放中键 -

 <RightMouse> 按住右键 扩展选择区

 <RightDrag> 按住并移动右键 扩展选择区

 <RightRelease> 释放右键 结束选择区

 <X1Mouse> 按住 X1 键 - *X1Mouse*

 <X1Drag> 按住并移动 X1 - *X1Drag*

 <X1Release> 释放 X1 键 - *X1Release*

 <X2Mouse> 按住 X2 键 - *X2Mouse*

 <X2Drag> 按住并移动 X2 - *X2Drag*

 <X2Release> 释放 X2 键 - *X2Release*

 

X1 和 X2 按钮指一些鼠标上的附加按钮。'Microsoft Explorer' 鼠标在右拇指位置有这

些键。目前 X1 和 X2 只能用于 Win32 环境。

 

示例:

  :noremap <MiddleMouse> <LeftMouse><MiddleMouse>

在鼠标中键点击的位置粘贴 (不然,粘贴在光标所在的位置进行)。

 

  :noremap <LeftRelease> <LeftRelease>y

在可视模式下立即抽出选择区。

 

注意使用了 ":noremap" 而不是 "map",以免发生递归映射。

 

  :map <X1Mouse> <C-O>

  :map <X2Mouse> <C-I>

把 X1 和 X2 键定义为跳转表的前进和后退,见 |CTRL-O| 和 |CTRL-I|。

 

  *mouse-swap-buttons*

要交换鼠标左键和右键的含义:

  :noremap <LeftMouse> <RightMouse>

  :noremap <LeftDrag> <RightDrag>

  :noremap <LeftRelease> <RightRelease>

  :noremap <RightMouse> <LeftMouse>

  :noremap <RightDrag> <LeftDrag>

  :noremap <RightRelease> <LeftRelease>

  :noremap g<LeftMouse> <C-RightMouse>

  :noremap g<RightMouse> <C-LeftMouse>

  :noremap! <LeftMouse> <RightMouse>

  :noremap! <LeftDrag> <RightDrag>

  :noremap! <LeftRelease> <RightRelease>

  :noremap! <RightMouse> <LeftMouse>

  :noremap! <RightDrag> <LeftDrag>

  :noremap! <RightRelease> <LeftRelease>

 

 vim:tw=78:ts=8:ft=help:norl:

 

参考  http://topic.csdn.net/u/20081124/17/ce367f9f-bf3a-4d84-a075-341d9e7bc509.html

2013-09-09 07:46:33 c1505011056 阅读数 488


linux 有自己的 input 子系统,可以统一管理鼠标和键盘事件。
基于输入子系统 实现的 uinput 可以方便的在用户空间模拟鼠标和键盘事件。
当然,也可以自己造轮子, 做一个字符设备接收用户输入,根据输入,投递 input 事件。
还有一种方式就是直接 往 evnent 里写入数据, 都可以达到控制鼠标键盘的功能。

本篇文章就是演示直接写入 event 的方法。 
linux/input.h中有定义,这个文件还定义了标准按键的编码等

struct input_event {
    struct timeval time;  //按键时间
    __u16 type; //类型,在下面有定义
    __u16 code; //要模拟成什么按键
    __s32 value;//是按下还是释放
};

code:
事件的代码.如果事件的类型代码是EV_KEY,该代码code为设备键盘代码.代码植0~127为键盘上的按键代码, 0x110~0x116 为鼠标上按键代码,其中0x110(BTN_ LEFT)为鼠标左键,0x111(BTN_RIGHT)为鼠标右键,0x112(BTN_ MIDDLE)为鼠标中键.其它代码含义请参看include/linux /input.h文件. 如果事件的类型代码是EV_REL,code值表示轨迹的类型.如指示鼠标的X轴方向 REL_X (代码为0x00),指示鼠标的Y轴方向REL_Y(代码为0x01),指示鼠标中轮子方向REL_WHEEL(代码为0x08).

type:
EV_KEY,键盘
EV_REL,相对坐标
EV_ABS,绝对坐标

value:
事件的值.如果事件的类型代码是EV_KEY,当按键按下时值为1,松开时值为0;如果事件的类型代码是EV_ REL,value的正数值和负数值分别代表两个不同方向的值.
/*
 * Event types
 */

#define EV_SYN            0x00
#define EV_KEY            0x01 //按键
#define EV_REL            0x02 //相对坐标(轨迹球)
#define EV_ABS            0x03 //绝对坐标
#define EV_MSC            0x04 //其他
#define EV_SW            0x05
#define EV_LED            0x11 //LED
#define EV_SND            0x12//声音
#define EV_REP            0x14//repeat
#define EV_FF            0x15
#define EV_PWR            0x16
#define EV_FF_STATUS        0x17
#define EV_MAX            0x1f
#define EV_CNT            (EV_MAX+1)

下面是一个模拟鼠标和键盘输入的例子:

#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

void simulate_key(int fd,int kval)
{
    struct input_event event;
    event.type = EV_KEY;
    event.value = 1;
    event.code = kval;

    gettimeofday(&event.time,0);
    write(fd,&event,sizeof(event)) ;

        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));
   
        memset(&event, 0, sizeof(event));
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = kval;
        event.value = 0;
        write(fd, &event, sizeof(event));
        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));

}

void simulate_mouse(int fd)
{
    struct input_event event;
        memset(&event, 0, sizeof(event));
        gettimeofday(&event.time, NULL);
        event.type = EV_REL;
        event.code = REL_X;
        event.value = 10;
        write(fd, &event, sizeof(event));

        event.type = EV_REL;
        event.code = REL_Y;
        event.value = 10;
        write(fd, &event, sizeof(event));

        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));
}

int main()
{
    int fd_kbd; 
    int fd_mouse; 
    fd_kbd = open("/dev/input/event1",O_RDWR);
    if(fd_kbd<=0){
        printf("error open keyboard:\n");
        return -1;

    }

    fd_mouse = open("/dev/input/event2",O_RDWR); 
    if(fd_mouse<=0){
        printf("error open mouse\n");
        return -2;
    }

    int i = 0;
    for(i=0; i< 10; i++)
    {
        simulate_key(fd_kbd, KEY_A + i);
        simulate_mouse(fd_mouse);
        sleep(1);
    }

    close(fd_kbd);
}
模拟了鼠标和键盘的输入事件。
关于这里 open 哪个 event , 可以通过 cat /proc/bus/input/devices 
I: Bus=0017 Vendor=0001 Product=0001 Version=0100
N: Name="Macintosh mouse button emulation"
P: Phys=
S: Sysfs=/class/input/input0
U: Uniq=
H: Handlers=mouse0 event0 
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=3

I: Bus=0011 Vendor=0001 Product=0001 Version=ab41
N: Name="AT Translated Set 2 keyboard"
P: Phys=isa0060/serio0/input0
S: Sysfs=/class/input/input1
U: Uniq=
H: Handlers=kbd event1 
B: EV=120013
B: KEY=4 2000000 3803078 f800d001 feffffdf ffefffff ffffffff fffffffe
B: MSC=10
B: LED=7

I: Bus=0019 Vendor=0000 Product=0002 Version=0000
N: Name="Power Button (FF)"
P: Phys=LNXPWRBN/button/input0
S: Sysfs=/class/input/input3
U: Uniq=
H: Handlers=kbd event3 
B: EV=3
B: KEY=100000 0 0 0

I: Bus=0019 Vendor=0000 Product=0001 Version=0000
N: Name="Power Button (CM)"
P: Phys=PNP0C0C/button/input0
S: Sysfs=/class/input/input4
U: Uniq=
H: Handlers=kbd event4 
B: EV=3
B: KEY=100000 0 0 0

I: Bus=0003 Vendor=046d Product=c018 Version=0111
N: Name="Logitech USB Optical Mouse"
P: Phys=usb-0000:00:1d.1-2/input0
S: Sysfs=/class/input/input24
U: Uniq=
H: Handlers=mouse1 event2 
B: EV=7
B: KEY=70000 0 0 0 0 0 0 0 0
B: REL=103

我的鼠标是 罗技 的 Logitech USB Optical Mouse, 所以 鼠标是 event2
下面是一个读取 鼠标和键盘事件的例子:
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

static void show_event(struct input_event* event)
{
        printf("%d %d %d\n", event->type, event->code, event->value);

        return;
}

int main(int argc, char* argv[])
{
        struct input_event event = {{0}, 0};
        const char* file_name = argc == 2 ? argv[1] : "/dev/input/event2";

        int fd = open(file_name, O_RDWR);


        if(fd > 0)
        {

                while(1)
                {
                        int ret = read(fd, &event, sizeof(event));
                        if(ret == sizeof(event))
                        {
                                show_event(&event);
                        }
                        else
                        {
                                break;
                        }
                }
                close(fd);
        }

        return 0;
}

很多人对于 如何模拟 CTRL + SPACE 感兴趣, 下面也给个例子,呵呵。
void simulate_ctrl_space(int fd)
{
        struct input_event event;

     //先发送一个 CTRL 按下去的事件。
        event.type = EV_KEY;
        event.value = 1;
        event.code = KEY_LEFTCTRL;
        gettimeofday(&event.time,0);
        write(fd,&event,sizeof(event)) ;

        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));

     //先发送一个 SPACE 按下去的事件。
        event.type = EV_KEY;
        event.value = 1;
        event.code = KEY_SPACE;
        gettimeofday(&event.time,0);
        write(fd,&event,sizeof(event)) ;

     //发送一个 释放 SPACE 的事件
        memset(&event, 0, sizeof(event));
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = KEY_SPACE;
        event.value = 0;
        write(fd, &event, sizeof(event));

        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));


     //发送一个 释放 CTRL 的事件
        memset(&event, 0, sizeof(event));
        gettimeofday(&event.time, NULL);
        event.type = EV_KEY;
        event.code = KEY_LEFTCTRL;
        event.value = 0;
        write(fd, &event, sizeof(event));


        event.type = EV_SYN;
        event.code = SYN_REPORT;
        event.value = 0;
        write(fd, &event, sizeof(event));

}
2010-05-17 13:25:00 pottichu 阅读数 2118

因为公司的板子上键盘不好按,所以写个网络版的,方便调试。

 

client .c

 

 

 

 

server.c

 

 

 

 

linux usb 鼠标(2)

阅读数 489

4.2.1usb_endpoint_is_int_in判断端点是否为中断in类型staticinlineintusb_endpoint_is_int_in(conststructusb_endpoint_descriptor*epd){ return(usb_endpoint_xfer_int(epd)&&usb_endpoint_dir_in(epd));

博文 来自: tronteng

virtualbox linux鼠标切换

阅读数 698

virtualboxlinux鼠标切换 对于我的计算机,安装的是CentOS6.3系统,操作过程为:1.进入X窗口后,在VirtualBox的软件菜单里面选择“设备”--“安装增强功能”2.在桌面上出现一个光驱符号,表明光驱加载成功。3.打开终端,进入/media文件夹,会看到一个文件,名字为VBoxAdditions,进入该目录。 www.2cto

博文 来自: tyl314

linux 鼠标使用问题

阅读数 359

初次接触linux,在安装过程中,因为我的鼠标就是SUB接口的,所以在安装过程中就特地选择了USB接口,但在安装完系统后却发现鼠标就是不能动,经过一番网上查询后,终于找到了解决办法,具体原因说不出来,但问题确实是解决了,如果有能知道原因的,欢迎各位指正。(以下信息来自http://www.iteye.com/topic/986436): 环境:VMware7虚拟系统:Linux9

博文 来自: hezhenhuahwp

linux - windows远程鼠标

阅读数 213

框图linux端;获取鼠标坐标,并通过socket传输给windowsmouse:linux下的鼠标设备,目录:/dev/input/mouseX,每个mouseX对应有一个eventY,X和Y->0...n,X和Y并不一定对应。因为有些event是键盘的或者其他的输入设备。具体的设备对应关系应该由/proc/bus/input/devices文件

博文 来自: liqinghan

Linux 下鼠标对应的文件

阅读数 369

系统CentOS 内核2.6 鼠标:usb2.0鼠标对应的设备文件是 /dev/input/event1在linux下,执行如下的操作,然后移动鼠标会得到哪下的数据:[root@bogoninput]#cat/dev/input/event1(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(�(

博文 来自: pk_20140716
没有更多推荐了,返回首页