《2022年2022年键盘鼠标驱动 .pdf》由会员分享,可在线阅读,更多相关《2022年2022年键盘鼠标驱动 .pdf(19页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发1 Linux 操作系统课程报告串行端口程序设计姓名:连炳发班级:集成电路设计与集成系统学号:1015251030 指导教师:李国刚名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发2 PS/2 键盘鼠标驱动实验一、实验目的了解 PS/2 键盘鼠标协议和接口;了解模块驱动方法,掌握交
2、叉编译的概念及方法,学习鼠标驱动的方法。二、实验内容加载 PS/2 驱动模块,观察键盘鼠标的接管情况。三、预备知识 C 语言的基础知识。 Linux 的基本操作。了模块驱动的基本命令。四、实验设备及工具硬件: UP-NETARM2410-S 嵌入式实验仪,PC 机Pentumn500 以上 , 硬盘 40G 以上 , 内存大于128M。软件: PC 机操作系统 REDHAT LINUX 9.0 MINICOM AMRLINUX 开发环境五、实验原理1、PS/2 协议PS/2 设备接口广泛用于现代的鼠标和键盘,它由IBM 开发,现在是大多数键盘、鼠标与机通讯的标准协议。物理上的PS/2 接口是两
3、类连接器的一种:5 脚的 DIN 或6 脚的 mini DIN。这两种连接器(在电气特性上)是十分类似的,实际上两者只有一点不同那就是管脚的排列。这就意味着这两种连接器可以很容易用一种简单的硬件连线的适配器来转换。DIN 标准是由德国标准化组织建立的。PC 键盘可以有 6 脚的 mini-DIN 或5 脚的 DIN 连接器。具有 6 脚的mini-DIN 的键盘通常叫做“PS/2”键盘,而那些有5 脚的 DIN 的叫做“ AT ”设备(“ XT”键盘也是用 5 脚DIN,但它们非常古老并且多年前就不再生产了)。所以现代的为PC 生产的键盘不是PS/2, AT 就是 USB 的。鼠标流行着大量的
4、形状和大小、接口,最流行的类型可能算是PS/2 鼠标,现在 USB 鼠标渐渐开始流行起来了。每种连接器的引脚定义如图5.4.1 所示:在刚才提到的连接器上有四个有趣的管脚:地、5V、数据和时钟。主机提供5V,并且键盘 / 鼠标的地连接到主机的地上。数据和时钟都是集电极开路的,这就意味着它们通常保持高电平而且很容易下拉到地(逻辑0)。任何你连接到 PS/2 鼠标、键盘或主机的设备在时钟和数据线上要有一个大的上拉电阻。把线拉低名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 1
5、9 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发3 就置“ 0”,让线上浮成高电平就置“1”。参考图 5.4.2 中数据和时钟线的一般接口结构。PS/2 鼠标和键盘履行一种双向同步通信协议。换句话说,每次数据线上发送一位数据并且没在时钟线上发一个脉冲就被读入。键盘/ 鼠标可以发送数据到主机,而主机也可以发送数据到设备,但主机总是在总线上有优先权,它可以在任何时候抑制来自键盘/ 鼠标的通信,只要把时钟位拉低即可。图5.4.1 连接器的引脚定义图5.4.2 数据和时钟线的一般接口结构2、模块模块( module)是在内核空间运行
6、的程序,实际上是一种目标对象文件,没有链接,不能独立运行,但是可以装载到系统中作为内核的一部分运行,从而可以动态扩充内核的功能。模块最主要的用处就是用来实现设备驱动程序。Linux 下对于一个硬件的驱动,可以有两种方式:直接加载到内核代码中,启动内核时就会驱动此硬件设备。另一种就是以模块方式,编译生成一个.o 文件。当应用程序需要时再加载进内核空间运行。所以我们所说的一个硬件的驱动程序,通常指的就是一个驱动模块。对于一个设备,它可以在/dev 下面存在一个对应的逻辑设备节点,这个节点以文件的形式存在,但它不是普通意义上的文件,它是设备文件,更确切的说,它是设备节点。这个节点是通过 mknod
7、命令建立的,其中指定了主设备号和次设备号。主设备号表明了某一类设备,一般对应着确定的驱动程序;次设备号一般是区分不同属性,例如不同的使用方法,不同的位置,不同的操作。这个设备号是从/proc/devices 文件中获得的,所以一般是先有驱动程序在内核中,才有设备节点在目录中。这个设备号(特指主设备号)的主要作用,就是声明设备所使用的驱动程序。驱动程序和设备号是一一对应的,当你打开一个设备文件时,操作系统就已经知道这个设备所对应的驱动程序。对于一个硬件,Linux 是这样来进行驱动的:首先,我们必须提供一个.o 的驱动模块文件(这里我们只说明模块方式,其实内核方式是类似的)。我们要使用这个驱动程
8、序,首先要加载运行它( insmod *.o)。这样驱动就会根据自己的类型(字符设备类型或块设备类型,例如鼠标就是字符设备而硬盘就是块设备)向系统注册,注册成功系统会反馈一个主设备号,这个主设备号就是系统对它的唯一标识(例如硬盘块设备在/proc/devices 中显示的主设备号为 3 ,我们用 ls -l /dev/had 看到的主设备就肯定是3)。驱动就是根据此主设备号来创建一个一般放置在/dev 目录下的设备文件(mknod 命令用来创建它,它必须用主设备号这个参数)。在我们要访问此硬件时,就可以对设备文件通过open、read 、 write 等命令进行。而驱动就会接收到相应的read
9、 、write 操作而根据自己的模块中的相应函数进行了。3、Linux 键盘驱动的工作原理首先让我们通过以下的结构图5.4.3 来了解一下用户从终端的击键是如何工作的:_ _ _ / put_queue | |receive_buf| |tty_read /handle_scancode -|tty_queue|-|tty_ldisc|- / | | |buffer | _/ |_| |_| 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 19 页 - - - - - -
10、 - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发4 _ _ | |sys_read| | -|/dev/ttyX|-|user process| | | | | |_| |_| 图5.4.3 键盘结构图首先,当你输入一个键盘值的时候,键盘将会发送相应的scancodes 给键盘驱动。一个独立的击键可以产生一个六个scancodes 的队列。键盘驱动中的 handle_scancode()函数解析 scancodes 流并通过 kdb_translate()函数里的转换表( translation-table)将击键事件和键的释放事件(key releas
11、e events)转换成连续的 keycode 。比如, a 的 keycode 是30。击键 a 的时候便会产生keycode 30 。释放 a 键的时候会产生keycode 158 (128+30)。然后,这些 keycode 通过对 keymap 的查询被转换成相应key 符号。这步是一个相当复杂的过程。以上操作之后,获得的字符被送入raw tty 队列 -tty_flip_buffer。receive_buf()函数周期性的从tty_flip_buffer 中获得字符,然后把这些字符送入tty read 队列。当用户进程需要得到用户的输入的时候,它会在进程的标准输入(stdin )调用
12、 read() 函数。 sys_read()函数调用定义在相应的tty 设备(如 /dev/tty0)的 file_operations 结构中指向 tty_read 的read() 函数来读取字符并且返回给用户进程。file_operations 是文件操作结构,定义了文件操作行为的成员,结构如下,很容易理解:struct file_operations struct module *owner; loff_t (*llseek) (struct file *, loff_t, int); ssize_t (*read) (struct file *, char *, size_t, lof
13、f_t *);-这是本文提到的 write 函数int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, s
14、truct file *); int (*flush) (struct file *); int (*release) (struct inode *, struct file *); int (*fsync) (struct file *, struct dentry *, int datasync); int (*fasync) (int, struct file *, int); int (*lock) (struct file *, int, struct file_lock *); ssize_t (*readv) (struct file *, const struct iovec
15、 *, unsigned long, loff_t *); ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *); ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int); unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long
16、); ; 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发5 我们知道 unix 系统中设备也是文件,所以tty 设备我们也可以进行文件操作。键盘驱动器可以有如下4 种模式:- scancode (RAW 模式):应用程序取得输入的scancode 。这种模式通常用于应用程序实现自己的键盘驱动器,比如X11 程序。- keycode ( MEDIUMRA
17、W 模式):应用程序取得key 的击键和释放行为(通过keycode 来鉴别这两种行为)信息。- ASCII (XLATE 模式):应用程序取得keymap 定义的字符,该字符是8 位编码的。- Unicode ( UNICODE 模式):此模式唯一和ASCII 模式不同之处就是UNICODE 模式允许用户将自己的 10 进制值编写成 UTF8 的unicode 字符,如十进制的数可以编写成Ascii_0 到Ascii_9 ,或者用户 16 进制的值可以用Hex_0 到Hex_9 来代表。一个 keymap 可以产生出一系列 UTF8 的序列。六、程序分析分析源代码 Ps2_kbd_mouse
18、.c 使用者在键盘上按一个键,就产生一个中断请求,CPU 在响应中断时进入键盘的中断服务程序keyboard_interrupt()。人们往往以为键盘是很简单的设备, 但实际上键盘的结构和操作都不简单。我们以字符”A”为例来说明键盘的操作。当在键盘上按下一个键时, 键盘立即就向母板发出一个字节的代码, 称为”键盘扫描码”。具体位置取决于键的位置,”A”键的键盘扫描码为0 x1c。母板上的键盘接口在接收这个字节以后就把它转换成一种”系统扫描码” , 并将其存入控制器的内部缓冲区, 然后便向 CPU 发出一个中断请求。对于”A”键, 其系统扫描码为0 x1e。当 CPU 从键盘接口的数据寄存器读时
19、, 读出的就是系统扫描码。然后, 当放开” A”时 ,键盘又要向母板发出键盘扫描码, 而这次是两个字节, 第一个是 0 xf0, 表示是放开一个键;然后是 0 x1c, 表示是哪一个键. 同样母板上的键盘接口也要把它转换成系统扫描码、也要向CPU 发出中断请求 , 但是系统扫描码仍然是一个字节, 只是在 0 x1e 的基础上把最高位设成1, 变成 0 x9e。这样 ,在CPU 从键盘接口读出的单字节系统扫描码中, 其最高位表示按下或放开, 而低 7 位则与具体的键对应。不光对普通的字符键是如此, 对功能键和控制键也是一样。例如,左右两个 Shift 键的系统扫描码分别为0 x2a 和0 x36
20、。这样 , 以输入一个小写的”a”为例 ,CPU 实际上可能要发生4 次中断、要依次从键盘接口读出4 个字节的系统扫描码,例如 0 x36,0 x1e,0 x9e,0 xb6。对于把这个序列解释成什么, 那就是软件的事了 ; 如果解释成 ASCII 码 , 而键盘又没有锁定在大写状态, 那就是” a” 。由此可见 , 键盘接口向 CPU 发出中断请求并不意味着从键盘接收到了一个字符, 而只是意味着键盘上发生了某种事件。此外, 上面只是一般而言, 实际上还有不少例外。其中最重要的是所谓”扩充键”。早期的 PC 键盘上只有 83 个键 , 后来扩充到了101 键或 104 键, 例如右边的 Ctr
21、l 键就是一个扩充键。当按下或放开扩充键时, 键盘扫描码和系统扫描码都以一个0 xe0 字节开头 , 所以按下右边 Ctrl 键时的键盘扫描码是0 xe0,0 x14;放开时为 0 xe0,0 xf0,0 x14; 相应的系统扫描码则为0 xe0,0 x1d以及 0 xe0,0 x9d 。事件键盘扫描码系统扫描码按下” A”键 0 x1c 0 x1e 放开” A”键 0 xf0,0 x1c 0 x9e 按下右 Shift 键 0 x59 0 x36 放开右 Shift 键 0 xf0,0 x59 0 xb6 按下右 Ctrl 键 0 xe0,0 x14 0 xe0,0 x1d 名师资料总结 -
22、 - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发6 放开右 Ctrl 键 0 xe0,0 xf0,0 x14 0 xe0,0 x9d 之所以把键盘扫描码转换成系统扫描码, 是为了建立起一个统一的扫描码界面。这些转换是由键盘接口完成的,所以不占用 CPU 的时间。不过 , 有需要时也可以通过键盘控制器关闭这种转换。显然 , 对于软件而言键盘扫描码是不可见的, 所以我们在下
23、面讲到”扫描码”时都是指系统扫描码。此外, 按下一个键时产生的扫描码称为”make code”, 而放开一个键时产生的扫描码则称为”break code ” 。对扫描码的实际处理是由handle_scancode()完成的,其代码在/arm2410s/kernel-2410s/drivers/char/keyboard.c 中。void handle_scancode(unsigned char scancode, int down) unsigned char keycode; char up_flag = down ? 0 : 0200; driver_data) /* * We touc
24、h the tty structure via the ttytab array * without knowing whether or not tty is open, which * is inherently dangerous. We currently rely on that * fact that console_open sets tty-driver_data when * it opens it, and clears it when it closes it. */ tty = NULL; kbd = kbd_table + fg_console; - 前台虚拟终端号i
25、f (raw_mode = (kbd-kbdmode = VC_RAW) put_queue(scancode | up_flag); /* we do not return yet, because we want to maintain the key_down array, so that we have the correct values when finishing RAW mode or when changing VTs */ /* * Convert scancode to keycode */ if (!kbd_translate(scancode, &keycode, r
26、aw_mode) goto out; /* * At this point the variable keycode contains the keycode. * Note: the keycode must not be 0 (+Geert: on m68k 0 is valid). * We keep track of the up/down status of the key, and * return the keycode if in MEDIUMRAW mode. */ 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - -
27、- 名师精心整理 - - - - - - - 第 6 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发7 kbd_processkeycode(keycode, up_flag, 0); out: #ifdef CONFIG_CONSOLE_PM / bushi do_poke_blanked_console = 1; #endif schedule_console_callback(); 参数 down 为 1 表示扫描码的最高位为0,表示键处于按下状态。局部量up_flag 实际上相当于把扫描码的最高位抽了出来
28、。这里的pm_access() 是为电源管理留下的,其意图是在人机界面上长时间没有活动以后就使显示器进入省电模式,然后一旦有键盘输入时就恢复到正常运行。PC 机的控制台终端由显示器和键盘两部分构成,所以除tty_struct 数据结构外还有个kbd_struct 数据结构。同时,物理的显示器和键盘又可能用十多个虚拟终端,通过Alt 键与功能键的组合来切换,显然,每个虚拟终端都应该有自己的tty_struct 结构和kbd_struct 结构。为此内核中设立了tty_table和kbd_table两个数组,而全局量fg_console 则记录着当前的“前台”虚拟终端号,同时,为了便于后面的处理,
29、又设立了tty 和kbd 两个全局量,使它们分别指向“前台”虚拟终端的tty_struct 结构和kbd_struct 结构。如果前台终端的键盘工作于“原始”模式VC_RAW( 可以通过系统调用ioctl()设置,那就直接把键盘扫描码放到键盘的接收队列中,否则就要将扫描码转换成“键码”后才放到队列中。所谓”原始“(raw) 模式对于不同的层次有不同的意义,键盘的原始模式有两种,其中最原始的就是VC_RAW,表示直接把扫描码送给应用层。我们先看转换扫描码的函数static int Ps2_Kbd_translate(unsigned char scancode, unsigned char *k
30、eycode, char raw_mode) static int prev_scancode = 0; -保存状态DPRINTK(scancode = 0 x%xn,scancode); /* special prefix scancodes. */ if (scancode = 0 xe0 | scancode = 0 xe1) -扩充键判断prev_scancode = scancode; return 0; /* 0 xFF is sent by a few keyboards, ignore it. 0 x00 is error */ if (scancode = 0 x00 | s
31、cancode = 0 xff) - 无效码丢弃prev_scancode = 0; return 0; scancode &= 0 x7f; if (prev_scancode) /* * usually it will be 0 xe0, but a Pause key generates * e1 1d 45 e1 9d c5 when pressed, and nothing when released */ if (prev_scancode != 0 xe0) 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心
32、整理 - - - - - - - 第 7 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发8 if (prev_scancode = 0 xe1 & scancode = 0 x1d) - 特殊码 pause码处理prev_scancode = 0 x100; return 0; else if (prev_scancode = 0 x100 & scancode = 0 x45) *keycode = E1_PAUSE; prev_scancode = 0; else #ifdef KBD_REPORT_UNKN
33、 if (!raw_mode) printk(KERN_INFO keyboard: unknown e1 escape sequencen); #endif prev_scancode = 0; return 0; else prev_scancode = 0; /* * The keyboard maintains its own internal caps lock and * num lock statuses. In caps lock mode E0 AA precedes make * code and E0 2A follows break code. In num lock
34、mode, * E0 2A precedes make code and E0 AA follows break code. * We do our own book-keeping, so we will just ignore these. */ /* * For my keyboard there is no caps lock mode, but there are * both Shift-L and Shift-R modes. The former mode generates * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pai
35、rs. * So, we should also ignore the latter. - aebcwi.nl */ if (scancode = 0 x2a | scancode = 0 x36) return 0; if (e0_keysscancode) *keycode = e0_keysscancode; else #ifdef KBD_REPORT_UNKN if (!raw_mode) printk(KERN_INFO keyboard: unknown scancode e0 %02xn, scancode); #endif return 0; 名师资料总结 - - -精品资料
36、欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 8 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发9 else if (scancode = SC_LIM) 首先 , 如前所述 , 如果读入的扫描码是0 xe0( 或0 xe1), 那就是扩充键的前缀码。此时的扫描码是个序列 , 所以需要为之实现一种”有限状态机”, 全局量 prev_scancode 就是用于这个目的。这里先把前缀码作为一种状态保存在prev_scancode 中,
37、并返回 0, 表示这个字节应予丢弃。此外,0 x00 和0 xff 不是有效的扫描码, 也要丢弃。对于扫描码本身的处理因是否为扩充键而异。如果prev_scancode 非0, 那就说明在此之前的字节是个前缀码,此时又要看前缀码是否为0 xe0。前缀码 0 xe1 是个特例 , 在按下或放开 Pause 键的时候 , 键盘向主机发出一个三字节的序列0 xe1,0 x1d,0 x45或0 xe1,0 x1d,0 xc5 。所以代码中为这个序列设置了一个中间状态0 x100, 并对这个序列进行校验。如果三个字节都对, 那就是 E1_PAUSE, 否则就予以丢弃。除Pause 以外, 其他扩充键的前
38、缀码都是0 xe0。前面讲到 , 左右两个 Shift 键并非扩充键 , 但是有些键盘在 NumLock 或CapsLock 状态下操作左右Shift 键时会把它们当成扩充键。由于Linux 内核自己维持各种锁定状态, 所以丢弃作为扩充键的左右Shift 键扫描码。对于扩充键 , 从扫描码到键码的转换由数组e0_keys 提供 : static unsigned char e0_keys128 = 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x00-0 x07 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x08-0 x0f */ 0, 0, 0, 0, 0,
39、0, 0, 0, /* 0 x10-0 x17 */ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0 x18-0 x1f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x20-0 x27 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x28-0 x2f */ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0 x30-0 x37 */ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0 x38-0 x3f */ E0_DO, E0
40、_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0 x40-0 x47 */ E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, /* 0 x48-0 x4f */ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0 x50-0 x57 */ 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0 x58-0 x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x60-0 x
41、67 */ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0 x68-0 x6f */ /0, 0, 0, 0, 0, 0, 0, 0, /* 0 x70-0 x77 */ 0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0, /* 0 x70-0 x77 */ 0, 0, 0, E0_YEN, 0, 0, 0, 0 /* 0 x78-0 x7f */ ; 例如 , 右Ctrl 键的扫描码为 0 xe0,0 x1d,所以用 0 x1d 为下标查得其键码E0_RCTRL 。又如PageUp 键的扫描码为 0 xe0,0 x49,所以用 0 x49 为下标从表
42、中查得其键码E0_PGUP 。/* * Translation of escaped scancodes to keycodes. * This is now user-settable. * The keycodes 1-88,96-111,119 are fairly standard, and * should probably not be changed - changing might confuse X. * X also interprets scancode 0 x5d (KEY_Begin). 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - -
43、 - - - - - - - - 名师精心整理 - - - - - - - 第 9 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发10 * * For 1-88 keycode equals scancode. */ #define E0_KPENTER 96 #define E0_RCTRL 97 #define E0_KPSLASH 98 #define E0_PRSCR 99 #define E0_RALT 100 #define E0_BREAK 101 /* (control-pause) */ #de
44、fine E0_HOME 102 #define E0_UP 103 #define E0_PGUP 104 #define E0_LEFT 105 #define E0_RIGHT 106 #define E0_END 107 #define E0_DOWN 108 #define E0_PGDN 109 #define E0_INS 110 #define E0_DEL 111 /* for USB 106 keyboard */ #define E0_YEN 124 #define E0_BACKSLASH 89 #define E1_PAUSE 119 数组 e0_keys 的内容是可
45、以通过系统调用ioctl()设置的 , 但是这里的注释说改了以后可能会使 X window 软件弄糊涂。这也部分地回答了读者可能会有的疑问, 就是为什么需要”键码”。再看不带前缀的扫描码, 即非扩充键的扫描码: else if (scancode = SC_LIM) /* This happens with the FOCUS 9000 keyboard Its keys PF1.PF12 are reported to generate 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f Moreover, unless repeated, they do not gen
46、erate key-down events, so we have to zero up_flag below */ /* Also, Japanese 86/106 keyboards are reported to generate 0 x73 and 0 x7d for - and | respectively. */ /* Also, some Brazilian keyboard is reported to produce 0 x73 and 0 x7e for ? and KP-dot, respectively. */ *keycode = high_keysscancode
47、- SC_LIM; if (!*keycode) if (!raw_mode) -模式判断#ifdef KBD_REPORT_UNKN printk(KERN_INFO keyboard: unrecognized scancode (%02x) - ignoredn, scancode); 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 10 页,共 19 页 - - - - - - - - - 学院:信息学院班级: 10 集成学号: 1015251015 姓名:连炳发11 #en
48、dif return 0; else *keycode = scancode; return 1; 常数 SC_LIM 的值为 89,即 0 x59 。数值小于 SC_LIM 的扫描码与键码相同而无需转换:否则便由数组 high_key提供转换,转换时以(scancode_SC_LIM) 为下标。如下:static unsigned char high_keys128 - SC_LIM = RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0 x59-0 x5f */ 0, 0, 0, 0, 0, 0, 0, 0, /* 0 x60-0 x67 */ 0, 0, 0, 0
49、, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0 x68-0 x6f */ 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0 x70-0 x77 */ FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0 x78-0 x7b */ FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0 x7c-0 x7f */ ; 这个范围中的大多是功能键,其键码的数值在89 127 范围中,如 FOCUS_PF2 就是 PF2 键的键码 (FOCUS_PF1 的数值
50、为 85,与扫描码相同,所以不在这个数组中) 。七、实验步骤1、阅读和理解源代码进入 /arm2410s/kernel-2410s/drivers/char,使用 vi 编辑器或其他编辑器阅读理解源代码。2、宿主机与目标机连接1.REDHAT LINUX 9.0的安装在一台 PC 上安装 RedHat LINUX9.0, 选择 Custom 定制安装,在选择软件 Package 时最好将所有包都安装,需要空间约2.7G,如果选择最后一项:everything,即完全安装, 将安装 3张光盘的全部软件, 需要磁盘空间大约 5G 。因此建议提前为 REDHAT LINUX 的安装预留大约 515G