14_input子系统my_touch_device,my_touch_handlerLinux内核模块
01_basicLinux内核模块_the kernel was built by:x86 64-linux-gnu-gcc-12(ub-CSDN博客文章浏览阅读678次,点赞3次,收藏3次。环境ID=ubuntuMakefilemodules:clean:basic.creturn 0;运行效果。_the kernel was built by:x86 64-linux-gnu-gcc-12(ubuntu 12.3.0-1ubuntu1~22.04https://blog.csdn.net/m0_37132481/article/details/136157384环境
root@T:/media/sf_D_DRIVE/kmodule/14_input_dev# cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.1 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.1 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
root@T:/media/sf_D_DRIVE/kmodule/14_input_dev#
my_touch_device.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/cdev.h>
#include <uapi/linux/major.h>
#define TAG "HELLO# "
static struct input_dev *my_input_touch;
static int my_touch_device_init(void)
{
int err;
printk(TAG "%s called\n", __func__);
/* input device */
my_input_touch = input_allocate_device();
set_bit(EV_KEY, my_input_touch->evbit);
set_bit(KEY_Q, my_input_touch->keybit);
my_input_touch->name = "don't care";
/* for device match handler */
my_input_touch->id.product = 666;
err = input_register_device(my_input_touch);
return 0;
}
static void my_touch_device_exit(void)
{
printk(TAG "%s called\n", __func__);
input_unregister_device(my_input_touch);
}
module_init(my_touch_device_init);
module_exit(my_touch_device_exit);
MODULE_LICENSE("GPL");
my_touch_handler.c
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/input.h>
#include <linux/cdev.h>
#include <uapi/linux/major.h>
#define TAG "HELLO# "
struct my_touch
{
struct input_handle handle;
struct device dev;
struct cdev cdev;
struct class *class;
};
struct my_client
{
char touchdata[10];
struct my_touch *mytc;
};
static void my_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
printk(TAG "%s called, type,code,value=%u,%u,%d\n", __func__, type, code, value);
}
static int my_cdev_open(struct inode *inode, struct file *file)
{
struct my_touch *mytc = container_of(inode->i_cdev, struct my_touch, cdev);
struct my_client *client = kzalloc(sizeof(struct my_client), GFP_KERNEL);
printk(TAG "%s called\n", __func__);
client->mytc = mytc;
file->private_data = client;
return 0;
}
static int my_cdev_release(struct inode *inode, struct file *file)
{
struct my_client *client = file->private_data;
printk(TAG "%s called\n", __func__);
kfree(client);
return 0;
}
static ssize_t my_cdev_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
struct my_client *client = file->private_data;
// simulate hardware report
input_report_key(client->mytc->handle.dev, KEY_Q, 1);
input_report_key(client->mytc->handle.dev, KEY_Q, 0);
input_sync(client->mytc->handle.dev);
printk(TAG "%s called\n", __func__);
return simple_read_from_buffer(buf, size, ppos, client->touchdata, sizeof(client->touchdata));
}
static ssize_t my_cdev_write(struct file *file, const char __user *buf, size_t size, loff_t *ppos)
{
struct my_client *client = file->private_data;
printk(TAG "%s called\n", __func__);
/* in case of echo command */
if(size > sizeof(client->touchdata))
{
return -EINVAL;
}
else
{
/* nothing to do */
}
return simple_write_to_buffer(client->touchdata, sizeof(client->touchdata), ppos, buf, size);
}
static const struct file_operations my_cdev_fops = {
.owner = THIS_MODULE,
.open = my_cdev_open,
.release = my_cdev_release,
.read = my_cdev_read,
.write = my_cdev_write,
};
static int my_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
int err;
int minor;
struct my_touch *mytc;
printk(TAG "%s called\n", __func__);
mytc = kzalloc(sizeof(struct my_touch), GFP_KERNEL);
mytc->handle.dev = input_get_device(dev);
mytc->handle.handler = handler;
mytc->handle.private = mytc;
err = input_register_handle(&mytc->handle);
err = input_open_device(&mytc->handle);
minor = input_get_new_minor(0, 0, true);
device_initialize(&mytc->dev);
/* let udev create file /dev/input/mytouch%d */
dev_set_name(&mytc->dev, "mytouch%d", minor);
mytc->dev.devt = MKDEV(INPUT_MAJOR, minor);;
mytc->dev.class = &input_class;
cdev_init(&mytc->cdev, &my_cdev_fops);
/* create file /sys/dev/char/13:MONOR */
err = cdev_device_add(&mytc->cdev, &mytc->dev);
return 0;
}
static void my_disconnect(struct input_handle *handle)
{
struct my_touch *mytc = handle->private;
printk(TAG "%s called\n", __func__);
input_close_device(&mytc->handle);
input_unregister_handle(&mytc->handle);
cdev_device_del(&mytc->cdev, &mytc->dev);
input_free_minor(MINOR(mytc->dev.devt));
kfree(mytc);
}
static const struct input_device_id my_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_PRODUCT,
.product = 666,
},
{ },
};
static struct input_handler my_handler = {
.event = my_event,
.connect = my_connect,
.disconnect = my_disconnect,
.name = "my_handler",
.id_table = my_ids,
};
static int my_touch_handler_init(void)
{
int err;
printk(TAG "%s called\n", __func__);
/* input handler */
err = input_register_handler(&my_handler);
return 0;
}
static void my_touch_handler_exit(void)
{
printk(TAG "%s called\n", __func__);
input_unregister_handler(&my_handler);
}
module_init(my_touch_handler_init);
module_exit(my_touch_handler_exit);
MODULE_LICENSE("GPL");
效果