Linuxの高度な文字ドライバー入力サブシステム

入力サブシステムの役割とフレームワーク

  • 入力デバイスとは
  1. キー/キーボード
  2. マウス
  3. タッチスクリーン(タッチスクリーン):gt811、ft56xx
  4. ジョイスティックジョイスティック
  • 駆動する必要のある入力デバイスが複数ある場合、入力サブシステムが考慮されていない場合
  1. gt811
    デバイス番号、ファイル作成、ハードウェア初期化、fopの実現、ブロッキング、ハードウェア初期化(I2Cなど)
  2. ft56xx
    デバイス番号、ファイル作成、ハードウェア初期化、fopの実現、ブロッキング、ハードウェア初期化(I2Cなど)。
  • 複数の入力デバイスの共通点
    データの取得(ハードウェア操作)-------差別化と
    ユーザーへのレポート(xxx_read、copy_to_user、ブロッキング)------複数の入力デバイスが一般的
    です。いくつかの違いがあります。
    考慮し、一般的なコードを記述し、差別化されたコードをドライバーエンジニアに任せる汎用カーネルもいくつかあります。
  • 入力サブシステムとして設計:アプリケーションプログラマーとドライバープログラマーがプログラミングを簡単かつ統合できるようにします
  1. すべての入力デバイスと互換性があります
  2. 統一されたプログラミングドライブ方式(差別化されたハードウェア操作を実現するため)
  3. 統合アプリケーション操作インターフェイス:/ dev / input / event0、event1、open( "/ dev / input / event0、event1")、read(fd、struct input_event):structinput_eventバフは統合データパケットと見なすことができます

フレーム

  • フレームワーク:ドライバーは、
    ここに写真の説明を挿入
    ここに写真の説明を挿入
    入力コアレイヤーと入力ハンドラーレイヤーの3つのレイヤーに分かれています。カーネルに付属するコード。ドライバーエンジニアは、入力デバイスレイヤー(入力デバイスレイヤー)でプログラミングするだけで済みます。

入力サブシステムをプログラムする方法

  • 入力サブシステムのプログラミング方法—入力サブシステムを開発する簡単な方法を学びます
  • 前提条件:入力コアレイヤーコードと入力ハンドラーレイヤーコードには、カーネルに/drivers/input/input.c含まれている必要があります
    //コアレイヤーコード
    /drivers/input/evdev.c//イベントハンドラー
  • makemenuconfig
    デバイスドライバー
    >入力デバイスサポート—>
    ここに写真の説明を挿入
    汎用入力レイヤー
    イベントインターフェイス//入力ハンドラー層evdev.c

プログラミング手順:
(1)入力デバイスオブジェクトの割り当て
(2)入力デバイスオブジェクトの初期化
(3)入力デバイスオブジェクトの登録

  • レポートデータ
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)

パラメータ1:現在の入力デバイス
によって報告されたデータパラメータ2:報告されたデータのタイプはEV_KEY、EV_ABSです
パラメータ3:特定のデータは何ですか:KEY_POWER
パラメータ4:値は何ですか

  • ユーザースペースで読み取られたデータ:統合データパケット
struct input_event
{
    
    
	struct timeval time;   //时间戳
	__u16 type;  //数据类型
	__u16 code;  //具体数据是什么
	__s32 value;  //值是什么
}
  • コード例
#include<linux/init.h>
#include<linux/module.h>
#include<linux/input.h>

struct input_dev *inputdev;

static int __init simple_input_init(void)
{
    
    

    //编写输入子系统代码
    /*
     *(1)分配一个 input device 对象
     *(2)初始化 input device 对象
     *(3)注册 input device 对象
     * */

    int ret;
    inputdev = input_allocate_device(); 
    if(inputdev == NULL)
    {
    
    
        printk(KERN_ERR "input allocate device error\n");
        return -ENOMEM;
    }

    //当前设备能够产生按键数据
    __set_bit(EV_KEY,inputdev->evbit);
    //表示当前设备能够产生power按键
    __set_bit(KEY_POWER,inputdev->keybit);

    ret = input_register_device(inputdev);
    if(ret != 0)
    {
    
    
        printk(KERN_ERR "input register device error\n");
        goto err_0;
        return ret;
    }
    return 0;

err_0:
    input_free_device(inputdev);
    return ret;
}



static void __exit simple_input_exit()
{
    
    
    
    input_unregister_device(inputdev);
    input_free_device(inputdev);

}

module_init(simple_input_init);
module_exit(simple_input_exit);
MODULE_LICENSE("GPL");

ユーザースペースアプリケーション:

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

int main(void)
{
    
    
	int fd;
	int ret;
	struct input_event event;
	
	fd = open("/dev/event0",O_RDWR);
	if(fd < 0)
	{
    
    
		perror("open");
		exit(1);
	}
	
	while(1)
	{
    
    
		ret = read(fd,&event,sizeof(struct input_event));
		if(ret < 0)
		{
    
    
			perror("read");
			exit(1);
		}
		
		if(event.type == EV_KEY)
		{
    
    
			if(event.code == KEY_POWER)
			{
    
    
				if(event.value)   //按键按下
				{
    
    
					printf("__APP_USER__:power pressed\n");
				}
				else  //按键抬起
				{
    
    
					printf("__APP_USER__:power up\n");
				}
			}
		}
	}
	close(fd);
	return 0;
}

おすすめ

転載: blog.csdn.net/qq_41782149/article/details/99701533