UEFI开发探索07 – 关于SMBUS的开发故事

这篇博客曾经发表在高端调试的论坛上,我把它转移到这里来了。UEFI访问SMBUS设备,是我计划中要写的,这篇就作为其前言吧,其中没有任何与UEFI相关的内容。

当时我已经开发完了C850F320上的smubs访问代码(作为smbus device)、Legacy BIOS下的smbus访问代码(在dos下调试,运行于OptionRom上),期望在windows上开发一个驱动,能通过smbus直接访问C850F320。这能让目前产品的价格降低20元,以当时的出货量,一年的成本可以节省40w,很可观的。

我把这篇博客拷贝过来了,绝不是因为今天上午要开会,没时间写了。说不是就不是!

以下为原文:


这是以失败告终的故事,这个故事中我学会了两件事情:1 选择剑走偏锋的技术方法的不是神人,走多了会变成神经,比如不才我;2 童话故事里规则多简单,坏人必定玩完,好人从此过着美好的生活。可惜,现实不是童话,所以主板上串口没了、SMBus的Pin也不连了。

以上纯粹是牢骚,发泄下我对现实的不满。在我做的项目中,需要在BIOS和单片机、OS和单片机间选择一种可以传输少量数据的方法。我选择的是SMBus,用单片机(C850F320)构建SMBus Device,以PCI/PCI-E板卡的形式呈现。大家知道,在PCI/PCI-E上提供了SMBus的时钟和数据引脚,这样使得不需要任何连接线,插上卡就可以让BIOS和OS访问做好的SMBus Device了。写下这篇是为了总结我走过的道路,希望可以让别人在遇到同样的问题时,少走一些弯路。

1 开发板的结构和SMBus设备的构建

图1 支持SMBUS总线通讯的卡

这是我使用的开发板,F320提供了不少功能,在这个开发板上可以去模拟USB设备,很有意思。板卡是PCI形式的,其他功能就不描述了,我的目标是使用F320模拟出一个SMBus device。

F320的开发环境中提供了一些SMBus的例子,可以对照参考。从芯片手册中知道,SMBus 接口可以被配置为工作在主方式和/或从方式。在任一时刻,它将工作在下述4 种方式之一:主发送器、主接收器、从发送器或从接收器。SMBus 在产生起始条件时进入主方式,并保持在该方式直到产生一个停止条件或在总线竞争中失败。SMBus 在每个字节帧结束后都产生一个中断;但作为接收器时中断在ACK 周期之前产生,作为发送器时中断在ACK周期之后产生。

我要求的设备很简单,从发送器和从接收器,可以进行字节的读写。因此必须实现主控制器读从设备和主控制器写从设备的功能。芯片手册中也给出了详细的时序图,可以参照编码。不想将这篇文章拉得太长,具体的实现就不讨论了,可以参考中国科技论文在线上我以前写的一篇论文《PC机与单片机的SMBus底层通信实现》,上面给出了代码的架构。

2 软件实现

2.1 第一条道路-SMBus driver

我很希望微软铺建好了一条康庄大道,可以让我在OS层轻松的访问做好的SMBus设备。就像访问串口、访问USB HID设备一样,不需要特别去为设备写驱动,应用层的API 就搞定了,这样的世界多美好啊。

怀着这样的想法去寻找,没有发现微软提供的应用层接口。不过找到这篇古老的文档《SMBus Device Driver External Architecture Specification》,1999年的。里面提到了一大堆的术语,相当高深,看起来是找对了。简而言之,其访问方法分为三步:1 Obtaining a Handle to the SMBus,找到SMBus设备驱动的上级领导;2 Enumerating SMBus Information,枚举设备信息;3 Initiating SMBus Requests,准备相应的Request,比如SMB_READ_BYTE。

到这儿为止,相当顺利,我看到这些命令之后,再对照 SMBus协议来看,觉得应该可以成功。所以,废寝忘食的编了两天,写好了一个调试用的驱动。文档中的代码有些小错误,不过很容易修改。我主要想看看其中的FindDevicesOnSMBus能运作的怎么样,是否能够得到Handle。

好,准备一台有串口的台式机,搭建调试环境。启动windbg,下断,运行,然后开始一步步跟踪。执行完IoGetDeviceInterfaces(&GUID_SMB, NULL, 0, &pInterfaceList)之后,发现pInterfaceList的值是空的!我的尝试失败了。

回头去分析,我一直认为GUID_SMB提供的是smbus设备上层驱动的对象,驱动获取到handle后,可以对自己的设备( 如我构建的设备地址为0xF0)发送读写命令。不过在windows的驱动库中,我没有发现smbhc.sys和smbclass.sys,我想这可能是其原因。微软对SMBus的支持并没有像文档中描述的那样运作。不过,我搞不清楚Smbattery是怎么运作的,微软甚至提供了一个例子来演示,因学识原因没有看明白,希望哪位同学可以详细的阐述一下。

第一条道路的尝试以失败告终。

2.2 第二条道路-I/O 访问

BIOS访问SMBus设备的时候,比如访问SPD,是通过南桥的寄存器来访问的。以读字节为例,基本的流程如下:

;1. Write Base+0 = FFh (Clear status)

;2. Read s = Base+0, if s AND 9Fh !=0 then goto step1

;3. Write Base+4 = x (x = (Device address << 1) + 1)

;4. Write Base+3 = y (y = Data area offset = 0..FFh)

;5. Write Base+2 = 48h (start byte read command)

;6. Read s = Base+0, if s AND 4 != 0 then ERROR, if s AND 2 == 0 then repeat step6

;7. Read d = Base+5 (d = Data read)

;8. repeat step1 to step7 to read all data

写字节的流程也差不多,以上的伪代码是从Rw-everything安装后产生的文件rw.ini中摘录出来的。主板南桥的技术文档中一般也有相应的读写流程,可以参考看看。

这就提供了另外一个思路,在OS层提供I/O端口操作的驱动,按照上述的流程直接去访问SMBus设备。SMBus本身有仲裁机制,不会发生设备独占的事情,理论上应该可行。

为了便于调试,我决定在DOS下去写代码。微软提供了READ_PORT_UCHAR和WRITE_PORT_UCHAR以允许对设备进行I/O访问,驱动中可以直接使用。我的代码在DOS下运行,为了便于移植,我自己在代码中实现了同名的函数,其他的函数如果要I/O访问设备的话,必须调用它们。这样,如果代码在 Dos下调试通过,直接拷贝到搭建好的windows 驱动中,就可以使用了,相当方便。

我的目标是在所有主板上都可以访问SMBus设备,而每个厂家的SMBus的bus  number、device number、function number都不相同,所以在这条道路上,兼容性实现是个很大的问题。

很幸运,在Intel的主板上没有遇到什么问题,代码运行良好,不管是按字节读设备还是按字节写设备都没有问题。先后尝试了915、G31、Q45几款主板,DOS下读写设备,基本上没有遇到问题。将代码移植到驱动中,也很容易就编译通过了。

使用DriverMonitor加载驱动,运行测试代码,在XP下去读写上述做好的SMBus设备,运行良好。随后在Win7下也做了一些测试,没有问题。至此为止,一切似乎很美好。

我美滋滋的搭建了一个AMD的平台,南桥是ATI的SB800。将代码中的SMBus Base Address的获取位置修改为AMD的(Intel的是bus 0,dev 0x1f,fun 0x3,offset 0x20;AMD的为bus 0,dev 0x14,fun 0x0,offset 0x90)。访问结果:设备错误,我傻眼了。代码修改为读取SPD,幸好,SPD的数据可以正常读取,看来代码没有问题。

我开始冷静下来,在另外一块VIA主板上去做类似的实验,结果相同。到底是怎么回事呢?主板上有若干组SMBus,难道每组的访问方法不同?

找来硬件工程师,一起来做了一些实验。

首先用示波器去量信号:使用示波器去采集信息,将单片机的两个引脚连到示波器上。在Intel主板上采集,不管是访问spd还是访问控制卡,都有波形出现。但是在amd主板上,一直没有波形出现。开始怀疑是否pci 上的smbdat和smbclk是否连接到南桥了。在amd的pci/pci-e上分别去量smbus的引脚,在上电的时候,pci上的这两个引脚没有电,pci-e上的倒是有。

为了验证想法,将内存DIMM的SDA 和SCL直接连接到PCI控制卡对应的引脚上,再用原来的代码去访问。(AMD平台上做的实验)在插上内存后,访问是成功的(我的主板如果没有内存在DIMM槽内,似乎SMBus没有使能,也就无法访问设备了)。

得出的结论是:使用内存这组SMBus,访问我自己做的设备是成功的。因此,要么是访问PCI/PCI-E上的SMBus设备,需要做一些配置,要么硬件上根本没有将PCI/PCI-E的两个smbus pin连接。

其后是问遍所有我认识的主板工程师和BIOS工程师,不厌其烦的将上面的问题一遍遍的重复,耗费若干口水和脑细胞之后,上述想法得到了一些证实。确实存在硬件不连的可能性,但是在AMD的平台上,也确实有些主板需要配置后才能访问PCI/PIC-E的SMBus设备。如何去做,我已经没有精力再去研究了。如果你知道的话,望不吝赐教^^。

感谢开发过程中张老师、晓文、志坚、Jerry、Kevin、Terry、Frank、Fly给予的无私帮助,和你们的技术探讨是我最喜欢的事情。

25 total views, 5 views today

发表评论

电子邮件地址不会被公开。 必填项已用*标注