@ -26,11 +26,23 @@
# include "serial.h"
# include "pci.h"
# define PCI_SERIAL_MAX_PORTS 4
typedef struct PCISerialState {
PCIDevice dev ;
SerialState state ;
} PCISerialState ;
typedef struct PCIMultiSerialState {
PCIDevice dev ;
MemoryRegion iobar ;
uint32_t ports ;
char * name [ PCI_SERIAL_MAX_PORTS ] ;
SerialState state [ PCI_SERIAL_MAX_PORTS ] ;
uint32_t level [ PCI_SERIAL_MAX_PORTS ] ;
qemu_irq * irqs ;
} PCIMultiSerialState ;
static int serial_pci_init ( PCIDevice * dev )
{
PCISerialState * pci = DO_UPCAST ( PCISerialState , dev , dev ) ;
@ -47,6 +59,56 @@ static int serial_pci_init(PCIDevice *dev)
return 0 ;
}
static void multi_serial_irq_mux ( void * opaque , int n , int level )
{
PCIMultiSerialState * pci = opaque ;
int i , pending = 0 ;
pci - > level [ n ] = level ;
for ( i = 0 ; i < pci - > ports ; i + + ) {
if ( pci - > level [ i ] ) {
pending = 1 ;
}
}
qemu_set_irq ( pci - > dev . irq [ 0 ] , pending ) ;
}
static int multi_serial_pci_init ( PCIDevice * dev )
{
PCIDeviceClass * pc = PCI_DEVICE_GET_CLASS ( dev ) ;
PCIMultiSerialState * pci = DO_UPCAST ( PCIMultiSerialState , dev , dev ) ;
SerialState * s ;
int i ;
switch ( pc - > device_id ) {
case 0x0003 :
pci - > ports = 2 ;
break ;
case 0x0004 :
pci - > ports = 4 ;
break ;
}
assert ( pci - > ports > 0 ) ;
assert ( pci - > ports < = PCI_SERIAL_MAX_PORTS ) ;
pci - > dev . config [ PCI_INTERRUPT_PIN ] = 0x01 ;
memory_region_init ( & pci - > iobar , " multiserial " , 8 * pci - > ports ) ;
pci_register_bar ( & pci - > dev , 0 , PCI_BASE_ADDRESS_SPACE_IO , & pci - > iobar ) ;
pci - > irqs = qemu_allocate_irqs ( multi_serial_irq_mux , pci ,
pci - > ports ) ;
for ( i = 0 ; i < pci - > ports ; i + + ) {
s = pci - > state + i ;
s - > baudbase = 115200 ;
serial_init_core ( s ) ;
s - > irq = pci - > irqs [ i ] ;
pci - > name [ i ] = g_strdup_printf ( " uart #%d " , i + 1 ) ;
memory_region_init_io ( & s - > io , & serial_io_ops , s , pci - > name [ i ] , 8 ) ;
memory_region_add_subregion ( & pci - > iobar , 8 * i , & s - > io ) ;
}
return 0 ;
}
static void serial_pci_exit ( PCIDevice * dev )
{
PCISerialState * pci = DO_UPCAST ( PCISerialState , dev , dev ) ;
@ -56,6 +118,22 @@ static void serial_pci_exit(PCIDevice *dev)
memory_region_destroy ( & s - > io ) ;
}
static void multi_serial_pci_exit ( PCIDevice * dev )
{
PCIMultiSerialState * pci = DO_UPCAST ( PCIMultiSerialState , dev , dev ) ;
SerialState * s ;
int i ;
for ( i = 0 ; i < pci - > ports ; i + + ) {
s = pci - > state + i ;
serial_exit_core ( s ) ;
memory_region_destroy ( & s - > io ) ;
g_free ( pci - > name [ i ] ) ;
}
memory_region_destroy ( & pci - > iobar ) ;
qemu_free_irqs ( pci - > irqs ) ;
}
static const VMStateDescription vmstate_pci_serial = {
. name = " pci-serial " ,
. version_id = 1 ,
@ -67,11 +145,38 @@ static const VMStateDescription vmstate_pci_serial = {
}
} ;
static const VMStateDescription vmstate_pci_multi_serial = {
. name = " pci-serial-multi " ,
. version_id = 1 ,
. minimum_version_id = 1 ,
. fields = ( VMStateField [ ] ) {
VMSTATE_PCI_DEVICE ( dev , PCIMultiSerialState ) ,
VMSTATE_STRUCT_ARRAY ( state , PCIMultiSerialState , PCI_SERIAL_MAX_PORTS ,
0 , vmstate_serial , SerialState ) ,
VMSTATE_UINT32_ARRAY ( level , PCIMultiSerialState , PCI_SERIAL_MAX_PORTS ) ,
VMSTATE_END_OF_LIST ( )
}
} ;
static Property serial_pci_properties [ ] = {
DEFINE_PROP_CHR ( " chardev " , PCISerialState , state . chr ) ,
DEFINE_PROP_END_OF_LIST ( ) ,
} ;
static Property multi_2x_serial_pci_properties [ ] = {
DEFINE_PROP_CHR ( " chardev1 " , PCIMultiSerialState , state [ 0 ] . chr ) ,
DEFINE_PROP_CHR ( " chardev2 " , PCIMultiSerialState , state [ 1 ] . chr ) ,
DEFINE_PROP_END_OF_LIST ( ) ,
} ;
static Property multi_4x_serial_pci_properties [ ] = {
DEFINE_PROP_CHR ( " chardev1 " , PCIMultiSerialState , state [ 0 ] . chr ) ,
DEFINE_PROP_CHR ( " chardev2 " , PCIMultiSerialState , state [ 1 ] . chr ) ,
DEFINE_PROP_CHR ( " chardev3 " , PCIMultiSerialState , state [ 2 ] . chr ) ,
DEFINE_PROP_CHR ( " chardev4 " , PCIMultiSerialState , state [ 3 ] . chr ) ,
DEFINE_PROP_END_OF_LIST ( ) ,
} ;
static void serial_pci_class_initfn ( ObjectClass * klass , void * data )
{
DeviceClass * dc = DEVICE_CLASS ( klass ) ;
@ -86,6 +191,34 @@ static void serial_pci_class_initfn(ObjectClass *klass, void *data)
dc - > props = serial_pci_properties ;
}
static void multi_2x_serial_pci_class_initfn ( ObjectClass * klass , void * data )
{
DeviceClass * dc = DEVICE_CLASS ( klass ) ;
PCIDeviceClass * pc = PCI_DEVICE_CLASS ( klass ) ;
pc - > init = multi_serial_pci_init ;
pc - > exit = multi_serial_pci_exit ;
pc - > vendor_id = 0x1b36 ; /* Red Hat */
pc - > device_id = 0x0003 ;
pc - > revision = 1 ;
pc - > class_id = PCI_CLASS_COMMUNICATION_SERIAL ;
dc - > vmsd = & vmstate_pci_multi_serial ;
dc - > props = multi_2x_serial_pci_properties ;
}
static void multi_4x_serial_pci_class_initfn ( ObjectClass * klass , void * data )
{
DeviceClass * dc = DEVICE_CLASS ( klass ) ;
PCIDeviceClass * pc = PCI_DEVICE_CLASS ( klass ) ;
pc - > init = multi_serial_pci_init ;
pc - > exit = multi_serial_pci_exit ;
pc - > vendor_id = 0x1b36 ; /* Red Hat */
pc - > device_id = 0x0004 ;
pc - > revision = 1 ;
pc - > class_id = PCI_CLASS_COMMUNICATION_SERIAL ;
dc - > vmsd = & vmstate_pci_multi_serial ;
dc - > props = multi_4x_serial_pci_properties ;
}
static TypeInfo serial_pci_info = {
. name = " pci-serial " ,
. parent = TYPE_PCI_DEVICE ,
@ -93,9 +226,25 @@ static TypeInfo serial_pci_info = {
. class_init = serial_pci_class_initfn ,
} ;
static TypeInfo multi_2x_serial_pci_info = {
. name = " pci-serial-2x " ,
. parent = TYPE_PCI_DEVICE ,
. instance_size = sizeof ( PCIMultiSerialState ) ,
. class_init = multi_2x_serial_pci_class_initfn ,
} ;
static TypeInfo multi_4x_serial_pci_info = {
. name = " pci-serial-4x " ,
. parent = TYPE_PCI_DEVICE ,
. instance_size = sizeof ( PCIMultiSerialState ) ,
. class_init = multi_4x_serial_pci_class_initfn ,
} ;
static void serial_pci_register_types ( void )
{
type_register_static ( & serial_pci_info ) ;
type_register_static ( & multi_2x_serial_pci_info ) ;
type_register_static ( & multi_4x_serial_pci_info ) ;
}
type_init ( serial_pci_register_types )