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[]
+