Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192147
  • 博文数量: 111
  • 博客积分: 3010
  • 博客等级: 中校
  • 技术积分: 1240
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-07 07:46
文章分类

全部博文(111)

文章存档

2015年(2)

2014年(1)

2011年(1)

2010年(7)

2009年(100)

我的朋友

分类: LINUX

2009-08-07 10:09:07


转载时请注明出处和作者联系方式
文章出处:http://www.limodev.cn/blog
作者联系方式:李先静

6.X Window输入设备(TinyX)

X Window支持的基本输入设备有keyboard、mouse和touchscreen,keyboard有自己的驱动接口,而后两者具有相同的驱动接口。

输入设备的初始化。

1. X Server在初始化时会调用InitInput函数初始化输入设备。
2. InitInput调用KdInitInput完成TinyX输入设备的初始化。其参数LinuxMouseFuncs指向mouse驱动函数,LinuxKeyboardFuncs指向keyboard驱动的函数。
3. 在KdInitInput中,创建一个KdMouseInfo对象,放入kdMouseInfo链表中,并初始化这个KdMouseInfo对象。
4. 在KdInitInput中,把指向keyboard和mouse驱动的指针保存到kdMouseFuncs和kdKeyboardFuncs两个全局变量之中。
5. 在KdInitInput中,加载键盘映射表,初始化按键重复的数据结构,重置输入设备的状态。
6. 在KdInitInput中,创建keyboard和mouse设备,并注册这两个输入设备到系统中。
7. 如果支持touchscreen,把kdTsFuncs指向TsFuncs。

keyboard的驱动接口

typedef struct _KdKeyboardFuncs     {
void (*Load) (void);
int (*Init) (void);
void (*Leds) (int);
void (*Bell) (int, int, int);
void (*Fini) (void);
int LockLed;
} KdKeyboardFuncs;

下面我们来看一个实际例子(tinyx/linux/keyboard.c):

KdKeyboardFuncs LinuxKeyboardFuncs =     {
LinuxKeyboardLoad,
LinuxKeyboardInit,
LinuxKeyboardLeds,
LinuxKeyboardBell,
LinuxKeyboardFini,
3,
};

LinuxKeyboardLoad: 构建一个键值映射表,即从原始的按键值到虚拟键值间VK之间的映射。让虚拟键值独立于硬件的,可以提高应用程序的可移植性。

static void
LinuxKeyboardLoad (void)
{
readKernelMapping ();
}

LinuxKeyboardInit:初始化一些数据结构,并注册相关回调函数。这样,在有按键事件时,LinuxConsoleFd唤醒 select,并调用函数LinuxKeyboardRead读取按键事件,经过一些转换动作之后,调用KdHandleKeyboardEvent把事 件分发出去。

static int
LinuxKeyboardInit (void)
{
if (!LinuxKbdType)
LinuxKbdType = KdAllocInputType ();

KdRegisterFd (LinuxKbdType, LinuxConsoleFd, LinuxKeyboardRead, 0);
LinuxKeyboardEnable (LinuxConsoleFd, 0);
KdRegisterFdEnableDisable (LinuxConsoleFd,
LinuxKeyboardEnable,
LinuxKeyboardDisable);
return 1;
}

LinuxKeyboardLeds: 在某些键按下以后,需要点亮键盘灯(Caps Lock和 Num Lock等),这时候会调用这个函数,这是通过ioctl系统调用实现的。

static void
LinuxKeyboardLeds (int leds)
{
ioctl (LinuxConsoleFd, KDSETLED, leds & 7);
}

LinuxKeyboardBell:它的功能是发出蜂鸣声,至于为什么作为键盘驱动的一部分,可能是由于输入某些键值时要响一声吧(如,\a)。这也是通过ioctl系统调用实现的。

static void
LinuxKeyboardBell (int volume, int pitch, int duration)
{
if (volume && pitch)
{
ioctl(LinuxConsoleFd, KDMKTONE,
((1193190 / pitch) & 0xffff) |
(((unsigned long)duration *
volume / 50) << 16));

}
}

LinuxKeyboardFini:~初始化keyboard设备,即禁用keyboard,然后注销设备描述符。

static void
LinuxKeyboardFini (void)
{
LinuxKeyboardDisable (LinuxConsoleFd, 0);
KdUnregisterFds (LinuxKbdType, FALSE);
}

鼠标的接口:

typedef struct _KdMouseFuncs     {
int (*Init) (void);
void (*Fini) (void);
} KdMouseFuncs;

下面看一个实际例子(tinyx/linux/mouse.c)

KdMouseFuncs LinuxMouseFuncs =     {
MouseInit,
MouseFini,
};

MouseInit 打开设备文件,并注册一些回调函数。这样,在有mouse事件时,fd唤醒select,并调用函数MouseRead读取mouse事件,经过一些转换动作之后,调用KdHandleMouseEvent把事件分发出去。

char *kdefaultMouse[] =      {
"/dev/mouse",
"/dev/psaux",
"/dev/input/mice",
"/dev/adbmouse",
"/dev/ttyS0",
"/dev/ttyS1",
};

#define NUM_DEFAULT_MOUSE (sizeof (kdefaultMouse) / sizeof (kdefaultMouse[0]))

static int
MouseInit (void)
{
int i;
int fd = -1;
Kmouse *km;
KdMouseInfo *mi, *next;
int n = 0;
char *prot;

if (!MouseInputType)
MouseInputType = KdAllocInputType ();

for (mi = kdMouseInfo; mi; mi = next)
{
next = mi->next;
prot = mi->prot;
if (mi->inputType)
continue;
if (!mi->name)
{
for (i = 0; i < NUM_DEFAULT_MOUSE; i++)
{
if (kdNoSerialMouse && strstr(kdefaultMouse[i], "/dev/ttyS"))
continue;
fd = open (kdefaultMouse[i], 2);
if (fd >= 0)
{
mi->name = KdSaveString (kdefaultMouse[i]);
break;
}
}
}
else
fd = open (mi->name, 2);

if (fd >= 0)
{
km = (Kmouse *) xalloc (sizeof (Kmouse));
if (km)
{
km->iob.fd = fd;
km->iob.avail = km->iob.used = 0;
km->prot = 0;
km->i_prot = 0;
km->tty = isatty (fd);
mi->driver = km;
mi->inputType = MouseInputType;
MouseFirstProtocol (km, mi->prot);
if (KdRegisterFd (MouseInputType, fd, MouseRead, (void *) mi))
n++;
}
else
close (fd);
}
}
return n;
}

MouseFini: ~初始化mouse设备,即注销回调函数,并释放一些数据结构。

static void
MouseFini (void)
{
KdMouseInfo *mi;

KdUnregisterFds (MouseInputType, TRUE);
for (mi = kdMouseInfo; mi; mi = mi->next)
{
if (mi->inputType == MouseInputType)
{
xfree (mi->driver);
mi->driver = 0;
mi->inputType = 0;
}
}
}

触摸屏的接口

typedef struct _KdMouseFuncs     {
int (*Init) (void);
void (*Fini) (void);
} KdMouseFuncs;

触摸屏是作为鼠标来实现的。下面看一个实际例子(tinyx/linux/tslib.c)

KdMouseFuncs TsFuncs =     {
TslibInit,
TslibFini
};

TslibInit:打开设备文件,并注册一些回调函数。由于触摸屏涉及到去抖、滤波、校准等功能,相关对于鼠标来说,要复杂得多,所以这里是调用tslib来实现的。

在有笔点事件时,fd唤醒select,并调用函数TsRead读取笔点事件,经过一些转换动作之后,调用KdHandleMouseEvent把事件分发出去。

int
TslibInit (void)
{
int i;
KdMouseInfo *mi, *next;
int fd= 0;
int n = 0;

if (!TsInputType)
TsInputType = KdAllocInputType ();

for (mi = kdMouseInfo; mi; mi = next)
{
next = mi->next;
if (mi->inputType)
continue;

if (!mi->name)
{
for (i = 0; i < NUM_TS_NAMES; i++)
{
if(!(tsDev = ts_open(TsNames[i],0))) continue;
ts_config(tsDev);
fd=ts_fd(tsDev);
if (fd >= 0)
{
mi->name = KdSaveString (TsNames[i]);
break;
}
}
}

if (fd > 0 && tsDev != 0)
{
mi->driver = (void *) fd;
mi->inputType = TsInputType;
if (KdRegisterFd (TsInputType, fd, TsRead, (void *) mi))
n++;
}
else
if (fd > 0) close(fd);
}
}

TslibFini: ~初始化touchscreen设备,即注销相关的回调函数,并释放一些数据结构。

void
TslibFini (void)
{
KdMouseInfo *mi;

KdUnregisterFds (TsInputType, TRUE);
for (mi = kdMouseInfo; mi; mi = mi->next)
{
if (mi->inputType == TsInputType)
{
if(mi->driver) ts_close(tsDev);
mi->driver = 0;
mi->inputType = 0;
if (mi->name != NULL) {
free(mi->name);
mi->name = NULL;
}
}
}
}

有意思的是,驱动本身的接口并不能说明设备的特性,它只提供初始化和~初始化这类通用接口,在初始化时才注册设备描述符和相应的读取函数。

附:
对于xorg-server的版本,直接编译之后,tslib不工作,需要这样做:
1. TslibInit加下面一行代码:
pi->path = getenv(”TSLIB_TSDEVICE”);

2.设置环境变量:export TSLIB_TSDEVICE=/dev/input/eventX

3. 运行:/usr/bin/Xfbdev -mouse tslib

阅读(432) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~