input驱动简介
struct input_dev;
根据linux驱动的基本设计思路,任何设备可以挂载到任易的总线下,所以,input_dev也
不例外。
例如传统的PS2键盘,其实是一个串口设备,直到后来出的USB键盘,在系统中也是一个串口
只是在系统中看到设备是挂在/dev/input/下。
input设备驱动设计思路
目前我们见的input类开的设备基本都是USB接口,也就是,我们先要设计一个usb驱动框架。
我在之前的文章已经设计好了一个USB设备驱动的基本框架,今天来设计一下作为input设备继续
开发这个驱动。
目前我们常见的input设备有键盘、鼠标、触屏。这三种设备即有相同之后,也有不同之处。
键盘、鼠标一般都是挂在USB总线下,触屏是挂在I2C总线下。在设计驱动时,大体的思路和流程
基本不变,不同的总线设计稍有不同。
数据结构
这里还是以上一章的usb设备为基本框架设计一个input设备的驱动。
struct usb_input_dev {
struct input_dev *input;
struct usb_device *parent;
struct usb_endpoint_descriptor *ep;
struct mutex lock;
struct work_struct work;
struct workqueue_struct *wq;
struct hrtimer timer;
char *buf_out;
};
static void input_dev_work_func(struct work_struct *work)
{
struct usb_input_dev *dev = container_of(work, struct usb_input_dev, work);
}
static int input_dev_open(struct input_dev *input)
{
struct usb_input_dev *dev = input_get_drvdata(input);
queue_work(dev->wq, &dev->work);
hrtimer_start(&dev->timer, ktime_set(0, 200 * 1000000), HRTIMER_MODE_REL);
}
static void input_dev_close(struct input_dev *input)
{
struct usb_input_dev *dev = input_get_drvdata(input);
hrtimer_cancel(&dev->timer);
}
static enum hrtimer_restart input_dev_timer_restart(struct hrtimer *timer)
{
struct usb_input_dev *dev = container_of(timer, struct usb_input_dev, timer);
queue_work(dev->wq, &dev->work);
hrtimer_start(&dev->timer, ktime_set(0, 200 * 1000000), HRTIMER_MODE_REL);
return HRTIMER_NORESTART;
}
static int usb_input_probe(struct usb_interface *iface, struct usb_device_id *id)
{
int ret;
struct sub_endpoint_descriptor *ep;
struct usb_input_dev *dev;
struct usb_host_interface *alt = iface->cur_altsetting;
ret = usb_find_int_int_endpoint(alt, &ep);
if (ret) {
dev_err(&iface->dev, "can not found int in ep:%d\n", ret);
return -EIO;
}
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
dev->ep = ep;
dev->buf_out = kzalloc(512, GFP_KERNEL);
if (!dev->buf_out) {
kfree(dev);
return -ENOMEM;
}
dev->input = devm_input_allocate_device(iface->dev);
if (!dev->input) {
kfree(dev);
return -ENOMEM;
}
dev->usbdev = interface_to_usbdev(iface);
mutex_init(&dev->lock);
hrtimer_init(&dev->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
dev->timer.function = input_dev_timer_restart;
dev->wq = create_singlethread_workqueue("usb_dev");
if (!dev->wq) {
input_free_device(dev->input);
kfree(dev);
return -ENOMEM;
}
INIT_WORK(&dev->work, input_dev_work_func);
dev->input->open = usb_dev_open;
dev->input->close = usb_dev_close;
ret = input_register_device(dev->input);
if (ret) {
input_free_device(dev->input);
destroy_workqueue(dev->wq);
kfree(dev);
return ret;
}
input_set_drvdata(dev->input, dev);
usb_set_intfdata(iface, dev);
return 0;
}