/* * Dynamic device configuration and creation. * * Copyright (c) 2009 CodeSourcery * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see . */ #include "hw/qdev.h" #include "hw/sysbus.h" #include "monitor/monitor.h" #include "monitor/qdev.h" #include "qmp-commands.h" #include "sysemu/arch_init.h" #include "qapi/qmp/qerror.h" #include "qemu/config-file.h" #include "qemu/error-report.h" /* * Aliases were a bad idea from the start. Let's keep them * from spreading further. */ typedef struct QDevAlias { const char *typename; const char *alias; uint32_t arch_mask; } QDevAlias; static const QDevAlias qdev_alias_table[] = { { "virtio-blk-pci", "virtio-blk", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, { "virtio-net-pci", "virtio-net", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, { "virtio-serial-pci", "virtio-serial", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, { "virtio-balloon-pci", "virtio-balloon", QEMU_ARCH_ALL & ~QEMU_ARCH_S390X }, { "virtio-blk-ccw", "virtio-blk", QEMU_ARCH_S390X }, { "virtio-net-ccw", "virtio-net", QEMU_ARCH_S390X }, { "virtio-serial-ccw", "virtio-serial", QEMU_ARCH_S390X }, { "lsi53c895a", "lsi" }, { "ich9-ahci", "ahci" }, { "kvm-pci-assign", "pci-assign" }, { } }; static const char *qdev_class_get_alias(DeviceClass *dc) { const char *typename = object_class_get_name(OBJECT_CLASS(dc)); int i; for (i = 0; qdev_alias_table[i].typename; i++) { if (qdev_alias_table[i].arch_mask && !(qdev_alias_table[i].arch_mask & arch_type)) { continue; } if (strcmp(qdev_alias_table[i].typename, typename) == 0) { return qdev_alias_table[i].alias; } } return NULL; } static bool qdev_class_has_alias(DeviceClass *dc) { return (qdev_class_get_alias(dc) != NULL); } static void qdev_print_devinfo(DeviceClass *dc) { error_printf("name \"%s\"", object_class_get_name(OBJECT_CLASS(dc))); if (dc->bus_type) { error_printf(", bus %s", dc->bus_type); } if (qdev_class_has_alias(dc)) { error_printf(", alias \"%s\"", qdev_class_get_alias(dc)); } if (dc->desc) { error_printf(", desc \"%s\"", dc->desc); } if (dc->cannot_instantiate_with_device_add_yet) { error_printf(", no-user"); } error_printf("\n"); } static gint devinfo_cmp(gconstpointer a, gconstpointer b) { return strcasecmp(object_class_get_name((ObjectClass *)a), object_class_get_name((ObjectClass *)b)); } static void qdev_print_devinfos(bool show_no_user) { static const char *cat_name[DEVICE_CATEGORY_MAX + 1] = { [DEVICE_CATEGORY_BRIDGE] = "Controller/Bridge/Hub", [DEVICE_CATEGORY_USB] = "USB", [DEVICE_CATEGORY_STORAGE] = "Storage", [DEVICE_CATEGORY_NETWORK] = "Network", [DEVICE_CATEGORY_INPUT] = "Input", [DEVICE_CATEGORY_DISPLAY] = "Display", [DEVICE_CATEGORY_SOUND] = "Sound", [DEVICE_CATEGORY_MISC] = "Misc", [DEVICE_CATEGORY_MAX] = "Uncategorized", }; GSList *list, *elt; int i; bool cat_printed; list = g_slist_sort(object_class_get_list(TYPE_DEVICE, false), devinfo_cmp); for (i = 0; i <= DEVICE_CATEGORY_MAX; i++) { cat_printed = false; for (elt = list; elt; elt = elt->next) { DeviceClass *dc = OBJECT_CLASS_CHECK(DeviceClass, elt->data, TYPE_DEVICE); if ((i < DEVICE_CATEGORY_MAX ? !test_bit(i, dc->categories) : !bitmap_empty(dc->categories, DEVICE_CATEGORY_MAX)) || (!show_no_user && dc->cannot_instantiate_with_device_add_yet)) { continue; } if (!cat_printed) { error_printf("%s%s devices:\n", i ? "\n" : "", cat_name[i]); cat_printed = true; } qdev_print_devinfo(dc); } } g_slist_free(list); } static int set_property(void *opaque, const char *name, const char *value, Error **errp) { Object *obj = opaque; Error *err = NULL; if (strcmp(name, "driver") == 0) return 0; if (strcmp(name, "bus") == 0) return 0; object_property_parse(obj, value, name, &err); if (err != NULL) { error_propagate(errp, err); return -1; } return 0; } static const char *find_typename_by_alias(const char *alias) { int i; for (i = 0; qdev_alias_table[i].alias; i++) { if (qdev_alias_table[i].arch_mask && !(qdev_alias_table[i].arch_mask & arch_type)) { continue; } if (strcmp(qdev_alias_table[i].alias, alias) == 0) { return qdev_alias_table[i].typename; } } return NULL; } static DeviceClass *qdev_get_device_class(const char **driver, Error **errp) { ObjectClass *oc; DeviceClass *dc; oc = object_class_by_name(*driver); if (!oc) { const char *typename = find_typename_by_alias(*driver); if (typename) { *driver = typename; oc = object_class_by_name(*driver); } } if (!object_class_dynamic_cast(oc, TYPE_DEVICE)) { error_setg(errp, "'%s' is not a valid device model name", *driver); return NULL; } if (object_class_is_abstract(oc)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", "non-abstract device type"); return NULL; } dc = DEVICE_CLASS(oc); if (dc->cannot_instantiate_with_device_add_yet || (qdev_hotplug && !dc->hotpluggable)) { error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "driver", "pluggable device type"); return NULL; } return dc; } int qdev_device_help(QemuOpts *opts) { Error *local_err = NULL; const char *driver; DevicePropertyInfoList *prop_list; DevicePropertyInfoList *prop; driver = qemu_opt_get(opts, "driver"); if (driver && is_help_option(driver)) { qdev_print_devinfos(false); return 1; } if (!driver || !qemu_opt_has_help_opt(opts)) { return 0; } qdev_get_device_class(&driver, &local_err); if (local_err) { goto error; } prop_list = qmp_device_list_properties(driver, &local_err); if (local_err) { goto error; } for (prop = prop_list; prop; prop = prop->next) { error_printf("%s.%s=%s", driver, prop->value->name, prop->value->type); if (prop->value->has_description) { error_printf(" (%s)\n", prop->value->description); } else { error_printf("\n"); } } qapi_free_DevicePropertyInfoList(prop_list); return 1; error: error_printf("%s\n", error_get_pretty(local_err)); error_free(local_err); return 1; } static Object *qdev_get_peripheral(void) { static Object *dev; if (dev == NULL) { dev = container_get(qdev_get_machine(), "/peripheral"); } return dev; } static Object *qdev_get_peripheral_anon(void) { static Object *dev; if (dev == NULL) { dev = container_get(qdev_get_machine(), "/peripheral-anon"); } return dev; } #if 0 /* conversion from qerror_report() to error_set() broke their use */ static void qbus_list_bus(DeviceState *dev) { BusState *child; const char *sep = " "; error_printf("child buses at \"%s\":", dev->id ? dev->id : object_get_typename(OBJECT(dev))); QLIST_FOREACH(child, &dev->child_bus, sibling) { error_printf("%s\"%s\"", sep, child->name); sep = ", "; } error_printf("\n"); } static void qbus_list_dev(BusState *bus) { BusChild *kid; const char *sep = " "; error_printf("devices at \"%s\":", bus->name); QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; error_printf("%s\"%s\"", sep, object_get_typename(OBJECT(dev))); if (dev->id) error_printf("/\"%s\"", dev->id); sep = ", "; } error_printf("\n"); } #endif static BusState *qbus_find_bus(DeviceState *dev, char *elem) { BusState *child; QLIST_FOREACH(child, &dev->child_bus, sibling) { if (strcmp(child->name, elem) == 0) { return child; } } return NULL; } static DeviceState *qbus_find_dev(BusState *bus, char *elem) { BusChild *kid; /* * try to match in order: * (1) instance id, if present * (2) driver name * (3) driver alias, if present */ QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; if (dev->id && strcmp(dev->id, elem) == 0) { return dev; } } QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; if (strcmp(object_get_typename(OBJECT(dev)), elem) == 0) { return dev; } } QTAILQ_FOREACH(kid, &bus->children, sibling) { DeviceState *dev = kid->child; DeviceClass *dc = DEVICE_GET_CLASS(dev); if (qdev_class_has_alias(dc) && strcmp(qdev_class_get_alias(dc), elem) == 0) { return dev; } } return NULL; } static inline bool qbus_is_full(BusState *bus) { BusClass *bus_class = BUS_GE
/*
 * Copyright (c) 2011 Zhao Zhang <zhzhl555@gmail.com>
 *
 * Derived from driver/rtc/rtc-au1xxx.c
 *
 * 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.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/rtc.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/io.h>
#include <asm/mach-loongson1/loongson1.h>

#define LS1X_RTC_REG_OFFSET	(LS1X_RTC_BASE + 0x20)
#define LS1X_RTC_REGS(x) \
		((void __iomem *)KSEG1ADDR(LS1X_RTC_REG_OFFSET + (x)))

/*RTC programmable counters 0 and 1*/
#define SYS_COUNTER_CNTRL		(LS1X_RTC_REGS(0x20))
#define SYS_CNTRL_ERS			(1 << 23)
#define SYS_CNTRL_RTS			(1 << 20)
#define SYS_CNTRL_RM2			(1 << 19)
#define SYS_CNTRL_RM1			(1 << 18)
#define SYS_CNTRL_RM0			(1 << 17)
#define SYS_CNTRL_RS			(1 << 16)
#define SYS_CNTRL_BP			(1 << 14)
#define SYS_CNTRL_REN			(1 << 13)
#define SYS_CNTRL_BRT			(1 << 12)
#define SYS_CNTRL_TEN			(1 << 11)
#define SYS_CNTRL_BTT			(1 << 10)
#define SYS_CNTRL_E0			(1 << 8)
#define SYS_CNTRL_ETS			(1 << 7)
#define SYS_CNTRL_32S			(1 << 5)
#define SYS_CNTRL_TTS			(1 << 4)
#define SYS_CNTRL_TM2			(1 << 3)
#define SYS_CNTRL_TM1			(1 << 2)
#define SYS_CNTRL_TM0			(1 << 1)
#define SYS_CNTRL_TS			(1 << 0)

/* Programmable Counter 0 Registers */
#define SYS_TOYTRIM		(LS1X_RTC_REGS(0))
#define SYS_TOYWRITE0		(LS1X_RTC_REGS(4))
#define SYS_TOYWRITE1		(LS1X_RTC_REGS(8))
#define SYS_TOYREAD0		(LS1X_RTC_REGS(0xC))
#define SYS_TOYREAD1		(LS1X_RTC_REGS(0x10))
#define SYS_TOYMATCH0		(LS1X_RTC_REGS(0x14))
#define SYS_TOYMATCH1		(LS1X_RTC_REGS(0x18))
#define SYS_TOYMATCH2		(LS1X_RTC_REGS(0x1C))

/* Programmable Counter 1 Registers */
#define SYS_RTCTRIM		(LS1X_RTC_REGS(0x40))
#define SYS_RTCWRITE0		(LS1X_RTC_REGS(0x44))
#define SYS_RTCREAD0		(LS1X_RTC_REGS(0x48))
#define SYS_RTCMATCH0		(LS1X_RTC_REGS(0x4C))
#define SYS_RTCMATCH1		(LS1X_RTC_REGS(0x50))
#define SYS_RTCMATCH2		(LS1X_RTC_REGS(0x54))

#define LS1X_SEC_OFFSET		(4)
#define LS1X_MIN_OFFSET		(10)
#define LS1X_HOUR_OFFSET	(16)
#define LS1X_DAY_OFFSET		(21)
#define LS1X_MONTH_OFFSET	(26)


#define LS1X_SEC_MASK		(0x3f)
#define LS1X_MIN_MASK		(0x3f)
#define LS1X_HOUR_MASK		(0x1f)
#define LS1X_DAY_MASK		(0x1f)