(请保留-> 作者: 罗冰 https://blog.csdn.net/luobing4365)
这篇博客不是要写鼠标的历史,而是记录在很久以前,在Legacy BIOS下,我写鼠标驱动(BIOS/DOS下运行)的过程。
我对底层编写程序,从参加工作的时候就非常着迷。当时接手隔离卡5.0的开发维护,主体产品已经完成,我一直思考:怎么才能让产品和别家的不同呢?
介绍下背景知识:隔离卡V5.0是公司第一款采用PCI Oprom开发的产品,插上就可以出界面。省去了用户安装软件的过程,一推出就大受欢迎。我们采用的是沁恒电子的WCH365,代码也参考他们的DEMO开发的。很快,对手使用同样的芯片,有了同样的方案。
就是在这种情况下,我希望找到新的竞争点。突然想到,市场上所有的PCI Option ROM上的界面,都是支持键盘的,没有支持鼠标的。这不就是一个切入点吗?如图,这是当时的隔离卡。我工作的笔记本没带回来,图是从网上找到的,这么多年,没想到还能找到。
图1 易思克隔离卡v5.0
有了想法,执行起来也不容易。
问题1: 鼠标肯定是在图形模式下运行的,怎么无缝的将鼠标显示在目前的界面?
问题2: 针对鼠标的驱动代码量不能大,ROM只有32K,现在出货的产品已经有21.5K,留给鼠标驱动的就没有多少空间,必须控制代码量;
问题3: 我知道DOS下有int33h可以控制鼠标,也有大量的例子可以参考。可惜我们是在BIOS上运行的,无法调用;
第3个问题,实际可以通过BIOS提供的int 15h C2h的00~07功能来实现。这是支持PS/2鼠标的软中断(实际测试,USB有时候也支持),phoneix/award的BIOS手册上有相关描述。
图2 鼠标的bios中断
手册上只列出了中断的说明,如何运行却没有解释。
注意看AL=07的功能号,其中指明了ES:BX指向mouse driver。鼠标驱动是由用户自己编写,由BIOS来调用的。其原理如下:
1) 用户准备mouser driver,必须是FAR调用(跨段);
2) 当鼠标有任何动作时,比如移动、单击等,BIOS将会调用mouse driver,将鼠标的位置和状态传递给用户;
3) 每次的鼠标动作,都会触发BIOS调用三次mouse driver,每次只传送一个数据。传递的三个数据分别为鼠标状态、鼠标X坐标、鼠标Y坐标;
4) BIOS每次的传递方法为:将数据压入堆栈,再调用mouse driver。
也即在鼠标有动作时,BIOS依次的动作为(发生三次):
Push mouse_status(2字节)
Call far ptr mouse_driver(4字节)
数据就存在sp+4处。
这些过程有点像windows驱动,都是由系统来调用程序,只不过这个比windows简单很多。
有了这些背景知识,就可以编程了。
Mouse driver的主要功能如下:
1) 根据传过来的数据,在新的位置绘制鼠标图案,并消除原位置的鼠标图案,同时将原位置鼠标图案下掩盖的图形还原;
2) 准备全局变量,将鼠标的状态传递出去,让使用mouser driver的程序可以根据鼠标动作进行事件处理。
更细节的处理可以看源码,仍旧放在百度云上,有兴趣可以看看。不过估计没有什么人还会对看汇编程序感兴趣,为了减少代码量,全部都是汇编写的。
我也只是因为,再不把这篇博文写完,以后估计连源代码都找不到了。以前没有养成如现在一样规范写日志的习惯,日志记录非常分散,有些已经找不到了。
程序使用borland 3.1中的tasm编译,如果用微软的masm(16位)编译,有些宏名需要修改。
在实际运用过程中,发现AMI的bios支持得不是很好;USB的鼠标也不是很理想。代码中加了判断,如果不支持的话,就不会启用鼠标驱动。虽然不完美,也帮助公司确立了产品技术领先的形象,是一段让我颇为自豪的经历。
虚拟机下是没法运行的,所以不截图了。就把编译过程截下来吧:
图3 编译mouse driver
回到UEFI 的鼠标支持吧,估计要再过几个博客才会写到。UEFI中似乎没有中断的概念了,取而代之的是事件方式。怎么构建出一个让主程序不需要管理、只需要处理关心的鼠标事件的代码,类似windows的事件处理,简洁而高效,是一个需要深入思考的问题。
研究技术真的是没有止境。
Gitee地址:https://gitee.com/luobing4365/uefi-explorer
项目代码位于:/X2 Mouse driver下。