📄 最近新学linux对一个鼠标驱动的分析.cpp
字号:
fops_put(new_fops);
return -ENODEV;
}
old_fops = file->f_op;
file->f_op = new_fops;//将句柄的操作函数集给file->f_op
err = new_fops->open(inode, file);//执行输入驱动器的打开操作
if (err) {
fops_put(file->f_op);
file->f_op = fops_get(old_fops);
}
fops_put(old_fops);
return err;
}
联系err = new_fops->open(inode, file);
和static struct input_handler mousedev_handler = {
.event = mousedev_event,//鼠标事件回调函数
.connect = mousedev_connect,//连接device
.disconnect = mousedev_disconnect,
.fops = &mousedev_fops,//文件操作函数集
.minor = MOUSEDEV_MINOR_BASE,//次设备号基数
.name = "mousedev",//设备名
.id_table = mousedev_ids,//本驱动支持的设备ID
};
这个就相当于调用mousedev_handler.fops中的函数也即mousedev_fops的函数,
而mousedev_fops的open函数是mousedev_open
分配一个mousedev_list结构保存给file结构的私有数据
mousedev_list里保存了一个mousedev结构。。而mousedev也有个文件链表。这样当
中断发生时可以根据链表反向找到file结构,而后驱动器打开他拥有并存在的未打开的所有设备句柄
调用了input_open_device函数
“/input/mousedev . c”
static int mousedev_open(struct inode * inode, struct file * file)
{
struct mousedev_list *list;
struct input_handle *handle;
struct mousedev *mousedev;
int i;
#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
if (imajor(inode) == MISC_MAJOR)
i = MOUSEDEV_MIX;
else
#endif
i = iminor(inode) - MOUSEDEV_MINOR_BASE;
if (i >= MOUSEDEV_MINORS || !mousedev_table[i])
return -ENODEV;
if (!(list = kmalloc(sizeof(struct mousedev_list), GFP_KERNEL)))
return -ENOMEM;
memset(list, 0, sizeof(struct mousedev_list));
spin_lock_init(&list->packet_lock);
list->pos_x = xres / 2;
list->pos_y = yres / 2;
list->mousedev = mousedev_table[i];
list_add_tail(&list->node, &mousedev_table[i]->list);
file->private_data = list;
if (!list->mousedev->open++) {
if (list->mousedev->minor == MOUSEDEV_MIX) {
list_for_each_entry(handle, &mousedev_handler.h_list, h_node) {
mousedev = handle->private;
if (!mousedev->open && mousedev->exist)
input_open_device(handle);
}
} else
if (!mousedev_mix.open && list->mousedev->exist)
input_open_device(&list->mousedev->handle);
}
return 0;
}
input_open_device 调用设柄句柄中保存的设备指针的open函数直接打开设备
“/input/input . c”
int input_open_device(struct input_handle *handle)//在mousedev里的mousedevopen调用
{
handle->open++;
if (handle->dev->open)
return handle->dev->open(handle->dev);//调用具体设备的OPEN比如amimouse里的Open
return 0;
}
这就相当于打开了第三节中input_dev::open函数既amimouse_open函数
amimouse_open函数为设备申请了中断资源并设定了中断服务程序amimouse_interrupt
“/input/mouse/amimouse . c”
static int amimouse_open(struct input_dev *dev)
{
unsigned short joy0dat;
if (amimouse_used++)
return 0;
joy0dat = custom.joy0dat;
amimouse_lastx = joy0dat & 0xff;
amimouse_lasty = joy0dat >> 8;
if (request_irq(IRQ_AMIGA_VERTB, amimouse_interrupt, 0, "amimouse", amimouse_interrupt)) {
amimouse_used--;
printk(KERN_ERR "amimouse.c: Can't allocate irq %d\n", IRQ_AMIGA_VERTB);
return -EBUSY;
}
return 0;
}
中断服务程序amimouse_interrupt从内存得到数据//amimouse中断发生时会把数据存在一块固定地址
通过input_report_rel等函数通知设备已获得数据
“/input/mouse/amimouse . c”
static irqreturn_t amimouse_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
/**/
unsigned short joy0dat, potgor;
int nx, ny, dx, dy;
joy0dat = custom.joy0dat;
nx = joy0dat & 0xff;
ny = joy0dat >> 8;
dx = nx - amimouse_lastx;
dy = ny - amimouse_lasty;
if (dx < -127) dx = (256 + nx) - amimouse_lastx;
if (dx > 127) dx = (nx - 256) - amimouse_lastx;
if (dy < -127) dy = (256 + ny) - amimouse_lasty;
if (dy > 127) dy = (ny - 256) - amimouse_lasty;
amimouse_lastx = nx;
amimouse_lasty = ny;
potgor = custom.potgor;
input_regs(&amimouse_dev, fp);
input_report_rel(&amimouse_dev, REL_X, dx);
input_report_rel(&amimouse_dev, REL_Y, dy);
input_report_key(&amimouse_dev, BTN_LEFT, ciaa.pra & 0x40);
input_report_key(&amimouse_dev, BTN_MIDDLE, potgor & 0x0100);
input_report_key(&amimouse_dev, BTN_RIGHT, potgor & 0x0400);
input_sync(&amimouse_dev);
.......
return IRQ_HANDLED;
}
input_report_rel,input_report_key函数只是简单调用input_event函数
“/linux/input.h”
static inline void input_report_rel(struct input_dev *dev, unsigned int code, int value)
{
input_event(dev, EV_REL, code, value);
}
如果设备自已有专用event函数既input_dev结构中event非空 input_event调用event函数
如果与设备相关的设备句柄是唯一指定的保存在grab中就调用该句柄所指向的驱动器handler的event函数
否则遍历设备设备句柄链表调用句柄指向的驱动器event函数。。
这里因为amimouse没有专属的event函数而grab在input_register_device时在mousedev_connect函数中也没给值,
但其返回的设备句柄在设备的句柄链表里。所以会调用mousedev驱动器的event函数既mousedev_event函数
“/input/input . c”
void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct input_handle *handle;
if (type > EV_MAX || !test_bit(type, dev->evbit))
return;
add_input_randomness(type, code, value);
switch (type) {
case EV_SYN:
switch (code) {
case SYN_CONFIG:
if (dev->event) dev->event(dev, type, code, value);
break;
...
...
...
}
break;
}
if (dev->grab)
dev->grab->handler->event(dev->grab, type, code, value);
else
list_for_each_entry(handle, &dev->h_list, d_node)
if (handle->open)
handle->handler->event(handle, type, code, value);//见line 439
}
“/input/mousedev . c”
static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
{
struct mousedev *mousedev = handle->private;//在mousedev_connect中给handle的私有变量的mousedev指针
switch (type) {
....
case EV_SYN:
if (code == SYN_REPORT) {
if (mousedev->touch) {
mousedev->pkt_count++;
/* Input system eats duplicate events, but we need all of them
* to do correct averaging so apply present one forward
*/
fx(0) = fx(1);
fy(0) = fy(1);
}
mousedev_notify_readers(mousedev, &mousedev->packet);//通知设备有数据到达读取
mousedev->packet.dx = mousedev->packet.dy = mousedev->packet.dz = 0;
mousedev->packet.abs_event = 0;
}
break;
case EV_REL:
mousedev_rel_event(mousedev, code, value);
/****/
break;
....
}
}
static void mousedev_rel_event(struct mousedev *mousedev, unsigned int code, int value)
{
switch (code) {
case REL_X: mousedev->packet.dx += value; break;
case REL_Y: mousedev->packet.dy -= value; break;
case REL_WHEEL: mousedev->packet.dz -= value; break;
}
}
读取鼠标位置时
同打开文件一样,读取file时会调用file的f_op函数集的函数,但此是f_op已经在打开时付值为驱动器的函数集指针了。
既mousedev_fops函数集,其中的read函数为mousedev_read,他在本设备等待有输入发生。
“/input/mousedev . c”
static ssize_t mousedev_read(struct file * file, char __user * buffer, size_t count, loff_t *ppos)
{
struct mousedev_list *list = file->private_data;
int retval = 0;
if (!list->ready && !list->buffer && (file->f_flags & O_NONBLOCK))
return -EAGAIN;
retval = wait_event_interruptible(list->mousedev->wait,
!list->mousedev->exist || list->ready || list->buffer);
if (retval)
return retval;
if (!list->mousedev->exist)
return -ENODEV;
if (!list->buffer && list->ready) {
mousedev_packet(list, list->ps2);
list->buffer = list->bufsiz;
}
if (count > list->buffer)
count = list->buffer;
list->buffer -= count;
if (copy_to_user(buffer, list->ps2 + list->bufsiz - list->buffer - count, count))
return -EFAULT;
return count;
}
通过mousedev->list遍历打开本设备的所有mousedev_list结构并对他们付值,mousedev_list结构是在打开设备时
链接进list的,而在打开此设备的文件描述符File中的privatedata指向些list指针。。。而后置
list->ready为真表有数据到达,再唤醒一个在本设备等待读数据的进程
“/input/mousedev . c”
static void mousedev_notify_readers(struct mousedev *mousedev, struct mousedev_hw_data *packet)
{
struct mousedev_list *list;
struct mousedev_motion *p;
unsigned long flags;
list_for_each_entry(list, &mousedev->list, node) {
spin_lock_irqsave(&list->packet_lock, flags);
p = &list->packets[list->head];
if (list->ready && p->buttons != mousedev->packet.buttons) {
unsigned int new_head = (list->head + 1) % PACKET_QUEUE_LEN;
if (new_head != list->tail) {
p = &list->packets[list->head = new_head];
memset(p, 0, sizeof(struct mousedev_motion));
}
}
if (packet->abs_event) {
p->dx += packet->x - list->pos_x;
p->dy += packet->y - list->pos_y;
list->pos_x = packet->x;
list->pos_y = packet->y;
}
list->pos_x += packet->dx;
list->pos_x = list->pos_x < 0 ? 0 : (list->pos_x >= xres ? xres : list->pos_x);
list->pos_y += packet->dy;
list->pos_y = list->pos_y < 0 ? 0 : (list->pos_y >= yres ? yres : list->pos_y);
p->dx += packet->dx;
p->dy += packet->dy;
p->dz += packet->dz;
p->buttons = mousedev->packet.buttons;
if (p->dx || p->dy || p->dz || p->buttons != list->last_buttons)
list->ready = 1;
spin_unlock_irqrestore(&list->packet_lock, flags);
if (list->ready)
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
wake_up_interruptible(&mousedev->wait);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -