📄 rt_pci.c
字号:
: "=a" (ret) : "0" (PCIBIOS_WRITE_CONFIG_BYTE), "c" (value), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/int rt_pcibios_write_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); 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:" : "=a" (ret) : "0" (PCIBIOS_WRITE_CONFIG_WORD), "c" (value), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/int rt_pcibios_write_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); 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:" : "=a" (ret) : "0" (PCIBIOS_WRITE_CONFIG_DWORD), "c" (value), "b" (bx), "D" ((long) where), "S" (&pci_indirect)); restore_flags(flags); return (int) (ret & 0xff00) >> 8;}/***************************************************************************************/static void check_pcibios(void){ unsigned long signature; unsigned char present_status; unsigned char major_revision; unsigned char minor_revision; unsigned long flags; int pack; if ((pcibios_entry = bios32_service(PCI_SERVICE))) { pci_indirect.address = pcibios_entry; save_flags(flags); __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%edi)\n\t"#else "lcall *(%%edi)\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:\tshl $8, %%eax\n\t" "movw %%bx, %%ax" : "=d" (signature), "=a" (pack) : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "bx", "cx"); restore_flags(flags); present_status = (pack >> 16) & 0xff; major_revision = (pack >> 8) & 0xff; minor_revision = pack & 0xff; if (present_status || (signature != PCI_SIGNATURE)) { printf("ERROR: BIOS32 dice PCI BIOS, pero no PCI " "BIOS????\n"); pcibios_entry = 0; }#if DEBUG if (pcibios_entry) { printf ("pcibios_init : PCI BIOS revision %hhX.%hhX" " entrada en %#X\n", major_revision, minor_revision, pcibios_entry); }#endif }}/***************************************************************************************/static void pcibios_init(void){ union bios32 *check; unsigned char sum; int i, length; unsigned long bios32_entry = 0; /* El procedimiento estandar para localizar el directorio de servicios de BIOS32 se tiene que escanear una estructura BIOS32 valida entre los rangos 0xE0000 0xFFFFF */ for (check = (union bios32 *) 0xe0000; check <= (union bios32 *) 0xffff0; ++check) { if (check->fields.signature != BIOS32_SIGNATURE) continue; length = check->fields.length * 16; if (!length) continue; sum = 0; for (i = 0; i < length ; ++i) sum += check->chars[i]; if (sum != 0) continue; if (check->fields.revision != 0) { printf("pcibios_init : revision no soportada %d en %#X\n", check->fields.revision,(unsigned int) check); continue; }#if DEBUG printf("pcibios_init : BIOS32 Service Directory " "estructura en %#X\n", check);#endif if (!bios32_entry) { if (check->fields.entry >= 0x100000) { printf("pcibios_init: entrada en la memoria alta\n"); return; } else { bios32_entry = check->fields.entry;#if DEBUG printf("pcibios_init : BIOS32 Service Directory \nentrada en %#X\n", bios32_entry);#endif bios32_indirect.address = bios32_entry; } } } if (bios32_entry) check_pcibios();}/***************************************************************************************/int pcibios_set_irq_routing(struct pci_dev *dev, int pin, int irq){ int ret; __asm__(#ifdef ABSOLUTE_WITHOUT_ASTERISK "lcall (%%esi); cld\n\t"#else "lcall *(%%esi); cld\n\t"#endif "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" : "=a" (ret) : "0" (PCIBIOS_SET_PCI_HW_INT), "b" ((dev->bus << 8) | dev->devfn), "c" ((irq << 8) | (pin + 10)), "S" (&pci_indirect)); return !(ret & 0xff00);}#endif /* CONFIG_PCI_DIRECT no definido *//***************************************************************************************/int rt_pci_set_power_state(struct pci_dev *dev, int state){ int pm; u16 pmcsr; /* bound the state we're entering */ if (state > 3) state = 3; /* Validate current state: * Can enter D0 from any state, but if we can only go deeper * to sleep if we're already in a low power state */ if (state > 0 && dev->current_state > state) return -EINVAL; else if (dev->current_state == state) return 0; /* we're already there */ /* find PCI PM capability in list */ pm = rt_pci_find_capability(dev, PCI_CAP_ID_PM); /* abort if the device doesn't support PM capabilities */ if (!pm) return -EIO; /* check if this device supports the desired state */ if (state == 1 || state == 2) { u16 pmc; rt_pci_read_config_word(dev,pm + PCI_PM_PMC,&pmc); if (state == 1 && !(pmc & PCI_PM_CAP_D1)) return -EIO; else if (state == 2 && !(pmc & PCI_PM_CAP_D2)) return -EIO; } /* If we're in D3, force entire word to 0. * This doesn't affect PME_Status, disables PME_En, and * sets PowerState to 0. */ if (dev->current_state >= 3) pmcsr = 0; else { rt_pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr); pmcsr &= ~PCI_PM_CTRL_STATE_MASK; pmcsr |= state; } /* enter specified state */ rt_pci_write_config_word(dev, pm + PCI_PM_CTRL, pmcsr); /* Mandatory power management transition delays */ /* see PCI PM 1.1 5.6.1 table 18 */ if(state == 3 || dev->current_state == 3) { //set_current_state(TASK_UNINTERRUPTIBLE); //schedule_timeout(HZ/100); rtl_delay(200000); } else if(state == 2 || dev->current_state == 2) rtl_delay(200000); dev->current_state = state; return 0;}/** * rt_pci_find_capability - query for devices' capabilities * @dev: PCI device to query * @cap: capability code * * Tell if a device supports a given PCI capability. * Returns the address of the requested capability structure within the * device's PCI configuration space or 0 in case the device does not * support it. Possible values for @cap: * * %PCI_CAP_ID_PM Power Management * * %PCI_CAP_ID_AGP Accelerated Graphics Port * * %PCI_CAP_ID_VPD Vital Product Data * * %PCI_CAP_ID_SLOTID Slot Identification * * %PCI_CAP_ID_MSI Message Signalled Interrupts * * %PCI_CAP_ID_CHSWP CompactPCI HotSwap */int rt_pci_find_capability(struct pci_dev *dev, int cap){ u16 status; u8 pos, id; int ttl = 48; rt_pci_read_config_word(dev, PCI_STATUS, &status); if (!(status & PCI_STATUS_CAP_LIST)) return 0; switch (dev->hdr_type) { case PCI_HEADER_TYPE_NORMAL: case PCI_HEADER_TYPE_BRIDGE: rt_pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &pos); break; case PCI_HEADER_TYPE_CARDBUS: rt_pci_read_config_byte(dev, PCI_CB_CAPABILITY_LIST, &pos); break; default: return 0; } while (ttl-- && pos >= 0x40) { pos &= ~3; rt_pci_read_config_byte(dev, pos + PCI_CAP_LIST_ID, &id); if (id == 0xff) break; if (id == cap) return pos; rt_pci_read_config_byte(dev, pos + PCI_CAP_LIST_NEXT, &pos); } return 0;}/***************************************************************************************//* This function only can be called inside init_module *//***************************************************************************************/struct pci_dev * rt_pci_find_device(unsigned int vendor, unsigned int device, const struct pci_dev *from){ return(pci_find_device(vendor, device, from));}/***************************************************************************************//* This function only can be called inside init_module *//***************************************************************************************/int rt_pci_enable_device(struct pci_dev *dev){ return(pci_enable_device(dev));}/***************************************************************************************//** * rt_pci_restore_state - Restore the saved state of a PCI device * @dev: - PCI device that we're dealing with * @buffer: - saved PCI config space * */int rt_pci_restore_state(struct pci_dev *dev, u32 *buffer){ int i; if (buffer) { for (i = 0; i < 16; i++) rt_pci_write_config_dword(dev,i * 4, buffer[i]); } /* * otherwise, write the context information we know from bootup. * This works around a problem where warm-booting from Windows * combined with a D3(hot)->D0 transition causes PCI config * header data to be forgotten. */ else { for (i = 0; i < 6; i ++) rt_pci_write_config_dword(dev, PCI_BASE_ADDRESS_0 + (i * 4), dev->resource[i].start); rt_pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); } return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -