diff --git a/include/pci_bus.h b/include/pci_bus.h index adec2d9b..2dadfa06 100644 --- a/include/pci_bus.h +++ b/include/pci_bus.h @@ -1,86 +1,86 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * - * 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. - */ - -#ifndef DOSBOX_PCI_H -#define DOSBOX_PCI_H - -//#define PCI_FUNCTIONALITY_ENABLED 0 - -#if defined PCI_FUNCTIONALITY_ENABLED - -#define PCI_MAX_PCIDEVICES 10 -#define PCI_MAX_PCIFUNCTIONS 8 - - -class PCI_Device { -private: - Bits pci_id, pci_subfunction; - Bit16u vendor_id, device_id; - - // subdevices declarations, they will respond to pci functions 1 to 7 - // (main device is attached to function 0) - Bitu num_subdevices; - PCI_Device* subdevices[PCI_MAX_PCIFUNCTIONS-1]; - -public: - PCI_Device(Bit16u vendor, Bit16u device); - - Bits PCIId(void) { - return pci_id; - } - Bits PCISubfunction(void) { - return pci_subfunction; - } - Bit16u VendorID(void) { - return vendor_id; - } - Bit16u DeviceID(void) { - return device_id; - } - - void SetPCIId(Bitu number, Bits subfct); - - bool AddSubdevice(PCI_Device* dev); - void RemoveSubdevice(Bits subfct); - - PCI_Device* GetSubdevice(Bits subfct); - - Bit16u NumSubdevices(void) { - if (num_subdevices>PCI_MAX_PCIFUNCTIONS-1) return (Bit16u)(PCI_MAX_PCIFUNCTIONS-1); - return (Bit16u)num_subdevices; - } - - Bits GetNextSubdeviceNumber(void) { - if (num_subdevices>=PCI_MAX_PCIFUNCTIONS-1) return -1; - return (Bits)num_subdevices+1; - } - - virtual Bits ParseReadRegister(Bit8u regnum)=0; - virtual bool OverrideReadRegister(Bit8u regnum, Bit8u* rval, Bit8u* rval_mask)=0; - virtual Bits ParseWriteRegister(Bit8u regnum,Bit8u value)=0; - virtual bool InitializeRegisters(Bit8u registers[256])=0; - -}; - -bool PCI_IsInitialized(); - -RealPt PCI_GetPModeInterface(void); - -#endif - -#endif +/* + * Copyright (C) 2002-2011 The DOSBox Team + * + * 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. + */ + +#ifndef DOSBOX_PCI_H +#define DOSBOX_PCI_H + +//#define PCI_FUNCTIONALITY_ENABLED 0 + +#if defined PCI_FUNCTIONALITY_ENABLED + +#define PCI_MAX_PCIDEVICES 10 +#define PCI_MAX_PCIFUNCTIONS 8 + + +class PCI_Device { +private: + Bits pci_id, pci_subfunction; + Bit16u vendor_id, device_id; + + // subdevices declarations, they will respond to pci functions 1 to 7 + // (main device is attached to function 0) + Bitu num_subdevices; + PCI_Device* subdevices[PCI_MAX_PCIFUNCTIONS-1]; + +public: + PCI_Device(Bit16u vendor, Bit16u device); + + Bits PCIId(void) { + return pci_id; + } + Bits PCISubfunction(void) { + return pci_subfunction; + } + Bit16u VendorID(void) { + return vendor_id; + } + Bit16u DeviceID(void) { + return device_id; + } + + void SetPCIId(Bitu number, Bits subfct); + + bool AddSubdevice(PCI_Device* dev); + void RemoveSubdevice(Bits subfct); + + PCI_Device* GetSubdevice(Bits subfct); + + Bit16u NumSubdevices(void) { + if (num_subdevices>PCI_MAX_PCIFUNCTIONS-1) return (Bit16u)(PCI_MAX_PCIFUNCTIONS-1); + return (Bit16u)num_subdevices; + } + + Bits GetNextSubdeviceNumber(void) { + if (num_subdevices>=PCI_MAX_PCIFUNCTIONS-1) return -1; + return (Bits)num_subdevices+1; + } + + virtual Bits ParseReadRegister(Bit8u regnum)=0; + virtual bool OverrideReadRegister(Bit8u regnum, Bit8u* rval, Bit8u* rval_mask)=0; + virtual Bits ParseWriteRegister(Bit8u regnum,Bit8u value)=0; + virtual bool InitializeRegisters(Bit8u registers[256])=0; + +}; + +bool PCI_IsInitialized(); + +RealPt PCI_GetPModeInterface(void); + +#endif + +#endif diff --git a/src/hardware/pci_bus.cpp b/src/hardware/pci_bus.cpp index 43634ff9..88c402a4 100644 --- a/src/hardware/pci_bus.cpp +++ b/src/hardware/pci_bus.cpp @@ -1,444 +1,444 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * - * 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. - */ - - -#include "dosbox.h" -#include "inout.h" -#include "mem.h" -#include "pci_bus.h" -#include "setup.h" -#include "debug.h" -#include "callback.h" -#include "regs.h" - - -#if defined(PCI_FUNCTIONALITY_ENABLED) - -static Bit32u pci_caddress=0; // current PCI addressing -static Bitu pci_devices_installed=0; // number of registered PCI devices - -static Bit8u pci_cfg_data[PCI_MAX_PCIDEVICES][PCI_MAX_PCIFUNCTIONS][256]; // PCI configuration data -static PCI_Device* pci_devices[PCI_MAX_PCIDEVICES]; // registered PCI devices - - -// PCI address -// 31 - set for a PCI access -// 30-24 - 0 -// 23-16 - bus number (0x00ff0000) -// 15-11 - device number (slot) (0x0000f800) -// 10- 8 - subfunction number (0x00000700) -// 7- 2 - config register # (0x000000fc) - -static void write_pci_addr(Bitu port,Bitu val,Bitu iolen) { - LOG(LOG_PCI,LOG_NORMAL)("Write PCI address :=%x",val); - pci_caddress=val; -} - -static void write_pci_register(PCI_Device* dev,Bit8u regnum,Bit8u value) { - // vendor/device/class IDs/header type/etc. are read-only - if ((regnum<0x04) || ((regnum>=0x06) && (regnum<0x0c)) || (regnum==0x0e)) return; - if (dev==NULL) return; - switch (pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][0x0e]&0x7f) { // header-type specific handling - case 0x00: - if ((regnum>=0x28) && (regnum<0x30)) return; // subsystem information is read-only - break; - case 0x01: - case 0x02: - default: - break; - } - - // call device routine for special actions and the - // possibility to discard/replace the value that is to be written - Bits parsed_register=dev->ParseWriteRegister(regnum,value); - if (parsed_register>=0) - pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum]=(Bit8u)(parsed_register&0xff); -} - -static void write_pci(Bitu port,Bitu val,Bitu iolen) { - LOG(LOG_PCI,LOG_NORMAL)("Write PCI data :=%x (len %d)",port,val,iolen); - - // check for enabled/bus 0 - if ((pci_caddress & 0x80ff0000) == 0x80000000) { - Bit8u devnum = (Bit8u)((pci_caddress >> 11) & 0x1f); - Bit8u fctnum = (Bit8u)((pci_caddress >> 8) & 0x7); - Bit8u regnum = (Bit8u)((pci_caddress & 0xfc) + (port & 0x03)); - LOG(LOG_PCI,LOG_NORMAL)(" Write to device %x register %x (function %x) (:=%x)",devnum,regnum,fctnum,val); - - if (devnum>=pci_devices_installed) return; - PCI_Device* masterdev=pci_devices[devnum]; - if (masterdev==NULL) return; - if (fctnum>masterdev->NumSubdevices()) return; - - PCI_Device* dev=masterdev->GetSubdevice(fctnum); - if (dev==NULL) return; - - // write data to PCI device/configuration - switch (iolen) { - case 1: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); break; - case 2: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); - write_pci_register(dev,regnum+1,(Bit8u)((val>>8)&0xff)); break; - case 4: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); - write_pci_register(dev,regnum+1,(Bit8u)((val>>8)&0xff)); - write_pci_register(dev,regnum+2,(Bit8u)((val>>16)&0xff)); - write_pci_register(dev,regnum+3,(Bit8u)((val>>24)&0xff)); break; - } - } -} - - -static Bitu read_pci_addr(Bitu port,Bitu iolen) { - LOG(LOG_PCI,LOG_NORMAL)("Read PCI address -> %x",pci_caddress); - return pci_caddress; -} - -// read single 8bit value from register file (special register treatment included) -static Bit8u read_pci_register(PCI_Device* dev,Bit8u regnum) { - switch (regnum) { - case 0x00: - return (Bit8u)(dev->VendorID()&0xff); - case 0x01: - return (Bit8u)((dev->VendorID()>>8)&0xff); - case 0x02: - return (Bit8u)(dev->DeviceID()&0xff); - case 0x03: - return (Bit8u)((dev->DeviceID()>>8)&0xff); - - case 0x0e: - return (pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum]&0x7f) | - ((dev->NumSubdevices()>0)?0x80:0x00); - default: - break; - } - - // call device routine for special actions and possibility to discard/remap register - Bits parsed_regnum=dev->ParseReadRegister(regnum); - if ((parsed_regnum>=0) && (parsed_regnum<256)) - return pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][parsed_regnum]; - - Bit8u newval, mask; - if (dev->OverrideReadRegister(regnum, &newval, &mask)) { - Bit8u oldval=pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum] & (~mask); - return oldval | (newval & mask); - } - - return 0xff; -} - -static Bitu read_pci(Bitu port,Bitu iolen) { - LOG(LOG_PCI,LOG_NORMAL)("Read PCI data -> %x",pci_caddress); - - if ((pci_caddress & 0x80ff0000) == 0x80000000) { - Bit8u devnum = (Bit8u)((pci_caddress >> 11) & 0x1f); - Bit8u fctnum = (Bit8u)((pci_caddress >> 8) & 0x7); - Bit8u regnum = (Bit8u)((pci_caddress & 0xfc) + (port & 0x03)); - if (devnum>=pci_devices_installed) return 0xffffffff; - LOG(LOG_PCI,LOG_NORMAL)(" Read from device %x register %x (function %x); addr %x", - devnum,regnum,fctnum,pci_caddress); - - PCI_Device* masterdev=pci_devices[devnum]; - if (masterdev==NULL) return 0xffffffff; - if (fctnum>masterdev->NumSubdevices()) return 0xffffffff; - - PCI_Device* dev=masterdev->GetSubdevice(fctnum); - - if (dev!=NULL) { - switch (iolen) { - case 1: - { - Bit8u val8=read_pci_register(dev,regnum); - return val8; - } - case 2: - { - Bit16u val16=read_pci_register(dev,regnum); - val16|=(read_pci_register(dev,regnum+1)<<8); - return val16; - } - case 4: - { - Bit32u val32=read_pci_register(dev,regnum); - val32|=(read_pci_register(dev,regnum+1)<<8); - val32|=(read_pci_register(dev,regnum+2)<<16); - val32|=(read_pci_register(dev,regnum+3)<<24); - return val32; - } - default: - break; - } - } - } - return 0xffffffff; -} - - -static Bitu PCI_PM_Handler() { - LOG_MSG("PCI PMode handler, function %x",reg_ax); - return CBRET_NONE; -} - - -PCI_Device::PCI_Device(Bit16u vendor, Bit16u device) { - pci_id=-1; - pci_subfunction=-1; - vendor_id=vendor; - device_id=device; - num_subdevices=0; - for (Bitu dct=0;dct=0) && (number=0) && (subfct0) && (subfctNumSubdevices()) { - delete subdevices[subfct-1]; - subdevices[subfct-1]=NULL; - // should adjust things like num_subdevices as well... - } - } -} - -PCI_Device* PCI_Device::GetSubdevice(Bits subfct) { - if (subfct>=PCI_MAX_PCIFUNCTIONS) return NULL; - if (subfct>0) { - if (subfct<=this->NumSubdevices()) return subdevices[subfct-1]; - } else if (subfct==0) { - return this; - } - return NULL; -} - - -// queued devices (PCI device registering requested before the PCI framework was initialized) -static const Bitu max_rqueued_devices=16; -static Bitu num_rqueued_devices=0; -static PCI_Device* rqueued_devices[max_rqueued_devices]; - - -#include "pci_devices.h" - -class PCI:public Module_base{ -private: - bool initialized; - -protected: - IO_WriteHandleObject PCI_WriteHandler[5]; - IO_ReadHandleObject PCI_ReadHandler[5]; - - CALLBACK_HandlerObject callback_pci; - -public: - - PhysPt GetPModeCallbackPointer(void) { - return Real2Phys(callback_pci.Get_RealPointer()); - } - - bool IsInitialized(void) { - return initialized; - } - - // set up port handlers and configuration data - void InitializePCI(void) { - // install PCI-addressing ports - PCI_WriteHandler[0].Install(0xcf8,write_pci_addr,IO_MD); - PCI_ReadHandler[0].Install(0xcf8,read_pci_addr,IO_MD); - // install PCI-register read/write handlers - for (Bitu ct=0;ct<4;ct++) { - PCI_WriteHandler[1+ct].Install(0xcfc+ct,write_pci,IO_MB); - PCI_ReadHandler[1+ct].Install(0xcfc+ct,read_pci,IO_MB); - } - - for (Bitu dev=0; dev=0) { - // specific slot specified, basic check for validity - if (slot>=PCI_MAX_PCIDEVICES) return -1; - } else { - // auto-add to new slot, check if one is still free - if (pci_devices_installed>=PCI_MAX_PCIDEVICES) return -1; - } - - if (!initialized) InitializePCI(); - - if (slot<0) slot=pci_devices_installed; // use next slot - Bits subfunction=0; // main device unless specific already-occupied slot is requested - if (pci_devices[slot]!=NULL) { - subfunction=pci_devices[slot]->GetNextSubdeviceNumber(); - if (subfunction<0) E_Exit("Too many PCI subdevices!"); - } - - if (device->InitializeRegisters(pci_cfg_data[slot][subfunction])) { - device->SetPCIId(slot, subfunction); - if (pci_devices[slot]==NULL) { - pci_devices[slot]=device; - pci_devices_installed++; - } else { - pci_devices[slot]->AddSubdevice(device); - } - - return slot; - } - - return -1; - } - - void Deinitialize(void) { - initialized=false; - pci_devices_installed=0; - num_rqueued_devices=0; - pci_caddress=0; - - for (Bitu dev=0; devNumSubdevices()>0) { - for (Bitu sct=1;sctGetSubdevice(sct); - if (sdev!=NULL) { - if ((sdev->VendorID()==vendor_id) && (sdev->DeviceID()==device_id)) { - pci_devices[dct]->RemoveSubdevice(sct); - } - } - } - } - - if ((pci_devices[dct]->VendorID()==vendor_id) && (pci_devices[dct]->DeviceID()==device_id)) { - delete pci_devices[dct]; - pci_devices[dct]=NULL; - } - } - } - - // check if all devices have been removed - bool any_device_left=false; - for (Bitu dct=0;dct=pci_devices_installed) break; - if (pci_devices[dct]!=NULL) { - any_device_left=true; - break; - } - } - if (!any_device_left) Deinitialize(); - - Bitu last_active_device=PCI_MAX_PCIDEVICES; - for (Bitu dct=0;dct0) { - // register all devices that have been added before the PCI bus was instantiated - for (Bitu dct=0;dctRegisterPCIDevice(rqueued_devices[dct]); - } - num_rqueued_devices=0; - } - } - - ~PCI(){ - initialized=false; - pci_devices_installed=0; - num_rqueued_devices=0; - } - -}; - -static PCI* pci_interface=NULL; - - -PhysPt PCI_GetPModeInterface(void) { - if (pci_interface) { - return pci_interface->GetPModeCallbackPointer(); - } - return 0; -} - -bool PCI_IsInitialized() { - if (pci_interface) return pci_interface->IsInitialized(); - return false; -} - - -void PCI_ShutDown(Section* sec){ - delete pci_interface; - pci_interface=NULL; -} - -void PCI_Init(Section* sec) { - pci_interface = new PCI(sec); - sec->AddDestroyFunction(&PCI_ShutDown,false); -} - -#endif +/* + * Copyright (C) 2002-2011 The DOSBox Team + * + * 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. + */ + + +#include "dosbox.h" +#include "inout.h" +#include "mem.h" +#include "pci_bus.h" +#include "setup.h" +#include "debug.h" +#include "callback.h" +#include "regs.h" + + +#if defined(PCI_FUNCTIONALITY_ENABLED) + +static Bit32u pci_caddress=0; // current PCI addressing +static Bitu pci_devices_installed=0; // number of registered PCI devices + +static Bit8u pci_cfg_data[PCI_MAX_PCIDEVICES][PCI_MAX_PCIFUNCTIONS][256]; // PCI configuration data +static PCI_Device* pci_devices[PCI_MAX_PCIDEVICES]; // registered PCI devices + + +// PCI address +// 31 - set for a PCI access +// 30-24 - 0 +// 23-16 - bus number (0x00ff0000) +// 15-11 - device number (slot) (0x0000f800) +// 10- 8 - subfunction number (0x00000700) +// 7- 2 - config register # (0x000000fc) + +static void write_pci_addr(Bitu port,Bitu val,Bitu iolen) { + LOG(LOG_PCI,LOG_NORMAL)("Write PCI address :=%x",val); + pci_caddress=val; +} + +static void write_pci_register(PCI_Device* dev,Bit8u regnum,Bit8u value) { + // vendor/device/class IDs/header type/etc. are read-only + if ((regnum<0x04) || ((regnum>=0x06) && (regnum<0x0c)) || (regnum==0x0e)) return; + if (dev==NULL) return; + switch (pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][0x0e]&0x7f) { // header-type specific handling + case 0x00: + if ((regnum>=0x28) && (regnum<0x30)) return; // subsystem information is read-only + break; + case 0x01: + case 0x02: + default: + break; + } + + // call device routine for special actions and the + // possibility to discard/replace the value that is to be written + Bits parsed_register=dev->ParseWriteRegister(regnum,value); + if (parsed_register>=0) + pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum]=(Bit8u)(parsed_register&0xff); +} + +static void write_pci(Bitu port,Bitu val,Bitu iolen) { + LOG(LOG_PCI,LOG_NORMAL)("Write PCI data :=%x (len %d)",port,val,iolen); + + // check for enabled/bus 0 + if ((pci_caddress & 0x80ff0000) == 0x80000000) { + Bit8u devnum = (Bit8u)((pci_caddress >> 11) & 0x1f); + Bit8u fctnum = (Bit8u)((pci_caddress >> 8) & 0x7); + Bit8u regnum = (Bit8u)((pci_caddress & 0xfc) + (port & 0x03)); + LOG(LOG_PCI,LOG_NORMAL)(" Write to device %x register %x (function %x) (:=%x)",devnum,regnum,fctnum,val); + + if (devnum>=pci_devices_installed) return; + PCI_Device* masterdev=pci_devices[devnum]; + if (masterdev==NULL) return; + if (fctnum>masterdev->NumSubdevices()) return; + + PCI_Device* dev=masterdev->GetSubdevice(fctnum); + if (dev==NULL) return; + + // write data to PCI device/configuration + switch (iolen) { + case 1: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); break; + case 2: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); + write_pci_register(dev,regnum+1,(Bit8u)((val>>8)&0xff)); break; + case 4: write_pci_register(dev,regnum+0,(Bit8u)(val&0xff)); + write_pci_register(dev,regnum+1,(Bit8u)((val>>8)&0xff)); + write_pci_register(dev,regnum+2,(Bit8u)((val>>16)&0xff)); + write_pci_register(dev,regnum+3,(Bit8u)((val>>24)&0xff)); break; + } + } +} + + +static Bitu read_pci_addr(Bitu port,Bitu iolen) { + LOG(LOG_PCI,LOG_NORMAL)("Read PCI address -> %x",pci_caddress); + return pci_caddress; +} + +// read single 8bit value from register file (special register treatment included) +static Bit8u read_pci_register(PCI_Device* dev,Bit8u regnum) { + switch (regnum) { + case 0x00: + return (Bit8u)(dev->VendorID()&0xff); + case 0x01: + return (Bit8u)((dev->VendorID()>>8)&0xff); + case 0x02: + return (Bit8u)(dev->DeviceID()&0xff); + case 0x03: + return (Bit8u)((dev->DeviceID()>>8)&0xff); + + case 0x0e: + return (pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum]&0x7f) | + ((dev->NumSubdevices()>0)?0x80:0x00); + default: + break; + } + + // call device routine for special actions and possibility to discard/remap register + Bits parsed_regnum=dev->ParseReadRegister(regnum); + if ((parsed_regnum>=0) && (parsed_regnum<256)) + return pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][parsed_regnum]; + + Bit8u newval, mask; + if (dev->OverrideReadRegister(regnum, &newval, &mask)) { + Bit8u oldval=pci_cfg_data[dev->PCIId()][dev->PCISubfunction()][regnum] & (~mask); + return oldval | (newval & mask); + } + + return 0xff; +} + +static Bitu read_pci(Bitu port,Bitu iolen) { + LOG(LOG_PCI,LOG_NORMAL)("Read PCI data -> %x",pci_caddress); + + if ((pci_caddress & 0x80ff0000) == 0x80000000) { + Bit8u devnum = (Bit8u)((pci_caddress >> 11) & 0x1f); + Bit8u fctnum = (Bit8u)((pci_caddress >> 8) & 0x7); + Bit8u regnum = (Bit8u)((pci_caddress & 0xfc) + (port & 0x03)); + if (devnum>=pci_devices_installed) return 0xffffffff; + LOG(LOG_PCI,LOG_NORMAL)(" Read from device %x register %x (function %x); addr %x", + devnum,regnum,fctnum,pci_caddress); + + PCI_Device* masterdev=pci_devices[devnum]; + if (masterdev==NULL) return 0xffffffff; + if (fctnum>masterdev->NumSubdevices()) return 0xffffffff; + + PCI_Device* dev=masterdev->GetSubdevice(fctnum); + + if (dev!=NULL) { + switch (iolen) { + case 1: + { + Bit8u val8=read_pci_register(dev,regnum); + return val8; + } + case 2: + { + Bit16u val16=read_pci_register(dev,regnum); + val16|=(read_pci_register(dev,regnum+1)<<8); + return val16; + } + case 4: + { + Bit32u val32=read_pci_register(dev,regnum); + val32|=(read_pci_register(dev,regnum+1)<<8); + val32|=(read_pci_register(dev,regnum+2)<<16); + val32|=(read_pci_register(dev,regnum+3)<<24); + return val32; + } + default: + break; + } + } + } + return 0xffffffff; +} + + +static Bitu PCI_PM_Handler() { + LOG_MSG("PCI PMode handler, function %x",reg_ax); + return CBRET_NONE; +} + + +PCI_Device::PCI_Device(Bit16u vendor, Bit16u device) { + pci_id=-1; + pci_subfunction=-1; + vendor_id=vendor; + device_id=device; + num_subdevices=0; + for (Bitu dct=0;dct=0) && (number=0) && (subfct0) && (subfctNumSubdevices()) { + delete subdevices[subfct-1]; + subdevices[subfct-1]=NULL; + // should adjust things like num_subdevices as well... + } + } +} + +PCI_Device* PCI_Device::GetSubdevice(Bits subfct) { + if (subfct>=PCI_MAX_PCIFUNCTIONS) return NULL; + if (subfct>0) { + if (subfct<=this->NumSubdevices()) return subdevices[subfct-1]; + } else if (subfct==0) { + return this; + } + return NULL; +} + + +// queued devices (PCI device registering requested before the PCI framework was initialized) +static const Bitu max_rqueued_devices=16; +static Bitu num_rqueued_devices=0; +static PCI_Device* rqueued_devices[max_rqueued_devices]; + + +#include "pci_devices.h" + +class PCI:public Module_base{ +private: + bool initialized; + +protected: + IO_WriteHandleObject PCI_WriteHandler[5]; + IO_ReadHandleObject PCI_ReadHandler[5]; + + CALLBACK_HandlerObject callback_pci; + +public: + + PhysPt GetPModeCallbackPointer(void) { + return Real2Phys(callback_pci.Get_RealPointer()); + } + + bool IsInitialized(void) { + return initialized; + } + + // set up port handlers and configuration data + void InitializePCI(void) { + // install PCI-addressing ports + PCI_WriteHandler[0].Install(0xcf8,write_pci_addr,IO_MD); + PCI_ReadHandler[0].Install(0xcf8,read_pci_addr,IO_MD); + // install PCI-register read/write handlers + for (Bitu ct=0;ct<4;ct++) { + PCI_WriteHandler[1+ct].Install(0xcfc+ct,write_pci,IO_MB); + PCI_ReadHandler[1+ct].Install(0xcfc+ct,read_pci,IO_MB); + } + + for (Bitu dev=0; dev=0) { + // specific slot specified, basic check for validity + if (slot>=PCI_MAX_PCIDEVICES) return -1; + } else { + // auto-add to new slot, check if one is still free + if (pci_devices_installed>=PCI_MAX_PCIDEVICES) return -1; + } + + if (!initialized) InitializePCI(); + + if (slot<0) slot=pci_devices_installed; // use next slot + Bits subfunction=0; // main device unless specific already-occupied slot is requested + if (pci_devices[slot]!=NULL) { + subfunction=pci_devices[slot]->GetNextSubdeviceNumber(); + if (subfunction<0) E_Exit("Too many PCI subdevices!"); + } + + if (device->InitializeRegisters(pci_cfg_data[slot][subfunction])) { + device->SetPCIId(slot, subfunction); + if (pci_devices[slot]==NULL) { + pci_devices[slot]=device; + pci_devices_installed++; + } else { + pci_devices[slot]->AddSubdevice(device); + } + + return slot; + } + + return -1; + } + + void Deinitialize(void) { + initialized=false; + pci_devices_installed=0; + num_rqueued_devices=0; + pci_caddress=0; + + for (Bitu dev=0; devNumSubdevices()>0) { + for (Bitu sct=1;sctGetSubdevice(sct); + if (sdev!=NULL) { + if ((sdev->VendorID()==vendor_id) && (sdev->DeviceID()==device_id)) { + pci_devices[dct]->RemoveSubdevice(sct); + } + } + } + } + + if ((pci_devices[dct]->VendorID()==vendor_id) && (pci_devices[dct]->DeviceID()==device_id)) { + delete pci_devices[dct]; + pci_devices[dct]=NULL; + } + } + } + + // check if all devices have been removed + bool any_device_left=false; + for (Bitu dct=0;dct=pci_devices_installed) break; + if (pci_devices[dct]!=NULL) { + any_device_left=true; + break; + } + } + if (!any_device_left) Deinitialize(); + + Bitu last_active_device=PCI_MAX_PCIDEVICES; + for (Bitu dct=0;dct0) { + // register all devices that have been added before the PCI bus was instantiated + for (Bitu dct=0;dctRegisterPCIDevice(rqueued_devices[dct]); + } + num_rqueued_devices=0; + } + } + + ~PCI(){ + initialized=false; + pci_devices_installed=0; + num_rqueued_devices=0; + } + +}; + +static PCI* pci_interface=NULL; + + +PhysPt PCI_GetPModeInterface(void) { + if (pci_interface) { + return pci_interface->GetPModeCallbackPointer(); + } + return 0; +} + +bool PCI_IsInitialized() { + if (pci_interface) return pci_interface->IsInitialized(); + return false; +} + + +void PCI_ShutDown(Section* sec){ + delete pci_interface; + pci_interface=NULL; +} + +void PCI_Init(Section* sec) { + pci_interface = new PCI(sec); + sec->AddDestroyFunction(&PCI_ShutDown,false); +} + +#endif diff --git a/src/hardware/pci_devices.h b/src/hardware/pci_devices.h index 9a026807..72a73fc4 100644 --- a/src/hardware/pci_devices.h +++ b/src/hardware/pci_devices.h @@ -1,18 +1,18 @@ -/* - * Copyright (C) 2002-2011 The DOSBox Team - * - * 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. - */ - +/* + * Copyright (C) 2002-2011 The DOSBox Team + * + * 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. + */ +