Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
Xing Lin
qemu
Commits
69b91039
Commit
69b91039
authored
May 18, 2004
by
bellard
Browse files
PCI support
git-svn-id:
svn://svn.savannah.nongnu.org/qemu/trunk@818
c046a42c-6fe2-441c-8c8c-71466251a162
parent
158156d1
Changes
10
Hide whitespace changes
Inline
Side-by-side
Changelog
View file @
69b91039
...
...
@@ -8,6 +8,9 @@ version 0.5.6:
- int13 CDROM BIOS fix (aka Solaris x86 install CD fix)
- int15, ah=86 BIOS fix (aka Solaris x86 hardware probe hang up fix)
- BSR/BSF "undefined behaviour" fix
- vmdk2raw: convert VMware disk images to raw images
- PCI support
- NE2K PCI support
version 0.5.5:
...
...
Makefile.target
View file @
69b91039
...
...
@@ -232,7 +232,7 @@ ifeq ($(ARCH),alpha)
endif
# must use static linking to avoid leaving stuff in virtual address space
VL_OBJS
=
vl.o osdep.o block.o monitor.o
VL_OBJS
=
vl.o osdep.o block.o monitor.o
pci.o pci2isa.o
ifeq
($(TARGET_ARCH), i386)
# Hardware support
...
...
hw/ide.c
View file @
69b91039
...
...
@@ -1433,18 +1433,14 @@ static void ide_guess_geometry(IDEState *s)
}
}
void
ide_init
(
int
iobase
,
int
iobase2
,
int
irq
,
BlockDriverState
*
hd0
,
BlockDriverState
*
hd1
)
static
void
ide_init
2
(
IDEState
*
ide_state
,
int
irq
,
BlockDriverState
*
hd0
,
BlockDriverState
*
hd1
)
{
IDEState
*
s
,
*
ide_state
;
IDEState
*
s
;
static
int
drive_serial
=
1
;
int
i
,
cylinders
,
heads
,
secs
;
int64_t
nb_sectors
;
ide_state
=
qemu_mallocz
(
sizeof
(
IDEState
)
*
2
);
if
(
!
ide_state
)
return
;
for
(
i
=
0
;
i
<
2
;
i
++
)
{
s
=
ide_state
+
i
;
if
(
i
==
0
)
...
...
@@ -1483,6 +1479,22 @@ void ide_init(int iobase, int iobase2, int irq,
s
->
irq
=
irq
;
ide_reset
(
s
);
}
}
/***********************************************************/
/* ISA IDE definitions */
void
isa_ide_init
(
int
iobase
,
int
iobase2
,
int
irq
,
BlockDriverState
*
hd0
,
BlockDriverState
*
hd1
)
{
IDEState
*
ide_state
;
ide_state
=
qemu_mallocz
(
sizeof
(
IDEState
)
*
2
);
if
(
!
ide_state
)
return
;
ide_init2
(
ide_state
,
irq
,
hd0
,
hd1
);
register_ioport_write
(
iobase
,
8
,
1
,
ide_ioport_write
,
ide_state
);
register_ioport_read
(
iobase
,
8
,
1
,
ide_ioport_read
,
ide_state
);
if
(
iobase2
)
{
...
...
@@ -1496,3 +1508,87 @@ void ide_init(int iobase, int iobase2, int irq,
register_ioport_write
(
iobase
,
4
,
4
,
ide_data_writel
,
ide_state
);
register_ioport_read
(
iobase
,
4
,
4
,
ide_data_readl
,
ide_state
);
}
/***********************************************************/
/* PCI IDE definitions */
typedef
struct
PCIIDEState
{
PCIDevice
dev
;
IDEState
ide_if
[
4
];
}
PCIIDEState
;
static
uint32_t
ide_read_config
(
PCIDevice
*
d
,
uint32_t
address
,
int
len
)
{
uint32_t
val
;
val
=
0
;
memcpy
(
&
val
,
d
->
config
+
address
,
len
);
return
val
;
}
static
void
ide_write_config
(
PCIDevice
*
d
,
uint32_t
address
,
uint32_t
val
,
int
len
)
{
memcpy
(
d
->
config
+
address
,
&
val
,
len
);
}
static
void
ide_map
(
PCIDevice
*
pci_dev
,
int
region_num
,
uint32_t
addr
,
uint32_t
size
,
int
type
)
{
PCIIDEState
*
d
=
(
PCIIDEState
*
)
pci_dev
;
IDEState
*
ide_state
;
if
(
region_num
<=
3
)
{
ide_state
=
&
d
->
ide_if
[(
region_num
>>
1
)
*
2
];
if
(
region_num
&
1
)
{
register_ioport_read
(
addr
+
2
,
1
,
1
,
ide_status_read
,
ide_state
);
register_ioport_write
(
addr
+
2
,
1
,
1
,
ide_cmd_write
,
ide_state
);
}
else
{
register_ioport_write
(
addr
,
8
,
1
,
ide_ioport_write
,
ide_state
);
register_ioport_read
(
addr
,
8
,
1
,
ide_ioport_read
,
ide_state
);
/* data ports */
register_ioport_write
(
addr
,
2
,
2
,
ide_data_writew
,
ide_state
);
register_ioport_read
(
addr
,
2
,
2
,
ide_data_readw
,
ide_state
);
register_ioport_write
(
addr
,
4
,
4
,
ide_data_writel
,
ide_state
);
register_ioport_read
(
addr
,
4
,
4
,
ide_data_readl
,
ide_state
);
}
}
}
/* hd_table must contain 4 block drivers */
void
pci_ide_init
(
BlockDriverState
**
hd_table
)
{
PCIIDEState
*
d
;
uint8_t
*
pci_conf
;
d
=
(
PCIIDEState
*
)
pci_register_device
(
"IDE"
,
sizeof
(
PCIIDEState
),
0
,
-
1
,
ide_read_config
,
ide_write_config
);
pci_conf
=
d
->
dev
.
config
;
pci_conf
[
0x00
]
=
0x86
;
// Intel
pci_conf
[
0x01
]
=
0x80
;
pci_conf
[
0x02
]
=
0x00
;
// fake
pci_conf
[
0x03
]
=
0x01
;
// fake
pci_conf
[
0x0a
]
=
0x01
;
// class_sub = PCI_IDE
pci_conf
[
0x0b
]
=
0x01
;
// class_base = PCI_mass_storage
pci_conf
[
0x0e
]
=
0x80
;
// header_type = PCI_multifunction, generic
pci_conf
[
0x2c
]
=
0x86
;
// subsys vendor
pci_conf
[
0x2d
]
=
0x80
;
// subsys vendor
pci_conf
[
0x2e
]
=
0x00
;
// fake
pci_conf
[
0x2f
]
=
0x01
;
// fake
pci_register_io_region
((
PCIDevice
*
)
d
,
0
,
0x8
,
PCI_ADDRESS_SPACE_IO
,
ide_map
);
pci_register_io_region
((
PCIDevice
*
)
d
,
1
,
0x4
,
PCI_ADDRESS_SPACE_IO
,
ide_map
);
pci_register_io_region
((
PCIDevice
*
)
d
,
2
,
0x8
,
PCI_ADDRESS_SPACE_IO
,
ide_map
);
pci_register_io_region
((
PCIDevice
*
)
d
,
3
,
0x4
,
PCI_ADDRESS_SPACE_IO
,
ide_map
);
ide_init2
(
&
d
->
ide_if
[
0
],
14
,
hd_table
[
0
],
hd_table
[
1
]);
ide_init2
(
&
d
->
ide_if
[
2
],
15
,
hd_table
[
2
],
hd_table
[
3
]);
}
hw/ne2000.c
View file @
69b91039
...
...
@@ -368,7 +368,7 @@ static uint32_t ne2000_ioport_read(void *opaque, uint32_t addr)
}
static
inline
void
ne2000_mem_writeb
(
NE2000State
*
s
,
uint32_t
addr
,
uint32_t
val
)
uint32_t
val
)
{
if
(
addr
<
32
||
(
addr
>=
NE2000_PMEM_START
&&
addr
<
NE2000_MEM_SIZE
))
{
...
...
@@ -382,8 +382,17 @@ static inline void ne2000_mem_writew(NE2000State *s, uint32_t addr,
addr
&=
~
1
;
/* XXX: check exact behaviour if not even */
if
(
addr
<
32
||
(
addr
>=
NE2000_PMEM_START
&&
addr
<
NE2000_MEM_SIZE
))
{
s
->
mem
[
addr
]
=
val
;
s
->
mem
[
addr
+
1
]
=
val
>>
8
;
*
(
uint16_t
*
)(
s
->
mem
+
addr
)
=
cpu_to_le16
(
val
);
}
}
static
inline
void
ne2000_mem_writel
(
NE2000State
*
s
,
uint32_t
addr
,
uint32_t
val
)
{
addr
&=
~
3
;
/* XXX: check exact behaviour if not even */
if
(
addr
<
32
||
(
addr
>=
NE2000_PMEM_START
&&
addr
<
NE2000_MEM_SIZE
))
{
*
(
uint32_t
*
)(
s
->
mem
+
addr
)
=
cpu_to_le32
(
val
);
}
}
...
...
@@ -402,12 +411,23 @@ static inline uint32_t ne2000_mem_readw(NE2000State *s, uint32_t addr)
addr
&=
~
1
;
/* XXX: check exact behaviour if not even */
if
(
addr
<
32
||
(
addr
>=
NE2000_PMEM_START
&&
addr
<
NE2000_MEM_SIZE
))
{
return
s
->
mem
[
addr
]
|
(
s
->
mem
[
addr
+
1
]
<<
8
);
return
le16_to_cpu
(
*
(
uint16_t
*
)
(
s
->
mem
+
addr
)
);
}
else
{
return
0xffff
;
}
}
static
inline
uint32_t
ne2000_mem_readl
(
NE2000State
*
s
,
uint32_t
addr
)
{
addr
&=
~
3
;
/* XXX: check exact behaviour if not even */
if
(
addr
<
32
||
(
addr
>=
NE2000_PMEM_START
&&
addr
<
NE2000_MEM_SIZE
))
{
return
le32_to_cpu
(
*
(
uint32_t
*
)(
s
->
mem
+
addr
));
}
else
{
return
0xffffffff
;
}
}
static
void
ne2000_asic_ioport_write
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
NE2000State
*
s
=
opaque
;
...
...
@@ -468,6 +488,53 @@ static uint32_t ne2000_asic_ioport_read(void *opaque, uint32_t addr)
return
ret
;
}
static
void
ne2000_asic_ioport_writel
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
NE2000State
*
s
=
opaque
;
#ifdef DEBUG_NE2000
printf
(
"NE2000: asic writel val=0x%04x
\n
"
,
val
);
#endif
if
(
s
->
rcnt
==
0
)
return
;
/* 32 bit access */
ne2000_mem_writel
(
s
,
s
->
rsar
,
val
);
s
->
rsar
+=
4
;
s
->
rcnt
-=
4
;
/* wrap */
if
(
s
->
rsar
==
s
->
stop
)
s
->
rsar
=
s
->
start
;
if
(
s
->
rcnt
==
0
)
{
/* signal end of transfert */
s
->
isr
|=
ENISR_RDC
;
ne2000_update_irq
(
s
);
}
}
static
uint32_t
ne2000_asic_ioport_readl
(
void
*
opaque
,
uint32_t
addr
)
{
NE2000State
*
s
=
opaque
;
int
ret
;
/* 32 bit access */
ret
=
ne2000_mem_readl
(
s
,
s
->
rsar
);
s
->
rsar
+=
4
;
s
->
rcnt
-=
4
;
/* wrap */
if
(
s
->
rsar
==
s
->
stop
)
s
->
rsar
=
s
->
start
;
if
(
s
->
rcnt
==
0
)
{
/* signal end of transfert */
s
->
isr
|=
ENISR_RDC
;
ne2000_update_irq
(
s
);
}
#ifdef DEBUG_NE2000
printf
(
"NE2000: asic readl val=0x%04x
\n
"
,
ret
);
#endif
return
ret
;
}
static
void
ne2000_reset_ioport_write
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
/* nothing to do (end of reset pulse) */
...
...
@@ -480,7 +547,7 @@ static uint32_t ne2000_reset_ioport_read(void *opaque, uint32_t addr)
return
0
;
}
void
ne2000_init
(
int
base
,
int
irq
,
NetDriverState
*
nd
)
void
isa_
ne2000_init
(
int
base
,
int
irq
,
NetDriverState
*
nd
)
{
NE2000State
*
s
;
...
...
@@ -505,3 +572,78 @@ void ne2000_init(int base, int irq, NetDriverState *nd)
qemu_add_read_packet
(
nd
,
ne2000_can_receive
,
ne2000_receive
,
s
);
}
/***********************************************************/
/* PCI NE2000 definitions */
typedef
struct
PCINE2000State
{
PCIDevice
dev
;
NE2000State
ne2000
;
}
PCINE2000State
;
static
uint32_t
ne2000_read_config
(
PCIDevice
*
d
,
uint32_t
address
,
int
len
)
{
uint32_t
val
;
val
=
0
;
memcpy
(
&
val
,
d
->
config
+
address
,
len
);
return
val
;
}
static
void
ne2000_write_config
(
PCIDevice
*
d
,
uint32_t
address
,
uint32_t
val
,
int
len
)
{
memcpy
(
d
->
config
+
address
,
&
val
,
len
);
}
static
void
ne2000_map
(
PCIDevice
*
pci_dev
,
int
region_num
,
uint32_t
addr
,
uint32_t
size
,
int
type
)
{
PCINE2000State
*
d
=
(
PCINE2000State
*
)
pci_dev
;
NE2000State
*
s
=
&
d
->
ne2000
;
register_ioport_write
(
addr
,
16
,
1
,
ne2000_ioport_write
,
s
);
register_ioport_read
(
addr
,
16
,
1
,
ne2000_ioport_read
,
s
);
register_ioport_write
(
addr
+
0x10
,
1
,
1
,
ne2000_asic_ioport_write
,
s
);
register_ioport_read
(
addr
+
0x10
,
1
,
1
,
ne2000_asic_ioport_read
,
s
);
register_ioport_write
(
addr
+
0x10
,
2
,
2
,
ne2000_asic_ioport_write
,
s
);
register_ioport_read
(
addr
+
0x10
,
2
,
2
,
ne2000_asic_ioport_read
,
s
);
register_ioport_write
(
addr
+
0x10
,
4
,
4
,
ne2000_asic_ioport_writel
,
s
);
register_ioport_read
(
addr
+
0x10
,
4
,
4
,
ne2000_asic_ioport_readl
,
s
);
register_ioport_write
(
addr
+
0x1f
,
1
,
1
,
ne2000_reset_ioport_write
,
s
);
register_ioport_read
(
addr
+
0x1f
,
1
,
1
,
ne2000_reset_ioport_read
,
s
);
}
void
pci_ne2000_init
(
NetDriverState
*
nd
)
{
PCINE2000State
*
d
;
NE2000State
*
s
;
uint8_t
*
pci_conf
;
d
=
(
PCINE2000State
*
)
pci_register_device
(
"NE2000"
,
sizeof
(
PCINE2000State
),
0
,
-
1
,
ne2000_read_config
,
ne2000_write_config
);
pci_conf
=
d
->
dev
.
config
;
pci_conf
[
0x00
]
=
0xec
;
// Realtek 8029
pci_conf
[
0x01
]
=
0x10
;
pci_conf
[
0x02
]
=
0x29
;
pci_conf
[
0x03
]
=
0x80
;
pci_conf
[
0x0a
]
=
0x00
;
// ethernet network controller
pci_conf
[
0x0b
]
=
0x02
;
pci_conf
[
0x0e
]
=
0x00
;
// header_type
/* XXX: do that in the BIOS */
pci_conf
[
0x3c
]
=
11
;
// interrupt line
pci_conf
[
0x3d
]
=
1
;
// interrupt pin
pci_register_io_region
((
PCIDevice
*
)
d
,
0
,
0x100
,
PCI_ADDRESS_SPACE_IO
,
ne2000_map
);
s
=
&
d
->
ne2000
;
s
->
irq
=
11
;
s
->
nd
=
nd
;
ne2000_reset
(
s
);
qemu_add_read_packet
(
nd
,
ne2000_can_receive
,
ne2000_receive
,
s
);
}
hw/pc.c
View file @
69b91039
...
...
@@ -380,6 +380,11 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
stw_raw
(
phys_ram_base
+
KERNEL_PARAMS_ADDR
+
0x210
,
0x01
);
}
if
(
pci_enabled
)
{
i440fx_init
();
piix3_init
();
}
/* init basic PC hardware */
register_ioport_write
(
0x80
,
1
,
1
,
ioport80_write
,
NULL
);
...
...
@@ -401,17 +406,25 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
fd
=
serial_open_device
();
serial_init
(
0x3f8
,
4
,
fd
);
nb_nics1
=
nb_nics
;
if
(
nb_nics1
>
NE2000_NB_MAX
)
nb_nics1
=
NE2000_NB_MAX
;
for
(
i
=
0
;
i
<
nb_nics1
;
i
++
)
{
ne2000_init
(
ne2000_io
[
i
],
ne2000_irq
[
i
],
&
nd_table
[
i
]);
}
if
(
pci_enabled
)
{
for
(
i
=
0
;
i
<
nb_nics
;
i
++
)
{
pci_ne2000_init
(
&
nd_table
[
i
]);
}
pci_ide_init
(
bs_table
);
}
else
{
nb_nics1
=
nb_nics
;
if
(
nb_nics1
>
NE2000_NB_MAX
)
nb_nics1
=
NE2000_NB_MAX
;
for
(
i
=
0
;
i
<
nb_nics1
;
i
++
)
{
isa_ne2000_init
(
ne2000_io
[
i
],
ne2000_irq
[
i
],
&
nd_table
[
i
]);
}
for
(
i
=
0
;
i
<
2
;
i
++
)
{
ide_init
(
ide_iobase
[
i
],
ide_iobase2
[
i
],
ide_irq
[
i
],
bs_table
[
2
*
i
],
bs_table
[
2
*
i
+
1
]);
for
(
i
=
0
;
i
<
2
;
i
++
)
{
isa_ide_init
(
ide_iobase
[
i
],
ide_iobase2
[
i
],
ide_irq
[
i
],
bs_table
[
2
*
i
],
bs_table
[
2
*
i
+
1
]);
}
}
kbd_init
();
DMA_init
();
...
...
@@ -426,4 +439,10 @@ void pc_init(int ram_size, int vga_ram_size, int boot_device,
floppy_controller
=
fdctrl_init
(
6
,
2
,
0
,
0x3f0
,
fd_table
);
cmos_init
(
ram_size
,
boot_device
);
/* must be done after all PCI devices are instanciated */
/* XXX: should be done in the Bochs BIOS */
if
(
pci_enabled
)
{
pci_bios_init
();
}
}
hw/pci.c
0 → 100644
View file @
69b91039
/*
* QEMU PCI bus manager
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "vl.h"
//#define DEBUG_PCI
typedef
struct
PCIBridge
{
uint32_t
config_reg
;
PCIDevice
**
pci_bus
[
256
];
}
PCIBridge
;
static
PCIBridge
pci_bridge
;
target_phys_addr_t
pci_mem_base
;
/* -1 for devfn means auto assign */
PCIDevice
*
pci_register_device
(
const
char
*
name
,
int
instance_size
,
int
bus_num
,
int
devfn
,
PCIConfigReadFunc
*
config_read
,
PCIConfigWriteFunc
*
config_write
)
{
PCIBridge
*
s
=
&
pci_bridge
;
PCIDevice
*
pci_dev
,
**
bus
;
if
(
!
s
->
pci_bus
[
bus_num
])
{
s
->
pci_bus
[
bus_num
]
=
qemu_mallocz
(
256
*
sizeof
(
PCIDevice
*
));
if
(
!
s
->
pci_bus
[
bus_num
])
return
NULL
;
}
bus
=
s
->
pci_bus
[
bus_num
];
if
(
devfn
<
0
)
{
for
(
devfn
=
0
;
devfn
<
256
;
devfn
+=
8
)
{
if
(
!
bus
[
devfn
])
goto
found
;
}
return
NULL
;
found:
;
}
pci_dev
=
qemu_mallocz
(
instance_size
);
if
(
!
pci_dev
)
return
NULL
;
pci_dev
->
bus_num
=
bus_num
;
pci_dev
->
devfn
=
devfn
;
pstrcpy
(
pci_dev
->
name
,
sizeof
(
pci_dev
->
name
),
name
);
pci_dev
->
config_read
=
config_read
;
pci_dev
->
config_write
=
config_write
;
bus
[
devfn
]
=
pci_dev
;
return
pci_dev
;
}
void
pci_register_io_region
(
PCIDevice
*
pci_dev
,
int
region_num
,
uint32_t
size
,
int
type
,
PCIMapIORegionFunc
*
map_func
)
{
PCIIORegion
*
r
;
if
((
unsigned
int
)
region_num
>=
6
)
return
;
r
=
&
pci_dev
->
io_regions
[
region_num
];
r
->
addr
=
-
1
;
r
->
size
=
size
;
r
->
type
=
type
;
r
->
map_func
=
map_func
;
}
static
void
pci_config_writel
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
PCIBridge
*
s
=
opaque
;
s
->
config_reg
=
val
;
}
static
uint32_t
pci_config_readl
(
void
*
opaque
,
uint32_t
addr
)
{
PCIBridge
*
s
=
opaque
;
return
s
->
config_reg
;
}
static
void
unmap_region
(
PCIIORegion
*
r
)
{
if
(
r
->
addr
==
-
1
)
return
;
#ifdef DEBUG_PCI
printf
(
"unmap addr=%08x size=%08x
\n
"
,
r
->
addr
,
r
->
size
);
#endif
if
(
r
->
type
&
PCI_ADDRESS_SPACE_IO
)
{
isa_unassign_ioport
(
r
->
addr
,
r
->
size
);
}
else
{
cpu_register_physical_memory
(
r
->
addr
+
pci_mem_base
,
r
->
size
,
IO_MEM_UNASSIGNED
);
}
}
static
void
pci_data_write
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
,
int
len
)
{
PCIBridge
*
s
=
opaque
;
PCIDevice
**
bus
,
*
pci_dev
;
int
config_addr
,
reg
;
#if defined(DEBUG_PCI) && 0
printf
(
"pci_data_write: addr=%08x val=%08x len=%d
\n
"
,
s
->
config_reg
,
val
,
len
);
#endif
if
(
!
(
s
->
config_reg
&
(
1
<<
31
)))
{
return
;
}
if
((
s
->
config_reg
&
0x3
)
!=
0
)
{
return
;
}
bus
=
s
->
pci_bus
[(
s
->
config_reg
>>
16
)
&
0xff
];
if
(
!
bus
)
return
;
pci_dev
=
bus
[(
s
->
config_reg
>>
8
)
&
0xff
];
if
(
!
pci_dev
)
return
;
config_addr
=
(
s
->
config_reg
&
0xfc
)
|
(
addr
&
3
);
#if defined(DEBUG_PCI)
printf
(
"pci_config_write: %s: addr=%02x val=%08x len=%d
\n
"
,
pci_dev
->
name
,
config_addr
,
val
,
len
);
#endif
if
(
len
==
4
&&
(
config_addr
>=
0x10
&&
config_addr
<
0x10
+
4
*
6
))
{
PCIIORegion
*
r
;
reg
=
(
config_addr
-
0x10
)
>>
2
;
r
=
&
pci_dev
->
io_regions
[
reg
];
if
(
r
->
size
==
0
)
goto
default_config
;
if
(
val
!=
0xffffffff
&&
val
!=
0
)
{
/* XXX: the memory assignment should be global to handle
overlaps, but it is not needed at this stage */
/* first unmap the old region */
unmap_region
(
r
);
/* change the address */
if
(
r
->
type
&
PCI_ADDRESS_SPACE_IO
)
r
->
addr
=
val
&
~
0x3
;
else
r
->
addr
=
val
&
~
0xf
;
#ifdef DEBUG_PCI
printf
(
"map addr=%08x size=%08x type=%d
\n
"
,
r
->
addr
,
r
->
size
,
r
->
type
);
#endif
r
->
map_func
(
pci_dev
,
reg
,
r
->
addr
,
r
->
size
,
r
->
type
);
}
/* now compute the stored value */
val
&=
~
(
r
->
size
-
1
);
val
|=
r
->
type
;
*
(
uint32_t
*
)(
pci_dev
->
config
+
0x10
+
reg
*
4
)
=
cpu_to_le32
(
val
);
}
else
{
default_config:
pci_dev
->
config_write
(
pci_dev
,
config_addr
,
val
,
len
);
}
}
static
uint32_t
pci_data_read
(
void
*
opaque
,
uint32_t
addr
,
int
len
)
{
PCIBridge
*
s
=
opaque
;
PCIDevice
**
bus
,
*
pci_dev
;
int
config_addr
;
uint32_t
val
;
if
(
!
(
s
->
config_reg
&
(
1
<<
31
)))
goto
fail
;
if
((
s
->
config_reg
&
0x3
)
!=
0
)
goto
fail
;
bus
=
s
->
pci_bus
[(
s
->
config_reg
>>
16
)
&
0xff
];
if
(
!
bus
)
goto
fail
;
pci_dev
=
bus
[(
s
->
config_reg
>>
8
)
&
0xff
];
if
(
!
pci_dev
)
{
fail:
val
=
0
;
goto
the_end
;
}
config_addr
=
(
s
->
config_reg
&
0xfc
)
|
(
addr
&
3
);
val
=
pci_dev
->
config_read
(
pci_dev
,
config_addr
,
len
);
#if defined(DEBUG_PCI)
printf
(
"pci_config_read: %s: addr=%02x val=%08x len=%d
\n
"
,
pci_dev
->
name
,
config_addr
,
val
,
len
);
#endif
the_end:
#if defined(DEBUG_PCI) && 0
printf
(
"pci_data_read: addr=%08x val=%08x len=%d
\n
"
,
s
->
config_reg
,
val
,
len
);
#endif
return
val
;
}
static
void
pci_data_writeb
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
pci_data_write
(
opaque
,
addr
,
val
,
1
);
}
static
void
pci_data_writew
(
void
*
opaque
,
uint32_t
addr
,
uint32_t
val
)
{
pci_data_write
(
opaque
,
addr
,
val
,
2
);
}