5873b26a82
bochs.h already not include iodev.h which reduces compilation dependences for almost all cpu and fpu files, now cpu files will not be recompiled if iodev includes was changed
594 lines
17 KiB
C++
594 lines
17 KiB
C++
/*
|
|
* PCIDEV: PCI host device mapping
|
|
* Copyright (C) 2003 - Frank Cornelis
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License version 2 as published by the Free Software Foundation.
|
|
*
|
|
* This library 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
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/*
|
|
* Based on pcivga code:
|
|
* Copyright (C) 2002,2003 Mike Nordell
|
|
*/
|
|
|
|
// Define BX_PLUGGABLE in files that can be compiled into plugins. For
|
|
// platforms that require a special tag on exported symbols, BX_PLUGGABLE
|
|
// is used to know when we are exporting symbols and when we are importing.
|
|
#define BX_PLUGGABLE
|
|
|
|
#include "iodev.h"
|
|
#if BX_PCI_SUPPORT && BX_PCI_DEV_SUPPORT
|
|
|
|
#include "kernel_pcidev.h"
|
|
|
|
#include <sys/ioctl.h>
|
|
#include <signal.h>
|
|
#include <linux/pci.h>
|
|
|
|
#define LOG_THIS thePciDevAdapter->
|
|
|
|
bx_pcidev_c* thePciDevAdapter = 0;
|
|
|
|
int
|
|
libpcidev_LTX_plugin_init(plugin_t *plugin, plugintype_t type, int argc, char *argv[])
|
|
{
|
|
thePciDevAdapter = new bx_pcidev_c ();
|
|
bx_devices.pluginPciDevAdapter = thePciDevAdapter;
|
|
BX_REGISTER_DEVICE_DEVMODEL(plugin, type, thePciDevAdapter, BX_PLUGIN_PCIDEV);
|
|
return 0; // Success
|
|
}
|
|
|
|
void
|
|
libpcidev_LTX_plugin_fini(void)
|
|
{
|
|
}
|
|
|
|
|
|
bx_pcidev_c::bx_pcidev_c(void)
|
|
{
|
|
put("PCI2H");
|
|
settype(PCIDEVLOG);
|
|
}
|
|
|
|
bx_pcidev_c::~bx_pcidev_c(void)
|
|
{
|
|
// nothing for now
|
|
BX_DEBUG(("Exit."));
|
|
}
|
|
|
|
|
|
static void pcidev_sighandler(int param)
|
|
{
|
|
unsigned long irq = ((bx_pcidev_c *)bx_devices.pluginPciDevAdapter)->irq;
|
|
BX_INFO(("Interrupt received."));
|
|
DEV_pic_lower_irq(irq);
|
|
/*
|
|
* We need to first lower the IRQ line or else we don't
|
|
* get any IRQs through
|
|
*/
|
|
DEV_pic_raise_irq(irq);
|
|
}
|
|
|
|
|
|
static bool pcidev_mem_read_handler(unsigned long addr, unsigned long len, void *data, void *param)
|
|
{
|
|
struct region_struct *region = (struct region_struct *)param;
|
|
bx_pcidev_c *pcidev = region->pcidev;
|
|
int fd = pcidev->pcidev_fd;
|
|
if (fd == -1)
|
|
return false; /* we failed to handle the request, so let a default handler do it for us */
|
|
|
|
BX_INFO(("Reading I/O memory at %#x", addr));
|
|
struct pcidev_io_struct io;
|
|
io.address = addr + region->host_start - region->start;
|
|
int ret;
|
|
switch(len) {
|
|
case 1:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_BYTE, &io);
|
|
*(unsigned char *)data = io.value;
|
|
break;
|
|
case 2:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_WORD, &io);
|
|
*(unsigned short *)data = io.value;
|
|
break;
|
|
case 4:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_MEM_DWORD, &io);
|
|
*(unsigned long *)data = io.value;
|
|
break;
|
|
default:
|
|
BX_ERROR(("Unsupported pcidev read mem operation"));
|
|
break;
|
|
}
|
|
if (ret == -1) {
|
|
BX_ERROR(("pcidev read mem error"));
|
|
}
|
|
return true; // ok, we handled the request
|
|
}
|
|
|
|
|
|
static bool pcidev_mem_write_handler(unsigned long addr, unsigned long len, void *data, void *param)
|
|
{
|
|
struct region_struct *region = (struct region_struct *)param;
|
|
bx_pcidev_c *pcidev = region->pcidev;
|
|
int fd = pcidev->pcidev_fd;
|
|
if (fd == -1)
|
|
return false; /* we failed to handle the request, so let a default handler do it for us */
|
|
|
|
BX_INFO(("Writing I/O memory at %#x", addr));
|
|
struct pcidev_io_struct io;
|
|
io.address = addr + region->host_start - region->start;
|
|
int ret;
|
|
switch(len) {
|
|
case 1:
|
|
io.value = *(unsigned char *)data;
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_BYTE, &io);
|
|
break;
|
|
case 2:
|
|
io.value = *(unsigned short *)data;
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_WORD, &io);
|
|
break;
|
|
case 4:
|
|
io.value = *(unsigned long *)data;
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_MEM_DWORD, &io);
|
|
break;
|
|
default:
|
|
BX_ERROR(("Unsupported pcidev write mem operation"));
|
|
break;
|
|
}
|
|
if (ret == -1) {
|
|
BX_ERROR(("pcidev write mem error"));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
static const char * const pcidev_name = "Experimental PCI 2 host PCI";
|
|
|
|
void
|
|
bx_pcidev_c::init(void)
|
|
{
|
|
// called once when bochs initializes
|
|
BX_PCIDEV_THIS pcidev_fd = -1;
|
|
int fd;
|
|
fd = open("/dev/pcidev", O_RDWR);
|
|
if (fd == -1) {
|
|
switch(errno) {
|
|
case ENODEV:
|
|
BX_ERROR(("The pcidev kernel module is not loaded!"));
|
|
break;
|
|
default:
|
|
perror("open /dev/pcidev");
|
|
break;
|
|
}
|
|
return;
|
|
}
|
|
BX_PCIDEV_THIS pcidev_fd = fd;
|
|
struct pcidev_find_struct find;
|
|
unsigned short vendor = bx_options.pcidev.Ovendor->get();
|
|
unsigned short device = bx_options.pcidev.Odevice->get();
|
|
find.deviceID = device;
|
|
find.vendorID = vendor;
|
|
if (ioctl(fd, PCIDEV_IOCTL_FIND, &find) == -1) {
|
|
switch (errno) {
|
|
case ENOENT:
|
|
BX_ERROR(("PCI device not found on host system."));
|
|
break;
|
|
case EBUSY:
|
|
BX_ERROR(("PCI device already used by another kernel module."));
|
|
break;
|
|
default:
|
|
perror("ioctl");
|
|
break;
|
|
}
|
|
close(fd);
|
|
BX_PCIDEV_THIS pcidev_fd = -1;
|
|
return;
|
|
}
|
|
BX_INFO(("vendor: %x; device: %x @ host %x:%x.%d", vendor, device,
|
|
find.bus, find.device, find.func));
|
|
|
|
DEV_register_pci_handlers(this,
|
|
pci_read_handler,
|
|
pci_write_handler,
|
|
DEV_find_free_devfunc(),
|
|
pcidev_name);
|
|
|
|
BX_PCIDEV_THIS irq = PCIDEV_IRQ; // initial irq value
|
|
/*
|
|
* Next function just checks against IRQ sharing... for now Bochs
|
|
* does not allow this... should be changed... IRQ sharing for PCI
|
|
* devices is quite common
|
|
*/
|
|
DEV_register_irq(BX_PCIDEV_THIS irq, pcidev_name);
|
|
|
|
for (int idx = 0; idx < PCIDEV_COUNT_RESOURCES; idx++) {
|
|
if (!find.resources[idx].start)
|
|
continue;
|
|
BX_INFO(("PCI resource @ %x-%x (%s)", find.resources[idx].start,
|
|
find.resources[idx].end,
|
|
(find.resources[idx].flags & PCIDEV_RESOURCE_IO ? "I/O" : "Mem")));
|
|
BX_PCIDEV_THIS regions[idx].start = find.resources[idx].start;
|
|
BX_PCIDEV_THIS regions[idx].end = find.resources[idx].end;
|
|
BX_PCIDEV_THIS regions[idx].host_start = find.resources[idx].start; // we start with an identical mapping
|
|
struct pcidev_io_struct io;
|
|
io.address = PCI_BASE_ADDRESS_0 + idx * 4;
|
|
if (ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io) == -1)
|
|
BX_ERROR(("Error reading a base address config reg."));
|
|
BX_PCIDEV_THIS regions[idx].config_value = io.value;
|
|
/*
|
|
* We will use ®ion[idx] as parameter for our I/O or memory
|
|
* handler. So we provide a pcidev pointer to the pcidev object
|
|
* in order for the handle to be able to use its pcidev object
|
|
*/
|
|
BX_PCIDEV_THIS regions[idx].pcidev = this;
|
|
unsigned long flags = find.resources[idx].flags;
|
|
if (flags & PCIDEV_RESOURCE_IO) {
|
|
BX_INFO(("Registering I/O port handler for %#x to %#x", find.resources[idx].start,
|
|
find.resources[idx].end));
|
|
if (!DEV_register_ioread_handler_range(&(BX_PCIDEV_THIS regions[idx]),
|
|
read_handler, find.resources[idx].start,
|
|
find.resources[idx].end, "pcidev", 7))
|
|
BX_ERROR(("Could not register I/O port read handler range %#x to %#x",
|
|
find.resources[idx].start, find.resources[idx].end));
|
|
if (!DEV_register_iowrite_handler_range(&(BX_PCIDEV_THIS regions[idx]),
|
|
write_handler, find.resources[idx].start,
|
|
find.resources[idx].end, "pcidev", 7))
|
|
BX_ERROR(("Could not register I/O port write handler range %#x to %#x",
|
|
find.resources[idx].start, find.resources[idx].end));
|
|
}
|
|
else if (flags & PCIDEV_RESOURCE_MEM) {
|
|
BX_INFO(("Registering memory I/O handler for %#x to %#x", find.resources[idx].start,
|
|
find.resources[idx].end));
|
|
DEV_register_memory_handlers(pcidev_mem_read_handler,
|
|
&(BX_PCIDEV_THIS regions[idx]),
|
|
pcidev_mem_write_handler,
|
|
&(BX_PCIDEV_THIS regions[idx]),
|
|
find.resources[idx].start,
|
|
find.resources[idx].end);
|
|
}
|
|
}
|
|
|
|
struct sigaction sa;
|
|
sa.sa_handler = pcidev_sighandler;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sigaction(SIGUSR1, &sa, NULL);
|
|
|
|
/*
|
|
* The kernel pcidev will fire SIGUSR1 signals when it receives
|
|
* interrupts from the host PCI device.
|
|
*/
|
|
ioctl(fd, PCIDEV_IOCTL_INTERRUPT, 1);
|
|
|
|
/*
|
|
* Let the kernel fire some fake IRQ signals
|
|
*/
|
|
//ioctl(fd, PCIDEV_IOCTL_INTERRUPT_TEST, 1);
|
|
}
|
|
|
|
void
|
|
bx_pcidev_c::reset(unsigned type)
|
|
{
|
|
}
|
|
|
|
|
|
// static pci configuration space read callback handler
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
|
|
Bit32u
|
|
bx_pcidev_c::pci_read_handler(void *this_ptr, Bit8u address, unsigned io_len)
|
|
{
|
|
#if !BX_USE_PCIDEV_SMF
|
|
bx_pcidev_c *class_ptr = (bx_pcidev_c *) this_ptr;
|
|
|
|
return class_ptr->pci_read(address, io_len);
|
|
}
|
|
|
|
|
|
Bit32u
|
|
bx_pcidev_c::pci_read(Bit8u address, unsigned io_len)
|
|
{
|
|
#else
|
|
UNUSED(this_ptr);
|
|
#endif // !BX_USE_PCIDEV_SMF
|
|
|
|
if (io_len > 4 || io_len == 0) {
|
|
BX_DEBUG(("Experimental PCIDEV read register 0x%02x, len=%u !",
|
|
(unsigned) address, (unsigned) io_len));
|
|
return 0xffffffff;
|
|
}
|
|
|
|
int fd = BX_PCIDEV_THIS pcidev_fd;
|
|
if (fd == -1)
|
|
return 0xffffffff;
|
|
|
|
struct pcidev_io_struct io;
|
|
int ret;
|
|
io.address = address;
|
|
switch(io_len) {
|
|
case 1:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_BYTE, &io);
|
|
break;
|
|
case 2:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_WORD, &io);
|
|
break;
|
|
case 4:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_CONFIG_DWORD, &io);
|
|
break;
|
|
}
|
|
if (ret == -1)
|
|
BX_ERROR(("pcidev config read error"));
|
|
|
|
// we don't use the host irq line but our own bochs irq line
|
|
if (address == PCI_INTERRUPT_LINE) {
|
|
io.value = (io.value & 0xffffff00) | (BX_PCIDEV_THIS irq & 0xff);
|
|
}
|
|
if (PCI_BASE_ADDRESS_0 <= address && address <= PCI_BASE_ADDRESS_5) {
|
|
BX_INFO(("Reading pcidev base address %d.",
|
|
(address - PCI_BASE_ADDRESS_0) / 4));
|
|
if (address & 3)
|
|
BX_ERROR(("base address not aligned!"));
|
|
io.value = BX_PCIDEV_THIS regions[(address - PCI_BASE_ADDRESS_0) >> 2].config_value;
|
|
}
|
|
|
|
return io.value;
|
|
}
|
|
|
|
|
|
// static pci configuration space write callback handler
|
|
// redirects to non-static class handler to avoid virtual functions
|
|
|
|
void
|
|
bx_pcidev_c::pci_write_handler(void *this_ptr, Bit8u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#if !BX_USE_PCIDEV_SMF
|
|
bx_pcidev_c *class_ptr = (bx_pcidev_c *) this_ptr;
|
|
|
|
class_ptr->pci_write(address, value, io_len);
|
|
}
|
|
|
|
void
|
|
bx_pcidev_c::pci_write(Bit8u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#else
|
|
UNUSED(this_ptr);
|
|
#endif // !BX_USE_PCIDEV_SMF
|
|
|
|
if (io_len > 4 || io_len == 0) {
|
|
BX_DEBUG(("Experimental PCIDEV write register 0x%02x, len=%u !",
|
|
(unsigned) address, (unsigned) io_len));
|
|
return;
|
|
}
|
|
|
|
int fd = BX_PCIDEV_THIS pcidev_fd;
|
|
if (fd == -1)
|
|
return;
|
|
|
|
// we do a host 2 guest irq line mapping
|
|
if (address == PCI_INTERRUPT_LINE) {
|
|
value &= 0xff;
|
|
BX_INFO(("Changing the pcidev irq line from %d to %d",
|
|
BX_PCIDEV_THIS irq, value));
|
|
if (BX_PCIDEV_THIS irq)
|
|
DEV_unregister_irq(BX_PCIDEV_THIS irq, pcidev_name);
|
|
BX_PCIDEV_THIS irq = value;
|
|
if (BX_PCIDEV_THIS irq) // win98 likes to set irq = 0 at power off
|
|
DEV_register_irq(BX_PCIDEV_THIS irq, pcidev_name);
|
|
return;
|
|
}
|
|
if (PCI_BASE_ADDRESS_0 <= address && address <= PCI_BASE_ADDRESS_5) {
|
|
/*
|
|
* Two things to do here:
|
|
* - update the cached config space value via a probe
|
|
* - remap the I/O or memory handler if required
|
|
*/
|
|
BX_INFO(("Changing pcidev base address %d. New value: %#x",
|
|
(address - PCI_BASE_ADDRESS_0) / 4, value));
|
|
if (address & 3) {
|
|
BX_ERROR(("base address not aligned!"));
|
|
return;
|
|
}
|
|
int io_reg_idx = (address - PCI_BASE_ADDRESS_0) >> 2;
|
|
struct pcidev_io_struct io;
|
|
int ret;
|
|
io.address = address;
|
|
io.value = value;
|
|
ret = ioctl(fd, PCIDEV_IOCTL_PROBE_CONFIG_DWORD, &io);
|
|
if (ret == -1) {
|
|
BX_ERROR(("Error probing a base address reg!"));
|
|
return;
|
|
}
|
|
unsigned long base = io.value;
|
|
BX_PCIDEV_THIS regions[io_reg_idx].config_value = base;
|
|
/* remap the I/O or memory handler if required using io.value
|
|
* We assume that an I/O memory region will stay and I/O memory
|
|
* region. And that an I/O port region also will stay an I/O port
|
|
* region.
|
|
*/
|
|
if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_MEMORY) {
|
|
BX_INFO(("Remapping memory region from %#x to %#x",
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
base & PCI_BASE_ADDRESS_MEM_MASK));
|
|
if (BX_PCIDEV_THIS regions[io_reg_idx].start && // dirty hack
|
|
!DEV_unregister_memory_handlers(pcidev_mem_read_handler,
|
|
pcidev_mem_write_handler,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end))
|
|
BX_ERROR(("Error while unregistering old memory handlers!"));
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end =
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end +
|
|
(base & PCI_BASE_ADDRESS_MEM_MASK) -
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start;
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start = base & PCI_BASE_ADDRESS_MEM_MASK;
|
|
if (BX_PCIDEV_THIS regions[io_reg_idx].start) // dirty hack
|
|
DEV_register_memory_handlers(pcidev_mem_read_handler,
|
|
&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
pcidev_mem_write_handler,
|
|
&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end);
|
|
}
|
|
else {
|
|
/*
|
|
* Remap our I/O port handlers here.
|
|
*/
|
|
BX_INFO(("Remapping I/O port region from %#x to %#x",
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
base & PCI_BASE_ADDRESS_IO_MASK));
|
|
if (BX_PCIDEV_THIS regions[io_reg_idx].start) { // dirty hack
|
|
if (!DEV_unregister_ioread_handler_range(&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
read_handler,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end,
|
|
7))
|
|
BX_ERROR(("Error while unregistering old I/O port read handlers!"));
|
|
if (!DEV_unregister_iowrite_handler_range(&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
write_handler,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end,
|
|
7))
|
|
BX_ERROR(("Error while unregistering old I/O port write handlers!"));
|
|
}
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end =
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end +
|
|
(base & PCI_BASE_ADDRESS_IO_MASK) -
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start;
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start = base & PCI_BASE_ADDRESS_IO_MASK;
|
|
if (BX_PCIDEV_THIS regions[io_reg_idx].start) { // dirty hack
|
|
DEV_register_ioread_handler_range(
|
|
&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
read_handler,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end,
|
|
"pcidev", 7);
|
|
DEV_register_iowrite_handler_range(
|
|
&(BX_PCIDEV_THIS regions[io_reg_idx]),
|
|
write_handler,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].start,
|
|
BX_PCIDEV_THIS regions[io_reg_idx].end,
|
|
"pcidev", 7);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
struct pcidev_io_struct io;
|
|
int ret;
|
|
io.address = address;
|
|
io.value = value;
|
|
|
|
switch(io_len) {
|
|
case 1:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_BYTE, &io);
|
|
break;
|
|
case 2:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_WORD, &io);
|
|
break;
|
|
case 4:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_CONFIG_DWORD, &io);
|
|
break;
|
|
}
|
|
if (ret == -1)
|
|
BX_ERROR(("pcidev config write error"));
|
|
}
|
|
|
|
|
|
Bit32u
|
|
bx_pcidev_c::read_handler(void *param, Bit32u address, unsigned io_len)
|
|
{
|
|
#if !BX_USE_PCIDEV_SMF
|
|
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
|
|
|
|
return class_ptr->read(param, address, io_len);
|
|
}
|
|
|
|
Bit32u
|
|
bx_pcidev_c::read(void *param, Bit32u address, unsigned io_len)
|
|
{
|
|
#endif // !BX_USE_PCIDEV_SMF
|
|
|
|
struct region_struct *region = (struct region_struct *)param;
|
|
Bit32u value;
|
|
|
|
int fd = BX_PCIDEV_THIS pcidev_fd;
|
|
if (fd == -1)
|
|
return 0xffffffff;
|
|
|
|
struct pcidev_io_struct io;
|
|
// here we map the io address
|
|
io.address = address + region->host_start - region->start;
|
|
int ret;
|
|
switch(io_len) {
|
|
case 1:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_BYTE, &io);
|
|
break;
|
|
case 2:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_WORD, &io);
|
|
break;
|
|
case 4:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_READ_IO_DWORD, &io);
|
|
break;
|
|
}
|
|
if (ret == -1) {
|
|
BX_ERROR(("pcidev read I/O error"));
|
|
io.value = 0xffffffff;
|
|
}
|
|
|
|
return io.value;
|
|
}
|
|
|
|
void
|
|
bx_pcidev_c::write_handler(void *param, Bit32u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#if !BX_USE_PCIDEV_SMF
|
|
bx_pcidev_c *class_ptr = ((struct region_struct *)param)->pcidev;
|
|
|
|
class_ptr->write(param, address, value, io_len);
|
|
}
|
|
|
|
void
|
|
bx_pcidev_c::write(void *param, Bit32u address, Bit32u value, unsigned io_len)
|
|
{
|
|
#else
|
|
//UNUSED(this_ptr);
|
|
#endif // !BX_USE_PCIDEV_SMF
|
|
|
|
struct region_struct *region = (struct region_struct *)param;
|
|
|
|
int fd = BX_PCIDEV_THIS pcidev_fd;
|
|
if (fd == -1)
|
|
return;
|
|
|
|
struct pcidev_io_struct io;
|
|
int ret;
|
|
// here we map the I/O address
|
|
io.address = address + region->host_start - region->start;
|
|
io.value = value;
|
|
|
|
switch(io_len) {
|
|
case 1:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_BYTE, &io);
|
|
break;
|
|
case 2:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_WORD, &io);
|
|
break;
|
|
case 4:
|
|
ret = ioctl(fd, PCIDEV_IOCTL_WRITE_IO_DWORD, &io);
|
|
break;
|
|
}
|
|
if (ret == -1)
|
|
BX_ERROR(("pcidev I/O write error"));
|
|
}
|
|
|
|
#endif // BX_PCI_SUPPORT && BX_PCI_DEV_SUPPORT
|