M平台input设备分析

在Android平台通常有多个输入设备,遥控器,按键板,触摸屏/触摸框,鼠标,蓝牙笔等等。
归根结柢都是属于Linux 平台的一个input device,上面的多个种类的输入设备是input 
device 的封装。
下面以手上平台为例,一起学习了解遥控器设备的注册流程。
  1. android 输入设备的查询

如图:
在这里插入图片描述
上面描述了四个输入设备:触摸框(libxTouchScreen),按键板(MStar Smart TV Keypad),空鼠(cv simulate mouse),遥控器(Sharp Smart TV IR Receiver)。如果想看各个输入设备和android层按键的的映射关系(*.kl)。

  1. linux event 与 android keyevent 映射

可以通过dumpsys input查看

INPUT MANAGER (dumpsys input)

Input Manager State:
  Interactive: true
  System UI Visibility: 0x0
  Pointer Speed: 0
  Pointer Gestures Enabled: true
  Show Touches: false

Event Hub State:
  BuiltInKeyboardId: -2
  Devices:
    -1: Virtual
      Classes: 0x40000023
      Path: <virtual>
      Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd
      Location: 
      ControllerNumber: 0
      UniqueId: <virtual>
      Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
      KeyLayoutFile: /system/usr/keylayout/Generic.kl
      KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false
    1: libxTouchScreen
      Classes: 0x80000014
      Path: /dev/input/event4
      Descriptor: d0adc8211820a452e94d90216845733a1280d769
      Location: 
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0003, vendor=0x0000, product=0x0000, version=0x0004
      KeyLayoutFile: 
      KeyCharacterMapFile: 
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false
    2: MStar Smart TV Keypad
      Classes: 0x00000001
      Path: /dev/input/event3
      Descriptor: 8f43d929a9472e8dc54d48a6c41e2435e8eaff35
      Location: 
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0006, vendor=0x3697, product=0x0002, version=0x0000
      KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0002.kl
      KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false
    3: cv simulate mouse
      Classes: 0x00000009
      Path: /dev/input/event2
      Descriptor: 4055b8a032ccf50ef66dbe2ff99f3b2474e9eab5
      Location: smouse/input0
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0019, vendor=0xbeef, product=0xdead, version=0x0001
      KeyLayoutFile: /system/usr/keylayout/Generic.kl
      KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false
    4: MCE IR Keyboard/Mouse (ir)
      Classes: 0x0000000b
      Path: /dev/input/event1
      Descriptor: 2b764a30c0f74e1362d8ef86c5e4f12150af666f
      Location: /input0
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
      KeyLayoutFile: /system/usr/keylayout/Generic.kl
      KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false
    5: Sharp Smart TV IR Receiver
      Classes: 0x00000001
      Path: /dev/input/event0
      Descriptor: 0e50bdc18d3ae0b6f247100cbd99062d93c208eb
      Location: /dev/ir
      ControllerNumber: 0
      UniqueId: 
      Identifier: bus=0x0018, vendor=0x3697, product=0x0001, version=0x0001
      KeyLayoutFile: /system/usr/keylayout/Vendor_3697_Product_0001.kl
      KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
      ConfigurationFile: 
      HaveKeyboardLayoutOverlay: false

遥控器和按键板事件与android的映射关系,可以看KeyLayoutFile 参数值,例如:
/system/usr/keylayout/Vendor_3697_Product_0002.kl 和/system/usr/keylayout/Vendor_3697_Product_0001.kl 分别是按键板,遥控器的映射表。

  1. linux input 设备注册流程

下面以一张图来简答介绍一下注册流程,如下:
在这里插入图片描述
各个厂商的遥控器,长虹,创维,康佳,tcl,海信等等,会注册到mstar ir 的模块中,中间再注册到Input 中,最后设备添加到内核中。

  • 通过rc_map_register (@rc-main.c) 将rc_map注册到rc_map_list 链表中
static int __init init_rc_map_cultraview_tv(void)
{
    return rc_map_register(&cultraview_tv_map);
}

static void __exit exit_rc_map_cultraview_tv(void)
{
    rc_map_unregister(&cultraview_tv_map);
}
  • mstar ir 在驱动加载过程中通过probe注册设备
static int mstar_ir_drv_probe(struct platform_device *pdev) {
    int retval=0;
    if (!(pdev->name) || strcmp(pdev->name,"Mstar-ir")
        || pdev->id!=0) {
        retval = -ENXIO;
    }

    IRDev.u32IRFlag = 0;
    retval = mod_ir_init();
    if (!retval) {
        pdev->dev.platform_data=&IRDev;
    }

#ifdef CONFIG_CV_SIMULATE_MOUSE
    if (device_create_file(&pdev->dev, &dev_attr_smouse_enable))
        printk("Warnning: can't create sysfs smouse_enable attribute\n");
#endif

    return retval;
}

mod_ir_init 继续往下走

static int mod_ir_init(void) {
    int ret;
    dev_t dev;
#ifdef CONFIG_MSTAR_UDEV_NODE
    ir_class = class_create(THIS_MODULE, MDRV_NAME_IR);
    if (IS_ERR(ir_class))
    {
        return PTR_ERR(ir_class);
    }
#endif
    if (IRDev.s32IRMajor) {
        dev = MKDEV(IRDev.s32IRMajor, IRDev.s32IRMinor);
        ret = register_chrdev_region(dev, MOD_IR_DEVICE_COUNT, MDRV_NAME_IR);
    } else {
        ret = alloc_chrdev_region(&dev, IRDev.s32IRMinor, MOD_IR_DEVICE_COUNT, MDRV_NAME_IR);
        IRDev.s32IRMajor = MAJOR(dev);
    }

    if ( 0 > ret) {
        IR_PRINT("Unable to get major %d\n", IRDev.s32IRMajor);
        return ret;
    }

    cdev_init(&IRDev.cDevice, &IRDev.IRFop);
    if (0!= (ret= cdev_add(&IRDev.cDevice, dev, MOD_IR_DEVICE_COUNT))) {
        IR_PRINT("Unable add a character device\n");
        unregister_chrdev_region(dev, MOD_IR_DEVICE_COUNT);
        return ret;
    }

#ifdef CONFIG_MSTAR_IR_INPUT_DEVICE
    MDrv_IR_Input_Init();
    MDrv_IR_Init(0);
    IRDev.u32IRFlag |= (IRFLAG_IRENABLE|IRFLAG_HWINITED);
#endif
#ifdef CONFIG_MSTAR_UDEV_NODE
    device_create(ir_class, NULL, dev, NULL, MDRV_NAME_IR);
#endif
    return 0;
}

MDrv_IR_Input_Init 接着注册RC device设备

int MDrv_IR_Input_Init(void) {
    char *map_name = RC_MAP_MSTAR_TV;
    char *input_name = "MStar Smart TV IR Receiver";  //  设备名称
    __u16 vendor_id = 0x3697UL;

    int err = 0;
    struct rc_dev *dev;

    ir = kzalloc(sizeof(struct mstar_ir), GFP_KERNEL);
	dev = rc_allocate_device();
    if (!ir || !dev)
        return -ENOMEM;

    // init input device
    ir->dev = dev;

    //  设置input设备的属性,名称,类型,vendor id,product id,支持的遥控器协议等
    //   可以dumpsys input 查看设备对应的属性,都是此处设置
    dev->driver_name = MDRV_NAME_IR;
    dev->map_name = map_name;
    dev->driver_type = RC_DRIVER_IR_RAW;
    dev->input_name = input_name;
    dev->input_phys = "/dev/ir";
    dev->input_id.bustype = BUS_I2C;
    dev->input_id.vendor = vendor_id;
    dev->input_id.product = 0x0001UL;
    dev->input_id.version = 1;
    dev->allowed_protos = RC_TYPE_ALL;
    err = rc_register_device(dev);
    if (err) {
        rc_free_device(dev);
        kfree(ir);
        return err;
    }
    // No auto-repeat.
    clear_bit(EV_REP, ir->dev->input_dev->evbit);

#ifdef CONFIG_CV_SIMULATE_MOUSE
    //if smouse init fail just ignore.
    ir->sm = smouse_init(ir->dev);
    if (ir->sm == NULL)
        printk("csign: smouse_init failed\n");
#endif
    init_completion(&key_completion);
    key_dispatch_workqueue = create_workqueue("keydispatch_wq");
    queue_work(key_dispatch_workqueue, &key_dispatch_thread);
    return 0;
}
  • 分解rc device 为input device

将分解开的rc device 设备继续向下注册

int input_register_device(struct input_dev *dev)
{
	static atomic_t input_no = ATOMIC_INIT(0);
	struct input_devres *devres = NULL;
	struct input_handler *handler;
	unsigned int packet_size;
	const char *path;
	int error;
	......
	error = device_add(&dev->dev);
	......
}

至此,完成了遥控器设备(“Sharp Smart TV IR Receiver”)的整个注册流程。另外“cv simulate mouse”设备的注册如下:

struct smouse *smouse_init(struct rc_dev *rc)
{
    struct smouse *s = NULL;
    struct input_dev *idev = NULL;

    s = (struct smouse *)kzalloc(sizeof(*s), GFP_KERNEL);
    idev = input_allocate_device();
    if (!s || !idev) {
        goto fail1; 
    }
    s->rc = rc;
    s->idev = idev;
    s->rc_state = RC_UP;
    s->sm_mode = 0; //default isn't simulate mouse mode
    //  input 设备的属性设置
    idev->name = "cv simulate mouse";
    idev->phys = "smouse/input0";
    idev->id.bustype = BUS_HOST;
    idev->id.vendor = 0xbeef;
    idev->id.product = 0xdead;
    idev->id.version = 0x0001;
    idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
    idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
    idev->keybit[BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
    set_bit(KEY_UNKNOWN, idev->keybit);
    //  input 注册
    if (input_register_device(idev))
        goto fail2;
    
    init_timer(&s->slide_timer);
    s->slide_timer.data = (long)s;
    s->slide_timer.function = mouse_slide_fn;
    s->slide_delay = SLIDE_DELAY;    //250;
    s->slide_period = SLIDE_PERIOD;  //33;

    return s;
fail2:
    input_free_device(idev);
fail1:
    if (s) 
        kfree(s);
    return NULL;
}
  • input 设备(RC)的 event 设置
    这个event 设置也就是所谓的遥控码值设置,定义一个rc_map_table
static struct rc_map_table hisense_tv[] = {
    // 1st IR controller.  第一款遥控码值表
    { 0xBF0D, KEY_POWER },
    { 0xBF0E, KEY_MUTE },
    { 0xBF1A, KEY_SLEEP },
    { 0xBF11, KEY_AUDIO },      // SOUND_MODE
    { 0xBF10, KEY_CAMERA },     // PICTURE_MODE
    { 0xBF13, KEY_ZOOM },       // ASPECT_RATIO
    { 0xBF0B, KEY_CHANNEL },    // CHANNEL_RETURN
	......
    // Hisense extended
    { 0xBF1C, KEY_F1 },         // HISENSE_SAVEMODE
    { 0xBF49, KEY_F2 },         // HISENSE_AUDIO_TRACK
    { 0xBF5D, KEY_F3 },         // HISENSE_BROADCAST

    // 2nd IR cotroller.  第二款遥控器码值表
	......
	{ 0xFC50, KEY_FN_RDRV_PLUS },
	{ 0xFC46, KEY_FN_RDRV_INC },
	{ 0xFC4C, KEY_FN_GDRV_PLUS },
	{ 0xFC5A, KEY_FN_GDRV_INC },
	{ 0xFC49, KEY_FN_BDRV_PLUS },
	{ 0xFC4A, KEY_FN_BDRV_INC },
	{ 0xFC44, KEY_FN_RCUT_PLUS },
	{ 0xFC41, KEY_FN_RCUT_INC },
	{ 0xFC4B, KEY_FN_GCUT_PLUS },
	{ 0xFC51, KEY_FN_GCUT_INC },
	{ 0xFC08, KEY_FN_BCUT_PLUS },
	{ 0xFC45, KEY_FN_BCUT_INC },
    ......
};

映射表中右侧是驱动定义(@input.h)的事件,且每个事件都是唯一的,左侧十六进制是遥控头码和码值的组合值(遥控器头码+按键码值),如上面数组,头码有0xBF,0XFC,理论上就需要可以支持两组遥控器,一般有一个工厂遥控器和客供遥控器。

  • 头码设置
    主要是设置IR_HEADER_CODE0,IR_HEADER_CODE1,在头文件@ K:\huiyi\base_648\vendor\mstar\kernel\linaro\mstar2\drv\ir\IR_${VendorName}.h,海信对应的就是IR_HISENSE.h
    在这里插入图片描述
  • 多遥控器遥控器支持
    在这里插入图片描述
    mdrv_ir.c 中会根据客户情况,设置多个头码,例如IR_HISENSE.h中
    在这里插入图片描述
    FCTORY_HEADER_RECEIVE 和PCCOMMAND_HEADER_RECEIVE 是设置多遥控必须开启的,IR_FHEADER_CODE0,IR_FHEADER_CODE1 和IR_PHEADER_CODE0,IR_PHEADER_CODE1 两组则属于扩展部分的遥控器。
    双遥控器,如下:
    在这里插入图片描述
    其中IR_FHEADER_CV_CODE0,IR_FHEADER_CV_CODE1 是第二组遥控器头码码值。以上是整个遥控器设备按键配置,注册流程。后续分享m平台模拟input 设备的知识。
  1. 新增标准HID设备键值配置
    首先查看所有input 设备的属性,特别是vendor id ,product id。
    cat /proc/bus/input/devices 执行如下:
    在这里插入图片描述
    在这里插入图片描述
    我们可以看到两组vendor id ,product id, 这样我们在 /system/usr/keylayout/ 目录
    在这里插入图片描述
    这里添加Vendor_xxxx_Product_yyyy.kl 文件,然后通过getevent 将获取的物理键值和
    android 里面KeyEvent 里面对应的按键字符匹配上即可。
    在这里插入图片描述
    这里按键就可以一步步流到android层了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值