docs: Document DeviceState handling.
Change-Id: Ib3dbcf9b3eb7e150515625a974f11037d80aeacb
diff --git a/docs/DEVICE-STATE.TXT b/docs/DEVICE-STATE.TXT
new file mode 100644
index 0000000..49ed713
--- /dev/null
+++ b/docs/DEVICE-STATE.TXT
@@ -0,0 +1,293 @@
+DeviceState/SysBus in master/qemu:
+===========================================================================
+
+Defined in <hw/qdev-core.h>
+
+Typical sequence to create a new DeviceState instance:
+
+ DeviceState* dev = qdev_create(parent_bus, device_class_name);
+ qdev_set_prop_int(dev, "<property-name>", value);
+ ... // set other properties.
+ qdev_init(dev); // real initialization / realization here.
+ return dev;
+
+Registering a new DeviceState class (a.k.a. DeviceInfo):
+
+ DeviceInfo info = g_malloc0(sizeof(*info));
+ info->name = DEVICE_CLASS_NAME;
+ info->size = sizeof(MyDeviceState);
+ info->init = my_device_state_init;
+ info->bus_type = DEVICE_BUS_TYPE; // SYSTEM / PCI / LSI / etc.
+ qdev_register(&info);
+
+
+DeviceState has:
+
+ type : *DeviceType -> should really be DeviceInfo, see below.
+ parent_bus: *BusState -> parent bus the device is attached to.
+ props: *DeviceProperty -> WHAT ARE THESE ???
+ num_gpio_out: int -> number of output IRQ pins.
+ gpio_out: *qemu_irq -> array of output IRQ pins.
+ num_gpio_in: int -> number of input IRQ pins.
+ gpio_in: *qemu_irq -> array of input IRQ pins.
+ child_bus: QLIST_HEAD(, BusState) -> optional child bus provided by device?
+ nd: *NICInfo ?? -> WHAT IS THIS ???
+ sibling: QLIST_ENTRY(DeviceState) -> next device attached to same |parent_bus|.
+
+BusState has:
+ parent: *DeviceState -> parent device, if any?
+ name: *char -> bus name. What is used for?
+ type: BusType -> SYSTEM, PCI, SCSI, I2C or SSI. Why?
+
+DeviceInfo: -> Really a device class descriptor.
+ name: *const char -> Name of device class.
+ size: size_t -> Size of device instance, must be >= sizeof(DeviceState).
+ props: *DevicePropList ->
+
+ init: qdev_initfn
+ bus_type: BusType.
+
+DeviceType: -> Defined and used by hw/core/qdev.c to to maintain the list of
+ registered DeviceInfo values (added by calling qdev_register()).
+ info: *DeviceInfo -> device class descriptor.
+ next: *DeviceType -> next item in list.
+
+DeviceProperty:
+ name: *const_char -> property name.
+ type: DevicePropertyType -> INT, PTR or DEV ???
+ value: union{uint64_t, void*} -> property value.
+
+DevicePropList: Individual array item describing a device property.
+ Used in DeviceInfo to list which properties a given DeviceState
+ supports.
+ name: *const_char -> property name.
+ type: DevicePropertyType -> INT, PTR or DEV ?
+
+// Create a new, totally empty, DeviceState instance.
+// |bus| is the parent bus instance, if NULL, this indicates that the device
+// will be attached to the main system bus (created internally on demand by
+// this function).
+// |name| is the device class name, i.e. must match the |name| field of a
+// registered DeviceInfo.
+// Return a new DeviceState instance on success, panic on failure.
+//
+// IMPORTANT: The DeviceState is allocated with g_malloc0() but is not
+// initialized when the function returns!! It is just added
+// to the parent bus' list.
+//
+// Possible failure modes:
+// - |name| doesn't match a registered DeviceInfo.
+// - The |bus_type| field of the DeviceInfo does not match the one of
+// the parent |bus|.
+DeviceState* qdev_create(BusState* bus, const char* name);
+
+// Initialize a given DeviceState. Assumes that all device properties were
+// set before calling this function, and that IRQs and MMIO regions are also
+// already connected. This simply calls the |init| function of the device's
+// DeviceInfo class descriptor.
+void qdev_init(DeviceState* dev);
+
+// Unlink a device from a bus and free the structure. NOTE: This does not
+// perform any de-initialization.
+qdev_free(DeviceState* dev);
+
+// Sets a device property to a given integer value.
+// |dev| is the target DeviceState that holds the property value.
+// |name| is the property name.
+// |value| is the 64-bit value.
+// NOTE: This function doesn't check that the property name actually
+// matches any of the properties listed in the DeviceInfo, or
+// that their type matches. It also doesn't check for any
+// previously existing with the same name, it just prepends
+// to the list.
+void qdev_set_prop(DeviceState* dev, const char* name, uint64_t value);
+
+// Same a qdev_set_prop() for property values of type DEV
+void qdev_set_prop_dev(DeviceState* dev, const char* name DeviceState* value);
+
+// Same a qdev_set_prop() for property values of type PTR
+void qdev_set_prop_ptr(DeviceState* dev, const char* name, void* value);
+
+// Find if the device |dev| has a value for property |name|, and return it
+// if it does, otherwise return |def|. This assert()s that the property
+// type is an integer (INT).
+uint64_t qdev_get_prop_int(DeviceState* dev, const char* name, uint64_t def);
+
+// Find if the device |dev| has a pointer value for property |name|, and
+// return it if it does. Otherwise, assert(NULL). NOTE THE UNEXPECTED ASSERT
+// HERE!
+void* qdev_get_prop_ptr(DeviceState* dev, const char* name);
+
+// Find if the device |dev| has a DeviceState value for property |name|,
+// and return it if it does, or NULL if it doesn't.
+DeviceState* qdev_get_prop_dev(DeviceState* dev, const char* name);
+
+// Despite its name, this doesn't do any kind of initialization, this just
+// returns a new CharDriverState which was previously added to the global
+// |serial_hds| or |virtcon_hds| arrays. Which one is selected depends
+// on the device's DeviceInfo |name| field. If it starts with 'virtio'
+// then it comes from |virtcon_hds|, otherwise from |serial_hds|.
+// There is a FIXME here to 'get rid of this hack'.
+CharDriveState* qdev_init_chardev(DeviceState* dev);
+
+// Just return device's |parent_bus| field falue.
+BusState* qdev_get_parent_bus(DeviceState* dev);
+
+// Allocate |n| input IRQ pins that all will be handled by the |handler|
+// callback for device |dev|.
+void qdev_init_gpio_in(DeviceState* dev, qemu_irq_handler handler, int n);
+
+// Allocate |n| output IRQ pins that all will be handled by the |handler|
+// callback for device |dev|.
+void qdev_init_gpio_out(DeviceState* dev, qemu_irq_handler handler, int n);
+
+// Return IRQ pin indexed by |n| for device |dev|.
+// The value of |n| must be between 0 (included) and the value passed
+// to qdev_init_qpio_in() (excluded).
+qemu_irq qdev_get_gpio_in(DeviceState* dev, int n);
+
+// Guess what.
+qemu_irq qdev_get_gpio_out(DeviceState* dev, int n);
+
+// Set the |nd| field of a given DeviceState. Looks like it's network related.
+void qdev_set_netdev(DeviceState* dev, NICInfo* nd);
+
+// Create a new VLANClientState instance using the device's |nd| field
+// to extract the vlan, model and name to call qemu_new_vlan_client().
+// assert that qdev_set_netdev() was called previously on the device.
+// WHY???
+VLANClientState* qdev_get_vlan_client(DeviceState *dev,
+ NetCanReceive* can_receive,
+ NetReceive* receive,
+ NetReceiveIOV* receive_iov,
+ NetCleanup* cleanup,
+ void* opaque);
+
+// Return |dev|'s MAC address into |*macaddr| (6 bytes), extracting it from
+// the device's netdev |nd| field.
+void qdev_get_macaddr(DeviceState* dev, uint8_t* macaddr);
+
+// UNUSED AND PROBABLY MISPLACED, since it completely ignores |dev|.
+// Used to get the BlockDriverState instance of a given block interface |type|.
+// This calls drive_get(type, 0, unit), where |unit| is computed internally
+// by a static type-specific counter.
+BlockDriverState* qdev_init_bdrv(DeviceState* dev, BlockInterfaceType type);
+
+// Return a device's child bus of a given name, or NULL.
+// |dev| is the device that may provide its own buses.
+// |name| is the name of the child bus to match.
+BusState* qdev_get_child_bus(DeviceState* state, const char* name);
+
+// Create new bus instance.
+// |type| is the bus type (SYSTEM, PCI, SCSI, I2C, SSI)
+// |size| is the instance size, must be >= sizeof(BusState).
+// |parent| is the parent bbus, can be NULL.
+// |name| is the bus' name.
+BusState* qbus_create(BusType type,
+ size_t size,
+ DeviceState* parent,
+ const char* name);
+
+// Supposed to return a string describing the device's path from the
+// main system bus. Currently unimplemented, always return NULL!
+char* qdev_get_dev_path(DeviceState* dev);
+
+SysBusDevice:
+ qdev: DeviceState -> base DeviceState members.
+ num_irq: int -> number of IRQs used by bus?
+ irqs: qemu_irq[32] -> array of pointers to IRQ pins.
+ irqp: (*qemu_irq)[32] -> array of pointers to pointers to IRQ pins? WHAT???
+ num_mmio: int -> number of MMIO regions.
+ mmio: struct{}[5] -> array of MMIO region descriptor.
+
+ Each mmio region has:
+ addr: hwaddr
+ size: hwaddr
+ cb: mmio_mapfunc cb -> function used to map I/O memory.
+ iofunc: int
+
+SysBusDeviceInfo:
+ qdev: DeviceInfo -> base DeviceInfo class descriptor.
+ init: sysbuf_initfn -> bus initialization function. ???
+
+// Register a new SysBusDevice class. This creates a new SysBusDeviceInfo
+// instance recording the name, size and initialization function corresponding
+// to a class of SysBufDevice instances.
+// |name| is the DeviceInfo class name.
+// |size| is the instance size, must be >= sizeof(SysBusDevice)
+// |init| if the sysbus_initfn for instances of this class.
+sysbus_register_dev(const char* name, size_t size, sysbus_initfn init);
+
+// Used internally to set the parent DeviceInfo |bus_type| and |init|.
+// before calling qdev_register() to register the system bus device class.
+sysbus_register_withprop(SysBusDeviceInfo* info);
+
+// Allocate but do not map a new MMIO region of |size| bytes, using
+// the |iofunc| MMIO function index.
+// |dev| points to an existing SysBusDevice.
+// NOTE: The region can later be mapped by calling sysbus_mmio_map.
+void sysbus_init_mmio(SysBusDevice* dev, hwaddr size, int iofunc);
+
+// REMOVED: Allocate but do not map a new MMIO region of |size| byutes, using
+// a custom |cb| mapping callback.
+// |dev| points to an existing SysBusDevice.
+// NOTE: The region can later be mapped by calling sysbus_mmio_map.
+void sysbus_init_mmio_cb(SysBusDevice* dev, hwaddr size, mmio_mapfunc cb);
+
+// Map a system bus device MMIO region, identified by index |n|, at address
+// |addr|. The index correspond to the sequence of previous calls to
+// sysbus_init_mmio() or sysbus_init_mmio_cb(). First call creates index 0.
+// NOTE: It's possible to call this multiple time to remap the region to
+// a different address.
+void sysbus_mmio_map(SysBusDevice* dev, int n, hwaddr addr);
+
+// Allocate an IRQ source. The function takes the address of a qemu_irq
+// value that can be populated/set later, by calling sysbus_connect_irq.
+// In other words, this function records the pointer in an array for later
+// user.
+sysbus_init_irq(SysBusDevice* dev, qemu_irq* p);
+
+// Connect an IRQ source to the actual device. |n| is an index corresponding
+// to the sequence of previous calls to sysbus_init_irq(), and |irq| is the
+// IRQ to use as the source. This function really writes |irq| to the pointer
+// that was previously registered with sysbus_init_irq(), and nothing more.
+sysbus_connect_irq(SysBusDevice* dev, int n, qemu_irq irq);
+
+// Pass all
+sysbus_pass_irq(SysBusDevice* dev, SysBusDevice* target);
+
+PCIDevice:
+ qdev: DeviceState -> base DeviceState fields.
+ config: uint8_t[256] -> PCI config space?
+ bus: *PCIBus -> PCI Bus instance this device belongs to.
+ devfn: int -> PCI device function index
+ name: char[64]
+ io_regions: PCIIORegion[PCI_NUM_REGIONS]
+ config_read: *PCIConfigReadFunc
+ config_write: *PCIConfigWriteFunc
+ unregister: *PCIUnregisterFunc
+
+ irq: *qemu_irq -> IRQ objects for the INTA-INTD pins ???
+ irq_state: int[4] -> current IRQ levels. ???
+
+PCIIORegion:
+ addr: uint32_t -> PCI mapping address, -1 means not mapped.
+ size: uint32_t
+ type: uint8_t
+ map_func: *PCIMapIORegioFunc
+
+PCIBus:
+ qbus: BusState -> base BusState fields.
+ bus_num: int -> ?
+ devfn_min: int -> ?
+ set_irq: pci_set_irq_fn
+ map_irq: pci_map_irq_fn
+ config_reg: uint32_t -> UNUSED
+ low_set_irq: qemu_irq_handler
+ irq_opaque: qemu_irq
+ devices: (*PCIDevice)[256]
+ parent_dev: *PCIDevice
+ next: *PCIBus
+ nirq: int
+ irq_count: int[]
+