|
Packit |
7d1034 |
/*
|
|
Packit |
7d1034 |
* Copyright (c) 2009, 2012 Samuel Thibault
|
|
Packit |
7d1034 |
* Heavily inspired from the freebsd, netbsd, and openbsd backends
|
|
Packit |
7d1034 |
* (C) Copyright Eric Anholt 2006
|
|
Packit |
7d1034 |
* (C) Copyright IBM Corporation 2006
|
|
Packit |
7d1034 |
* Copyright (c) 2008 Juan Romero Pardines
|
|
Packit |
7d1034 |
* Copyright (c) 2008 Mark Kettenis
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* Permission to use, copy, modify, and distribute this software for any
|
|
Packit |
7d1034 |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit |
7d1034 |
* copyright notice and this permission notice appear in all copies.
|
|
Packit |
7d1034 |
*
|
|
Packit |
7d1034 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
Packit |
7d1034 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
Packit |
7d1034 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
Packit |
7d1034 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit |
7d1034 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
Packit |
7d1034 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
Packit |
7d1034 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
7d1034 |
#include "config.h"
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <unistd.h>
|
|
Packit |
7d1034 |
#include <stdio.h>
|
|
Packit |
7d1034 |
#include <stdlib.h>
|
|
Packit |
7d1034 |
#include <errno.h>
|
|
Packit |
7d1034 |
#include <fcntl.h>
|
|
Packit |
7d1034 |
#include <sys/mman.h>
|
|
Packit |
7d1034 |
#include <string.h>
|
|
Packit |
7d1034 |
#include <strings.h>
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include "pciaccess.h"
|
|
Packit |
7d1034 |
#include "pciaccess_private.h"
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#if defined(__GNU__)
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <sys/io.h>
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_enable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (!ioperm(0, 0xffff, 1))
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_disable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (!ioperm(0, 0xffff, 0))
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#elif defined(__GLIBC__)
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <sys/io.h>
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_enable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (!iopl(3))
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_disable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (!iopl(0))
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#elif defined(__CYGWIN__)
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#include <windows.h>
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* WinIo declarations */
|
|
Packit |
7d1034 |
typedef BYTE bool;
|
|
Packit |
7d1034 |
typedef struct tagPhysStruct {
|
|
Packit |
7d1034 |
DWORD64 dwPhysMemSizeInBytes;
|
|
Packit |
7d1034 |
DWORD64 pvPhysAddress;
|
|
Packit |
7d1034 |
DWORD64 PhysicalMemoryHandle;
|
|
Packit |
7d1034 |
DWORD64 pvPhysMemLin;
|
|
Packit |
7d1034 |
DWORD64 pvPhysSection;
|
|
Packit |
7d1034 |
} tagPhysStruct;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
typedef bool (_stdcall* INITIALIZEWINIO)(void);
|
|
Packit |
7d1034 |
typedef void (_stdcall* SHUTDOWNWINIO)(void);
|
|
Packit |
7d1034 |
typedef bool (_stdcall* GETPORTVAL)(WORD,PDWORD,BYTE);
|
|
Packit |
7d1034 |
typedef bool (_stdcall* SETPORTVAL)(WORD,DWORD,BYTE);
|
|
Packit |
7d1034 |
typedef PBYTE (_stdcall* MAPPHYSTOLIN)(tagPhysStruct*);
|
|
Packit |
7d1034 |
typedef bool (_stdcall* UNMAPPHYSMEM)(tagPhysStruct*);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
SHUTDOWNWINIO ShutdownWinIo;
|
|
Packit |
7d1034 |
GETPORTVAL GetPortVal;
|
|
Packit |
7d1034 |
SETPORTVAL SetPortVal;
|
|
Packit |
7d1034 |
INITIALIZEWINIO InitializeWinIo;
|
|
Packit |
7d1034 |
MAPPHYSTOLIN MapPhysToLin;
|
|
Packit |
7d1034 |
UNMAPPHYSMEM UnmapPhysicalMemory;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_enable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
HMODULE lib = NULL;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if ((GetVersion() & 0x80000000) == 0) {
|
|
Packit |
7d1034 |
/* running on NT, try WinIo version 3 (32 or 64 bits) */
|
|
Packit |
7d1034 |
#ifdef WIN64
|
|
Packit |
7d1034 |
lib = LoadLibrary("WinIo64.dll");
|
|
Packit |
7d1034 |
#else
|
|
Packit |
7d1034 |
lib = LoadLibrary("WinIo32.dll");
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!lib) {
|
|
Packit |
7d1034 |
fprintf(stderr, "Failed to load WinIo library.\n");
|
|
Packit |
7d1034 |
return 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define GETPROC(n, d) \
|
|
Packit |
7d1034 |
n = (d) GetProcAddress(lib, #n); \
|
|
Packit |
7d1034 |
if (!n) { \
|
|
Packit |
7d1034 |
fprintf(stderr, "Failed to load " #n " function.\n"); \
|
|
Packit |
7d1034 |
return 1; \
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
GETPROC(InitializeWinIo, INITIALIZEWINIO);
|
|
Packit |
7d1034 |
GETPROC(ShutdownWinIo, SHUTDOWNWINIO);
|
|
Packit |
7d1034 |
GETPROC(GetPortVal, GETPORTVAL);
|
|
Packit |
7d1034 |
GETPROC(SetPortVal, SETPORTVAL);
|
|
Packit |
7d1034 |
GETPROC(MapPhysToLin, MAPPHYSTOLIN);
|
|
Packit |
7d1034 |
GETPROC(UnmapPhysicalMemory, UNMAPPHYSMEM);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#undef GETPROC
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!InitializeWinIo()) {
|
|
Packit |
7d1034 |
fprintf(stderr, "Failed to initialize WinIo.\n"
|
|
Packit |
7d1034 |
"NOTE: WinIo.dll and WinIo.sys must be in the same directory as the executable!\n");
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
x86_disable_io(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
ShutdownWinIo();
|
|
Packit |
7d1034 |
return 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline uint8_t
|
|
Packit |
7d1034 |
inb(uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
DWORD pv;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (GetPortVal(port, &pv, 1))
|
|
Packit |
7d1034 |
return (uint8_t)pv;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline uint16_t
|
|
Packit |
7d1034 |
inw(uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
DWORD pv;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (GetPortVal(port, &pv, 2))
|
|
Packit |
7d1034 |
return (uint16_t)pv;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline uint32_t
|
|
Packit |
7d1034 |
inl(uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
DWORD pv;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (GetPortVal(port, &pv, 4))
|
|
Packit |
7d1034 |
return (uint32_t)pv;
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline void
|
|
Packit |
7d1034 |
outb(uint8_t value, uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
SetPortVal(port, value, 1);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline void
|
|
Packit |
7d1034 |
outw(uint16_t value, uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
SetPortVal(port, value, 2);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static inline void
|
|
Packit |
7d1034 |
outl(uint32_t value, uint16_t port)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
SetPortVal(port, value, 4);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#else
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#error How to enable IO ports on this system?
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCI_VENDOR(reg) ((reg) & 0xFFFF)
|
|
Packit |
7d1034 |
#define PCI_VENDOR_INVALID 0xFFFF
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCI_VENDOR_ID 0x00
|
|
Packit |
7d1034 |
#define PCI_SUB_VENDOR_ID 0x2c
|
|
Packit |
7d1034 |
#define PCI_VENDOR_ID_COMPAQ 0x0e11
|
|
Packit |
7d1034 |
#define PCI_VENDOR_ID_INTEL 0x8086
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCI_DEVICE(reg) (((reg) >> 16) & 0xFFFF)
|
|
Packit |
7d1034 |
#define PCI_DEVICE_INVALID 0xFFFF
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCI_CLASS 0x08
|
|
Packit |
7d1034 |
#define PCI_CLASS_DEVICE 0x0a
|
|
Packit |
7d1034 |
#define PCI_CLASS_DISPLAY_VGA 0x0300
|
|
Packit |
7d1034 |
#define PCI_CLASS_BRIDGE_HOST 0x0600
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCIC_DISPLAY 0x03
|
|
Packit |
7d1034 |
#define PCIS_DISPLAY_VGA 0x00
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#define PCI_HDRTYPE 0x0E
|
|
Packit |
7d1034 |
#define PCI_IRQ 0x3C
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
struct pci_system_x86 {
|
|
Packit |
7d1034 |
struct pci_system system;
|
|
Packit |
7d1034 |
int (*read)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size);
|
|
Packit |
7d1034 |
int (*write)(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size);
|
|
Packit |
7d1034 |
};
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf1_probe(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned long sav;
|
|
Packit |
7d1034 |
int res = ENODEV;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
outb(0x01, 0xCFB);
|
|
Packit |
7d1034 |
sav = inl(0xCF8);
|
|
Packit |
7d1034 |
outl(0x80000000, 0xCF8);
|
|
Packit |
7d1034 |
if (inl(0xCF8) == 0x80000000)
|
|
Packit |
7d1034 |
res = 0;
|
|
Packit |
7d1034 |
outl(sav, 0xCF8);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return res;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf1_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned addr = 0xCFC + (reg & 3);
|
|
Packit |
7d1034 |
unsigned long sav;
|
|
Packit |
7d1034 |
int ret = 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
|
|
Packit |
7d1034 |
return EIO;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
sav = inl(0xCF8);
|
|
Packit |
7d1034 |
outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
|
|
Packit |
7d1034 |
/* NOTE: x86 is already LE */
|
|
Packit |
7d1034 |
switch (size) {
|
|
Packit |
7d1034 |
case 1: {
|
|
Packit |
7d1034 |
uint8_t *val = data;
|
|
Packit |
7d1034 |
*val = inb(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 2: {
|
|
Packit |
7d1034 |
uint16_t *val = data;
|
|
Packit |
7d1034 |
*val = inw(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 4: {
|
|
Packit |
7d1034 |
uint32_t *val = data;
|
|
Packit |
7d1034 |
*val = inl(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
outl(sav, 0xCF8);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf1_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned addr = 0xCFC + (reg & 3);
|
|
Packit |
7d1034 |
unsigned long sav;
|
|
Packit |
7d1034 |
int ret = 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (bus >= 0x100 || dev >= 32 || func >= 8 || reg >= 0x100 || size > 4 || size == 3)
|
|
Packit |
7d1034 |
return EIO;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
sav = inl(0xCF8);
|
|
Packit |
7d1034 |
outl(0x80000000 | (bus << 16) | (dev << 11) | (func << 8) | (reg & ~3), 0xCF8);
|
|
Packit |
7d1034 |
/* NOTE: x86 is already LE */
|
|
Packit |
7d1034 |
switch (size) {
|
|
Packit |
7d1034 |
case 1: {
|
|
Packit |
7d1034 |
const uint8_t *val = data;
|
|
Packit |
7d1034 |
outb(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 2: {
|
|
Packit |
7d1034 |
const uint16_t *val = data;
|
|
Packit |
7d1034 |
outw(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 4: {
|
|
Packit |
7d1034 |
const uint32_t *val = data;
|
|
Packit |
7d1034 |
outl(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
outl(sav, 0xCF8);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf2_probe(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
outb(0, 0xCFB);
|
|
Packit |
7d1034 |
outb(0, 0xCF8);
|
|
Packit |
7d1034 |
outb(0, 0xCFA);
|
|
Packit |
7d1034 |
if (inb(0xCF8) == 0 && inb(0xCFA) == 0)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ENODEV;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf2_read(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, void *data, unsigned size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned addr = 0xC000 | dev << 8 | reg;
|
|
Packit |
7d1034 |
int ret = 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
|
|
Packit |
7d1034 |
return EIO;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
outb((func << 1) | 0xF0, 0xCF8);
|
|
Packit |
7d1034 |
outb(bus, 0xCFA);
|
|
Packit |
7d1034 |
/* NOTE: x86 is already LE */
|
|
Packit |
7d1034 |
switch (size) {
|
|
Packit |
7d1034 |
case 1: {
|
|
Packit |
7d1034 |
uint8_t *val = data;
|
|
Packit |
7d1034 |
*val = inb(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 2: {
|
|
Packit |
7d1034 |
uint16_t *val = data;
|
|
Packit |
7d1034 |
*val = inw(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 4: {
|
|
Packit |
7d1034 |
uint32_t *val = data;
|
|
Packit |
7d1034 |
*val = inl(addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
default:
|
|
Packit |
7d1034 |
ret = EIO;
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
outb(0, 0xCF8);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_conf2_write(unsigned bus, unsigned dev, unsigned func, pciaddr_t reg, const void *data, unsigned size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned addr = 0xC000 | dev << 8 | reg;
|
|
Packit |
7d1034 |
int ret = 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (bus >= 0x100 || dev >= 16 || func >= 8 || reg >= 0x100)
|
|
Packit |
7d1034 |
return EIO;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
outb((func << 1) | 0xF0, 0xCF8);
|
|
Packit |
7d1034 |
outb(bus, 0xCFA);
|
|
Packit |
7d1034 |
/* NOTE: x86 is already LE */
|
|
Packit |
7d1034 |
switch (size) {
|
|
Packit |
7d1034 |
case 1: {
|
|
Packit |
7d1034 |
const uint8_t *val = data;
|
|
Packit |
7d1034 |
outb(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 2: {
|
|
Packit |
7d1034 |
const uint16_t *val = data;
|
|
Packit |
7d1034 |
outw(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
case 4: {
|
|
Packit |
7d1034 |
const uint32_t *val = data;
|
|
Packit |
7d1034 |
outl(*val, addr);
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
default:
|
|
Packit |
7d1034 |
ret = EIO;
|
|
Packit |
7d1034 |
break;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
outb(0, 0xCF8);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Check that this really looks like a PCI configuration. */
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_system_x86_check(struct pci_system_x86 *pci_sys_x86)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int dev;
|
|
Packit |
7d1034 |
uint16_t class, vendor;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Look on bus 0 for a device that is a host bridge, a VGA card,
|
|
Packit |
7d1034 |
* or an intel or compaq device. */
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
for (dev = 0; dev < 32; dev++) {
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(0, dev, 0, PCI_CLASS_DEVICE, &class, sizeof(class)))
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
if (class == PCI_CLASS_BRIDGE_HOST || class == PCI_CLASS_DISPLAY_VGA)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(0, dev, 0, PCI_VENDOR_ID, &vendor, sizeof(vendor)))
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
if (vendor == PCI_VENDOR_ID_INTEL || class == PCI_VENDOR_ID_COMPAQ)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ENODEV;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_nfuncs(struct pci_system_x86 *pci_sys_x86, int bus, int dev)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
uint8_t hdr;
|
|
Packit |
7d1034 |
int err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_sys_x86->read(bus, dev, 0, PCI_HDRTYPE, &hdr, sizeof(hdr));
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (err)
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return hdr & 0x80 ? 8 : 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/**
|
|
Packit |
7d1034 |
* Read a VGA rom using the 0xc0000 mapping.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_read_rom(struct pci_device *dev, void *buffer)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
void *bios;
|
|
Packit |
7d1034 |
int memfd;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if ((dev->device_class & 0x00ffff00) !=
|
|
Packit |
7d1034 |
((PCIC_DISPLAY << 16) | ( PCIS_DISPLAY_VGA << 8))) {
|
|
Packit |
7d1034 |
return ENOSYS;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
memfd = open("/dev/mem", O_RDONLY | O_CLOEXEC);
|
|
Packit |
7d1034 |
if (memfd == -1)
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
bios = mmap(NULL, dev->rom_size, PROT_READ, 0, memfd, 0xc0000);
|
|
Packit |
7d1034 |
if (bios == MAP_FAILED) {
|
|
Packit |
7d1034 |
close(memfd);
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
memcpy(buffer, bios, dev->rom_size);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
munmap(bios, dev->rom_size);
|
|
Packit |
7d1034 |
close(memfd);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/** Returns the number of regions (base address registers) the device has */
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_get_num_regions(uint8_t header_type)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
switch (header_type & 0x7f) {
|
|
Packit |
7d1034 |
case 0:
|
|
Packit |
7d1034 |
return 6;
|
|
Packit |
7d1034 |
case 1:
|
|
Packit |
7d1034 |
return 2;
|
|
Packit |
7d1034 |
case 2:
|
|
Packit |
7d1034 |
return 1;
|
|
Packit |
7d1034 |
default:
|
|
Packit |
7d1034 |
fprintf(stderr,"unknown header type %02x\n", header_type);
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/** Masks out the flag bigs of the base address register value */
|
|
Packit |
7d1034 |
static uint32_t
|
|
Packit |
7d1034 |
get_map_base( uint32_t val )
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (val & 0x01)
|
|
Packit |
7d1034 |
return val & ~0x03;
|
|
Packit |
7d1034 |
else
|
|
Packit |
7d1034 |
return val & ~0x0f;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/** Returns the size of a region based on the all-ones test value */
|
|
Packit |
7d1034 |
static unsigned
|
|
Packit |
7d1034 |
get_test_val_size( uint32_t testval )
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
unsigned size = 1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (testval == 0)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Mask out the flag bits */
|
|
Packit |
7d1034 |
testval = get_map_base( testval );
|
|
Packit |
7d1034 |
if (!testval)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
while ((testval & 1) == 0) {
|
|
Packit |
7d1034 |
size <<= 1;
|
|
Packit |
7d1034 |
testval >>= 1;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return size;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_probe(struct pci_device *dev)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
uint8_t irq, hdrtype;
|
|
Packit |
7d1034 |
int err, i, bar;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Many of the fields were filled in during initial device enumeration.
|
|
Packit |
7d1034 |
* At this point, we need to fill in regions, rom_size, and irq.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_device_cfg_read_u8(dev, &irq, PCI_IRQ);
|
|
Packit |
7d1034 |
if (err)
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
dev->irq = irq;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_device_cfg_read_u8(dev, &hdrtype, PCI_HDRTYPE);
|
|
Packit |
7d1034 |
if (err)
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
bar = 0x10;
|
|
Packit |
7d1034 |
for (i = 0; i < pci_device_x86_get_num_regions(hdrtype); i++, bar += 4) {
|
|
Packit |
7d1034 |
uint32_t addr, testval;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Get the base address */
|
|
Packit |
7d1034 |
err = pci_device_cfg_read_u32(dev, &addr, bar);
|
|
Packit |
7d1034 |
if (err != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Test write all ones to the register, then restore it. */
|
|
Packit |
7d1034 |
err = pci_device_cfg_write_u32(dev, 0xffffffff, bar);
|
|
Packit |
7d1034 |
if (err != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
pci_device_cfg_read_u32(dev, &testval, bar);
|
|
Packit |
7d1034 |
err = pci_device_cfg_write_u32(dev, addr, bar);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (addr & 0x01)
|
|
Packit |
7d1034 |
dev->regions[i].is_IO = 1;
|
|
Packit |
7d1034 |
if (addr & 0x04)
|
|
Packit |
7d1034 |
dev->regions[i].is_64 = 1;
|
|
Packit |
7d1034 |
if (addr & 0x08)
|
|
Packit |
7d1034 |
dev->regions[i].is_prefetchable = 1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Set the size */
|
|
Packit |
7d1034 |
dev->regions[i].size = get_test_val_size(testval);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* Set the base address value */
|
|
Packit |
7d1034 |
if (dev->regions[i].is_64) {
|
|
Packit |
7d1034 |
uint32_t top;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_device_cfg_read_u32(dev, &top, bar + 4);
|
|
Packit |
7d1034 |
if (err != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
dev->regions[i].base_addr = ((uint64_t)top << 32) |
|
|
Packit |
7d1034 |
get_map_base(addr);
|
|
Packit |
7d1034 |
bar += 4;
|
|
Packit |
7d1034 |
i++;
|
|
Packit |
7d1034 |
} else {
|
|
Packit |
7d1034 |
dev->regions[i].base_addr = get_map_base(addr);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
/* If it's a VGA device, set up the rom size for read_rom using the
|
|
Packit |
7d1034 |
* 0xc0000 mapping.
|
|
Packit |
7d1034 |
*/
|
|
Packit |
7d1034 |
if ((dev->device_class & 0x00ffff00) ==
|
|
Packit |
7d1034 |
((PCIC_DISPLAY << 16) | (PCIS_DISPLAY_VGA << 8)))
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
dev->rom_size = 64 * 1024;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#if defined(__CYGWIN__)
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_map_range(struct pci_device *dev,
|
|
Packit |
7d1034 |
struct pci_device_mapping *map)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
tagPhysStruct phys;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
phys.pvPhysAddress = (DWORD64)(DWORD32)map->base;
|
|
Packit |
7d1034 |
phys.dwPhysMemSizeInBytes = map->size;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
map->memory = (PDWORD)MapPhysToLin(&phys);
|
|
Packit |
7d1034 |
if (map->memory == NULL)
|
|
Packit |
7d1034 |
return EFAULT;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_unmap_range(struct pci_device *dev,
|
|
Packit |
7d1034 |
struct pci_device_mapping *map)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
tagPhysStruct phys;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
phys.pvPhysAddress = (DWORD64)(DWORD32)map->base;
|
|
Packit |
7d1034 |
phys.dwPhysMemSizeInBytes = map->size;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (!UnmapPhysicalMemory(&phys))
|
|
Packit |
7d1034 |
return EFAULT;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#else
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_map_range(struct pci_device *dev,
|
|
Packit |
7d1034 |
struct pci_device_mapping *map)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
int memfd = open("/dev/mem", O_RDWR | O_CLOEXEC);
|
|
Packit |
7d1034 |
int prot = PROT_READ;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (memfd == -1)
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (map->flags & PCI_DEV_MAP_FLAG_WRITABLE)
|
|
Packit |
7d1034 |
prot |= PROT_WRITE;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
map->memory = mmap(NULL, map->size, prot, MAP_SHARED, memfd, map->base);
|
|
Packit |
7d1034 |
close(memfd);
|
|
Packit |
7d1034 |
if (map->memory == MAP_FAILED)
|
|
Packit |
7d1034 |
return errno;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_unmap_range(struct pci_device *dev,
|
|
Packit |
7d1034 |
struct pci_device_mapping *map)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
return pci_device_generic_unmap_range(dev, map);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
#endif
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_read(struct pci_device *dev, void *data,
|
|
Packit |
7d1034 |
pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_read)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
|
|
Packit |
7d1034 |
int err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
*bytes_read = 0;
|
|
Packit |
7d1034 |
while (size > 0) {
|
|
Packit |
7d1034 |
int toread = 1 << (ffs(0x4 + (offset & 0x03)) - 1);
|
|
Packit |
7d1034 |
if (toread > size)
|
|
Packit |
7d1034 |
toread = size;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_sys_x86->read(dev->bus, dev->dev, dev->func, offset, data, toread);
|
|
Packit |
7d1034 |
if (err)
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
offset += toread;
|
|
Packit |
7d1034 |
data = (char*)data + toread;
|
|
Packit |
7d1034 |
size -= toread;
|
|
Packit |
7d1034 |
*bytes_read += toread;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_write(struct pci_device *dev, const void *data,
|
|
Packit |
7d1034 |
pciaddr_t offset, pciaddr_t size, pciaddr_t *bytes_written)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_system_x86 *pci_sys_x86 = (struct pci_system_x86 *) pci_sys;
|
|
Packit |
7d1034 |
int err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
*bytes_written = 0;
|
|
Packit |
7d1034 |
while (size > 0) {
|
|
Packit |
7d1034 |
int towrite = 4;
|
|
Packit |
7d1034 |
if (towrite > size)
|
|
Packit |
7d1034 |
towrite = size;
|
|
Packit |
7d1034 |
if (towrite > 4 - (offset & 0x3))
|
|
Packit |
7d1034 |
towrite = 4 - (offset & 0x3);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
err = pci_sys_x86->write(dev->bus, dev->dev, dev->func, offset, data, towrite);
|
|
Packit |
7d1034 |
if (err)
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
offset += towrite;
|
|
Packit |
7d1034 |
data = (const char*)data + towrite;
|
|
Packit |
7d1034 |
size -= towrite;
|
|
Packit |
7d1034 |
*bytes_written += towrite;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
pci_system_x86_destroy(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
x86_disable_io();
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static struct pci_io_handle *
|
|
Packit |
7d1034 |
pci_device_x86_open_legacy_io(struct pci_io_handle *ret,
|
|
Packit |
7d1034 |
struct pci_device *dev, pciaddr_t base, pciaddr_t size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
x86_enable_io();
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret->base = base;
|
|
Packit |
7d1034 |
ret->size = size;
|
|
Packit |
7d1034 |
ret->is_legacy = 1;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
pci_device_x86_close_io(struct pci_device *dev, struct pci_io_handle *handle)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
/* Like in the Linux case, do not disable I/O, as it may be opened several
|
|
Packit |
7d1034 |
* times, and closed fewer times. */
|
|
Packit |
7d1034 |
/* x86_disable_io(); */
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static uint32_t
|
|
Packit |
7d1034 |
pci_device_x86_read32(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
return inl(reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static uint16_t
|
|
Packit |
7d1034 |
pci_device_x86_read16(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
return inw(reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static uint8_t
|
|
Packit |
7d1034 |
pci_device_x86_read8(struct pci_io_handle *handle, uint32_t reg)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
return inb(reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
pci_device_x86_write32(struct pci_io_handle *handle, uint32_t reg,
|
|
Packit |
7d1034 |
uint32_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
outl(data, reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
pci_device_x86_write16(struct pci_io_handle *handle, uint32_t reg,
|
|
Packit |
7d1034 |
uint16_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
outw(data, reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static void
|
|
Packit |
7d1034 |
pci_device_x86_write8(struct pci_io_handle *handle, uint32_t reg,
|
|
Packit |
7d1034 |
uint8_t data)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
outb(data, reg + handle->base);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_map_legacy(struct pci_device *dev, pciaddr_t base,
|
|
Packit |
7d1034 |
pciaddr_t size, unsigned map_flags, void **addr)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_device_mapping map;
|
|
Packit |
7d1034 |
int err;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
map.base = base;
|
|
Packit |
7d1034 |
map.size = size;
|
|
Packit |
7d1034 |
map.flags = map_flags;
|
|
Packit |
7d1034 |
err = pci_device_x86_map_range(dev, &map);
|
|
Packit |
7d1034 |
*addr = map.memory;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return err;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int
|
|
Packit |
7d1034 |
pci_device_x86_unmap_legacy(struct pci_device *dev, void *addr,
|
|
Packit |
7d1034 |
pciaddr_t size)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_device_mapping map;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
map.size = size;
|
|
Packit |
7d1034 |
map.flags = 0;
|
|
Packit |
7d1034 |
map.memory = addr;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return pci_device_x86_unmap_range(dev, &map);
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static const struct pci_system_methods x86_pci_methods = {
|
|
Packit |
7d1034 |
.destroy = pci_system_x86_destroy,
|
|
Packit |
7d1034 |
.read_rom = pci_device_x86_read_rom,
|
|
Packit |
7d1034 |
.probe = pci_device_x86_probe,
|
|
Packit |
7d1034 |
.map_range = pci_device_x86_map_range,
|
|
Packit |
7d1034 |
.unmap_range = pci_device_x86_unmap_range,
|
|
Packit |
7d1034 |
.read = pci_device_x86_read,
|
|
Packit |
7d1034 |
.write = pci_device_x86_write,
|
|
Packit |
7d1034 |
.fill_capabilities = pci_fill_capabilities_generic,
|
|
Packit |
7d1034 |
.open_legacy_io = pci_device_x86_open_legacy_io,
|
|
Packit |
7d1034 |
.close_io = pci_device_x86_close_io,
|
|
Packit |
7d1034 |
.read32 = pci_device_x86_read32,
|
|
Packit |
7d1034 |
.read16 = pci_device_x86_read16,
|
|
Packit |
7d1034 |
.read8 = pci_device_x86_read8,
|
|
Packit |
7d1034 |
.write32 = pci_device_x86_write32,
|
|
Packit |
7d1034 |
.write16 = pci_device_x86_write16,
|
|
Packit |
7d1034 |
.write8 = pci_device_x86_write8,
|
|
Packit |
7d1034 |
.map_legacy = pci_device_x86_map_legacy,
|
|
Packit |
7d1034 |
.unmap_legacy = pci_device_x86_unmap_legacy,
|
|
Packit |
7d1034 |
};
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
static int pci_probe(struct pci_system_x86 *pci_sys_x86)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
if (pci_system_x86_conf1_probe() == 0) {
|
|
Packit |
7d1034 |
pci_sys_x86->read = pci_system_x86_conf1_read;
|
|
Packit |
7d1034 |
pci_sys_x86->write = pci_system_x86_conf1_write;
|
|
Packit |
7d1034 |
if (pci_system_x86_check(pci_sys_x86) == 0)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (pci_system_x86_conf2_probe() == 0) {
|
|
Packit |
7d1034 |
pci_sys_x86->read = pci_system_x86_conf2_read;
|
|
Packit |
7d1034 |
pci_sys_x86->write = pci_system_x86_conf2_write;
|
|
Packit |
7d1034 |
if (pci_system_x86_check(pci_sys_x86) == 0)
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return ENODEV;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
_pci_hidden int
|
|
Packit |
7d1034 |
pci_system_x86_create(void)
|
|
Packit |
7d1034 |
{
|
|
Packit |
7d1034 |
struct pci_device_private *device;
|
|
Packit |
7d1034 |
int ret, bus, dev, ndevs, func, nfuncs;
|
|
Packit |
7d1034 |
struct pci_system_x86 *pci_sys_x86;
|
|
Packit |
7d1034 |
uint32_t reg;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = x86_enable_io();
|
|
Packit |
7d1034 |
if (ret)
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys_x86 = calloc(1, sizeof(struct pci_system_x86));
|
|
Packit |
7d1034 |
if (pci_sys_x86 == NULL) {
|
|
Packit |
7d1034 |
x86_disable_io();
|
|
Packit |
7d1034 |
return ENOMEM;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
pci_sys = &pci_sys_x86->system;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ret = pci_probe(pci_sys_x86);
|
|
Packit |
7d1034 |
if (ret) {
|
|
Packit |
7d1034 |
x86_disable_io();
|
|
Packit |
7d1034 |
free(pci_sys_x86);
|
|
Packit |
7d1034 |
pci_sys = NULL;
|
|
Packit |
7d1034 |
return ret;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->methods = &x86_pci_methods;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
ndevs = 0;
|
|
Packit |
7d1034 |
for (bus = 0; bus < 256; bus++) {
|
|
Packit |
7d1034 |
for (dev = 0; dev < 32; dev++) {
|
|
Packit |
7d1034 |
nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
|
|
Packit |
7d1034 |
for (func = 0; func < nfuncs; func++) {
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
|
|
Packit |
7d1034 |
PCI_VENDOR(reg) == 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
ndevs++;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
pci_sys->num_devices = ndevs;
|
|
Packit |
7d1034 |
pci_sys->devices = calloc(ndevs, sizeof(struct pci_device_private));
|
|
Packit |
7d1034 |
if (pci_sys->devices == NULL) {
|
|
Packit |
7d1034 |
x86_disable_io();
|
|
Packit |
7d1034 |
free(pci_sys_x86);
|
|
Packit |
7d1034 |
pci_sys = NULL;
|
|
Packit |
7d1034 |
return ENOMEM;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
device = pci_sys->devices;
|
|
Packit |
7d1034 |
for (bus = 0; bus < 256; bus++) {
|
|
Packit |
7d1034 |
for (dev = 0; dev < 32; dev++) {
|
|
Packit |
7d1034 |
nfuncs = pci_nfuncs(pci_sys_x86, bus, dev);
|
|
Packit |
7d1034 |
for (func = 0; func < nfuncs; func++) {
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(bus, dev, func, PCI_VENDOR_ID, ®, sizeof(reg)) != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
if (PCI_VENDOR(reg) == PCI_VENDOR_INVALID ||
|
|
Packit |
7d1034 |
PCI_VENDOR(reg) == 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
device->base.domain = device->base.domain_16 = 0;
|
|
Packit |
7d1034 |
device->base.bus = bus;
|
|
Packit |
7d1034 |
device->base.dev = dev;
|
|
Packit |
7d1034 |
device->base.func = func;
|
|
Packit |
7d1034 |
device->base.vendor_id = PCI_VENDOR(reg);
|
|
Packit |
7d1034 |
device->base.device_id = PCI_DEVICE(reg);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(bus, dev, func, PCI_CLASS, ®, sizeof(reg)) != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
device->base.device_class = reg >> 8;
|
|
Packit |
7d1034 |
device->base.revision = reg & 0xFF;
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
if (pci_sys_x86->read(bus, dev, func, PCI_SUB_VENDOR_ID, ®, sizeof(reg)) != 0)
|
|
Packit |
7d1034 |
continue;
|
|
Packit |
7d1034 |
device->base.subvendor_id = PCI_VENDOR(reg);
|
|
Packit |
7d1034 |
device->base.subdevice_id = PCI_DEVICE(reg);
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
device++;
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
}
|
|
Packit |
7d1034 |
|
|
Packit |
7d1034 |
return 0;
|
|
Packit |
7d1034 |
}
|