📄 rt_pci.c
字号:
/*********************************************************************************//* This file has been written by Sergio Perez Alca駃z <serpeal@upvnet.upv.es> *//* Departamento de Inform醫ica de Sistemas y Computadores *//* Universidad Polit閏nica de Valencia *//* Valencia (Spain) *//* *//* The RTL-lwIP project has been supported by the Spanish Government Research *//* Office (CICYT) under grant TIC2002-04123-C03-03 *//* *//* Copyright (c) March, 2003 SISTEMAS DE TIEMPO REAL EMPOTRADOS, FIABLES Y *//* DISTRIBUIDOS BASADOS EN COMPONENTES *//* *//* This program is free software; you can redistribute it and/or modify *//* it under the terms of the GNU General Public License as published by *//* the Free Software Foundation; either version 2 of the License, or *//* (at your option) any later version. *//* *//* This program is distributed in the hope that it will be useful, *//* but WITHOUT ANY WARRANTY; without even the implied warranty of *//* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *//* GNU General Public License for more details. *//* *//* You should have received a copy of the GNU General Public License *//* along with this program; if not, write to the Free Software *//* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *//* *//* Linking RTL-lwIP statically or dynamically with other modules is making a *//* combined work based on RTL-lwIP. Thus, the terms and conditions of the GNU *//* General Public License cover the whole combination. *//* *//* As a special exception, the copyright holders of RTL-lwIP give you *//* permission to link RTL-lwIP with independent modules that communicate with *//* RTL-lwIP solely through the interfaces, regardless of the license terms of *//* these independent modules, and to copy and distribute the resulting combined *//* work under terms of your choice, provided that every copy of the combined *//* work is accompanied by a complete copy of the source code of RTL-lwIP (the *//* version of RTL-lwIP used to produce the combined work), being distributed *//* under the terms of the GNU General Public License plus this exception. An *//* independent module is a module which is not derived from or based on *//* RTL-lwIP. *//* *//* Note that people who make modified versions of RTL-lwIP are not obligated to *//* grant this special exception for their modified versions; it is their choice *//* whether to do so. The GNU General Public License gives permission to *//* release a modified version without this exception; this exception also makes *//* it possible to release a modified version which carries forward this *//* exception. *//* *//* CONTRIBUTORS: -Miguel Masmano Tello <mmasmano@disca.upv.es> *//* -COMEDI *//* The Linux Control and Measurement Device Interface *//* David Schleef <ds@schleef.org> *//*********************************************************************************/#include <time.h>#include "rt_pci.h"#ifdef CONFIG_PCI_DIRECT#define PCIBIOS_SUCCESSFUL 0x00#define CONFIG_CMD(bus, device_fn, where) (0x80000000 | (bus << 16) | (device_fn << 8) | (where & ~3))/***************************************************************************************//** * rt_pci_enable_wake - enable device to generate PME# when suspended * @dev: - PCI device to operate on * @state: - Current state of device. * @enable: - Flag to enable or disable generation * * Set the bits in the device's PM Capabilities to generate PME# when * the system is suspended. * * -EIO is returned if device doesn't have PM Capabilities. * -EINVAL is returned if device supports it, but can't generate wake events. * 0 if operation is successful. * */int rt_pci_enable_wake(struct pci_dev *dev, u32 state, int enable){ int pm; u16 value; /* find PCI PM capability in list */ pm = rt_pci_find_capability(dev, PCI_CAP_ID_PM); /* If device doesn't support PM Capabilities, but request is to disable * wake events, it's a nop; otherwise fail */ if (!pm) return enable ? -EIO : 0; /* Check device's ability to generate PME# */ rt_pci_read_config_word(dev,pm+PCI_PM_PMC,&value); value &= PCI_PM_CAP_PME_MASK; value >>= ffs(value); /* First bit of mask */ /* Check if it can generate PME# from requested state. */ if (!value || !(value & (1 << state))) return enable ? -EINVAL : 0; rt_pci_read_config_word(dev, pm + PCI_PM_CTRL, &value); /* Clear PME_Status by writing 1 to it and enable PME# */ value |= PCI_PM_CTRL_PME_STATUS | PCI_PM_CTRL_PME_ENABLE; if (!enable) value &= ~PCI_PM_CTRL_PME_ENABLE; rt_pci_write_config_word(dev, pm + PCI_PM_CTRL, value); return 0;}/***************************************************************************************//** * rt_pci_save_state - save the PCI configuration space of a device before suspending * @dev: - PCI device that we're dealing with * @buffer: - buffer to hold config space context * * @buffer must be large enough to hold the entire PCI 2.2 config space * (>= 64 bytes). */int rt_pci_save_state(struct pci_dev *dev, u32 *buffer){ int i; if (buffer) { /* XXX: 100% dword access ok here? */ for (i = 0; i < 16; i++) rt_pci_read_config_dword(dev, i * 4,&buffer[i]); } return 0;}/***************************************************************************************/int rt_pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inb(0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_read_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inw(0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_read_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int *value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outb(value, 0xCFC + (where&3)); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_write_config_word (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outw(value, 0xCFC + (where&2)); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_write_config_dword (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int value){ outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); return PCIBIOS_SUCCESSFUL;}/***************************************************************************************/int rt_pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq){ rt_pcibios_write_config_byte ((int) dev->bus, (int) dev->devfn, PCI_INTERRUPT_LINE, irq); rt_pcibios_write_config_byte ((int) dev->bus, (int)dev->devfn, PCI_INTERRUPT_PIN, pin); return 1;}#undef CONFIG_CMD#else /* CONFIG_PCI_DIRECT no definido */static struct { unsigned long address; unsigned short segment;} bios32_indirect = { 0, KERN_CODE_SEG };static long pcibios_entry;static struct { unsigned long address; unsigned short segment;} pci_indirect = { 0, KERN_CODE_SEG };/***************************************************************************************/static unsigned long bios32_service(unsigned long service){ unsigned char return_code; /* %al */ unsigned long address; /* %ebx */ unsigned long length; /* %ecx */ unsigned long entry; /* %edx */ unsigned long flags; save_flags(flags); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%edi)"#else "lcall *(%%edi)"#endif : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry) : "0" (service), "1" (0), "D" (&bios32_indirect)); restore_flags(flags); switch (return_code) { case 0: return address + entry; case 0x80: /* No presente */ ethernet_printf("bios32_service(%d) : no presente\n", service); return 0; default: /* No deberia pasar */ ethernet_printf("bios32_service(%d) : devuelto %#X\n", service, return_code); return 0; }}/***************************************************************************************/int rt_pcibios_read_config_byte(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char *value){ unsigned long ret; unsigned long bx = (bus << 8) | device_fn; unsigned long flags; save_flags(flags); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t"#else "lcall *(%%esi)\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" : "=c" (*value), "=a" (ret) : "1" (PCIBIOS_READ_CONFIG_BYTE), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/int rt_pcibios_read_config_word(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned short *value){ unsigned long ret; unsigned long bx = (bus << 8) | device_fn; unsigned long flags; save_flags(flags); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t"#else "lcall *(%%esi)\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" : "=c" (*value), "=a" (ret) : "1" (PCIBIOS_READ_CONFIG_WORD), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/int rt_pcibios_read_config_dword(unsigned int bus, unsigned int device_fn, unsigned int where, unsigned int *value){ unsigned long ret; unsigned long bx = (bus << 8) | device_fn; unsigned long flags; save_flags(flags); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t"#else "lcall *(%%esi)\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" : "=c" (*value), "=a" (ret) : "1" (PCIBIOS_READ_CONFIG_DWORD), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/int rt_pcibios_write_config_byte (unsigned int bus, unsigned int device_fn, unsigned int where, unsigned char value){ unsigned long ret; unsigned long bx = (bus << 8) | device_fn; unsigned long flags; save_flags(flags); cli(); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi)\n\t"#else "lcall *(%%esi)\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:"
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -