- 论坛徽章:
- 0
|
11楼
发表于 2013-05-09 22:08
回复 7# xs3c
这个代码现在我写出来了,谢谢!
- /*
- 下面是我写的代码,目前知道的就这么多了
- 操作系统:Redhat 6.2
- 参考网址:http://wiki.osdev.org/PCI#Base_Address_Registers 维基百科对pci的详细介绍,看代码时可以一起看看,很有参考意义
- 下面是测试代码:
- 若你想看某个pci设备的配置信息,通过命令:lspci得到详细信息,比如下面是我的其中一个信息:
- 00:1b.0 Audio device: Intel Corporation 82801H (ICH8 Family) HD Audio Controller (rev 02)
- 那么我如何知道这个声卡设备的厂商ID和设备ID呢?
- 可以查看下面两个文件:
- #cat /sys/bus/pci/devices/0000\:00\:1b.0/device //设备ID文件
- 0x284b
- #cat /sys/bus/pci/devices/0000\:00\:1b.0/vendor //厂商ID文件
- 0x8066
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <sys/io.h>
- typedef unsigned long DWORD;
- typedef unsigned char BYTE;
- typedef unsigned int WORD;
- typedef unsigned short HALF;
- /* 计算pci空间地址基址 */
- #define MK_PDI(bus, device, func) (WORD)((bus&PCI_BUS_MAX)<<PCI_BUS_SHIFT | (device&PCI_DEVICE_MAX)<<PCI_DEVICE_SHIFT | (func&PCI_FUNC_MAX))
- #define MK_PCICONFIADDR(bus, device, func) (DWORD)(0x80000000L | (DWORD)MK_PDI(bus,device,func)<<8)
- /* PCI配置空间寄存器 */
- #define VENDOR_ID 0x8086 //要查找的产商ID
- #define DEVICE_ID 0x284b //要查找的设备ID
- /* 这两个寄存器是关键 */
- #define PCI_CONFIG_ADDRESS 0xCF8 //地址寄存器
- #define PCI_CONFIG_DATA 0xCFC //数据寄存器
- #define PCI_BUS_SHIFT 8
- #define PCI_DEVICE_SHIFT 3
- #define PCI_BUS_MAX 255 //最多256个总线 255=(0xff)
- #define PCI_DEVICE_MAX 31 //每个总线上面最多可以接32个设备 21=(0x1f)
- #define PCI_FUNC_MAX 7 //每个设备最多有8个功能号 7=(0x7)
- #define PCI_FUNCTION_MASK 0x0007
- void
- grub_traverse_pci (unsigned int vendor_id, unsigned int device_id)
- {
- int flag = 0;
- unsigned long indentify_id;
- unsigned char bus, device, func; //总线号、设备号、功能号这3个确定唯一的一个PCI设备
- unsigned int busAddr, busData; //pci配置空间地址、数据
- indentify_id = (device_id << 16) | vendor_id; //由配置空间中可知,device_id是高16位,vendor_id是低16位
- printf ("indentify_id =%x\n", indentify_id);
- /* 用3层循环遍历pci设备 */
- for (bus = 0; bus <= PCI_BUS_MAX ; bus++)
- {
- for (device = 0; device <= PCI_DEVICE_MAX; device++)
- {
- for (func = 0; func <= PCI_FUNC_MAX; func++)
- {
- busAddr = MK_PCICONFIADDR (bus, device, func); //计算配置空间的基址地址
- // busAddr = (0x80000000L |bus << 16 | device << 11 | func << 8); //这种方法和上面方法是一个意思,
- /* 使用内嵌汇编来代替outl函数 */
- // __asm__ __volatile__ ("outl %0,%w1": :"a" (busAddr), "Nd" (PCI_CONFIG_ADDRESS));
- outl (busAddr, PCI_CONFIG_ADDRESS); //向配置空间的地址寄存器0xcf8写入地址
- __asm__ __volatile__ ("inl %w1,%0":"=a" (busData):"Nd" (PCI_CONFIG_DATA));
- // busData = inl (PCI_CONFIG_DATA); //读取数据
- // printf ("### %x, %x\n",(HALF)busData, busData);
- /* 假如busData=0x284b8086,那么(unsigned short)busData=8086 */
- if ((unsigned short) busData != 0xffff) //只需比较它的2个字节,通过产商ID和ffff比较来判断这个设备是否存在
- {
- // printf ("%x %x %x %x %x\n", bus, device, func, busAddr, busData);
- //#if 0
- if (indentify_id == busData) //查找Vendor ID和Device ID分别是8086和284b的设备
- {
- printf ("bus=%x,device=%x,func=%x,busAddr=%x,busData=%x\n", bus, device, func, busAddr, busData);
- flag = 1; //找到设备后就退出
- break;
- }
- //#endif
- }
- }
- if (flag)
- break;
- }
- if (flag)
- break;
- }
- /* 找到设备后读取它的配置空间信息 */
- if (flag)
- {
- // printf ("VendorID=%x, DeviceID=%x\n", (unsigned short)busData, busData >> 16); //将busData右移得到设备ID
- /* 获得Command部分,可以通过设置它的bit0、bit1和bit2这3位为1,bit0\bit1可以达到函数pci_enable_device的功能,就是为了开启io和内存映射,bit2是达到函数pci_set_master()的功能,让设备能够成为.. */
- /* 内嵌汇编 */
- __asm__ __volatile__ ("outl %0,%w1": :"a" (busAddr | 0x4), "Nd" (PCI_CONFIG_ADDRESS));
- // outl (busAddr | 0x4, PCI_CONFIG_ADDRESS); //向配置空间的地址寄存器0xcf8写入地址 (这行代码和上面代码一个意思)
- __asm__ __volatile__ ("inl %w1,%0":"=a" (busData):"Nd" (PCI_CONFIG_DATA));
- // busData = inl (PCI_CONFIG_DATA); //读取数据
- printf ("Command=%x\n", (unsigned short)busData); //得到command部分
- __asm__ __volatile__ ("outl %0,%w1": :"a" (busData | 0x00000007), "Nd" (PCI_CONFIG_DATA));
- // outl (busData | 0x00000007, PCI_CONFIG_DATA); //将最低的3位置1
-
- /* Test:查看是否写的正确 */
- __asm__ __volatile__ ("inl %w1,%0":"=a" (busData):"Nd" (PCI_CONFIG_DATA));
- // busData = inl (PCI_CONFIG_DATA); //读取数据
- printf ("Command=%x\n", (unsigned short)busData); //得到command部分
- /* 获得class code 和subclass、ProgIF、Reversion ID*/
- __asm__ __volatile__ ("outl %0,%w1": :"a" (busAddr | 0x8), "Nd" (PCI_CONFIG_ADDRESS));
- // outl (busAddr | 0x8, PCI_CONFIG_ADDRESS); //向配置空间的地址寄存器0xcf8写入地址
- __asm__ __volatile__ ("inl %w1,%0":"=a" (busData):"Nd" (PCI_CONFIG_DATA));
- // busData = inl (PCI_CONFIG_DATA); //读取数据
- printf ("Class code=%x,Subclass=%x, progif=%x, Reversion ID=%x\n",(busData & 0xff000000) >> 24, (busData & 0x00ff0000) >> 16,(busData & 0xff00) >> 8 ,(BYTE)busData);
- /* 获得基址 */
- int i;
- // char *buf = (char *) malloc (20);
- char buf[20];
- memset (buf,'0', 20);
- unsigned int base;
- unsigned int BarAddr[6];
- unsigned int bar_bak;
- unsigned int bar_len = 0;
- for (i = 0; i < 6; i++)
- {
- base = 0x10;
- base += i*4;
- // printf ("base=%x\n", base);
- __asm__ __volatile__ ("outl %0,%w1": :"a" (busAddr | base), "Nd" (PCI_CONFIG_ADDRESS));
- // outl (busAddr | base, PCI_CONFIG_ADDRESS); //想配置空间的地址寄存器0xcf8写入地址
- __asm__ __volatile__ ("inl %w1,%0":"=a" (BarAddr[i]):"Nd" (PCI_CONFIG_DATA));
- // BarAddr[i] = inl (PCI_CONFIG_DATA); //读取数据
- if (BarAddr[i] & 0x00000001) //假如最低位为1,说明这个地址是给IO空间的
- printf ("IO address,BarAddr[%d]=%x\n", i, BarAddr[i] & 0xfffffffc);
- else
- printf ("Memory address,BarAddr[%d]=%x\n", i, BarAddr[i] & 0xfffffff0);
- /* 获得需要的空间大小 */
- bar_bak = BarAddr[i]; //注意这里一定要保存原来的值
- printf ("bar_bak=%x\n", bar_bak);
- __asm__ __volatile__ ("outl %0,%w1": :"a" (busAddr | base), "Nd" (PCI_CONFIG_ADDRESS));
- // outl (busAddr | base, PCI_CONFIG_ADDRESS); //要操作的寄存器地址
- __asm__ __volatile__ ("outl %0,%w1": :"a" (0xffffffff), "Nd" (PCI_CONFIG_DATA)); //向这个Bar全部写1
- // outl (0xffffffff, PCI_CONFIG_DATA); //写入0xffffffff
- __asm__ __volatile__ ("inl %w1,%0":"=a" (busData):"Nd" (PCI_CONFIG_DATA)); //再读出它的值
- bar_len = ~(busData) + 1; //取返+1
- printf ("bar_len=%x\n", bar_len);
- // bar_len = ~(inl (PCI_CONFIG_DATA)) + 1; //再读出寄存器值取返,加1
- __asm__ __volatile__ ("outl %0,%w1": :"a" (bar_bak), "Nd" (PCI_CONFIG_DATA));
- // outl (bar_bak, PCI_CONFIG_DATA); //最后将原来值写回去
- /* Test:查看是不是写进去的再读出来和之前的是否一样--最后结果说明是对的 */
- #if 0
- outl (busAddr | base, PCI_CONFIG_ADDRESS);
- printf ("### %x\n", inl (PCI_CONFIG_DATA));
- #endif
- }
- #if 0
- /* 查看HeadType段 */
- outl (busAddr | 0x0c, PCI_CONFIG_ADDRESS); //想配置空间的地址寄存器0xcf8写入地址
- busData = inl (PCI_CONFIG_DATA); //读取数据
- printf ("Header Type=%x\n",(busData & 0x00ff0000) >> 16 );
- #endif
- }
- }
- int
- main ()
- {
- iopl (3); //设置IO端口权限
- grub_traverse_pci (VENDOR_ID, DEVICE_ID);
-
- return 0;
- }
复制代码 |
|