《Linux驱动:s3c2410/s3c2440 ts驱动分析--终结篇》

发布者:清新天空最新更新时间:2024-07-09 来源: elecfans关键字:Linux驱动  s3c2410  s3c2440 手机看文章 扫描二维码
随时随地手机看文章

ts.dev->id.bustype = BUS_RS232;

ts.dev->id.vendor = 0xDEAD;

ts.dev->id.product = 0xBEEF;

ts.dev->id.version = S3C2410TSVERSION;

4.3.3 注册

input_register_device(ts.dev);

自此,该驱动设备注册到输入子系统中,会和事件处理层程序evdev匹配。


五,输入子系统

输入子系统分为三个层次,设备驱动层、核心层、以及事件处理层。

图片来源于网络

三个层级间的处理和联系

六,驱动层ts程序和事件处理层程序evdev匹配

6.1 evdev的注册

编译进内核,系统启动时自动加载,进而调用其evdev_init函数。


6.1.1 编译进内核

linux-2.6.22.6/drivers/input/Makefile


obj-$(CONFIG_INPUT_EVDEV)   += evdev.o

linux-2.6.22.6/.config


CONFIG_INPUT_EVDEV=y

6.1.2 调用evdev_init,注册到输入子系统

static struct input_handler evdev_handler = {

    .event =    evdev_event,

    .connect =  evdev_connect,

    .disconnect =   evdev_disconnect,

    .fops =     &evdev_fops,

    .minor =    EVDEV_MINOR_BASE,

    .name =     'evdev',

    .id_table = evdev_ids,

};


static int __init evdev_init(void)

{

    return input_register_handler(&evdev_handler);

}

6.2 驱动层ts程序注册到输入子系统

由第四点的s3c2410ts_probe函数分析可知,驱动层通过input_register_device接口注册到输入子系统。


input_register_device(ts.dev);

6.3 匹配

6.3.1 evdev注册时尝试匹配驱动层ts程序

int input_register_handler(struct input_handler *handler)

{

    struct input_dev *dev;


    INIT_LIST_HEAD(&handler->h_list);


    if (handler->fops != NULL) {

        if (input_table[handler->minor >> 5])

            return -EBUSY;


        input_table[handler->minor >> 5] = handler;

    }


    // 将处理层程序加入到input_handler_list链表

    list_add_tail(&handler->node, &input_handler_list);  


    // 从设备驱动层链表中取出每一个设备驱动层程序,和事件处理层程序匹配

    list_for_each_entry(dev, &input_dev_list, node)     

        input_attach_handler(dev, handler);


    input_wakeup_procfs_readers();

    return 0;

}


static int input_attach_handler(struct input_dev *dev, struct input_handler *handler)

{

    const struct input_device_id *id;

    int error;


    // 和事件处理层程序中设置的黑名单进行匹配,如果设备驱动层程序在白名单中,则忽略!

    if (handler->blacklist && input_match_device(handler->blacklist, dev))

        return -ENODEV;


    // 进行匹配

    id = input_match_device(handler->id_table, dev);

    if (!id)

        return -ENODEV;


    // 调用事件处理层程序中的connect函数 使事件处理层程序和设备驱动层程序建立联系。

    error = handler->connect(handler, dev, id);

    if (error && error != -ENODEV)

        printk(KERN_ERR

            'input: failed to attach handler %s to device %s, '

            'error: %dn',

            handler->name, kobject_name(&dev->cdev.kobj), error);


    return error;

}


static const struct input_device_id *input_match_device(const struct input_device_id *id,

                            struct input_dev *dev)

{

    int i;


    // id:

    // static const struct input_device_id evdev_ids[] = {

    //  { .driver_info = 1 },   /* Matches all devices */

    //  { },            /* Terminating zero entry */

    // };


    // dev:

    // ts.dev->id.bustype = BUS_RS232;

    // ts.dev->id.vendor = 0xDEAD;

    // ts.dev->id.product = 0xBEEF;

    // ts.dev->id.version = S3C2410TSVERSION;


    // evdev事件处理层程序成功匹配ts驱动层程序

    for (; id->flags || id->driver_info; id++) {


        if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)

            if (id->bustype != dev->id.bustype)

                continue;


        if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)

            if (id->vendor != dev->id.vendor)

                continue;


        if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)

            if (id->product != dev->id.product)

                continue;


        if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)

            if (id->version != dev->id.version)

                continue;


        MATCH_BIT(evbit,  EV_MAX);

        MATCH_BIT(keybit, KEY_MAX);

        MATCH_BIT(relbit, REL_MAX);

        MATCH_BIT(absbit, ABS_MAX);

        MATCH_BIT(mscbit, MSC_MAX);

        MATCH_BIT(ledbit, LED_MAX);

        MATCH_BIT(sndbit, SND_MAX);

        MATCH_BIT(ffbit,  FF_MAX);

        MATCH_BIT(swbit,  SW_MAX);


        return id;

    }


    return NULL;

}

6.3.2 驱动层ts程序注册时尝试匹配evdev

int input_register_device(struct input_dev *dev)

{

    static atomic_t input_no = ATOMIC_INIT(0);

    struct input_handler *handler;

    const char *path;

    int error;


    set_bit(EV_SYN, dev->evbit);


    /*

     * If delay and period are pre-set by the driver, then autorepeating

     * is handled by the driver itself and we don't do it in input.c.

     */


    init_timer(&dev->timer);

    if (!dev->rep[REP_DELAY] && !dev->rep[REP_PERIOD]) {

        dev->timer.data = (long) dev;

        dev->timer.function = input_repeat_key;

        dev->rep[REP_DELAY] = 250;

        dev->rep[REP_PERIOD] = 33;

    }


    /* 没有定义设备的getkeycode函数,则使用默认的获取键值函数 */

    if (!dev->getkeycode)

        dev->getkeycode = input_default_getkeycode;


     /*没有定义设备的setkeycode函数,则使用默认的设定键值函数*/

    if (!dev->setkeycode)

        dev->setkeycode = input_default_setkeycode;


    // 将设备驱动层程序加入到input_dev_list链表

    list_add_tail(&dev->node, &input_dev_list);


    snprintf(dev->cdev.class_id, sizeof(dev->cdev.class_id),

         'input%ld', (unsigned long) atomic_inc_return(&input_no) - 1);


    if (!dev->cdev.dev)

        dev->cdev.dev = dev->dev.parent;


    // 会在/sys/class/input设备类下创建设备 /sys/class/input/input%ld

    error = class_device_add(&dev->cdev);

    if (error)

        return error;


    path = kobject_get_path(&dev->cdev.kobj, GFP_KERNEL);

    printk(KERN_INFO 'input: %s as %sn',

        dev->name ? dev->name : 'Unspecified device', path ? path : 'N/A');

    kfree(path);


    // 从事件处理层程序链表中取出每一个事件处理层程序,和设备驱动层程序匹配

    list_for_each_entry(handler, &input_handler_list, node)

        input_attach_handler(dev, handler);


    input_wakeup_procfs_readers();


    return 0;

}


调用 input_attach_handler 之后的流程和evdev注册时尝试匹配驱动层ts程序一样

6.3.3 匹配成功建立联系

static int evdev_connect(struct input_handler *handler, struct input_dev *dev,

             const struct input_device_id *id)

{

    struct evdev *evdev;

    struct class_device *cdev;

    dev_t devt;

    int minor;

    int error;


    // 从evdev_table数组中取出空位。最多支持32个设备。

    for (minor = 0; minor < EVDEV_MINORS && evdev_table[minor]; minor++);

    if (minor == EVDEV_MINORS) {

        printk(KERN_ERR 'evdev: no more free evdev devicesn');

        return -ENFILE;

    }


    evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL);

    if (!evdev)

        return -ENOMEM;


    INIT_LIST_HEAD(&evdev->client_list);

    init_waitqueue_head(&evdev->wait);


    evdev->exist = 1;

    evdev->minor = minor;

    // handle中的handler成员指向了配对成功的handler,

    //           dev成员指向了配对成功的device,

    //           private成员则指向了evdev设备本身。

    // 将设备驱动层程序存储在evdev handle中

    evdev->handle.dev = dev;

    evdev->handle.name = evdev->name;

    // 将事件处理层程序存储在evdev handle中

    evdev->handle.handler = handler;

    evdev->handle.private = evdev;

    sprintf(evdev->name, 'event%d', minor);


    evdev_table[minor] = evdev;


    // 在/sys/class/input设备类下创建设备/sys/class/input/event0,并创建设备节点/dev/event%d  自此应用程序就可以通过设备节点读取与设置硬件设备

    //           input类的主设备号        创建设备的次设备号

    devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor);

    cdev = class_device_create(&input_class, &dev->cdev, devt,dev->cdev.dev, evdev->name);

    if (IS_ERR(cdev)) {

        error = PTR_ERR(cdev);

        goto err_free_evdev;

    }


    /* temporary symlink to keep userspace happy */

    error = sysfs_create_link(&input_class.subsys.kobj,

                  &cdev->kobj, evdev->name);

    if (error)

        goto err_cdev_destroy;

[1] [2] [3]
关键字:Linux驱动  s3c2410  s3c2440 引用地址:《Linux驱动:s3c2410/s3c2440 ts驱动分析--终结篇》

上一篇:《Linux驱动:s3c2440 lcd 驱动分析》
下一篇:《Linux驱动:s3c2410/s3c2440 ts驱动分析 之二》

小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved