#include <hal/hwtimer.h>
#include <lunaix/spike.h>
-
-_default struct hwtimer*
-select_platform_timer()
-{
- fail("not implemented");
-}
\ No newline at end of file
#include <lunaix/types.h>
#include <lunaix/hart_state.h>
+#include <lunaix/device.h>
#include <hal/devtree.h>
#define msi_data(msiv) ((msiv).msi_data)
#define msi_vect(msiv) ((msiv).mapped_iv)
+typedef void* msienv_t;
+
void
isrm_init();
isrm_ivfree(int iv);
/**
- * @brief Allocate an iv resource for os services
+ * @brief Begin MSI allocation for given device
*
* @param iv
*/
-int
-isrm_ivosalloc(isr_cb handler);
+msienv_t
+isrm_msi_start(struct device* dev);
/**
- * @brief Allocate an iv resource for external events
- *
- * @param iv
+ * @brief Query number of msi avaliable for the device
*/
int
-isrm_ivexalloc(isr_cb handler);
+isrm_msi_avaliable(msienv_t msienv);
/**
- * @brief Allocate an iv resource for MSI use
- *
- * @param iv
+ * @brief Allocate a msi resource within defined msi resource list
+ * for the device, indexed by `index`
*/
msi_vector_t
-isrm_msialloc(isr_cb handler);
+isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler);
+
+/**
+ * @brief Set the sideband information will be used for upcoming
+ * allocations
+ */
+void
+isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband);
+
+/**
+ * @brief Done MSI allocation
+ */
+void
+isrm_msi_done(msienv_t msienv);
+
+static inline must_inline msi_vector_t
+isrm_msi_alloc_simple(struct device* dev, cpu_t cpu, isr_cb handler)
+{
+ msi_vector_t v;
+ msienv_t env;
+
+ env = isrm_msi_start(dev);
+ v = isrm_msi_alloc(env, cpu, 0, handler);
+ isrm_msi_done(env);
+
+ return v;
+}
/**
* @brief Bind the iv according to given device tree node
* @param node
*/
int
-isrm_bind_dtnode(struct dt_intr_node* node);
+isrm_bind_dtn(struct dt_intr_node* node);
/**
* @brief Get the handler associated with the given iv
isrm_bindiv(LUNAIX_SYS_CALL, syscall_hndlr);
}
-struct hwtimer*
-select_platform_timer()
-{
- struct hwtimer* timer;
-
- timer = apic_hwtimer_context();
- if (timer->supported(timer)) {
- return timer;
- }
-
- // TODO select alternatives...
-
- fail("no timer to use.");
-}
-
void
update_tss()
{
#include <lunaix/spike.h>
-#include <lunaix/owloysius.h>
+#include <lunaix/device.h>
#include <asm/x86_isrm.h>
#include "asm/x86.h"
isrm_notify_eoi(id, LUNAIX_SCHED);
}
+msienv_t
+isrm_msi_start(struct device* dev)
+{
+ /*
+ * In x86, the MSI topology is rather simple, as the only
+ * source is the PCI itself, and the write destination is
+ * explictly defined in specification, so we don't need the
+ * msienv to hold dynamically probed address
+ */
+ return NULL;
+}
+
+int
+isrm_msi_avaliable(msienv_t msienv)
+{
+ return 1;
+}
+
msi_vector_t
-isrm_msialloc(isr_cb handler)
+isrm_msi_alloc(msienv_t msienv, cpu_t cpu, int index, isr_cb handler)
{
unsigned int iv = isrm_ivexalloc(handler);
+ // we ignore the cpu redirection for now.
return (msi_vector_t){
- .msi_addr = 0xfee00000,
+ .msi_addr = __APIC_BASE_PADDR,
.msi_data = iv,
.mapped_iv = iv
};
}
+void
+isrm_msi_set_sideband(msienv_t msienv, ptr_t sideband)
+{
+ return;
+}
+
+void
+isrm_msi_done(msienv_t msienv)
+{
+ return;
+}
+
+
+
int
-isrm_bind_dtnode(struct dt_intr_node* node)
+isrm_bind_dtn(struct dt_intr_node* node)
{
fail("not supported");
}
-static void
-__intc_init()
+static int
+__intc_create(struct device_def* devdef, morph_t* obj)
{
apic_init();
ioapic_init();
arch_intc_ctx.name = "i386_apic";
arch_intc_ctx.irq_attach = ioapic_irq_remap;
arch_intc_ctx.notify_eoi = apic_on_eoi;
+
+ return 0;
}
-owloysius_fetch_init(__intc_init, on_earlyboot);
\ No newline at end of file
+
+
+static struct device_def i386_intc = {
+ def_device_class(INTEL, CFG, INTC),
+ def_device_name("i386 apic"),
+ def_on_create(__intc_create)
+};
+EXPORT_DEVICE(i386_intc, &i386_intc, load_sysconf);
\ No newline at end of file
#include <asm/x86_isrm.h>
#include "asm/soc/apic.h"
-LOG_MODULE("APIC_TIMER")
+LOG_MODULE("timer(apic)")
#define LVT_ENTRY_TIMER(vector, mode) (LVT_DELIVERY_FIXED | mode | vector)
#define APIC_BASETICKS 0x100000
-// Don't optimize them! Took me an half hour to figure that out...
-
-static volatile u8_t apic_timer_done = 0;
-static volatile ticks_t base_freq = 0;
-static volatile ticks_t systicks = 0;
-
-static timer_tick_cb tick_cb = NULL;
-
static void
temp_intr_routine_apic_timer(const struct hart_state* state)
{
- apic_timer_done = 1;
+ struct hwtimer_pot* pot;
+
+ pot = (struct hwtimer_pot*)isrm_get_payload(state);
+ pot->systick_raw = (ticks_t)-1;
}
static void
apic_timer_tick_isr(const struct hart_state* state)
{
- systicks++;
-
- if (likely((ptr_t)tick_cb)) {
- tick_cb();
- }
-}
-
-static int
-apic_timer_check(struct hwtimer* hwt)
-{
- // TODO check whether apic timer is supported
- return 1;
-}
+ struct hwtimer_pot* pot;
-static ticks_t
-apic_get_systicks()
-{
- return systicks;
-}
+ pot = (struct hwtimer_pot*)isrm_get_payload(state);
+ pot->systick_raw++;
-static ticks_t
-apic_get_base_freq()
-{
- return base_freq;
+ if (likely(__ptr(pot->callback))) {
+ pot->callback();
+ }
}
-void
-apic_timer_init(struct hwtimer* timer, u32_t hertz, timer_tick_cb timer_cb)
+static void
+__apic_timer_calibrate(struct hwtimer_pot* pot, u32_t hertz)
{
- ticks_t frequency = hertz;
- tick_cb = timer_cb;
+ ticks_t base_freq = 0;
cpu_disable_interrupt();
// Setup APIC timer
- // Remap the IRQ 8 (rtc timer's vector) to RTC_TIMER_IV in ioapic
- // (Remarks IRQ 8 is pin INTIN8)
- // See IBM PC/AT Technical Reference 1-10 for old RTC IRQ
- // See Intel's Multiprocessor Specification for IRQ - IOAPIC INTIN
- // mapping config.
-
// grab ourselves these irq numbers
u32_t iv_timer = isrm_ivexalloc(temp_intr_routine_apic_timer);
+ isrm_set_payload(iv_timer, __ptr(pot));
// Setup a one-shot timer, we will use this to measure the bus speed. So we
// can then calibrate apic timer to work at *nearly* accurate hz
*/
-#ifdef __LUNAIXOS_DEBUG__
- if (frequency < 1000) {
- WARN("Frequency too low. Millisecond timer might be dodgy.");
- }
-#endif
-
- apic_timer_done = 0;
-
- sysrtc->cls_mask(sysrtc);
+ sysrtc->ops->set_proactive(sysrtc, true);
apic_write_reg(APIC_TIMER_ICR, APIC_BASETICKS); // start APIC timer
- // enable interrupt, just for our RTC start ticking!
+ pot->systick_raw = 0;
cpu_enable_interrupt();
- wait_until(apic_timer_done);
+ wait_until(!(pot->systick_raw + 1));
cpu_disable_interrupt();
+ isrm_ivfree(iv_timer);
- sysrtc->set_mask(sysrtc);
-
- base_freq = sysrtc->get_counts(sysrtc);
+ sysrtc->ops->set_proactive(sysrtc, false);
+
+ base_freq = sysrtc->live;
base_freq = APIC_BASETICKS / base_freq * sysrtc->base_freq;
+ pot->base_freq = base_freq;
+ pot->systick_raw = 0;
assert_msg(base_freq, "Fail to initialize timer (NOFREQ)");
+ INFO("hw: %u Hz; os: %u Hz", base_freq, hertz);
- kprintf("hw: %u Hz; os: %u Hz", base_freq, frequency);
+ apic_write_reg(APIC_TIMER_ICR, base_freq / hertz);
+
+ iv_timer = isrm_ivexalloc(apic_timer_tick_isr);
+ isrm_set_payload(iv_timer, __ptr(pot));
+
+ apic_write_reg(
+ APIC_TIMER_LVT,
+ LVT_ENTRY_TIMER(iv_timer, LVT_TIMER_PERIODIC));
+}
- // cleanup
- isrm_ivfree(iv_timer);
+static struct hwtimer_pot_ops potops = {
+ .calibrate = __apic_timer_calibrate,
+};
- ticks_t tphz = base_freq / frequency;
- timer->base_freq = base_freq;
- apic_write_reg(APIC_TIMER_ICR, tphz);
+static int
+__apic_timer_load(struct device_def* def)
+{
+ struct device* timer;
- apic_write_reg(
- APIC_TIMER_LVT,
- LVT_ENTRY_TIMER(isrm_ivexalloc(apic_timer_tick_isr), LVT_TIMER_PERIODIC));
+ timer = device_allocsys(NULL, NULL);
+
+ hwtimer_attach_potens(timer, HWTIMER_MAX_PRECEDENCE, &potops);
+ register_device_var(timer, &def->class, "apic-timer");
+ return 0;
}
-struct hwtimer*
-apic_hwtimer_context()
+
+static struct device_def x86_apic_timer =
{
- static struct hwtimer apic_hwt = {
- .name = "apic_timer",
- .class = DEVCLASSV(DEVIF_SOC, DEVFN_TIME, DEV_TIMER, DEV_TIMER_APIC),
- .init = apic_timer_init,
- .supported = apic_timer_check,
- .systicks = apic_get_systicks
- };
-
- return &apic_hwt;
-}
+ def_device_class(INTEL, TIME, TIMER_APIC),
+ def_device_name("Intel APIC Timer"),
+
+ def_on_load(__apic_timer_load)
+};
+EXPORT_DEVICE(apic_timer, &x86_apic_timer, load_sysconf);
#define RTC_INDEX_PORT 0x70
#define RTC_TARGET_PORT 0x71
-#define WITH_NMI_DISABLED 0x80
-
#define RTC_CURRENT_CENTRY 20
#define RTC_REG_YRS 0x9
struct mc146818
{
- struct hwrtc* rtc_context;
+ struct hwrtc_potens* rtc_context;
u32_t rtc_iv;
- u32_t tick_counts;
};
#define rtc_state(data) ((struct mc146818*)(data))
-static u8_t
+static inline u8_t
rtc_read_reg(u8_t reg_selector)
{
port_wrbyte(RTC_INDEX_PORT, reg_selector);
return port_rdbyte(RTC_TARGET_PORT);
}
-static void
+static inline void
rtc_write_reg(u8_t reg_selector, u8_t val)
{
port_wrbyte(RTC_INDEX_PORT, reg_selector);
port_wrbyte(RTC_TARGET_PORT, val);
}
-static void
+static inline void
rtc_enable_timer()
{
u8_t regB = rtc_read_reg(RTC_REG_B);
rtc_write_reg(RTC_REG_B, regB | RTC_TIMER_ON);
}
-static void
+static inline void
rtc_disable_timer()
{
u8_t regB = rtc_read_reg(RTC_REG_B);
}
static void
-rtc_getwalltime(struct hwrtc* rtc, datetime_t* datetime)
+rtc_getwalltime(struct hwrtc_potens* rtc, datetime_t* datetime)
{
datetime_t current;
}
static void
-rtc_setwalltime(struct hwrtc* rtc, datetime_t* datetime)
+rtc_setwalltime(struct hwrtc_potens* rtc, datetime_t* datetime)
{
u8_t reg = rtc_read_reg(RTC_REG_B);
reg = reg & ~RTC_SET;
rtc_write_reg(RTC_REG_B, reg & ~RTC_SET);
}
-static int
-mc146818_check_support(struct hwrtc* rtc)
-{
-#if __ARCH__ == i386
- return 1;
-#else
- return 0;
-#endif
-}
-
static void
__rtc_tick(const struct hart_state* hstate)
{
struct mc146818* state = (struct mc146818*)isrm_get_payload(hstate);
- state->tick_counts++;
+ state->rtc_context->live++;
(void)rtc_read_reg(RTC_REG_C);
}
static void
-rtc_set_mask(struct hwrtc* rtc)
+rtc_set_proactive(struct hwrtc_potens* pot, bool proactive)
{
- rtc->state = RTC_STATE_MASKED;
- rtc_disable_timer();
-}
-
-static void
-rtc_cls_mask(struct hwrtc* rtc)
-{
- struct mc146818* state = rtc_state(rtc->data);
-
- rtc->state = 0;
- state->tick_counts = 0;
- rtc_enable_timer();
+ if (proactive) {
+ pot->state = 0;
+ rtc_enable_timer();
+ }
+ else {
+ pot->state = RTC_STATE_MASKED;
+ rtc_disable_timer();
+ }
}
static int
-rtc_chfreq(struct hwrtc* rtc, int freq)
+rtc_chfreq(struct hwrtc_potens* rtc, int freq)
{
return ENOTSUP;
}
static int
-rtc_getcnt(struct hwrtc* rtc)
+__rtc_calibrate(struct hwrtc_potens* pot)
{
- struct mc146818* state = rtc_state(rtc->data);
- return state->tick_counts;
-}
+ struct mc146818* state;
-static int
-rtc_init(struct device_def* devdef)
-{
u8_t reg = rtc_read_reg(RTC_REG_A);
reg = (reg & ~0x7f) | RTC_FREQUENCY_1024HZ | RTC_DIVIDER_33KHZ;
rtc_write_reg(RTC_REG_A, reg);
// Make sure the rtc timer is disabled by default
rtc_disable_timer();
- struct hwrtc* rtc = hwrtc_alloc_new("mc146818");
- struct mc146818* state = valloc(sizeof(struct mc146818));
+ pot->base_freq = RTC_TIMER_BASE_FREQUENCY;
- state->rtc_context = rtc;
+ state = (struct mc146818*)potens_dev(pot)->underlay;
state->rtc_iv = isrm_bindirq(PC_AT_IRQ_RTC, __rtc_tick);
- isrm_set_payload(state->rtc_iv, (ptr_t)state);
+ isrm_set_payload(state->rtc_iv, __ptr(state));
+
+ return 0;
+}
+
+static struct hwrtc_potens_ops ops = {
+ .get_walltime = rtc_getwalltime,
+ .set_walltime = rtc_setwalltime,
+ .set_proactive = rtc_set_proactive,
+ .chfreq = rtc_chfreq,
+ .calibrate = __rtc_calibrate
+};
+
+static int
+rtc_load(struct device_def* devdef)
+{
+ struct device* dev;
+ struct mc146818* state;
+ struct hwrtc_potens* pot;
+
+ state = valloc(sizeof(struct mc146818));
+ dev = device_allocsys(NULL, state);
+
+ pot = hwrtc_attach_potens(dev, &ops);
+ if (!pot) {
+ return 1;
+ }
- rtc->state = RTC_STATE_MASKED;
- rtc->data = state;
- rtc->base_freq = RTC_TIMER_BASE_FREQUENCY;
- rtc->get_walltime = rtc_getwalltime;
- rtc->set_walltime = rtc_setwalltime;
- rtc->set_mask = rtc_set_mask;
- rtc->cls_mask = rtc_cls_mask;
- rtc->get_counts = rtc_getcnt;
- rtc->chfreq = rtc_chfreq;
+ pot->state = RTC_STATE_MASKED;
+ state->rtc_context = pot;
- hwrtc_register(&devdef->class, rtc);
+ register_device(dev, &devdef->class, "mc146818");
return 0;
}
static struct device_def devrtc_mc146818 = {
- .name = "MC146818 RTC",
- .class = DEVCLASS(DEVIF_SOC, DEVFN_TIME, DEV_RTC),
- .init = rtc_init
+ def_device_class(INTEL, TIME, RTC),
+ def_device_name("x86 legacy RTC"),
+ def_on_load(rtc_load)
};
-EXPORT_DEVICE(mc146818, &devrtc_mc146818, load_timedev);
\ No newline at end of file
+EXPORT_DEVICE(mc146818, &devrtc_mc146818, load_sysconf);
\ No newline at end of file
}
static int
-ps2_kbd_init(struct device_def* devdef)
+ps2_kbd_create(struct device_def* devdef, morph_t* obj)
{
memset(&cmd_q, 0, sizeof(cmd_q));
}
static struct device_def devrtc_i8042kbd = {
- .name = "i8042 Keyboard",
- .class = DEVCLASS(DEVIF_SOC, DEVFN_INPUT, DEV_KBD),
- .init = ps2_kbd_init
+ def_device_class(INTEL, INPUT, KBD),
+ def_device_name("i8042 Keyboard"),
+ def_on_create(ps2_kbd_create)
};
EXPORT_DEVICE(i8042_kbd, &devrtc_i8042kbd, load_onboot);
}
int
-pdev_randdev_init(struct device_def* devdef)
+pdev_randdev_create(struct device_def* devdef, morph_t* obj)
{
// FIXME add check on cpuid for presence of rdrand
struct device* devrand = device_allocseq(NULL, NULL);
}
static struct device_def devrandx86_def = {
- .name = "x86 On-Chip RNG",
- .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_RNG),
- .init = pdev_randdev_init};
+ def_device_class(INTEL, CHAR, RNG),
+ def_device_name("x86 On-Chip RNG"),
+ def_on_create(pdev_randdev_create)
+};
EXPORT_DEVICE(randdev, &devrandx86_def, load_onboot);
\ No newline at end of file
void
isrm_irq_attach(int irq, int iv, cpu_t dest, u32_t flags);
+/**
+ * @brief Allocate an iv resource for os services
+ *
+ * @param iv
+ */
+int
+isrm_ivosalloc(isr_cb handler);
+
+/**
+ * @brief Allocate an iv resource for external events
+ *
+ * @param iv
+ */
+int
+isrm_ivexalloc(isr_cb handler);
#endif /* __LUNAIX_X86_ISRM_H */
return ptr;
}
+unsigned long
+strlen(const char* str)
+{
+ unsigned long _c;
+ asm volatile("movq %1, %%rdi\n"
+ "movq $-1, %%rcx\n"
+ "repne scasb\n"
+ "neg %%rcx\n"
+ "movq %%rcx, %0\n"
+ : "=r" (_c)
+ : "r"(str), "a"(0)
+ : "rdi", "rcx", "memory");
+
+ return _c - 2;
+}
+
+unsigned long
+strnlen(const char* str, unsigned long max_len)
+{
+ unsigned long _c;
+ asm volatile("movq %1, %%rdi\n"
+ "movq %2, %%rcx\n"
+ "repne scasb\n"
+ "movq %%rcx, %0\n"
+ : "=r" (_c)
+ : "r"(str), "r"(max_len), "a"(0)
+ : "rdi", "rcx", "memory");
+
+ return max_len - _c - 1;
+}
+
#else
void*
memcpy(void* dest, const void* src, unsigned long num)
use("bus")
if config("use_devicetree"):
- sources("devtree.c")
\ No newline at end of file
+ use("devtree")
\ No newline at end of file
#include <hal/acpi/acpi.h>
-#include <lunaix/device.h>
+#include <lunaix/owloysius.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
#include <lunaix/syslog.h>
}
static int
-acpi_init(struct device_def* devdef)
+__gather_acpi_table()
{
acpi_rsdp_t* rsdp = acpi_locate_rsdp();
return 0;
}
-struct device_def acpi_sysdev = { .name = "ACPI Proxy",
- .class =
- DEVCLASS(DEVIF_FMW, DEVFN_CFG, DEV_ACPI),
- .init = acpi_init };
-EXPORT_DEVICE(acpi, &acpi_sysdev, load_sysconf);
\ No newline at end of file
+owloysius_fetch_init(__gather_acpi_table, on_sysconf);
\ No newline at end of file
#define HBA_CLB_SIZE 1024
#define HBA_MY_IE (HBA_PxINTR_DHR | HBA_PxINTR_TFE | HBA_PxINTR_OF)
-#define AHCI_DEVCLASS DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA)
+#define AHCI_DEVCLASS DEVCLASS(LUNAIX, STORAGE, SATA)
// #define DO_HBA_FULL_RESET
#include <lunaix/spike.h>
+#include <lunaix/status.h>
#include <hal/ahci/ahci.h>
#include <hal/pci.h>
static int
-ahci_pci_bind(struct device_def* def, struct device* dev)
+ahci_pci_create(struct device_def* def, morph_t* morphed)
{
- struct pci_device* ahci_dev;
+ struct pci_probe* probe;
+ struct device* dev;
struct pci_base_addr* bar6;
struct ahci_driver* ahci_drv;
msi_vector_t msiv;
- ahci_dev = PCI_DEVICE(dev);
- bar6 = pci_device_bar(ahci_dev, 5);
+ probe = changeling_try_reveal(morphed, pci_probe_morpher);
+ if (!probe) {
+ return EINVAL;
+ }
+
+ bar6 = pci_device_bar(probe, 5);
assert_msg(pci_bar_mmio_space(bar6), "AHCI: BAR#6 is not MMIO.");
pci_reg_t cmd = 0;
pci_cmd_set_bus_master(&cmd);
pci_cmd_set_mmio(&cmd);
pci_cmd_set_msi(&cmd);
- pci_apply_command(ahci_dev, cmd);
+ pci_apply_command(probe, cmd);
- assert(pci_capability_msi(ahci_dev));
+ assert(pci_capability_msi(probe));
- msiv = isrm_msialloc(ahci_hba_isr);
- pci_setup_msi(ahci_dev, msiv);
+ msiv = pci_msi_setup_simple(probe, ahci_hba_isr);
struct ahci_driver_param param = {
.mmio_base = bar6->start,
};
ahci_drv = ahci_driver_init(¶m);
- pci_bind_instance(ahci_dev, ahci_drv);
+ dev = device_allocvol(NULL, ahci_drv);
+
+ device_setname(dev_meta(dev),
+ "pci-ahci%d", devclass_mkvar(&def->class));
+
+ pci_bind_instance(probe, dev);
return 0;
}
-static int
-ahci_pci_init(struct device_def* def)
+static bool
+ahci_pci_compat(struct pci_probe* probe)
{
- return pci_bind_definition_all(pcidev_def(def));
+ return pci_device_class(probe) == AHCI_HBA_CLASS;
}
-static bool
-ahci_pci_compat(struct pci_device_def* def,
- struct pci_device* pcidev)
+static int
+ahci_pci_register(struct device_def* def)
{
- return pci_device_class(pcidev) == AHCI_HBA_CLASS;
+ return !pci_register_driver(def, ahci_pci_compat);
}
-static struct pci_device_def ahcidef = {
- .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA),
- .name = "Generic AHCI",
- .init = ahci_pci_init,
- .bind = ahci_pci_bind },
- .test_compatibility = ahci_pci_compat
+static struct device_def ahcidef =
+{
+ def_device_class(GENERIC, STORAGE, SATA),
+ def_device_name("Generic AHCI (pci-bus)"),
+
+ def_on_register(ahci_pci_register),
+ def_on_create(ahci_pci_create),
+
+ def_non_trivial
};
-EXPORT_PCI_DEVICE(ahci, &ahcidef, load_postboot);
\ No newline at end of file
+EXPORT_DEVICE(ahci, &ahcidef, load_postboot);
\ No newline at end of file
LOG_MODULE("PCI")
-static DEFINE_LLIST(pci_devices);
-static DECLARE_HASHTABLE(pci_devcache, 8);
+/*
+ device instance for pci bridge,
+ currently, lunaix only support one bridge controller.
+*/
+static struct device* pci_bridge;
-static struct device_cat* pcidev_cat;
-static struct device_def pci_def;
-
-void
-pci_probe_msi_info(struct pci_device* device);
+static morph_t* pci_probers;
+static DECLARE_HASHTABLE(pci_drivers, 8);
static inline void
-pci_log_device(struct pci_device* pcidev)
+pci_log_device(struct pci_probe* probe)
{
- pciaddr_t loc = pcidev->loc;
- struct device_def* binddef = pcidev->binding.def;
+ pciaddr_t loc = probe->loc;
kprintf("pci.%03d:%02d:%02d, class=%p, vendor:dev=%04x:%04x",
PCILOC_BUS(loc),
PCILOC_DEV(loc),
PCILOC_FN(loc),
- pcidev->class_info,
- PCI_DEV_VENDOR(pcidev->device_info),
- PCI_DEV_DEVID(pcidev->device_info));
+ probe->class_info,
+ PCI_DEV_VENDOR(probe->device_info),
+ PCI_DEV_DEVID(probe->device_info));
}
-static struct pci_device*
-pci_create_device(pciaddr_t loc, ptr_t pci_base, int devinfo)
+static void
+__pci_probe_msi_info(struct pci_probe* probe)
{
- pci_reg_t class = pci_read_cspace(pci_base, 0x8);
-
- u32_t devid = PCI_DEV_DEVID(devinfo);
- u32_t vendor = PCI_DEV_VENDOR(devinfo);
- pci_reg_t intr = pci_read_cspace(pci_base, 0x3c);
+ // Note that Virtualbox have to use ICH9 chipset for MSI support.
+ // Qemu seems ok with default PIIX3, Bochs is pending to test...
+ // See https://www.virtualbox.org/manual/ch03.html (section 3.5.1)
+ pci_reg_t status =
+ pci_read_cspace(probe->cspace_base, PCI_REG_STATUS_CMD) >> 16;
- struct pci_device* device = vzalloc(sizeof(struct pci_device));
- device->class_info = class;
- device->device_info = devinfo;
- device->cspace_base = pci_base;
- device->intr_info = intr;
+ if (!(status & 0x10)) {
+ probe->msi_loc = 0;
+ return;
+ }
- device_create(&device->dev, dev_meta(pcidev_cat), DEV_IFSYS, NULL);
+ pci_reg_t cap_ptr = pci_read_cspace(probe->cspace_base, 0x34) & 0xff;
+ u32_t cap_hdr;
- pci_probe_msi_info(device);
- pci_probe_bar_info(device);
+ while (cap_ptr) {
+ cap_hdr = pci_read_cspace(probe->cspace_base, cap_ptr);
+ if ((cap_hdr & 0xff) == 0x5) {
+ // MSI
+ probe->msi_loc = cap_ptr;
+ return;
+ }
+ cap_ptr = (cap_hdr >> 8) & 0xff;
+ }
+}
- llist_append(&pci_devices, &device->dev_chain);
- register_device(&device->dev, &pci_def.class, "%x", loc);
- pci_def.class.variant++;
- return device;
+static void
+__pci_probe_bar_info(struct pci_probe* probe)
+{
+ u32_t bar;
+ struct pci_base_addr* ba;
+ for (size_t i = 0; i < PCI_BAR_COUNT; i++) {
+ ba = &probe->bar[i];
+ ba->size = pci_bar_sizing(probe, &bar, i + 1);
+ if (PCI_BAR_MMIO(bar)) {
+ ba->start = PCI_BAR_ADDR_MM(bar);
+ ba->type |= PCI_BAR_CACHEABLE(bar) ? BAR_TYPE_CACHABLE : 0;
+ ba->type |= BAR_TYPE_MMIO;
+ } else {
+ ba->start = PCI_BAR_ADDR_IO(bar);
+ }
+ }
}
-int
-pci_bind_definition(struct pci_device_def* pcidef, bool* more)
+static void
+__pci_add_prober(pciaddr_t loc, ptr_t pci_base, int devinfo)
{
- if (!pcidef->devdef.bind) {
- ERROR("pcidev %xh:%xh.%d is unbindable",
- pcidef->devdef.class.fn_grp,
- pcidef->devdef.class.device,
- pcidef->devdef.class.variant);
- return EINVAL;
- }
+ struct pci_probe* prober;
+ morph_t* probe_morph;
- *more = false;
+ pci_reg_t class = pci_read_cspace(pci_base, 0x8);
- bool bind_attempted = 0;
- int errno = 0;
+ u32_t devid = PCI_DEV_DEVID(devinfo);
+ u32_t vendor = PCI_DEV_VENDOR(devinfo);
+ pci_reg_t intr = pci_read_cspace(pci_base, 0x3c);
- struct device_def* devdef;
- struct pci_device *pos, *n;
- llist_for_each(pos, n, &pci_devices, dev_chain)
- {
- if (binded_pcidev(pos)) {
- continue;
- }
+ prober = vzalloc(sizeof(*prober));
- bool matched;
+ prober->class_info = class;
+ prober->device_info = devinfo;
+ prober->cspace_base = pci_base;
+ prober->intr_info = intr;
+ prober->loc = loc;
- assert(pcidef->test_compatibility);
- matched = pcidef->test_compatibility(pcidef, pos);
+ changeling_morph_anon(pci_probers, prober->mobj, pci_probe_morpher);
- if (!matched) {
- continue;
- }
+ __pci_probe_msi_info(prober);
+ __pci_probe_bar_info(prober);
- if (bind_attempted) {
- *more = true;
- break;
- }
+ pci_log_device(prober);
+}
- bind_attempted = true;
- devdef = &pcidef->devdef;
- errno = devdef->bind(devdef, &pos->dev);
+static int
+__pci_bind(struct pci_registry* reg, struct pci_probe* probe)
+{
+ int errno;
+ struct device_def* devdef;
- if (errno) {
- ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d",
- pos->loc,
- devdef->class.fn_grp,
- devdef->class.device,
- devdef->class.variant,
- errno);
- continue;
- }
+ if (probe->bind) {
+ return EEXIST;
+ }
- pos->binding.def = &pcidef->devdef;
+ if (!reg->check_compact(probe)) {
+ return EINVAL;
+ }
+
+ devdef = reg->definition;
+ errno = devdef->create(devdef, &probe->mobj);
+
+ if (errno) {
+ ERROR("pci_loc:%x, bind (%xh:%xh.%d) failed, e=%d",
+ probe->loc,
+ devdef->class.fn_grp,
+ devdef->class.device,
+ devdef->class.variant,
+ errno);
}
return errno;
}
int
-pci_bind_definition_all(struct pci_device_def* pcidef)
+pci_bind_driver(struct pci_registry* reg)
{
- int e = 0;
- bool more = false;
- do {
- if ((e = pci_bind_definition(pcidef, &more))) {
- break;
+ struct pci_probe* probe;
+ int errno = 0;
+
+ morph_t *pos, *n;
+ changeling_for_each(pos, n, pci_probers)
+ {
+ probe = changeling_reveal(pos, pci_probe_morpher);
+
+ errno = __pci_bind(reg, probe);
+ if (errno) {
+ continue;
}
- } while (more);
+ }
- return e;
+ return errno;
}
void
}
}
- struct pci_device *pos, *n;
- hashtable_hash_foreach(pci_devcache, pci_loc, pos, n, dev_cache)
+ struct pci_probe* prober;
+ morph_t *pos, *n;
+ changeling_for_each(pos, n, pci_probers)
{
- if (pos->loc == pci_loc) {
- pci_log_device(pos);
+ prober = changeling_reveal(pos, pci_probe_morpher);
+ if (prober->loc == pci_loc) {
+ pci_log_device(prober);
return;
}
}
- struct pci_device* pcidev = pci_create_device(pci_loc, base, reg1);
- if (pcidev) {
- pcidev->loc = pci_loc;
- hashtable_hash_in(pci_devcache, &pcidev->dev_cache, pci_loc);
- pci_log_device(pcidev);
+ __pci_add_prober(pci_loc, base, reg1);
+}
+
+static struct pci_registry*
+__pci_registry_get(struct device_def* def)
+{
+ struct pci_registry *pos, *n;
+ unsigned int hash;
+
+ hash = hash_32(__ptr(def), HSTR_FULL_HASH);
+ hashtable_hash_foreach(pci_drivers, hash, pos, n, entries)
+ {
+ if (pos->definition == def) {
+ return pos;
+ }
}
+
+ return NULL;
}
-void
-pci_scan()
+static int
+__pci_proxied_devdef_load(struct device_def* def)
{
- for (u32_t loc = 0; loc < (pciaddr_t)-1; loc += 8) {
- pci_probe_device((pciaddr_t)loc);
+ struct pci_registry* reg;
+ int errno = 0;
+
+ reg = __pci_registry_get(def);
+ assert(reg);
+
+ return pci_bind_driver(reg);
+}
+
+bool
+pci_register_driver(struct device_def* def, pci_id_checker_t checker)
+{
+ struct pci_registry* reg;
+ unsigned int hash;
+
+ if (!checker) {
+ return false;
+ }
+
+ if (__pci_registry_get(def)) {
+ return false;
}
+
+ reg = valloc(sizeof(*reg));
+
+ *reg = (struct pci_registry) {
+ .check_compact = checker,
+ .definition = def,
+ };
+
+ device_chain_loader(def, __pci_proxied_devdef_load);
+
+ hash = hash_32(__ptr(def), HSTR_FULL_HASH);
+ hashtable_hash_in(pci_drivers, ®->entries, hash);
+
+ return true;
}
void
-pci_probe_bar_info(struct pci_device* device)
+pci_scan()
{
- u32_t bar;
- struct pci_base_addr* ba;
- for (size_t i = 0; i < PCI_BAR_COUNT; i++) {
- ba = &device->bar[i];
- ba->size = pci_bar_sizing(device, &bar, i + 1);
- if (PCI_BAR_MMIO(bar)) {
- ba->start = PCI_BAR_ADDR_MM(bar);
- ba->type |= PCI_BAR_CACHEABLE(bar) ? BAR_TYPE_CACHABLE : 0;
- ba->type |= BAR_TYPE_MMIO;
- } else {
- ba->start = PCI_BAR_ADDR_IO(bar);
- }
+ for (u32_t loc = 0; loc < (pciaddr_t)-1; loc += 8) {
+ pci_probe_device((pciaddr_t)loc);
}
}
-void
-pci_setup_msi(struct pci_device* device, msi_vector_t msiv)
+static void
+__pci_config_msi(struct pci_probe* probe, msi_vector_t msiv)
{
// PCI LB Spec. (Rev 3) Section 6.8 & 6.8.1
ptr_t msi_addr = msi_addr(msiv);
u32_t msi_data = msi_data(msiv);
- pci_reg_t reg1 = pci_read_cspace(device->cspace_base, device->msi_loc);
+ pci_reg_t reg1 = pci_read_cspace(probe->cspace_base, probe->msi_loc);
pci_reg_t msg_ctl = reg1 >> 16;
int offset_cap64 = !!(msg_ctl & MSI_CAP_64BIT) * 4;
- pci_write_cspace(device->cspace_base,
- PCI_MSI_ADDR_LO(device->msi_loc),
+ pci_write_cspace(probe->cspace_base,
+ PCI_MSI_ADDR_LO(probe->msi_loc),
msi_addr);
if (offset_cap64) {
- pci_write_cspace(device->cspace_base,
- PCI_MSI_ADDR_HI(device->msi_loc),
+ pci_write_cspace(probe->cspace_base,
+ PCI_MSI_ADDR_HI(probe->msi_loc),
(u64_t)msi_addr >> 32);
}
- pci_write_cspace(device->cspace_base,
- PCI_MSI_DATA(device->msi_loc, offset_cap64),
+ pci_write_cspace(probe->cspace_base,
+ PCI_MSI_DATA(probe->msi_loc, offset_cap64),
msi_data & 0xffff);
if ((msg_ctl & MSI_CAP_MASK)) {
pci_write_cspace(
- device->cspace_base, PCI_MSI_MASK(device->msi_loc, offset_cap64), 0);
+ probe->cspace_base, PCI_MSI_MASK(probe->msi_loc, offset_cap64), 0);
}
// manipulate the MSI_CTRL to allow device using MSI to request service.
reg1 = (reg1 & 0xff8fffff) | 0x10000;
- pci_write_cspace(device->cspace_base, device->msi_loc, reg1);
+ pci_write_cspace(probe->cspace_base, probe->msi_loc, reg1);
}
-void
-pci_probe_msi_info(struct pci_device* device)
+msienv_t
+pci_msi_start(struct pci_probe* probe)
{
- // Note that Virtualbox have to use ICH9 chipset for MSI support.
- // Qemu seems ok with default PIIX3, Bochs is pending to test...
- // See https://www.virtualbox.org/manual/ch03.html (section 3.5.1)
- pci_reg_t status =
- pci_read_cspace(device->cspace_base, PCI_REG_STATUS_CMD) >> 16;
+ /*
+ As a PCI bridge/root complex can be initialised from device tree node,
+ in that case, general information such as routing, rid remapping,
+ are vital to all msi setup of all peripherals under it.
+
+ Therefore, a wrapper around isrm_msi_* is needed in order to
+ improve overall readability and usability, where the bridge
+ device instance that contain these information will be
+ automatically passed to the underlay as credential to perform
+ configuration.
+ */
+
+ msienv_t env;
+
+ env = isrm_msi_start(pci_bridge);
+ isrm_msi_set_sideband(env, pci_requester_id(probe));
- if (!(status & 0x10)) {
- device->msi_loc = 0;
- return;
- }
+ return env;
+}
- pci_reg_t cap_ptr = pci_read_cspace(device->cspace_base, 0x34) & 0xff;
- u32_t cap_hdr;
+msi_vector_t
+pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe,
+ int i, isr_cb handler)
+{
+ msi_vector_t msiv;
- while (cap_ptr) {
- cap_hdr = pci_read_cspace(device->cspace_base, cap_ptr);
- if ((cap_hdr & 0xff) == 0x5) {
- // MSI
- device->msi_loc = cap_ptr;
- return;
- }
- cap_ptr = (cap_hdr >> 8) & 0xff;
- }
+ msiv = isrm_msi_alloc(msienv, 0, i, handler);
+ __pci_config_msi(probe, msiv);
+
+ return msiv;
}
size_t
-pci_bar_sizing(struct pci_device* dev, u32_t* bar_out, u32_t bar_num)
+pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num)
{
- pci_reg_t bar = pci_read_cspace(dev->cspace_base, PCI_REG_BAR(bar_num));
+ pci_reg_t sized, bar;
+
+ bar = pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num));
if (!bar) {
*bar_out = 0;
return 0;
}
- pci_write_cspace(dev->cspace_base, PCI_REG_BAR(bar_num), 0xffffffff);
- pci_reg_t sized =
- pci_read_cspace(dev->cspace_base, PCI_REG_BAR(bar_num)) & ~0x1;
+ pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), 0xffffffff);
+
+ sized =
+ pci_read_cspace(probe->cspace_base, PCI_REG_BAR(bar_num)) & ~0x1;
+
if (PCI_BAR_MMIO(bar)) {
sized = PCI_BAR_ADDR_MM(sized);
}
+
*bar_out = bar;
- pci_write_cspace(dev->cspace_base, PCI_REG_BAR(bar_num), bar);
+ pci_write_cspace(probe->cspace_base, PCI_REG_BAR(bar_num), bar);
+
return ~sized + 1;
}
-struct pci_device*
-pci_get_device_by_id(u16_t vendorId, u16_t deviceId)
-{
- u32_t dev_info = vendorId | (deviceId << 16);
- struct pci_device *pos, *n;
- llist_for_each(pos, n, &pci_devices, dev_chain)
- {
- if (pos->device_info == dev_info) {
- return pos;
- }
- }
-
- return NULL;
-}
-
-struct pci_device*
-pci_get_device_by_class(u32_t class)
-{
- struct pci_device *pos, *n;
- llist_for_each(pos, n, &pci_devices, dev_chain)
- {
- if (PCI_DEV_CLASS(pos->class_info) == class) {
- return pos;
- }
- }
-
- return NULL;
-}
-
void
-pci_apply_command(struct pci_device* pcidev, pci_reg_t cmd)
+pci_apply_command(struct pci_probe* probe, pci_reg_t cmd)
{
pci_reg_t rcmd;
ptr_t base;
- base = pcidev->cspace_base;
+ base = probe->cspace_base;
rcmd = pci_read_cspace(base, PCI_REG_STATUS_CMD);
cmd = cmd & 0xffff;
static void
__pci_read_cspace(struct twimap* map)
{
- struct pci_device* pcidev = (struct pci_device*)(map->data);
+ struct pci_probe* probe;
+
+ probe = twimap_data(map, struct pci_probe*);
for (size_t i = 0; i < 256; i += sizeof(pci_reg_t)) {
*(pci_reg_t*)(map->buffer + i) =
- pci_read_cspace(pcidev->cspace_base, i);
+ pci_read_cspace(probe->cspace_base, i);
}
map->size_acc = 256;
static void
__pci_read_revid(struct twimap* map)
{
- int class = twimap_data(map, struct pci_device*)->class_info;
- twimap_printf(map, "0x%x", PCI_DEV_REV(class));
+ struct pci_probe* probe;
+
+ probe = twimap_data(map, struct pci_probe*);
+ twimap_printf(map, "0x%x", PCI_DEV_REV(probe->class_info));
}
static void
__pci_read_class(struct twimap* map)
{
- int class = twimap_data(map, struct pci_device*)->class_info;
- twimap_printf(map, "0x%x", PCI_DEV_CLASS(class));
+ struct pci_probe* probe;
+
+ probe = twimap_data(map, struct pci_probe*);
+ twimap_printf(map, "0x%x", PCI_DEV_CLASS(probe->class_info));
}
static void
__pci_read_devinfo(struct twimap* map)
{
- int devinfo = twimap_data(map, struct pci_device*)->device_info;
- twimap_printf(
- map, "%x:%x", PCI_DEV_VENDOR(devinfo), PCI_DEV_DEVID(devinfo));
+ struct pci_probe* probe;
+
+ probe = twimap_data(map, struct pci_probe*);
+ twimap_printf(map, "%x:%x",
+ PCI_DEV_VENDOR(probe->device_info),
+ PCI_DEV_DEVID(probe->device_info));
}
static void
__pci_bar_read(struct twimap* map)
{
- struct pci_device* pcidev = twimap_data(map, struct pci_device*);
- int bar_index = twimap_index(map, int);
+ struct pci_probe* probe;
+ int bar_index;
+
+ probe = twimap_data(map, struct pci_probe*);
+ bar_index = twimap_index(map, int);
- struct pci_base_addr* bar = &pcidev->bar[bar_index];
+ struct pci_base_addr* bar = &probe->bar[bar_index];
if (!bar->start && !bar->size) {
twimap_printf(map, "[%d] not present \n", bar_index);
static void
__pci_read_binding(struct twimap* map)
{
- struct pci_device* pcidev = twimap_data(map, struct pci_device*);
- struct device_def* devdef = pcidev->binding.def;
- if (!devdef) {
+ struct pci_probe* probe;
+ struct devident* devid;
+
+ probe = twimap_data(map, struct pci_probe*);
+ if (!probe->bind) {
return;
}
- twimap_printf(map,
- "%xh:%xh.%d",
- devdef->class.fn_grp,
- devdef->class.device,
- devdef->class.variant);
+ devid = &probe->bind->ident;
+
+ twimap_printf(map, "%xh:%xh.%d",
+ devid->fn_grp,
+ DEV_KIND_FROM(devid->unique),
+ DEV_VAR_FROM(devid->unique));
}
static void
pci_build_fsmapping()
{
struct twifs_node *pci_class = twifs_dir_node(NULL, "pci"), *pci_dev;
- struct pci_device *pos, *n;
struct twimap* map;
+ struct pci_probe* probe;
+ morph_t *pos, *n;
- map = twifs_mapping(pci_class, NULL, "rescan");
- map->read = __pci_trigger_bus_rescan;
+ // TODO bus rescan is not ready yet
+ // map = twifs_mapping(pci_class, NULL, "rescan");
+ // map->read = __pci_trigger_bus_rescan;
- llist_for_each(pos, n, &pci_devices, dev_chain)
+ changeling_for_each(pos, n, pci_probers)
{
- pci_dev = twifs_dir_node(pci_class, "%x", pos->loc);
+ probe = changeling_reveal(pos, pci_probe_morpher);
+ pci_dev = twifs_dir_node(pci_class, "%x", probe->loc);
- map = twifs_mapping(pci_dev, pos, "config");
+ map = twifs_mapping(pci_dev, probe, "config");
map->read = __pci_read_cspace;
- map = twifs_mapping(pci_dev, pos, "revision");
+ map = twifs_mapping(pci_dev, probe, "revision");
map->read = __pci_read_revid;
- map = twifs_mapping(pci_dev, pos, "class");
+ map = twifs_mapping(pci_dev, probe, "class");
map->read = __pci_read_class;
- map = twifs_mapping(pci_dev, pos, "binding");
+ map = twifs_mapping(pci_dev, probe, "binding");
map->read = __pci_read_binding;
- map = twifs_mapping(pci_dev, pos, "io_bases");
+ map = twifs_mapping(pci_dev, probe, "io_bases");
map->read = __pci_bar_read;
map->go_next = __pci_bar_gonext;
}
/*---------- PCI 3.0 HBA device definition ----------*/
static int
-pci_load_devices(struct device_def* def)
+pci_register(struct device_def* def)
{
- pcidev_cat = device_addcat(NULL, "pci");
-
- pci_scan();
+ pci_probers = changeling_spawn(NULL, "pci_realm");
return 0;
}
-void
-pci_bind_instance(struct pci_device* pcidev, void* devobj)
+static int
+pci_create(struct device_def* def, morph_t* obj)
{
- pcidev->dev.underlay = devobj;
- pcidev->binding.dev = devobj;
+ devtree_link_t devtree_node;
+
+ devtree_node = changeling_try_reveal(obj, dt_node_morpher);
+
+ pci_bridge = device_allocsys(NULL, NULL);
+ device_set_devtree_node(pci_bridge, devtree_node);
+
+ register_device(pci_bridge, &def->class, "pci_bridge");
+
+ pci_scan();
+
+ return 0;
}
static struct device_def pci_def = {
- .name = "Generic PCI",
- .class = DEVCLASS(DEVIF_SOC, DEVFN_BUSIF, DEV_PCI),
- .init = pci_load_devices
+ def_device_name("Generic PCI"),
+ def_device_class(GENERIC, BUSIF, PCI),
+
+ def_on_register(pci_register),
+ def_on_create(pci_create)
};
EXPORT_DEVICE(pci3hba, &pci_def, load_sysconf);
}
static int
-pdev_nulldev_init(struct device_def* def)
+pdev_nulldev_create(struct device_def* def, morph_t* obj)
{
struct device* devnull = device_allocseq(NULL, NULL);
devnull->ops.write_page = __null_wr_pg;
}
static struct device_def devnull_def = {
- .name = "null",
- .class = DEVCLASSV(DEVIF_NON, DEVFN_PSEUDO, DEV_NULL, DEV_BUILTIN_NULL),
- .init = pdev_nulldev_init};
+ def_device_name("edendi"),
+ def_device_class(LUNAIX, PSEUDO, NIHIL),
+ def_on_create(pdev_nulldev_create)
+};
EXPORT_DEVICE(nulldev, &devnull_def, load_onboot);
}
static int
-pdev_zerodev_init(struct device_def* def)
+pdev_zerodev_create(struct device_def* def, morph_t* obj)
{
struct device* devzero = device_allocseq(NULL, NULL);
devzero->ops.read_page = __zero_rd_pg;
}
static struct device_def devzero_def = {
- .name = "zero",
- .class = DEVCLASSV(DEVIF_NON, DEVFN_PSEUDO, DEV_ZERO, DEV_BUILTIN_ZERO),
- .init = pdev_zerodev_init};
+ def_device_name("nihil"),
+ def_device_class(LUNAIX, PSEUDO, ZERO),
+ def_on_create(pdev_zerodev_create)
+};
EXPORT_DEVICE(zerodev, &devzero_def, load_onboot);
struct console
{
- struct capability_meta* tp_cap;
+ struct potens_meta* tp_cap;
struct lx_timer* flush_timer;
struct fifo_buf output;
struct fifo_buf input;
fifo_putone(&lx_console.input, ttychr);
- struct termport_capability* tpcap;
- tpcap = get_capability(lx_console.tp_cap, typeof(*tpcap));
+ struct termport_potens* tpcap;
+ tpcap = get_potens(lx_console.tp_cap, typeof(*tpcap));
term_notify_data_avaliable(tpcap);
pwake_all(&lx_reader);
waitq_init(&lx_reader);
input_add_listener(__lxconsole_listener);
- struct termport_capability* tp_cap;
-
- tp_cap = new_capability(TERMPORT_CAP, struct termport_capability);
- term_cap_set_operations(tp_cap, termport_default_ops);
-
- lx_console.tp_cap = cap_meta(tp_cap);
- device_grant_capability(tty_dev, lx_console.tp_cap);
-
register_device(tty_dev, &devdef->class, "vcon");
- term_create(tty_dev, "VCON");
+ term_attach_potens(tty_dev, NULL, "VCON");
return 0;
}
static struct device_def lxconsole_def = {
- .name = "Lunaix Virtual Console",
- .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN),
- .init = lxconsole_spawn_ttydev
+ def_device_name("Lunaix Virtual Console"),
+ def_device_class(LUNAIX, TTY, VTERM),
+ def_on_load(lxconsole_spawn_ttydev)
};
EXPORT_DEVICE(lxconsole, &lxconsole_def, load_onboot);
\ No newline at end of file
#include <asm/pagetable.h>
#include <hal/serial.h>
-#include <hal/term.h>
LOG_MODULE("serial")
pwake_one(&sdev->wq_rxdone);
- struct termport_capability* tpcap;
- tpcap = get_capability(sdev->tp_cap, typeof(*tpcap));
- term_notify_data_avaliable(tpcap);
+ term_notify_data_avaliable(sdev->tp_cap);
}
void
#define RXBUF_SIZE 512
-static struct termport_cap_ops tpcap_ops = {
+static struct termport_pot_ops tppot_ops = {
.set_cntrl_mode = __serial_set_cntrl_mode,
.set_clkbase = __serial_set_baseclk,
.set_speed = __serial_set_speed
struct serial_dev*
serial_create(struct devclass* class, char* if_ident)
{
- struct serial_dev* sdev = vzalloc(sizeof(struct serial_dev));
- struct device* dev = device_allocseq(dev_meta(serial_cat), sdev);
+ struct serial_dev* sdev;
+ struct device* dev;
+
+ sdev = vzalloc(sizeof(struct serial_dev));
+ dev = device_allocseq(dev_meta(serial_cat), sdev);
+
dev->ops.read = __serial_read;
dev->ops.read_page = __serial_read_page;
dev->ops.read_async = __serial_read_async;
sdev->dev = dev;
dev->underlay = sdev;
- struct termport_capability* tp_cap =
- new_capability(TERMPORT_CAP, struct termport_capability);
-
- term_cap_set_operations(tp_cap, &tpcap_ops);
- sdev->tp_cap = cap_meta(tp_cap);
-
waitq_init(&sdev->wq_rxdone);
waitq_init(&sdev->wq_txdone);
rbuffer_init(&sdev->rxbuf, valloc(RXBUF_SIZE), RXBUF_SIZE);
llist_append(&serial_devs, &sdev->sdev_list);
- device_grant_capability(dev, cap_meta(tp_cap));
-
- register_device(dev, class, "%s%d", if_ident, class->variant);
-
- term_create(dev, if_ident);
+ register_device_var(dev, class, "%s", if_ident);
INFO("interface: %s, %xh:%xh.%d", dev->name_val,
class->fn_grp, class->device, class->variant);
- class->variant++;
+ sdev->tp_cap = term_attach_potens(dev, &tppot_ops, if_ident);
+
return sdev;
}
--- /dev/null
+#include <lunaix/device.h>
+
+#include <hal/pci.h>
+
+#include "16x50.h"
+
+extern_hook_load(isa16x50_create_once);
+extern_hook_create(pci16650_pci_create);
+extern_hook_register(pci16x50_pci_register);
+
+static int
+uart_16x50_load(struct device_def* def)
+{
+ isa16x50_create_once(def);
+ return 0;
+}
+
+static int
+uart_16x50_create(struct device_def* def, morph_t* morphed)
+{
+ if (morph_type_of(morphed, pci_probe_morpher)) {
+ pci16650_pci_create(def, morphed);
+ }
+
+ return 0;
+}
+
+static int
+uart_16x50_register(struct device_def* def)
+{
+ pci16x50_pci_register(def);
+
+ return 0;
+}
+
+static struct device_def uart_dev = {
+ def_device_class(GENERIC, CHAR, UART16550),
+ def_device_name("16550 UART"),
+
+ def_on_register(uart_16x50_register),
+ def_on_load(uart_16x50_load),
+ def_on_create(uart_16x50_create)
+};
+EXPORT_DEVICE(uart16550_pmio, &uart_dev, load_onboot);
\ No newline at end of file
uart_handle_irq_overlap(vector, &com_ports);
}
-static int
-upiom_init(struct device_def* def)
+int
+isa16x50_create_once(struct device_def* def)
{
int irq3 = 3, irq4 = 4;
u16_t ioports[] = { 0x3F8, 0x2F8, 0x3E8, 0x2E8 };
}
return 0;
-}
-
-static struct device_def uart_pmio_def = {
- .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_UART16550),
- .name = "16550 UART (pmio, isa-bus)",
- .init = upiom_init
-};
-EXPORT_DEVICE(uart16550_pmio, &uart_pmio_def, load_onboot);
\ No newline at end of file
+}
\ No newline at end of file
static DEFINE_LLIST(pci_ports);
+
static void
uart_msi_irq_handler(const struct hart_state* hstate)
{
uart_handle_irq_overlap(vector, &pci_ports);
}
-static int
-pci16550_init(struct device_def* def)
-{
- return pci_bind_definition_all(pcidev_def(def));
-}
-
static bool
-pci16650_check_compat(struct pci_device_def* def,
- struct pci_device* pcidev)
+pci16x50_check_compat(struct pci_probe* probe)
{
unsigned int classid;
- classid = pci_device_class(pcidev);
+ classid = pci_device_class(probe);
return (classid & 0xffff00) == PCI_DEVICE_16x50_UART;
}
-static int
-pci16650_binder(struct device_def* def, struct device* dev)
+int
+pci16x50_pci_register(struct device_def* def)
+{
+ return !pci_register_driver(def, pci16x50_check_compat);
+}
+
+int
+pci16x50_pci_create(struct device_def* def, morph_t* obj)
{
struct pci_base_addr* bar;
- struct pci_device* pcidev;
+ struct pci_probe* probe;
struct uart16550* uart;
struct serial_dev* sdev;
msi_vector_t msiv;
- pcidev = PCI_DEVICE(dev);
+ probe = changeling_reveal(obj, pci_probe_morpher);
pci_reg_t cmd = 0;
cmd = 0;
pci_cmd_set_msi(&cmd);
- bar = pci_device_bar(pcidev, i);
+ bar = pci_device_bar(probe, i);
if (bar->size == 0) {
continue;
}
if (!pci_bar_mmio_space(bar)) {
#ifdef CONFIG_PCI_PMIO
pci_cmd_set_pmio(&cmd);
- pci_apply_command(pcidev, cmd);
+ pci_apply_command(probe, cmd);
uart = uart16x50_pmio_create(bar->start);
#else
- WARN("plaform configured to not support pmio access.")
+ WARN("plaform configured to not support pmio access.");
continue;
#endif
} else
{
pci_cmd_set_mmio(&cmd);
- pci_apply_command(pcidev, cmd);
+ pci_apply_command(probe, cmd);
uart = uart16x50_mmio_create(bar->start, bar->size);
}
continue;
}
- if (!pci_capability_msi(pcidev)) {
+ if (!pci_capability_msi(probe)) {
WARN("failed to fallback to legacy INTx: not supported.");
continue;
}
- msiv = isrm_msialloc(uart_msi_irq_handler);
+ sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
+
+ msiv = pci_msi_setup_simple(probe, uart_msi_irq_handler);
isrm_set_payload(msi_vect(msiv), __ptr(uart));
- pci_setup_msi(pcidev, msiv);
INFO("base: 0x%x (%s), irq=%d (%s)",
bar->start,
pci_bar_mmio_space(bar) ? "mmio" : "pmio",
msi_vect(msiv),
- pci_capability_msi(pcidev) ? "msi" : "intx, re-routed");
+ pci_capability_msi(probe) ? "msi" : "intx, re-routed");
uart->iv = msi_vect(msiv);
- sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
- pci_bind_instance(pcidev, sdev);
+ pci_bind_instance(probe, sdev->dev);
}
return 0;
}
-
-static struct pci_device_def uart_pci_def = {
- .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_CHAR, DEV_UART16550),
- .name = "16550 UART (PCI/MMIO)",
- .init = pci16550_init,
- .bind = pci16650_binder },
- .test_compatibility = pci16650_check_compat
-};
-EXPORT_PCI_DEVICE(uart16550_pci, &uart_pci_def, load_onboot);
\ No newline at end of file
"16x50_base.c",
"16x50_pmio.c",
"16x50_mmio.c",
+ "16x50_dev.c",
])
if config("xt_16x50"):
--- /dev/null
+sources([
+ "dt_interrupt.c",
+ "dt.c",
+ "dtm.c"
+])
\ No newline at end of file
#include <hal/devtree.h>
+#include <klibc/string.h>
+
+static inline bool
+propeq(struct fdt_iter* it, const char* key)
+{
+ return streq(fdtit_prop_key(it), key);
+}
+
+static inline void
+__mkprop_val32(struct fdt_iter* it, struct dt_prop_val* val)
+{
+ val->u32_val = le(*(u32_t*)&it->prop[1]);
+ val->size = le(it->prop->len);
+}
+
+static inline void
+__mkprop_val64(struct fdt_iter* it, struct dt_prop_val* val)
+{
+ val->u64_val = le64(*(u64_t*)&it->prop[1]);
+ val->size = le(it->prop->len);
+}
+
+static inline void
+__mkprop_ptr(struct fdt_iter* it, struct dt_prop_val* val)
+{
+ val->ptr_val = __ptr(&it->prop[1]);
+ val->size = le(it->prop->len);
+}
+
+static inline u32_t
+__prop_getu32(struct fdt_iter* it)
+{
+ return le(*(u32_t*)&it->prop[1]);
+}
+
+bool
+parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node);
+
bool
parse_stdintr_prop(struct fdt_iter* it, struct dt_intr_node* node);
#include <lunaix/mm/valloc.h>
#include <lunaix/syslog.h>
-
-#include <klibc/string.h>
+#include <lunaix/owloysius.h>
#include "devtree.h"
LOG_MODULE("dtb")
+static morph_t* devtree_obj_root;
static struct dt_context dtctx;
void
rsvdi->block = NULL;
}
-static inline bool
-propeq(struct fdt_iter* it, const char* key)
-{
- return streq(fdtit_prop_key(it), key);
-}
-
-static inline void
-__mkprop_val32(struct fdt_iter* it, struct dt_prop_val* val)
-{
- val->u32_val = le(*(u32_t*)&it->prop[1]);
- val->size = le(it->prop->len);
-}
-
-static inline void
-__mkprop_val64(struct fdt_iter* it, struct dt_prop_val* val)
-{
- val->u64_val = le64(*(u64_t*)&it->prop[1]);
- val->size = le(it->prop->len);
-}
-
-static inline void
-__mkprop_ptr(struct fdt_iter* it, struct dt_prop_val* val)
-{
- val->ptr_val = __ptr(&it->prop[1]);
- val->size = le(it->prop->len);
-}
-
-static inline u32_t
-__prop_getu32(struct fdt_iter* it)
-{
- return le(*(u32_t*)&it->prop[1]);
-}
-
static bool
__parse_stdbase_prop(struct fdt_iter* it, struct dt_node_base* node)
{
if (propeq(it, "compatible")) {
__mkprop_ptr(it, &node->compat);
}
-
- else if (propeq(it, "model")) {
- node->model = (const char*)&prop[1];
- }
else if (propeq(it, "phandle")) {
node->phandle = __prop_getu32(it);
- hashtable_hash_in(dtctx.phnds_table,
- &node->phnd_link, node->phandle);
}
else if (propeq(it, "#address-cells")) {
return true;
}
+static inline void
+__dt_node_set_name(struct dt_node_base* node, const char* name)
+{
+ changeling_setname(&node->mobj, name);
+}
+
+static inline void
+__init_prop_table(struct dt_node_base* node)
+{
+ struct dt_prop_table* propt;
+
+ propt = valloc(sizeof(*propt));
+ hashtable_init(propt->_op_bucket);
+}
+
+#define prop_table_add(node, prop) \
+ hashtable_hash_in( (node)->props->_op_bucket, \
+ &(prop)->ht, (prop)->key.hash);
+
static void
__parse_other_prop(struct fdt_iter* it, struct dt_node_base* node)
{
__mkprop_ptr(it, &prop->val);
hstr_rehash(&prop->key, HSTR_FULL_HASH);
- hash = prop->key.hash;
- hashtable_hash_in(node->_op_bucket, &prop->ht, hash);
+ prop_table_add(node, prop);
}
static void
return;
}
- if (__parse_stdintr_prop(it, &node->intr)) {
+ if (parse_stdintr_prop(it, &node->intr)) {
return;
}
static inline void
__init_node(struct dt_node_base* node)
{
- hashtable_init(node->_op_bucket);
- llist_init_head(&node->children);
+ morph_t* parent;
- if (node->parent)
+ parent = devtree_obj_root;
+ if (node->parent) {
+ parent = node->mobj.parent;
node->_std = node->parent->_std;
+ }
+
+ __init_prop_table(node);
+ changeling_morph_anon(parent, node->mobj, dt_morpher);
}
static inline void
node->parent = prev;
__init_node_regular((struct dt_node*)node);
- llist_append(&prev->children, &node->siblings);
llist_append(&dtctx.nodes, &node->nodes);
}
- node->name = (const char*)&it.pos[1];
+ __dt_node_set_name(node, (const char*)&it.pos[1]);
}
if (unlikely(is_root_level)) {
dt_resolve_phandle(dt_phnd_t phandle)
{
struct dt_node_base *pos, *n;
- hashtable_hash_foreach(dtctx.phnds_table, phandle, pos, n, phnd_link)
+ llist_for_each(pos, n, &dtctx.nodes, nodes)
{
if (pos->phandle == phandle) {
return (struct dt_node*)pos;
__byname_predicate(struct dt_node_iter* iter, struct dt_node_base* node)
{
int i = 0;
- const char* be_matched = node->name;
+ const char* be_matched = HSTR_VAL(node->mobj.name);
const char* name = (const char*)iter->closure;
while (be_matched[i] && name[i])
iter->closure = closure;
iter->pred = pred;
- struct dt_node_base *pos, *n;
- llist_for_each(pos, n, &node->base.children, siblings)
+ morph_t *pos, *n;
+ struct dt_node_base* base;
+ changeling_for_each(pos, n, &node->mobj)
{
- if (pred(iter, pos)) {
- iter->matched = pos;
+ base = &changeling_reveal(pos, dt_morpher)->base;
+ if (pred(iter, base)) {
+ iter->matched = base;
break;
}
}
return false;
}
- struct dt_node_base *pos, *head;
+ struct dt_node *node;
+ morph_t *pos, *head;
- head = iter->head;
- pos = iter->matched;
- *matched = pos;
+ head = dt_mobj(iter->head);
+ pos = dt_mobj(iter->matched);
+ *matched = iter->matched;
- while (&pos->siblings != &head->children)
+ while (&pos->sibs != &head->subs)
{
- pos = list_next(pos, struct dt_node_base, siblings);
+ pos = list_next(pos, morph_t, sibs);
+ node = changeling_reveal(pos, dt_morpher);
- if (!iter->pred(iter, pos)) {
+ if (!iter->pred(iter, &node->base)) {
continue;
}
- iter->matched = pos;
+ iter->matched = &node->base;
return true;
}
hstr_rehash(&hashed_name, HSTR_FULL_HASH);
hash = hashed_name.hash;
- hashtable_hash_foreach(base->_op_bucket, hash, pos, n, ht)
+ hashtable_hash_foreach(base->props->_op_bucket, hash, pos, n, ht)
{
if (HSTR_EQ(&pos->key, &hashed_name)) {
return &pos->val;
}
return NULL;
-}
\ No newline at end of file
+}
+
+struct dt_context*
+dt_main_context()
+{
+ return &dtctx;
+}
+
+static void
+__init_devtree()
+{
+ devtree_obj_root = changeling_spawn(NULL, NULL);
+}
+owloysius_fetch_init(__init_devtree, on_sysconf);
\ No newline at end of file
static void
__mask_key(struct dt_intr_mapkey* k, struct dt_intr_mapkey* mask)
{
- for (int i = 0; i < k->size; i++)
+ for (unsigned int i = 0; i < k->size; i++)
{
k->val[i] &= mask->val[i];
}
return false;
}
- for (int i = 0; i < k1->size; i++)
+ for (unsigned int i = 0; i < k1->size; i++)
{
if (k1->val[i] != k2->val[i]) {
return false;
llist_for_each(pos, n, &i_nexus->map->mapent, ents) {
if (__compare_key(&pos->key, &key))
{
+ __destory_key(&key);
return &pos->parent_props;
}
}
__destory_key(&key);
+ return NULL;
}
bool
--- /dev/null
+#include <hal/devtreem.h>
+#include <lunaix/device.h>
+#include <lunaix/mm/valloc.h>
+#include <lunaix/syslog.h>
+#include <lunaix/owloysius.h>
+#include <lunaix/status.h>
+
+#include <klibc/string.h>
+
+LOG_MODULE("dtm")
+
+static DECLARE_HASHTABLE(registry, 32);
+static struct device_cat* dt_category;
+
+struct figura
+{
+ char val;
+ bool optional;
+};
+
+#define hash(def) ((unsigned int)__ptr(def))
+
+static struct dtm_driver_record*
+__locate_record(struct device_def* def)
+{
+ struct dtm_driver_record *p, *n;
+
+ hashtable_hash_foreach(registry, hash(def), p, n, node)
+ {
+ if (p->def == def) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+
+static inline void
+__get_patternlet(const char* str, unsigned i, size_t len,
+ struct figura* fig)
+{
+ fig->optional = (i + 1 < len && str[i + 1] == '?');
+
+ if (i >= len) {
+ fig->val = 0;
+ return;
+ }
+
+ fig->val = str[i];
+}
+
+/**
+ * A simplified regular expression matcher:
+ * 1. '*' matches any substring including empty string
+ * 2. '?' mark the prefixed character optional (an epsilon transition)
+ */
+static bool
+__try_match(const char* str, const char* pattern, size_t pat_sz)
+{
+ unsigned j = 0, i = 0;
+ int saved_star = -1, saved_pos = 0;
+ size_t str_sz = strlen(str);
+
+ char c;
+ struct figura p0, p1;
+
+ while (i < str_sz) {
+ c = str[i++];
+ __get_patternlet(pattern, j, pat_sz, &p0);
+ __get_patternlet(pattern, j + 1, pat_sz, &p1);
+
+ if (p0.val == c) {
+ j += 1 + !!p0.optional;
+ saved_pos = (int)i;
+ continue;
+ }
+
+ if (p0.val == '*') {
+ saved_pos = i;
+ saved_star = (int)j;
+
+ if (p1.optional || p1.val == c) {
+ ++j; --i;
+ }
+
+ continue;
+ }
+
+ if (p0.optional) {
+ --i; j += 2;
+ continue;
+ }
+
+ if (saved_star < 0) {
+ return false;
+ }
+
+ j = (unsigned)saved_star;
+ i = (unsigned)saved_pos;
+ }
+
+ return j + 1 >= pat_sz;
+}
+
+static struct device_meta*
+__try_create_categorical(struct dt_node_base *p)
+{
+ if (!p) return NULL;
+
+ struct device_meta* parent = NULL;
+ struct device_cat* cat;
+
+ parent = __try_create_categorical(p->parent);
+ parent = parent ?: dev_meta(dt_category);
+
+ if (!p->compat.size) {
+ return parent;
+ }
+
+ if (p->binded_dev) {
+ cat = changeling_reveal(p->binded_dev, devcat_morpher);
+ }
+ else {
+ cat = device_addcat(parent, HSTR_VAL(dt_mobj(p)->name));
+ p->binded_dev = dev_mobj(cat);
+ }
+
+ return dev_meta(cat);
+}
+
+static bool
+compat_matched(struct dtm_driver_record* rec, struct dt_node_base *base)
+{
+ const char *compat;
+ struct dtm_driver_info *p, *n;
+
+ list_for_each(p, n, rec->infos.first, node)
+ {
+ size_t pat_len = strlen(p->pattern);
+ dtprop_strlst_foreach(compat, &base->compat)
+ {
+ if (__try_match(compat, p->pattern, pat_len)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+static int
+dtm_try_create_from(struct device_def* def)
+{
+ int err;
+ const char *name;
+ struct dt_context* dtctx;
+ struct dtm_driver_record* rec;
+ struct dt_node_base *p, *n;
+
+ dtctx = dt_main_context();
+
+ rec = __locate_record(def);
+ if (!rec) {
+ return ENOENT;
+ }
+
+ llist_for_each(p, n, &dtctx->nodes, nodes)
+ {
+ if (!p->compat.size) {
+ continue;
+ }
+
+ if (!compat_matched(rec, p)) {
+ continue;
+ }
+
+ __try_create_categorical(p);
+
+ if ((err = def->create(def, dt_mobj(p)))) {
+ name = HSTR_VAL(dt_mobj(p)->name);
+ WARN("failed to bind devtree node %s, err=%d", name, err);
+ }
+ }
+
+ return 0;
+}
+
+void
+dtm_register_entry(struct device_def* def, const char* pattern)
+{
+ struct dtm_driver_info* info;
+ struct dtm_driver_record* record;
+
+ info = valloc(sizeof(*info));
+ info->pattern = pattern;
+
+ record = __locate_record(def);
+ if (!record) {
+ record = valloc(sizeof(*record));
+ record->def = def;
+ list_head_init(&record->infos);
+
+ hashtable_hash_in(registry, &record->node, hash(def));
+ }
+
+ list_add(&record->infos, &info->node);
+
+ device_chain_loader(def, dtm_try_create_from);
+}
+
+static void
+dtm_init()
+{
+ hashtable_init(registry);
+
+ dt_category = device_addcat(NULL, "tree");
+}
+owloysius_fetch_init(dtm_init, on_sysconf);
\ No newline at end of file
struct device_cat* gfxa_devcat = NULL;
static int id = 0;
-static struct devclass gfxa_class = DEVCLASS(DEV_BUILTIN, DEVFN_DISP, DEV_GFXA);
+static struct devclass gfxa_class = DEVCLASS(GENERIC, DISP, GFXA);
static int
__gfxa_cmd_router(struct device* dev, u32_t req, va_list args)
#define VGA_REG_OFF 0x0400
static int
-vga_pci_bind(struct device_def* devdef, struct device* pcidev_base)
+vga_pci_bind(struct device_def* devdef, morph_t* obj)
{
- struct pci_device* pcidev = PCI_DEVICE(pcidev_base);
+ struct pci_probe* probe;
- struct pci_base_addr* fb = &pcidev->bar[0];
- struct pci_base_addr* mmio = &pcidev->bar[2];
+ struct pci_base_addr* fb;
+ struct pci_base_addr* mmio;
+
+ probe = changeling_reveal(obj, pci_probe_morpher);
+ fb = &probe->bar[0];
+ mmio = &probe->bar[2];
if (PCI_BAR_ADDR_IO(mmio->type)) {
return EINVAL;
}
- pci_reg_t cmd = pci_read_cspace(pcidev->cspace_base, PCI_REG_STATUS_CMD);
+ pci_reg_t cmd = pci_read_cspace(probe->cspace_base, PCI_REG_STATUS_CMD);
cmd |= (PCI_RCMD_MM_ACCESS | PCI_RCMD_DISABLE_INTR | PCI_RCMD_BUS_MASTER);
- pci_write_cspace(pcidev->cspace_base, PCI_REG_STATUS_CMD, cmd);
+ pci_write_cspace(probe->cspace_base, PCI_REG_STATUS_CMD, cmd);
ptr_t fb_mapped = ioremap(fb->start, FB256K);
ptr_t mmio_mapped = ioremap(mmio->start, mmio->size);
return 0;
}
-static int
-vga_pci_init(struct device_def* def)
-{
- return pci_bind_definition_all(pcidev_def(def));
-}
+static bool
+vga_pci_compat(struct pci_probe* probe)
+{
#define VGA_PCI_CLASS 0x30000
+ return pci_device_class(probe) == VGA_PCI_CLASS;
+}
-static bool
-vga_pci_compat(struct pci_device_def* def,
- struct pci_device* pcidev)
+static int
+vga_pci_register(struct device_def* def)
{
- return pci_device_class(pcidev) == VGA_PCI_CLASS;
+ return !pci_register_driver(def, vga_pci_compat);
}
+static struct device_def vga_pci_devdef = {
+ def_device_class(GENERIC, DISP, VGA),
+ def_device_name("Generic VGA"),
+
+ def_on_register(vga_pci_register),
+ def_on_create(vga_pci_bind),
-static struct pci_device_def vga_pci_devdef = {
- .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_DISP, DEV_VGA),
- .name = "Generic VGA",
- .init = vga_pci_init,
- .bind = vga_pci_bind },
- .test_compatibility = vga_pci_compat
+ def_non_trivial
};
-EXPORT_PCI_DEVICE(vga_pci, &vga_pci_devdef, load_onboot);
\ No newline at end of file
+EXPORT_DEVICE(vga_pci, &vga_pci_devdef, load_onboot);
\ No newline at end of file
#include <lunaix/fs/twimap.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/status.h>
+#include <lunaix/syslog.h>
#include <hal/hwrtc.h>
-const struct hwrtc* sysrtc;
-static int rtc_count = 0;
+const struct hwrtc_potens* sysrtc = NULL;
-DEFINE_LLIST(rtcs);
+static DEFINE_LLIST(rtcs);
+
+LOG_MODULE("hwrtc")
void
hwrtc_walltime(datetime_t* dt)
{
- sysrtc->get_walltime(sysrtc, dt);
+ sysrtc->ops->get_walltime(sysrtc, dt);
+}
+
+static inline struct hwrtc_potens*
+__rtc_potens(struct device* wrapper)
+{
+ struct potens_meta* pot;
+ pot = device_get_potens(wrapper, potens(HWRTC));
+ return ({ assert(pot); get_potens(pot, struct hwrtc_potens); });
}
static int
-hwrtc_ioctl(struct device* dev, u32_t req, va_list args)
+__hwrtc_ioctl(struct device* dev, u32_t req, va_list args)
{
- struct hwrtc* rtc = (struct hwrtc*)dev->underlay;
+ struct hwrtc_potens* pot;
+ struct hwrtc_potens_ops* ops;
+ struct device* rtcdev;
+
+ rtcdev = (struct device*) dev->underlay;
+ pot = __rtc_potens(rtcdev);
+ ops = pot->ops;
+
switch (req) {
case RTCIO_IMSK:
- rtc->set_mask(rtc);
+ ops->set_proactive(pot, false);
break;
case RTCIO_IUNMSK:
- rtc->cls_mask(rtc);
+ ops->set_proactive(pot, true);
break;
case RTCIO_SETDT:
datetime_t* dt = va_arg(args, datetime_t*);
- rtc->set_walltime(rtc, dt);
+ ops->set_walltime(pot, dt);
break;
case RTCIO_SETFREQ:
ticks_t* freq = va_arg(args, ticks_t*);
return EINVAL;
}
if (*freq) {
- return rtc->chfreq(rtc, *freq);
+ return ops->chfreq(pot, *freq);
}
- *freq = rtc->base_freq;
+ *freq = pot->base_freq;
break;
default:
- return EINVAL;
+ return rtcdev->ops.exec_cmd(dev, req, args);
}
return 0;
}
static int
-hwrtc_read(struct device* dev, void* buf, size_t offset, size_t len)
+__hwrtc_read(struct device* dev, void* buf, size_t offset, size_t len)
{
- struct hwrtc* rtc = (struct hwrtc*)dev->underlay;
- *((ticks_t*)buf) = rtc->get_counts(rtc);
+ struct hwrtc_potens* pot;
+
+ pot = __rtc_potens((struct device*)dev->underlay);
+ *((ticks_t*)buf) = pot->live;
return sizeof(ticks_t);
}
-struct hwrtc*
-hwrtc_alloc_new(char* name)
+static struct devclass proxy_rtc_clas = DEVCLASS(LUNAIX, TIME, RTC);
+
+static void
+__hwrtc_create_proxy(struct hwrtc_potens* pot, struct device* raw_rtcdev)
{
- struct hwrtc* rtc_instance = valloc(sizeof(struct hwrtc));
+ struct device* dev;
- if (!rtc_instance) {
- return NULL;
- }
+ dev = device_allocsys(NULL, raw_rtcdev);
+
+ dev->ops.exec_cmd = __hwrtc_ioctl;
+ dev->ops.read = __hwrtc_read;
- llist_append(&rtcs, &rtc_instance->rtc_list);
+ register_device_var(dev, &proxy_rtc_clas, "rtc");
- rtc_instance->id = rtc_count++;
- rtc_instance->name = name;
- struct device* rtcdev = device_allocsys(NULL, rtc_instance);
+ pot->rtc_proxy = dev;
+}
+
+struct hwrtc_potens*
+hwrtc_attach_potens(struct device* raw_rtcdev, struct hwrtc_potens_ops* ops)
+{
+ struct hwrtc_potens* hwpot;
+
+ if (!potens_check_unique(raw_rtcdev, potens(HWRTC)))
+ {
+ return NULL;
+ }
- rtcdev->ops.exec_cmd = hwrtc_ioctl;
- rtcdev->ops.read = hwrtc_read;
+ hwpot = new_potens(potens(HWRTC), struct hwrtc_potens);
+ hwpot->ops = ops;
+
+ device_grant_potens(raw_rtcdev, potens_meta(hwpot));
+ llist_append(&rtcs, &hwpot->rtc_potentes);
- rtc_instance->rtc_dev = rtcdev;
+ __hwrtc_create_proxy(hwpot, raw_rtcdev);
- return rtc_instance;
+ return hwpot;
}
void
-hwrtc_register(struct devclass* class, struct hwrtc* rtc)
+hwrtc_init()
{
- if (unlikely(!sysrtc)) {
- sysrtc = rtc;
+ assert(!llist_empty(&rtcs));
+
+ sysrtc = list_entry(rtcs.next, struct hwrtc_potens, rtc_potentes);
+
+ if (!sysrtc->ops->calibrate) {
+ return;
}
- class->variant = rtc->id;
- register_device(rtc->rtc_dev, class, "rtc%d", rtc->id);
+ int err = sysrtc->ops->calibrate(sysrtc);
+ if (err) {
+ FATAL("failed to calibrate rtc. name='%s', err=%d",
+ potens_dev(sysrtc)->name_val, err);
+ }
}
static void
__hwrtc_readinfo(struct twimap* mapping)
{
- struct hwrtc* rtc = twimap_data(mapping, struct hwrtc*);
- twimap_printf(mapping, "name: %s\n", rtc->name);
- twimap_printf(mapping, "frequency: %dHz\n", rtc->base_freq);
- twimap_printf(mapping, "ticks count: %d\n", rtc->get_counts(rtc));
- twimap_printf(mapping,
- "ticking: %s\n",
- (rtc->state & RTC_STATE_MASKED) ? "no" : "yes");
+ struct hwrtc_potens* pot;
+ struct device* owner;
+
+ pot = twimap_data(mapping, struct hwrtc_potens*);
+ owner = pot->pot_meta.owner;
+
+ twimap_printf(mapping, "device: %x.%x\n",
+ owner->ident.fn_grp, owner->ident.unique);
+
+ twimap_printf(mapping, "frequency: %dHz\n", pot->base_freq);
+ twimap_printf(mapping, "ticks count: %d\n", pot->live);
+ twimap_printf(mapping, "ticking: %s\n",
+ (pot->state & RTC_STATE_MASKED) ? "no" : "yes");
datetime_t dt;
- rtc->get_walltime(rtc, &dt);
+ pot->ops->get_walltime(pot, &dt);
twimap_printf(
mapping, "recorded date: %d/%d/%d\n", dt.year, dt.month, dt.day);
}
static void
-hwrtc_twifs_export(struct hwrtc* rtc)
+hwrtc_twifs_export(struct hwrtc_potens* pot)
{
- const char* name = rtc->rtc_dev->name.value;
- struct twimap* rtc_mapping = twifs_mapping(NULL, rtc, name);
+ const char* name = pot->rtc_proxy->name_val;
+ struct twimap* rtc_mapping = twifs_mapping(NULL, pot, name);
rtc_mapping->read = __hwrtc_readinfo;
}
static void
hwrtc_twifs_export_all()
{
- struct hwrtc *pos, *next;
- llist_for_each(pos, next, &rtcs, rtc_list)
+ struct hwrtc_potens *pos, *next;
+ llist_for_each(pos, next, &rtcs, rtc_potentes)
{
hwrtc_twifs_export(pos);
}
assert(device_addalias(NULL, dev_meta(dev), "tty"));
- if (!device_get_capability(dev, TERMIOS_CAP)) {
+ if (!device_get_potens(dev, potens(TERMPORT))) {
FATAL("not a terminal device: %s", console_dev);
}
}
-struct termport_cap_ops default_termport_cap_ops = {
+struct termport_pot_ops default_termport_pot_ops = {
.set_cntrl_mode = __tpcap_default_set_cntrl_mode,
.set_clkbase = __tpcap_default_set_baseclk,
.set_speed = __tpcap_default_set_speed
#include <lunaix/process.h>
#include <lunaix/spike.h>
#include <lunaix/status.h>
+#include <lunaix/syslog.h>
#include <usr/lunaix/ioctl_defs.h>
+LOG_MODULE("term");
+
#define termdev(dev) ((struct term*)(dev)->underlay)
#define LCNTL_TABLE_LEN (sizeof(line_controls) / sizeof(struct term_lcntl*))
-static struct devclass termdev_class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_VTERM);
+static struct devclass termdev_class = DEVCLASS(LUNAIX, TTY, VTERM);
struct device* sysconsole = NULL;
+extern struct termport_pot_ops default_termport_pot_ops;
+
static int
term_exec_cmd(struct device* dev, u32_t req, va_list args)
{
tios->c_baud = term->iospeed;
} break;
case TDEV_TCSETATTR: {
- struct termport_cap_ops* cap_ops;
+ struct termport_pot_ops* pot_ops;
struct termios* tios = va_arg(args, struct termios*);
term->iflags = tios->c_iflag;
goto done;
}
- cap_ops = term->tp_cap->cap_ops;
+ pot_ops = term->tp_cap->ops;
if (tios->c_baud != term->iospeed) {
term->iospeed = tios->c_baud;
- cap_ops->set_speed(term->chdev, tios->c_baud);
+ pot_ops->set_speed(term->chdev, tios->c_baud);
}
if (old_cf != tios->c_cflag) {
- cap_ops->set_cntrl_mode(term->chdev, tios->c_cflag);
+ pot_ops->set_cntrl_mode(term->chdev, tios->c_cflag);
}
} break;
default:
terminal->scratch_pad = valloc(sz_hlf);
}
-struct term*
-term_create(struct device* chardev, char* suffix)
+struct termport_potens*
+term_attach_potens(struct device* chardev,
+ struct termport_pot_ops* ops, char* suffix)
{
struct term* terminal;
struct device* tdev;
- struct capability_meta* termport_cap;
- struct capability_meta* tios_cap;
+ struct termport_potens* tp_cap;
terminal = vzalloc(sizeof(struct term));
if (!terminal) {
int cdev_var = DEV_VAR_FROM(chardev->ident.unique);
register_device(tdev, &termdev_class, "tty%s%d", suffix, cdev_var);
} else {
- register_device(tdev, &termdev_class, "tty%d", termdev_class.variant++);
+ register_device_var(tdev, &termdev_class, "tty");
}
- termport_cap = device_get_capability(chardev, TERMPORT_CAP);
- if (termport_cap) {
- terminal->tp_cap =
- get_capability(termport_cap, struct termport_capability);
-
- assert(terminal->tp_cap->cap_ops);
- terminal->tp_cap->term = terminal;
- }
+ INFO("spawned: %s", tdev->name_val);
+
+ tp_cap = new_potens(potens(TERMPORT), struct termport_potens);
+ tp_cap->ops = ops ?: &default_termport_pot_ops;
+
+ terminal->tp_cap = tp_cap;
+ tp_cap->term = terminal;
- tios_cap = new_capability_marker(TERMIOS_CAP);
- device_grant_capability(tdev, tios_cap);
+ device_grant_potens(tdev, potens_meta(tp_cap));
load_default_setting(terminal);
- return terminal;
+ return tp_cap;
}
int
}
void
-term_notify_data_avaliable(struct termport_capability* cap)
+term_notify_data_avaliable(struct termport_potens* cap)
{
struct term* term;
struct device* term_chrdev;
#include <hal/hwtimer.h>
-const struct hwtimer* systimer;
+const struct hwtimer_pot* systimer = NULL;
-ticks_t
-hwtimer_base_frequency()
-{
- assert(systimer);
- return systimer->base_freq;
-}
+static struct device_alias* timer_alias;
+static DEFINE_LLIST(timer_devices);
ticks_t
hwtimer_current_systicks()
{
assert(systimer);
- return systimer->systicks();
+ return systimer->systick_raw;
}
ticks_t
hwtimer_to_ticks(u32_t value, int unit)
{
assert(systimer);
+
// in case system frequency is less than 1000Hz
if (unit != TIME_MS) {
return systimer->running_freq * unit * value;
return freq_ms * value;
}
-static int
-__hwtimer_ioctl(struct device* dev, u32_t req, va_list args)
+static struct hwtimer_pot*
+__select_timer()
{
- struct hwtimer* hwt = (struct hwtimer*)dev->underlay;
- switch (req) {
- case TIMERIO_GETINFO:
- // TODO
- break;
-
- default:
- break;
+ struct hwtimer_pot *pos, *n, *sel = NULL;
+
+ llist_for_each(pos, n, &timer_devices, timers)
+ {
+ if (unlikely(!sel)) {
+ sel = pos;
+ continue;
+ }
+
+ if (sel->precedence < pos->precedence) {
+ sel = pos;
+ }
}
- return 0;
+
+ return sel;
}
void
hwtimer_init(u32_t hertz, void* tick_callback)
{
- struct hwtimer* hwt_ctx = select_platform_timer();
+ struct hwtimer_pot* selected;
+ struct device* time_dev;
+
+ selected = __select_timer();
- hwt_ctx->init(hwt_ctx, hertz, tick_callback);
- hwt_ctx->running_freq = hertz;
+ assert(selected);
+ systimer = selected;
- systimer = hwt_ctx;
+ selected->callback = tick_callback;
+ selected->running_freq = hertz;
+
+ selected->ops->calibrate(selected, hertz);
+
+ time_dev = potens_dev(selected);
+ timer_alias = device_addalias(NULL, dev_meta(time_dev), "timer");
+}
+
+
+struct hwtimer_pot*
+hwtimer_attach_potens(struct device* dev, int precedence,
+ struct hwtimer_pot_ops* ops)
+{
+ struct hwtimer_pot* hwpot;
+ struct potens_meta* pot;
+
+ if (!potens_check_unique(dev, potens(HWTIMER)))
+ {
+ return NULL;
+ }
- struct device* timerdev = device_allocsys(NULL, hwt_ctx);
+ hwpot = new_potens(potens(HWTIMER), struct hwtimer_pot);
+ hwpot->ops = ops;
+ hwpot->precedence = precedence;
+
+ device_grant_potens(dev, potens_meta(hwpot));
- timerdev->ops.exec_cmd = __hwtimer_ioctl;
+ llist_append(&timer_devices, &hwpot->timers);
- register_device(timerdev, &hwt_ctx->class, hwt_ctx->name);
+ return hwpot;
}
\ No newline at end of file
#include <lunaix/ds/hstr.h>
#include <lunaix/ds/hashtable.h>
#include <lunaix/boot_generic.h>
+#include <lunaix/changeling.h>
+
+#include <klibc/string.h>
#define le(v) ((((v) >> 24) & 0x000000ff) |\
(((v) << 8) & 0x00ff0000) |\
typedef unsigned int* dt_enc_t;
typedef unsigned int dt_phnd_t;
-typedef bool (*node_predicate_t)(struct dt_node_iter*, struct dt_node*);
+
+struct dt_node_base;
+struct dt_node_iter;
+typedef bool (*node_predicate_t)(struct dt_node_iter*, struct dt_node_base*);
#define PHND_NULL ((dt_phnd_t)-1)
{
union {
const char* str_val;
- const char** str_lst;
+ const char* str_lst;
};
ptr_t ptr_val;
struct dt_prop_val val;
};
+struct dt_prop_table
+{
+ union {
+ struct hbucket other_props[0];
+ struct hbucket _op_bucket[8];
+ };
+};
+
struct dt_node_base
{
+ morph_t mobj;
+
union {
struct {
unsigned char addr_c;
};
struct dt_node_base *parent;
- struct llist_header children;
- struct llist_header siblings;
struct llist_header nodes;
- struct hlist_node phnd_link;
-
- const char* name;
struct dt_prop_val compat;
- const char* model;
dt_phnd_t phandle;
- union {
- struct hbucket other_props[0];
- struct hbucket _op_bucket[8];
- };
+ struct dt_prop_table* props;
void* obj;
+ morph_t* binded_dev;
};
struct dt_root
struct dt_node
{
- struct dt_node_base base;
+ union {
+ morph_t mobj;
+ struct dt_node_base base;
+ };
+
struct dt_intr_node intr;
struct dt_prop_val reg;
struct dt_prop_val ranges;
struct dt_prop_val dma_ranges;
};
-
+#define dt_parent(node) ((node)->base.parent)
+#define dt_morpher morphable_attrs(dt_node, mobj)
+#define dt_mobj(node) (&(node)->mobj)
struct dt_intr_prop
{
return !!iter->matched;
}
+struct dt_context*
+dt_main_context();
+
/****
* DT Main Functions: Node-binding
#define dtprop_extract(dtpi, off) \
( (dt_enc_t) (&(dtpi)->prop_loc[(off)]) )
+#define dtprop_strlst_foreach(pos, prop) \
+ for (pos = (prop)->str_lst; \
+ pos <= &(prop)->str_lst[(prop)->size]; \
+ pos = &pos[strlen(pos) + 1])
+
static inline bool
dtprop_next_n(struct dt_prop_iter* dtpi, int n)
{
--- /dev/null
+#ifndef __LUNAIX_DEVTREE_TOP_H
+#define __LUNAIX_DEVTREE_TOP_H
+
+struct device_def;
+struct device;
+
+#ifdef CONFIG_USE_DEVICETREE
+
+#include "devtree.h"
+#include <lunaix/ds/hashtable.h>
+#include <lunaix/ds/list.h>
+#include <klibc/hash.h>
+
+typedef struct dt_node* devtree_link_t;
+
+#define dt_node_morpher morphable_attrs(dt_node, mobj)
+
+struct dtm_driver_info
+{
+ struct list_node node;
+ const char* pattern;
+};
+
+struct dtm_driver_record
+{
+ struct hlist_node node;
+ struct list_head infos;
+ struct device_def* def;
+};
+
+void
+dtm_register_entry(struct device_def* def, const char* pattern);
+
+#else
+
+#include <lunaix/types.h>
+
+typedef void* devtree_link_t;
+
+static inline void
+dtm_register_entry(struct device_def* def, const char* pattern)
+{
+ return;
+}
+
+#endif
+
+#endif /* __LUNAIX_DEVTREE_TOP_H */
#define RTC_STATE_MASKED 0x1
-#define EXPORT_RTC_DEVICE(id, init_fn) \
- export_ldga_el(rtcdev, id, ptr_t, init_fn)
+struct hwrtc_potens;
+struct hwrtc_potens_ops
+{
+ void (*get_walltime)(struct hwrtc_potens*, datetime_t*);
+ void (*set_walltime)(struct hwrtc_potens*, datetime_t*);
+ void (*set_proactive)(struct hwrtc_potens*, bool);
+ int (*chfreq)(struct hwrtc_potens*, int);
+
+ int (*calibrate)(struct hwrtc_potens*);
+};
-struct hwrtc
+struct hwrtc_potens
{
- struct llist_header rtc_list;
- struct device* rtc_dev;
+ POTENS_META;
+
+ struct llist_header rtc_potentes;
+ struct device* rtc_proxy;
- int id;
- char* name;
- void* data;
ticks_t base_freq;
+ volatile ticks_t live;
int state;
- void (*get_walltime)(struct hwrtc*, datetime_t*);
- void (*set_walltime)(struct hwrtc*, datetime_t*);
- void (*set_mask)(struct hwrtc*);
- void (*cls_mask)(struct hwrtc*);
- int (*get_counts)(struct hwrtc*);
- int (*chfreq)(struct hwrtc*, int);
+ struct hwrtc_potens_ops* ops;
};
-struct hwrtc*
-hwrtc_alloc_new(char* name);
+void
+hwrtc_init();
void
hwrtc_walltime(datetime_t* dt);
-void
-hwrtc_register(struct devclass* class, struct hwrtc* rtc);
+struct hwrtc_potens*
+hwrtc_attach_potens(struct device* raw_rtcdev, struct hwrtc_potens_ops* ops);
#endif /* __LUNAIX_HWRTC_H */
typedef void (*timer_tick_cb)();
-struct hwtimer
-{
- char* name;
- void* data;
+#define HWTIMER_MIN_PRECEDENCE 0
+#define HWTIMER_MAX_PRECEDENCE 15
- struct devclass class;
- struct device* timer_dev;
+struct hwtimer_pot;
+struct hwtimer_pot_ops
+{
+ void (*calibrate)(struct hwtimer_pot*, u32_t hertz);
+};
- int (*supported)(struct hwtimer*);
- void (*init)(struct hwtimer*, u32_t hertz, timer_tick_cb);
- ticks_t (*systicks)();
+struct hwtimer_pot
+{
+ POTENS_META;
+
+ struct llist_header timers;
+
+ int precedence;
+ timer_tick_cb callback;
ticks_t base_freq;
ticks_t running_freq;
+ volatile ticks_t systick_raw;
+
+ struct hwtimer_pot_ops* ops;
};
void
hwtimer_init(u32_t hertz, void* tick_callback);
-struct hwtimer*
-select_platform_timer();
-
-ticks_t
-hwtimer_base_frequency();
-
ticks_t
hwtimer_current_systicks();
ticks_t
hwtimer_to_ticks(u32_t value, int unit);
+struct hwtimer_pot*
+hwtimer_attach_potens(struct device* dev, int precedence,
+ struct hwtimer_pot_ops* ops);
+
+
#endif /* __LUNAIX_HWTIMER_H */
#include <lunaix/device.h>
#include <lunaix/ds/ldga.h>
#include <lunaix/ds/llist.h>
+#include <lunaix/ds/hashtable.h>
#include <lunaix/types.h>
+#include <lunaix/changeling.h>
#include <asm-generic/isrm.h>
-#define EXPORT_PCI_DEVICE(id, pci_devdef, stage) \
- EXPORT_DEVICE(id, &(pci_devdef)->devdef, stage)
-
-#define PCI_MATCH_EXACT -1
-#define PCI_MATCH_ANY 0
-#define PCI_MATCH_VENDOR 0xffff
-
-#define PCI_TDEV 0x0
-#define PCI_TPCIBRIDGE 0x1
-#define PCI_TCARDBRIDGE 0x2
-
#define PCI_VENDOR_INVLD 0xffff
#define PCI_REG_VENDOR_DEV 0
#define PCILOC_DEV(loc) (((loc) >> 3) & 0x1f)
#define PCILOC_FN(loc) ((loc) & 0x7)
-#define PCI_ID_ANY (-1)
-
typedef unsigned int pci_reg_t;
typedef u16_t pciaddr_t;
u32_t type;
};
-struct pci_device
+struct pci_probe
{
- struct device dev;
- struct llist_header dev_chain;
- struct hlist_node dev_cache;
-
- struct
- {
- struct device* dev;
- struct device_def* def;
- } binding;
+ morph_t mobj;
pciaddr_t loc;
u16_t intr_info;
u32_t cspace_base;
u32_t msi_loc;
struct pci_base_addr bar[6];
-};
-#define PCI_DEVICE(devbase) (container_of((devbase), struct pci_device, dev))
-struct pci_device_list
-{
- struct llist_header peers;
- struct pci_device* pcidev;
+ struct device* bind;
};
+#define pci_probe_morpher morphable_attrs(pci_probe, mobj)
-typedef void* (*pci_drv_init)(struct pci_device*);
+typedef bool (*pci_id_checker_t)(struct pci_probe*);
-#define PCI_DEVIDENT(vendor, id) \
- ((((id) & 0xffff) << 16) | (((vendor) & 0xffff)))
-
-struct pci_device_def
+struct pci_registry
{
- struct device_def devdef;
+ struct hlist_node entries;
+ struct device_def* definition;
- bool (*test_compatibility)(struct pci_device_def*, struct pci_device*);
+ pci_id_checker_t check_compact;
};
-#define pcidev_def(dev_def_ptr) \
- container_of((dev_def_ptr), struct pci_device_def, devdef)
-#define binded_pcidev(pcidev) ((pcidev)->binding.def)
-
-/**
- * @brief 根据类型代码(Class Code)去在拓扑中寻找一个设备
- * 类型代码请参阅: PCI LB Spec. Appendix D.
- *
- * @return struct pci_device*
- */
-struct pci_device* pci_get_device_by_class(u32_t class);
-
-/**
- * @brief 根据设备商ID和设备ID,在拓扑中寻找一个设备
- *
- * @param vendorId
- * @param deviceId
- * @return struct pci_device*
- */
-struct pci_device*
-pci_get_device_by_id(u16_t vendorId, u16_t deviceId);
+bool
+pci_register_driver(struct device_def* def, pci_id_checker_t checker);
/**
* @brief 初始化PCI设备的基地址寄存器。返回由该基地址代表的,
* @return size_t
*/
size_t
-pci_bar_sizing(struct pci_device* dev, u32_t* bar_out, u32_t bar_num);
+pci_bar_sizing(struct pci_probe* probe, u32_t* bar_out, u32_t bar_num);
/**
* @brief Bind an abstract device instance to the pci device
*
* @param pcidev pci device
- * @param devobj abstract device instance
+ * @param dev abstract device instance
*/
-void
-pci_bind_instance(struct pci_device* pcidev, void* devobj);
+static inline void
+pci_bind_instance(struct pci_probe* probe, struct device* dev)
+{
+ probe->bind = dev;
-void
-pci_probe_bar_info(struct pci_device* device);
+}
-void
-pci_setup_msi(struct pci_device* device, msi_vector_t msiv);
+msienv_t
+pci_msi_start(struct pci_probe* probe);
-void
-pci_probe_msi_info(struct pci_device* device);
+msi_vector_t
+pci_msi_setup_at(msienv_t msienv, struct pci_probe* probe,
+ int i, isr_cb handler);
-int
-pci_bind_definition(struct pci_device_def* pcidev_def, bool* more);
+static inline void
+pci_msi_done(msienv_t env)
+{
+ isrm_msi_done(env);
+}
+
+static inline msi_vector_t
+pci_msi_setup_simple(struct pci_probe* probe, isr_cb handler)
+{
+ msienv_t env;
+ msi_vector_t msiv;
+
+ env = pci_msi_start(probe);
+ msiv = pci_msi_setup_at(env, probe, 0, handler);
+ pci_msi_done(env);
+
+ return msiv;
+}
int
-pci_bind_definition_all(struct pci_device_def* pcidef);
+pci_bind_driver(struct pci_registry* reg);
+
static inline unsigned int
-pci_device_vendor(struct pci_device* pcidev)
+pci_device_vendor(struct pci_probe* probe)
{
- return PCI_DEV_VENDOR(pcidev->device_info);
+ return PCI_DEV_VENDOR(probe->device_info);
}
static inline unsigned int
-pci_device_devid(struct pci_device* pcidev)
+pci_device_devid(struct pci_probe* probe)
{
- return PCI_DEV_DEVID(pcidev->device_info);
+ return PCI_DEV_DEVID(probe->device_info);
}
static inline unsigned int
-pci_device_class(struct pci_device* pcidev)
+pci_device_class(struct pci_probe* probe)
{
- return PCI_DEV_CLASS(pcidev->class_info);
+ return PCI_DEV_CLASS(probe->class_info);
}
static inline struct pci_base_addr*
-pci_device_bar(struct pci_device* pcidev, int index)
+pci_device_bar(struct pci_probe* probe, int index)
{
- return &pcidev->bar[index];
+ return &probe->bar[index];
}
static inline void
*cmd |= PCI_RCMD_MM_ACCESS;
}
+static inline ptr_t
+pci_requester_id(struct pci_probe* probe)
+{
+ return probe->loc;
+}
static inline void
pci_cmd_set_pmio(pci_reg_t* cmd)
}
static inline bool
-pci_capability_msi(struct pci_device* pcidev)
+pci_capability_msi(struct pci_probe* probe)
{
- return !!pcidev->msi_loc;
+ return !!probe->msi_loc;
}
static inline int
-pci_intr_irq(struct pci_device* pcidev)
+pci_intr_irq(struct pci_probe* probe)
{
- return PCI_INTR_IRQ(pcidev->intr_info);
+ return PCI_INTR_IRQ(probe->intr_info);
}
void
-pci_apply_command(struct pci_device* pcidev, pci_reg_t cmd);
+pci_apply_command(struct pci_probe* probe, pci_reg_t cmd);
pci_reg_t
pci_read_cspace(ptr_t base, int offset);
#include <lunaix/ds/mutex.h>
#include <lunaix/ds/waitq.h>
#include <lunaix/ds/rbuffer.h>
+#include <hal/term.h>
#include <usr/lunaix/serial.h>
struct rbuffer rxbuf;
int wr_len;
- struct capability_meta* tp_cap;
+ struct termport_potens* tp_cap;
/**
* @brief Write buffer to TX. The return code indicate
#define ref_next(lbuf) (&(lbuf)->next)
#define deref(bref) (*(bref))
-/**
- * @brief Communication port capability that a device is supported natively,
- * or able to emulate low level serial transmission behaviour specify
- * by POSIX1-2008, section 11.
- *
- */
-#define TERMPORT_CAP 0x4d524554U
-
-/**
- * @brief A termios capability that a device provide interfaces which is
- * compliant to POSIX1-2008
- *
- */
-#define TERMIOS_CAP 0x534f4954U
-
struct term;
-struct termport_cap_ops
+struct termport_pot_ops
{
void (*set_speed)(struct device*, speed_t);
void (*set_clkbase)(struct device*, unsigned int);
void (*set_cntrl_mode)(struct device*, tcflag_t);
};
-struct termport_capability
+struct termport_potens
{
- CAPABILITY_META;
- struct termport_cap_ops* cap_ops;
+ POTENS_META;
+ struct termport_pot_ops* ops;
struct term* term;
};
char* scratch_pad;
pid_t fggrp;
- struct termport_capability* tp_cap;
+ struct termport_potens* tp_cap;
waitq_t line_in_event;
/* -- POSIX.1-2008 compliant fields -- */
extern struct device* sysconsole;
-struct term*
-term_create(struct device* chardev, char* suffix);
+struct termport_potens*
+term_attach_potens(struct device* chardev,
+ struct termport_pot_ops* ops, char* suffix);
int
term_bind(struct term* tdev, struct device* chdev);
int
lcntl_transform_outseq(struct term* tdev);
-static inline void
-term_cap_set_operations(struct termport_capability* cap,
- struct termport_cap_ops* ops)
-{
- cap->cap_ops = ops;
-}
-
void
-term_notify_data_avaliable(struct termport_capability* cap);
-
-#define termport_default_ops \
- ({ \
- extern struct termport_cap_ops default_termport_cap_ops;\
- &default_termport_cap_ops; \
- })
+term_notify_data_avaliable(struct termport_potens* cap);
#endif /* __LUNAIX_TERM_H */
--- /dev/null
+morphable(dt_node),
+morphable(pci_probe),
+
+morphable(device_meta),
+morphable(device_cat),
+morphable(device_alias),
+morphable(device),
\ No newline at end of file
--- /dev/null
+/**
+ * @brief Communication port capability that a device is supported natively,
+ * or able to emulate low level serial transmission behaviour specify
+ * by POSIX1-2008, section 11.
+ *
+ */
+potens(TERMPORT),
+
+/**
+ * @brief Hardware timer capability that allow such device to be integrated
+ and utilised by timer subsystem
+ *
+ */
+potens(HWTIMER),
+
+/**
+ * @brief RTC capability.
+ *
+ */
+potens(HWRTC),
\ No newline at end of file
--- /dev/null
+dev_id(VTERM),
+dev_id(RNG),
+
+dev_id(RTC),
+
+dev_id(SATA),
+dev_id(NVME),
+dev_id(PCI),
+dev_id(UART16550),
+
+dev_id(TIMER),
+dev_id(TIMER_APIC),
+dev_id(TIMER_HEPT),
+
+dev_id(NIHIL),
+dev_id(ZERO),
+dev_id(KBD),
+dev_id(GFXA),
+dev_id(VGA),
+dev_id(INTC),
\ No newline at end of file
--- /dev/null
+dev_fn(PSEUDO),
+dev_fn(CHAR),
+dev_fn(STORAGE),
+dev_fn(INPUT),
+dev_fn(TIME),
+dev_fn(BUSIF),
+dev_fn(TTY),
+dev_fn(DISP),
+dev_fn(CFG)
\ No newline at end of file
--- /dev/null
+dev_vn(LUNAIX),
+dev_vn(INTEL),
+dev_vn(ARM),
\ No newline at end of file
--- /dev/null
+#ifndef __LUNAIX_CHANGELING_H
+#define __LUNAIX_CHANGELING_H
+
+#include <lunaix/types.h>
+#include <lunaix/ds/llist.h>
+#include <lunaix/spike.h>
+#include <lunaix/ds/hstr.h>
+
+#define CHLG_ID (unsigned short)0x4c43
+
+#define morphable(struct_name) chlg_##struct_name
+#define __morpher_id(struct_name, field) morphable(struct_name)
+#define morpher_id(morpher) __morpher_id(morpher)
+
+enum changeling_idents
+{
+ morphable(anon) = 0,
+ #include <listings/changeling.lst>
+};
+
+/**
+ * changeling - a proud changeling of her majesty :)
+ * changeling reginae superbum
+ */
+struct changeling
+{
+ struct {
+ union {
+ struct
+ {
+ unsigned short sig;
+ unsigned short ident;
+ };
+
+ unsigned int magic;
+ };
+ };
+
+ int ref;
+ unsigned int uid;
+
+ struct changeling *parent;
+ struct llist_header sibs;
+ struct llist_header subs;
+ struct hstr name;
+};
+
+typedef struct changeling morph_t;
+
+#define morphable_attrs(struct_name, field) struct_name, field
+#define morphed_ptr(ptr_like) ((morph_t*)__ptr(ptr_like))
+#define morpher_uid(mobj) ((mobj)->uid)
+
+#define __changeling_morph(parent, chlg, name, struct_name, field) \
+ ({ \
+ changeling_init(parent, &(chlg), chlg_##struct_name, name); \
+ &(chlg); \
+ })
+
+#define __morph_type_of(chlg, struct_name, field) \
+ ((chlg)->ident == chlg_##struct_name)
+
+#define __changeling_cast(chlg, struct_name, field) \
+ container_of(chlg, struct struct_name, field)
+
+#define __changeling_try_reveal(chlg, struct_name, field) \
+ ({ \
+ struct struct_name* __r = NULL; \
+ if (__changeling_of(chlg, struct_name, field)) \
+ __r = __changeling_cast(chlg, struct_name, field); \
+ __r; \
+ })
+
+#define __changeling_reveal(chlg, struct_name, field) \
+ ({ \
+ struct struct_name* __r; \
+ __r = __changeling_try_reveal(chlg, struct_name, field); \
+ assert(__r); __r; \
+ })
+
+#define __changeling_of(chlg, struct_name, field) \
+ (chlg && (chlg)->sig == CHLG_ID \
+ && __morph_type_of(chlg, struct_name, field))
+
+
+#define changeling_morph(parent, chlg, name, morpher) \
+ __changeling_morph(parent, chlg, name, morpher)
+
+
+#define changeling_morph_anon(parent, chlg, morpher) \
+ __changeling_morph(parent, chlg, NULL, morpher)
+
+
+#define is_changeling(maybe_chlg) \
+ ((maybe_chlg) && morphed_ptr(maybe_chlg)->sig == CHLG_ID)
+
+
+#define morph_type_of(chlg, morpher) \
+ __morph_type_of(chlg, morpher)
+
+#define changeling_of(chlg, morpher) \
+ __changeling_of(chlg, morpher)
+
+#define changeling_try_reveal(chlg, morpher) \
+ __changeling_try_reveal(chlg, morpher)
+
+#define changeling_reveal(chlg, morpher) \
+ __changeling_reveal(chlg, morpher)
+
+#define changeling_for_each(pos, n, parent) \
+ llist_for_each(pos, n, &(parent)->subs, sibs)
+
+static inline morph_t*
+changeling_ref(morph_t* chlg)
+{
+ return ({ chlg->ref++; chlg; });
+}
+
+static inline morph_t*
+changeling_unref(morph_t* chlg)
+{
+ assert(chlg->ref > 0);
+ return ({ chlg->ref--; chlg; });
+}
+
+static inline void
+changeling_detach(morph_t* obj)
+{
+ if (llist_empty(&obj->sibs)) {
+ return;
+ }
+
+ changeling_unref(obj);
+ llist_delete(&obj->sibs);
+}
+
+static inline morph_t*
+changeling_attach(morph_t* parent, morph_t* obj)
+{
+ changeling_detach(obj);
+
+ llist_append(&parent->subs, &obj->sibs);
+ obj->parent = parent;
+
+ return changeling_ref(obj);
+}
+
+static inline void
+changeling_isolate(morph_t* obj)
+{
+ changeling_detach(obj);
+ assert(obj->ref == 0);
+}
+
+void
+changeling_init(morph_t* parent, morph_t* chlg,
+ unsigned int id, const char* name);
+
+morph_t*
+changeling_spawn(morph_t* parent, const char* name);
+
+morph_t*
+changeling_find(morph_t* parent, struct hstr* str);
+
+morph_t*
+changeling_get_at(morph_t* parent, int index);
+
+morph_t*
+changeling_setname(morph_t* chlg, const char* name);
+
+#endif /* __LUNAIX_CHANGELING_H */
#include <hal/hwrtc.h>
#include <hal/hwtimer.h>
-extern const struct hwrtc* sysrtc;
-extern const struct hwtimer* systimer;
-
-void
-clock_init();
+extern const struct hwrtc_potens* sysrtc;
+extern const struct hwtimer_pot* systimer;
void
clock_walltime(datetime_t* datetime);
time_t
clock_unixtime();
+static inline void
+clock_init()
+{
+ hwrtc_init();
+}
+
#endif /* __LUNAIX_CLOCK_H */
#define __section(name) __attribute__((section(name)))
#define weak_alias(name) __attribute__((weak, alias(name)))
#define optimize(opt) __attribute__((optimize(opt)))
-#define weak __attribute__((weak))
+#define _weak __attribute__((weak))
#define noret __attribute__((noreturn))
#define must_inline __attribute__((always_inline))
#define must_emit __attribute__((used))
#define unreachable __builtin_unreachable()
#define no_inline __attribute__((noinline))
-#define _default weak
+#define _default _weak
#define msbiti (sizeof(int) * 8 - 1)
#define clz(bits) __builtin_clz(bits)
#ifndef __LUNAIX_DEVICE_H
#define __LUNAIX_DEVICE_H
-#define DEVICE_NAME_SIZE 32
+#define DEVICE_NAME_SIZE 16
#include <lunaix/device_num.h>
#include <lunaix/ds/hashtable.h>
#include <lunaix/ds/mutex.h>
#include <lunaix/iopoll.h>
#include <lunaix/types.h>
+#include <lunaix/changeling.h>
+
+#include <hal/devtreem.h>
#include <usr/lunaix/device.h>
*/
#define load_sysconf ld_sysconf
-/**
- * @brief Mark the device definition should be loaded as time device, for
- * example a real time clock device. Such device will be loaded and managed by
- * clock subsystem
- */
-#define load_timedev ld_timedev
-
/**
* @brief Mark the device definition should be loaded automatically during the
* bootstrapping stage. Most of the driver do load there.
* @brief Declare a device class
*
*/
-#define DEVCLASS(devif, devfn, dev) \
+#define DEVCLASS(vendor, devfn, dev) \
(struct devclass) \
{ \
- .fn_grp = DEV_FNGRP(devif, devfn), .device = (dev), .variant = 0 \
+ .fn_grp = DEV_FNGRP(dev_vn(vendor), dev_fn(devfn)), \
+ .device = dev_id(dev), .variant = 0 \
}
-#define DEVCLASSV(devif, devfn, dev, devvar) \
- (struct devclass) \
- { \
- .fn_grp = DEV_FNGRP(devif, devfn), .device = (dev), \
- .variant = (devvar) \
- }
-
-#define DEV_STRUCT_MAGIC_MASK 0x56454440U
-#define DEV_STRUCT 0xc
-#define DEV_CAT 0xd
-#define DEV_ALIAS 0xf
-
-#define DEV_STRUCT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_STRUCT)
-#define DEV_CAT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_CAT)
-#define DEV_ALIAS_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_ALIAS)
-
#define DEV_MSKIF 0x00000003
-
#define DEV_IFVOL 0x0 // volumetric (block) device
#define DEV_IFSEQ 0x1 // sequential (character) device
#define DEV_IFSYS 0x3 // a system device
-struct capability_meta
+#define dev_object_root \
+ ({ extern morph_t* device_mobj_root; device_mobj_root; })
+
+/**
+ * A potens is a capability of the device
+ * ("potens", means "capable" in latin)
+ *
+ * A device can have multiple capabilities
+ * (or "potentes", plural form of potens)
+ *
+ * A group of devices with same capability will forms
+ * a "globus potentis" or "capability group". The
+ * group is completely a logical formation, meaning
+ * that it is not explictly coded.
+ *
+ * The idea of potens is to provide a unified and yet
+ * opaque method to decouple the device provide raw
+ * functionalities with any higher abstraction, such
+ * as other subsystem, or standard-compilance wrapper
+ * (e.g., POSIX terminal)
+ */
+struct potens_meta
{
- struct llist_header caps;
- unsigned int cap_type;
+ struct device* owner;
+
+ struct llist_header potentes;
+ unsigned int pot_type;
};
-#define CAPABILITY_META \
- union { \
- struct capability_meta cap_meta; \
- struct { \
- struct llist_header caps; \
- unsigned int cap_type; \
- }; \
+#define POTENS_META \
+ struct { \
+ union { \
+ struct potens_meta pot_meta; \
+ struct { \
+ struct llist_header potentes; \
+ unsigned int pot_type; \
+ }; \
+ }; \
}
-#define get_capability(cap, cap_type) \
- container_of((cap), cap_type, cap_meta)
-#define cap_meta(cap) (&(cap)->cap_meta)
+#define get_potens(cap, pot_struct) \
+ container_of((cap), pot_struct, pot_meta)
+#define potens_meta(cap) (&(cap)->pot_meta)
+#define potens_dev(cap) (potens_meta(cap)->owner)
-typedef struct llist_header capability_list_t;
+#define potens(name) POTENS_##name
+#define potens_check_unique(dev, pot_type) \
+ !device_get_potens(dev, pot_type)
-struct device_meta
+enum device_potens_type
{
- u32_t magic;
- struct llist_header siblings;
- struct llist_header children;
- struct device_meta* parent;
- struct hstr name;
-
- u32_t dev_uid;
-
- char name_val[DEVICE_NAME_SIZE];
+ potens(NON),
+ #include <listings/device_potens.lst>
};
+/**
+ * List of potentes of a device, pay attention to
+ * the spelling, "potentium", genitive plural of "potens".
+ */
+typedef struct llist_header potentium_list_t;
+
+
+#define DEVICE_META_FIELD \
+ struct { \
+ morph_t mobj; \
+ char name_val[DEVICE_NAME_SIZE]; \
+ };
+
#define DEVICE_METADATA \
union { \
struct device_meta meta; \
- struct { \
- u32_t magic; \
- struct llist_header siblings; \
- struct llist_header children; \
- struct device_meta* parent; \
- struct hstr name; \
- \
- u32_t dev_uid; \
- \
- char name_val[DEVICE_NAME_SIZE]; \
- }; \
- }
-
-#define dev_meta(dev) (&(dev)->meta)
-#define to_dev(dev) (container_of(dev,struct device, meta))
-#define to_catdev(dev) (container_of(dev,struct device_cat, meta))
-#define to_aliasdev(dev) (container_of(dev,struct device_alias, meta))
+ DEVICE_META_FIELD; \
+ }
+
+#define devmeta_morpher morphable_attrs(device_meta, mobj)
+#define devalias_morpher morphable_attrs(device_alias, mobj)
+#define devcat_morpher morphable_attrs(device_cat, mobj)
+#define device_morpher morphable_attrs(device, mobj)
+
+#define dev_meta(dev) (&(dev)->meta)
+#define dev_mobj(dev) (&(dev)->mobj)
+#define dev_morph(dev) ({ likely(dev) ? &(dev)->mobj : dev_object_root; })
+#define dev_uid(dev) (morpher_uid(&(dev)->mobj))
+#define to_dev(dev) (container_of(dev,struct device, meta))
+#define to_catdev(dev) (container_of(dev,struct device_cat, meta))
+#define to_aliasdev(dev) (container_of(dev,struct device_alias, meta))
+
+struct device_meta
+{
+ DEVICE_META_FIELD;
+};
struct device_alias {
DEVICE_METADATA;
DEVICE_METADATA;
- capability_list_t capabilities;
+ potentium_list_t potentium;
+
+#ifdef CONFIG_USE_DEVICETREE
+ devtree_link_t devtree_node;
+#endif
/* -- device state -- */
} ops;
};
+struct device_def;
+typedef int (*devdef_ldfn)(struct device_def*);
+
+struct device_ldfn_chain
+{
+ struct device_ldfn_chain* chain;
+ devdef_ldfn load;
+};
+
struct device_def
{
struct llist_header dev_list;
struct hlist_node hlist_if;
char* name;
- struct devclass class;
+ union
+ {
+ struct {
+ bool no_default_realm : 1;
+ };
+ int val;
+ } flags;
+
+
+ struct {
+ struct devclass class;
+ unsigned int class_hash;
+ };
+
+ struct device_ldfn_chain* load_chain;
/**
- * @brief Called when the driver is required to initialize itself.
+ * @brief
+ * Called when driver is required to register itself to the system
+ * All registration code should put it here.
+ *
+ * ad tabulam -
+ * "to the record" in latin. just in case anyone wonders.
+ * I am ran out of naming idea... have to improvise :)
*
*/
- int (*init)(struct device_def*);
+ devdef_ldfn ad_tabulam;
/**
- * @brief Called when the driver is required to bind with a device. This is
- * the case for a real-hardware-oriented driver
+ * @brief Called when the driver is loaded at it's desired load stage
*
*/
- int (*bind)(struct device_def*, struct device*);
+ devdef_ldfn load;
+
+ /**
+ * @brief Called when the driver is required to create device instance
+ * This is for device with their own preference of creation
+ * object that hold parameter for such creation is provided by second argument.
+ */
+ int (*create)(struct device_def*, morph_t*);
/**
* @brief Called when a driver is requested to detach from the device and
int (*free)(struct device_def*, void* instance);
};
-static inline bool must_inline
-valid_device_ref(void* maybe_dev) {
- if (!maybe_dev)
- return false;
-
- unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
- return (magic ^ DEV_STRUCT_MAGIC_MASK) <= 0xfU;
-}
-
-static inline bool must_inline
-valid_device_subtype_ref(void* maybe_dev, unsigned int subtype) {
- if (!maybe_dev)
- return false;
-
- unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
- return (magic ^ DEV_STRUCT_MAGIC_MASK) == subtype;
-}
-
-struct device*
-resolve_device(void* maybe_dev);
+#define def_device_name(dev_n) .name = dev_n
+#define def_device_class(_if, fn, dev) .class = DEVCLASS(_if, fn, dev)
+#define def_on_register(fn) .ad_tabulam = fn
+#define def_on_load(fn) .load = fn
+#define def_on_create(fn) .create = fn
+#define def_on_free(fn) .free = fn
+#define def_non_trivial .flags.no_default_realm = true
-struct device_meta*
-resolve_device_meta(void* maybe_dev);
+morph_t*
+resolve_device_morph(void* maybe_dev);
#define mark_device_doing_write(dev_ptr) (dev_ptr)->poll_evflags &= ~_POLLOUT
#define mark_device_done_write(dev_ptr) (dev_ptr)->poll_evflags |= _POLLOUT
return ((class->device & 0xffff) << 16) | ((class->variant & 0xffff));
}
+static inline struct device*
+resolve_device(void* maybe_dev) {
+ morph_t* mobj = resolve_device_morph(maybe_dev);
+ return changeling_try_reveal(mobj, device_morpher);
+}
+
void
device_scan_drivers();
device_setname(struct device_meta* dev, char* fmt, ...);
void
-device_register_generic(struct device_meta* dev, struct devclass* class, char* fmt, ...);
+device_register_generic(struct device_meta* dev, struct devclass* class,
+ char* fmt, ...);
#define register_device(dev, class, fmt, ...) \
device_register_generic(dev_meta(dev), class, fmt, ## __VA_ARGS__)
+#define register_device_var(dev, class, fmt, ...) \
+ ({device_register_generic( \
+ dev_meta(dev), class, \
+ fmt "%d", ## __VA_ARGS__, (class)->variant); \
+ devclass_mkvar(class); })
+
void
device_create(struct device* dev,
struct device_meta* parent,
struct device*
device_alloc(struct device_meta* parent, u32_t type, void* underlay);
+static inline void
+device_set_devtree_node(struct device* dev, devtree_link_t node)
+{
+ dev->devtree_node = node;
+}
+
static inline struct device* must_inline
device_allocsys(struct device_meta* parent, void* underlay)
{
}
struct device_alias*
-device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...);
+device_addalias(struct device_meta* parent, struct device_meta* aliased,
+ char* name_fmt, ...);
struct device_cat*
device_addcat(struct device_meta* parent, char* name_fmt, ...);
void
device_remove(struct device_meta* dev);
-struct device_meta*
-device_getbyid(struct llist_header* devlist, u32_t id);
-
-struct device_meta*
-device_getbyhname(struct device_meta* root_dev, struct hstr* name);
-
-struct device_meta*
-device_getbyname(struct device_meta* root_dev, const char* name, size_t len);
-
-struct device_meta*
-device_getbyoffset(struct device_meta* root_dev, int pos);
-
struct hbucket*
device_definitions_byif(int if_type);
/*------ Capability ------*/
-struct capability_meta*
-alloc_capability(int cap, unsigned int size);
+struct potens_meta*
+alloc_potens(int cap, unsigned int size);
-#define new_capability(cap_type, cap_impl)\
- ((cap_impl*)alloc_capability((cap_type), sizeof(cap_impl)))
+#define new_potens(pot_type, pot_struct)\
+ ((pot_struct*)alloc_potens((pot_type), sizeof(pot_struct)))
-#define new_capability_marker(cap_type)\
- (alloc_capability((cap_type), sizeof(struct capability_meta)))
+#define new_potens_marker(pot_type)\
+ (alloc_potens((pot_type), sizeof(struct potens_meta)))
void
-device_grant_capability(struct device* dev, struct capability_meta* cap);
+device_grant_potens(struct device* dev, struct potens_meta* cap);
+
+struct potens_meta*
+device_get_potens(struct device* dev, unsigned int pot_type);
-struct capability_meta*
-device_get_capability(struct device* dev, unsigned int cap_type);
/*------ Load hooks ------*/
void
void
device_sysconf_load();
+/**
+ * @brief Add the loader to the chain, used by device domain
+ * to inject their custom loading logic to the hook
+ */
+void
+device_chain_loader(struct device_def* def, devdef_ldfn fn);
+
+/**
+ * @brief Walk the chain and load in a use-and-burnt fashion.
+ * the chain will be deleted and freed after loading,
+ * regardless successful or not.
+ */
+void
+device_chain_load_once(struct device_def* def);
+
static inline void
device_lock(struct device* dev)
{
#define devprintf_expand(devident) (devident)->fn_grp, (devident)->unique
+
+/**
+ *
+ * Device def hooks extern
+ *
+ */
+
+static int
+default_onregister_hook(struct device_def* def)
+{
+ return 0;
+}
+
+static int
+default_onload_hook(struct device_def* def)
+{
+ return 0;
+}
+
+static int
+default_oncreate_hook(struct device_def* def, morph_t* morphed)
+{
+ return 0;
+}
+
+#define extern_hook_register(name) \
+ int weak_alias("default_onregister_hook") \
+ name(struct device_def* def)
+
+#define extern_hook_load(name) \
+ int weak_alias("default_onload_hook") \
+ name(struct device_def* def)
+
+#define extern_hook_create(name) \
+ int weak_alias("default_oncreate_hook") \
+ name(struct device_def* def, morph_t* morphed)
+
+
#endif /* __LUNAIX_DEVICE_H */
*/
-#define DEV_FNGRP(if_, function) \
- (((if_) & 0xffff) << 16) | ((function) & 0xffff)
+#define DEV_FNGRP(vendor, function) \
+ (((vendor) & 0xffff) << 16) | ((function) & 0xffff)
#define DEV_UNIQUE(devkind, variant) \
(((devkind) & 0xffff) << 16) | ((variant) & 0xffff)
#define DEV_KIND_FROM(unique) ((unique) >> 16)
#define DEV_VAR_FROM(unique) ((unique) & 0xffff)
-#define DEV_IF(fngrp) ((fngrp) >> 16)
+#define DEV_VN(fngrp) ((fngrp) >> 16)
#define DEV_FN(fngrp) (((fngrp) & 0xffff))
-#define DEVIF_NON 0x0
-#define DEVIF_SOC 0x1
-#define DEVIF_PCI 0x2
-#define DEVIF_USB 0x3
-#define DEVIF_SPI 0x4
-#define DEVIF_I2C 0x5
-#define DEVIF_FMW 0x6
-
-#define DEVFN_PSEUDO 0x0
-#define DEVFN_CHAR 0x1
-#define DEVFN_STORAGE 0x4
-#define DEVFN_INPUT 0x5
-#define DEVFN_TIME 0x6
-#define DEVFN_BUSIF 0x7
-#define DEVFN_TTY 0x8
-#define DEVFN_DISP 0x9
-#define DEVFN_CFG 0xa
-
-#define DEV_BUILTIN 0
-#define DEV_BUILTIN_NULL 0
-#define DEV_BUILTIN_ZERO 1
-#define DEV_BUILTIN_KMSG 2
-
-#define DEV_VTERM 1
-#define DEV_RNG 2
-#define DEV_RTC 3
-#define DEV_SATA 4
-#define DEV_NVME 5
-#define DEV_PCI 6
-#define DEV_UART16550 7
-
-#define DEV_TIMER 8
-#define DEV_TIMER_APIC 0
-#define DEV_TIMER_HEPT 1
-
-#define DEV_NULL 9
-#define DEV_ZERO 10
-#define DEV_KBD 11
-#define DEV_GFXA 12
-#define DEV_VGA 13
-#define DEV_ACPI 14
+#define dev_vn(x) DEVVN_##x
+#define dev_fn(x) DEVFN_##x
+#define dev_id(x) DEV_##x
+
+enum devnum_vn
+{
+ dev_vn(GENERIC),
+ #include <listings/devnum_vn.lst>
+};
+
+enum devnum_fn
+{
+ dev_fn(NON),
+ #include <listings/devnum_fn.lst>
+};
+
+enum devnum
+{
+ dev_id(NON),
+ #include <listings/devnum.lst>
+};
struct devident
{
u32_t fn_grp;
u32_t device;
u32_t variant;
- u32_t hash;
};
+static inline int
+devclass_mkvar(struct devclass* class)
+{
+ return class->variant++;
+}
+
#endif /* __LUNAIX_DEVICE_NUM_H */
--- /dev/null
+/**
+ * @file slist.h
+ * @author Lunaixsky
+ * @brief This singly linked list is adopted from Linux kernel
+ * <linux/llist.h>
+ * @version 0.1
+ * @date 2022-03-12
+ *
+ * @copyright Copyright (c) 2024
+ *
+ */
+#ifndef __LUNAIX_LIST_H
+#define __LUNAIX_LIST_H
+
+#include <lunaix/types.h>
+
+struct list_head {
+ struct list_node *first;
+};
+
+struct list_node {
+ struct list_node *next;
+};
+
+#define DEFINE_LIST(name) struct list_head name = { .first = NULL }
+
+static inline void
+list_head_init(struct list_head *list)
+{
+ list->first = NULL;
+}
+
+static inline void
+list_node_init(struct list_node *node)
+{
+ node->next = node;
+}
+
+#define slist_entry(ptr, type, member) \
+ container_of(ptr, type, member)
+
+#define member_address_is_nonnull(ptr, member) \
+ ((ptr_t)(ptr) + offsetof(typeof(*(ptr)), member) != 0)
+
+#define list_for_each(pos, n, node, member) \
+ for (pos = slist_entry((node), typeof(*pos), member); \
+ member_address_is_nonnull(pos, member) && \
+ (n = slist_entry(pos->member.next, typeof(*n), member), true); \
+ pos = n)
+
+static inline bool
+__llist_add_batch(struct list_node *new_first,
+ struct list_node *new_last,
+ struct list_head *head)
+{
+ new_last->next = head->first;
+ head->first = new_first;
+ return new_last->next == NULL;
+}
+
+static inline void
+list_add(struct list_head* head, struct list_node* node)
+{
+ __llist_add_batch(node, node, head);
+}
+
+#endif /* __LUNAIX_LIST_H */
* @brief stage where only basic memory management service
* is present
*/
+#define on_sysconf c_sysconf
+
+/**
+ * @brief stage where basic memory management service
+ * interrupt management and timer/clock service avaliable
+ */
#define on_earlyboot c_earlyboot
/**
#define invoke_init_function(stage) ldga_invoke_fn0(lunainit##_##stage)
+static inline void
+initfn_invoke_sysconf()
+{
+ invoke_init_function(on_sysconf);
+}
+
+static inline void
+initfn_invoke_earlyboot()
+{
+ invoke_init_function(on_earlyboot);
+}
+
+static inline void
+initfn_invoke_boot()
+{
+ invoke_init_function(on_boot);
+}
+
+static inline void
+initfn_invoke_postboot()
+{
+ invoke_init_function(on_postboot);
+}
+
#endif /* __LUNAIX_OWLOYSIUS_H */
/* Auto-generated data */
#define extern_autogen(name) \
- weak unsigned long __mark_name(autogen,name)[] = {}; \
+ _weak unsigned long __mark_name(autogen,name)[] = {}; \
extern unsigned long __mark_name(autogen,name)[];
#define autogen_name(name) __mark_name(autogen,name)
#define TIMER_MODE_PERIODIC 0x1
-struct lx_timer_context
-{
- struct lx_timer* active_timers;
- /**
- * @brief timer hardware base frequency (ticks per seconds)
- *
- */
- ticks_t base_frequency;
- /**
- * @brief Desired system running frequency
- *
- */
- ticks_t running_frequency;
- /**
- * @brief Ticks per hertz
- *
- */
- ticks_t tphz;
-};
-
-struct timer_init_param
-{
- struct lx_timer_context* context;
- void* timer_update_isr;
-};
-
struct lx_timer
{
struct llist_header link;
struct lx_timer*
timer_run(ticks_t ticks, void (*callback)(void*), void* payload, u8_t flags);
-struct lx_timer_context*
-timer_context();
-
#endif /* __LUNAIX_TIMER_H */
"lrud.c",
"bcache.c",
"syscall.c",
+ "changeling.c",
"kprint/kp_records.c",
"kprint/kprintf.c",
"time/clock.c",
bb_zone = bcache_create_zone("blk_buf");
bb_pile = cake_new_pile("blk_buf", sizeof(struct blk_buf), 1, 0);
}
-owloysius_fetch_init(__init_blkbuf, on_earlyboot)
\ No newline at end of file
+owloysius_fetch_init(__init_blkbuf, on_sysconf)
\ No newline at end of file
--- /dev/null
+#include <lunaix/changeling.h>
+#include <lunaix/mm/valloc.h>
+
+#include <klibc/string.h>
+
+static DEFINE_LLIST(chrysallidis);
+static unsigned int current_id = 0;
+
+void
+changeling_init(morph_t* parent, morph_t* chlg,
+ unsigned int id, const char* name)
+{
+ chlg->sig = CHLG_ID;
+ chlg->ident = id;
+ chlg->ref = 1;
+ chlg->uid = current_id++;
+
+ changeling_setname(chlg, name);
+
+ if (!parent) {
+ llist_append(&chrysallidis, &chlg->sibs);
+ } else {
+ llist_append(&parent->subs, &chlg->sibs);
+ }
+
+ llist_init_head(&chlg->subs);
+}
+
+morph_t*
+changeling_spawn(morph_t* parent, const char *name)
+{
+ morph_t* changeling;
+
+ changeling = valloc(sizeof(morph_t));
+ changeling_init(parent, changeling, chlg_anon, name);
+
+ return changeling;
+}
+
+morph_t*
+changeling_find(morph_t* parent, struct hstr* str)
+{
+ morph_t *p, *n;
+ llist_for_each(p, n, &parent->subs, sibs)
+ {
+ if (HSTR_EQ(&p->name, str)) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+morph_t*
+changeling_get_at(morph_t* parent, int index)
+{
+ morph_t *p, *n;
+ llist_for_each(p, n, &parent->subs, sibs)
+ {
+ if (!(index--)) {
+ return p;
+ }
+ }
+
+ return NULL;
+}
+
+morph_t*
+changeling_setname(morph_t* chlg, const char* name)
+{
+ if (name) {
+ chlg->name = HSTR(name, strlen(name));
+ hstr_rehash(&chlg->name, HSTR_FULL_HASH);
+ } else {
+ chlg->name = HHSTR(NULL, 0, 0);
+ }
+
+ return chlg;
+}
\ No newline at end of file
sources([
"device.c",
- "capability.c",
+ "potentem.c",
"devdb.c",
"devfs.c",
"input.c",
- "poll.c"
+ "poll.c",
])
+++ /dev/null
-#include <lunaix/device.h>
-#include <lunaix/mm/valloc.h>
-
-struct capability_meta*
-alloc_capability(int cap, unsigned int size)
-{
- struct capability_meta* cm = (struct capability_meta*)vzalloc(size);
-
- cm->cap_type = cap;
-
- return cm;
-}
-
-void
-device_grant_capability(struct device* dev, struct capability_meta* cap)
-{
- llist_append(&dev->capabilities, &cap->caps);
-}
-
-struct capability_meta*
-device_get_capability(struct device* dev, unsigned int cap_type)
-{
- struct capability_meta *pos, *n;
-
- llist_for_each(pos, n, &dev->capabilities, caps) {
- if (pos->cap_type == cap_type){
- return pos;
- }
- }
-
- return NULL;
-}
\ No newline at end of file
#include <lunaix/device.h>
#include <lunaix/fs/twifs.h>
#include <lunaix/status.h>
+#include <lunaix/syslog.h>
#include <klibc/hash.h>
#include <klibc/strfmt.h>
+LOG_MODULE("devdb")
+
static DECLARE_HASHTABLE(dev_registry, 32);
static DECLARE_HASHTABLE(dev_byif, 8);
static DEFINE_LLIST(dev_registry_flat);
hashtable_init(dev_registry);
hashtable_init(dev_byif);
- int idx = 0;
+ int idx = 0, errno;
struct device_def* devdef;
ldga_foreach(devdefs, struct device_def*, idx, devdef)
{
struct devclass* devc = &devdef->class;
u32_t hash = hash_dev(devc->fn_grp, devc->device);
- devc->hash = hash;
+ devdef->class_hash = hash;
if (!devdef->name) {
devdef->name = "<unspecified>";
}
+ errno = 0;
+ if (devdef->ad_tabulam) {
+ errno = devdef->ad_tabulam(devdef);
+ }
+
+ if (errno) {
+ ERROR("driver unable to register %xh:%xh.%d (err=%d)",
+ devdef->class.fn_grp,
+ devdef->class.device,
+ devdef->class.variant, errno);
+ continue;
+ }
+
hashtable_hash_in(dev_registry, &devdef->hlist, hash);
- hashtable_hash_in(dev_byif, &devdef->hlist_if, DEV_IF(devc->fn_grp));
+ hashtable_hash_in(dev_byif, &devdef->hlist_if, DEV_VN(devc->fn_grp));
llist_append(&dev_registry_flat, &devdef->dev_list);
}
struct device_def *pos, *n;
hashtable_hash_foreach(dev_registry, hash, pos, n, hlist)
{
- if (pos->class.hash != hash) {
+ if (pos->class_hash != hash) {
continue;
}
if (devclass_eq(devc, &pos->class)) {
struct device_def* devdef; \
ldga_foreach(dev_##stage, struct device_def*, idx, devdef) \
{ \
- devdef->init(devdef); \
+ device_chain_load_once(devdef); \
} \
})
#define device_load_on_stage(stage) __device_load_on_stage(stage)
struct device_def* def = twimap_index(mapping, struct device_def*);
int meta = def->class.fn_grp;
- ksnprintf(flags, 64, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
+ ksnprintf(flags, 64, "vn=%x, fn=%x", DEV_VN(meta), DEV_FN(meta));
twimap_printf(mapping,
"%08xh:%04d \"%s\" %s\n",
}
int
-devfs_get_itype(struct device_meta* dm)
+devfs_get_itype(morph_t* obj)
{
int itype = VFS_IFDEV;
- if (valid_device_subtype_ref(dm, DEV_CAT)) {
+ if (morph_type_of(obj, devcat_morpher)) {
return VFS_IFDIR;
}
- struct device* dev = resolve_device(dm);
- int dev_if = dev->dev_type & DEV_MSKIF;
+ struct device* dev = resolve_device(obj);
+
+ if (!dev) {
+ return itype;
+ }
+ int dev_if = dev->dev_type & DEV_MSKIF;
if (dev_if == DEV_IFVOL) {
itype |= VFS_IFVOLDEV;
}
return itype;
}
-int
-devfs_get_dtype(struct device_meta* dev)
+static inline int
+devfs_get_dtype(morph_t* dev_morph)
{
- if (valid_device_subtype_ref(dev, DEV_CAT)) {
+ if (morph_type_of(dev_morph, devcat_morpher)) {
return DT_DIR;
}
return DT_FILE;
}
+static inline morph_t*
+__try_resolve(struct v_inode* inode)
+{
+ if (!inode->data) {
+ return dev_object_root;
+ }
+
+ return resolve_device_morph(inode->data);
+}
+
int
-devfs_mknod(struct v_dnode* dnode, struct device_meta* dev)
+devfs_mknod(struct v_dnode* dnode, morph_t* obj)
{
- assert(dev);
+ struct v_inode* devnod;
+
+ assert(obj);
- struct v_inode* devnod = vfs_i_find(dnode->super_block, dev->dev_uid);
+ devnod = vfs_i_find(dnode->super_block, morpher_uid(obj));
if (!devnod) {
if ((devnod = vfs_i_alloc(dnode->super_block))) {
- devnod->id = dev->dev_uid;
- devnod->data = dev;
- devnod->itype = devfs_get_itype(dev);
+ devnod->id = morpher_uid(obj);
+ devnod->data = changeling_ref(obj);
+ devnod->itype = devfs_get_itype(obj);
vfs_i_addhash(devnod);
} else {
int
devfs_dirlookup(struct v_inode* this, struct v_dnode* dnode)
{
- void* data = this->data;
- struct device_meta* rootdev = resolve_device_meta(data);
+ morph_t *mobj, *root;
- if (data && !rootdev) {
+ root = __try_resolve(this);
+ if (!root) {
return ENOTDIR;
}
- struct device_meta* dev =
- device_getbyhname(rootdev, &dnode->name);
-
- if (!dev) {
+ mobj = changeling_find(root, &dnode->name);
+ if (!mobj) {
return ENOENT;
}
- return devfs_mknod(dnode, dev);
+ return devfs_mknod(dnode, mobj);
}
int
devfs_readdir(struct v_file* file, struct dir_context* dctx)
{
- void* data = file->inode->data;
- struct device_meta* rootdev = resolve_device_meta(data);
+ morph_t *mobj, *root;
- if (data && !rootdev) {
+ root = __try_resolve(file->inode);
+ if (!root) {
return ENOTDIR;
}
return 1;
}
- struct device_meta* dev =
- device_getbyoffset(rootdev, file->f_pos - 2);
-
- if (!dev) {
+ mobj = changeling_get_at(root, file->f_pos - 2);
+ if (!mobj) {
return 0;
}
- dctx->read_complete_callback(
- dctx, dev->name.value, dev->name.len, devfs_get_dtype(dev));
+ dctx->read_complete_callback(dctx,
+ mobj->name.value, mobj->name.len,
+ devfs_get_dtype(mobj));
return 1;
}
-
#include <lunaix/device.h>
#include <lunaix/fs.h>
#include <lunaix/fs/twifs.h>
#include <lunaix/spike.h>
#include <lunaix/syscall.h>
#include <lunaix/syscall_utils.h>
+#include <lunaix/owloysius.h>
#include <klibc/strfmt.h>
#include <klibc/string.h>
static DEFINE_LLIST(root_list);
-static volatile u32_t devid = 0;
-
-struct devclass default_devclass = {};
+morph_t* device_mobj_root;
void
device_setname_vargs(struct device_meta* dev, char* fmt, va_list args)
{
- size_t strlen = ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
-
- dev->name = HSTR(dev->name_val, strlen);
-
- hstr_rehash(&dev->name, HSTR_FULL_HASH);
+ ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
+ changeling_setname(dev_mobj(dev), dev->name_val);
}
void
-device_register_generic(struct device_meta* devm, struct devclass* class, char* fmt, ...)
+device_register_generic(struct device_meta* devm, struct devclass* class,
+ char* fmt, ...)
{
va_list args;
+ morph_t* morphed, *parent;
+
+ morphed = &devm->mobj;
va_start(args, fmt);
if (fmt) {
device_setname_vargs(devm, fmt, args);
}
- if (class && valid_device_subtype_ref(devm, DEV_STRUCT)) {
+ if (class && morph_type_of(morphed, device_morpher))
+ {
struct device* dev = to_dev(devm);
- dev->ident = (struct devident){ .fn_grp = class->fn_grp,
- .unique = DEV_UNIQUE(class->device,
- class->variant) };
+ dev->ident = (struct devident) {
+ .fn_grp = class->fn_grp,
+ .unique = DEV_UNIQUE(class->device, class->variant)
+ };
}
- devm->dev_uid = devid++;
-
- struct device_meta* parent = devm->parent;
+ parent = morphed->parent;
if (parent) {
- assert(valid_device_subtype_ref(parent, DEV_CAT));
- llist_append(&parent->children, &devm->siblings);
- } else {
- llist_append(&root_list, &devm->siblings);
+ changeling_attach(parent, morphed);
}
va_end(args);
}
-static void
-device_init_meta(struct device_meta* dmeta, struct device_meta* parent, unsigned int subtype)
-{
- dmeta->magic = DEV_STRUCT_MAGIC_MASK | subtype;
- dmeta->parent = parent;
-
- llist_init_head(&dmeta->children);
-}
-
void
-device_create(struct device* dev,
- struct device_meta* parent,
- u32_t type,
- void* underlay)
+device_create(struct device* dev, struct device_meta* parent,
+ u32_t type, void* underlay)
{
- dev->magic = DEV_STRUCT_MAGIC;
dev->underlay = underlay;
dev->dev_type = type;
- device_init_meta(dev_meta(dev), parent, DEV_STRUCT);
- llist_init_head(&dev->capabilities);
+ llist_init_head(&dev->potentium);
mutex_init(&dev->lock);
iopoll_init_evt_q(&dev->pollers);
}
}
device_create(dev, parent, type, underlay);
+ changeling_morph(dev_morph(parent), dev->mobj, NULL, device_morpher);
return dev;
}
return NULL;
}
- device_init_meta(dev_meta(dev), parent, DEV_ALIAS);
dev->alias = aliased;
+ changeling_ref(dev_mobj(aliased));
+ changeling_morph(dev_morph(parent), dev->mobj, NULL, devalias_morpher);
return dev;
}
return NULL;
}
- device_init_meta(dev_meta(dev), parent, DEV_CAT);
+ changeling_morph(dev_morph(parent), dev->mobj, NULL, devcat_morpher);
return dev;
}
-
void
device_setname(struct device_meta* dev, char* fmt, ...)
{
}
struct device_alias*
-device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...)
+device_addalias(struct device_meta* parent,
+ struct device_meta* aliased, char* name_fmt, ...)
{
va_list args;
va_start(args, name_fmt);
return dev;
}
-struct device_meta*
-device_getbyid(struct llist_header* devlist, u32_t id)
-{
- devlist = devlist ? devlist : &root_list;
- struct device_meta *pos, *n;
- llist_for_each(pos, n, devlist, siblings)
- {
- if (pos->dev_uid == id) {
- return pos;
- }
- }
-
- return NULL;
-}
-
-struct device_meta*
-device_getbyhname(struct device_meta* root_dev, struct hstr* name)
-{
- struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
- struct device_meta *pos, *n;
- llist_for_each(pos, n, devlist, siblings)
- {
- if (HSTR_EQ(&pos->name, name)) {
- return pos;
- }
- }
-
- return NULL;
-}
-
-struct device_meta*
-device_getbyname(struct device_meta* root_dev, const char* name, size_t len)
-{
- struct hstr hname = HSTR(name, len);
- hstr_rehash(&hname, HSTR_FULL_HASH);
-
- return device_getbyhname(root_dev, &hname);
-}
-
void
device_remove(struct device_meta* dev)
{
- llist_delete(&dev->siblings);
+ changeling_isolate(&dev->mobj);
vfree(dev);
}
-struct device_meta*
-device_getbyoffset(struct device_meta* root_dev, int offset)
-{
- struct llist_header* devlist = root_dev ? &root_dev->children : &root_list;
- struct device_meta *pos, *n;
- int off = 0;
- llist_for_each(pos, n, devlist, siblings)
- {
- if (off++ >= offset) {
- return pos;
- }
- }
- return NULL;
-}
-
void
device_populate_info(struct device* dev, struct dev_info* devinfo)
{
devinfo->dev_name.buf[buflen - 1] = 0;
}
-struct device_meta*
-resolve_device_meta(void* maybe_dev) {
- if (!valid_device_ref(maybe_dev)) {
+morph_t*
+resolve_device_morph(void* maybe_dev)
+{
+ struct device_alias* da = NULL;
+ morph_t *morphed;
+
+ morphed = morphed_ptr(maybe_dev);
+
+ if (!is_changeling(morphed)) {
return NULL;
}
- struct device_meta* dm = (struct device_meta*)maybe_dev;
- unsigned int subtype = dm->magic ^ DEV_STRUCT_MAGIC_MASK;
-
- switch (subtype)
+ if (morph_type_of(morphed, device_morpher))
{
- case DEV_STRUCT:
- case DEV_CAT:
- return dm;
-
- case DEV_ALIAS: {
- struct device_meta* aliased_dm = dm;
-
- while(valid_device_subtype_ref(aliased_dm, DEV_ALIAS)) {
- aliased_dm = to_aliasdev(aliased_dm)->alias;
- }
-
- return aliased_dm;
- }
- default:
- return NULL;
+ return morphed;
}
-}
-struct device*
-resolve_device(void* maybe_dev) {
- struct device_meta* dm = resolve_device_meta(maybe_dev);
-
- if (!valid_device_subtype_ref(dm, DEV_STRUCT)) {
- return NULL;
+ if (morph_type_of(morphed, devcat_morpher))
+ {
+ return morphed;
+ }
+
+ while(morph_type_of(morphed, devalias_morpher))
+ {
+ da = changeling_reveal(morphed, devalias_morpher);
+ morphed = &da->alias->mobj;
}
- return to_dev(dm);
+ return da ? morphed : NULL;
}
void
iopoll_wake_pollers(&dev->pollers);
}
+void
+device_chain_loader(struct device_def* def, devdef_ldfn fn)
+{
+ struct device_ldfn_chain* node;
+
+ node = valloc(sizeof(*node));
+ node->load = fn;
+
+ if (!def->load_chain) {
+ node->chain = NULL;
+ }
+ else {
+ node->chain = def->load_chain;
+ }
+
+ def->load_chain = node;
+}
+
+void
+device_chain_load_once(struct device_def* def)
+{
+ struct device_ldfn_chain *node, *next;
+
+ if (def->load) {
+ def->load(def);
+ }
+
+ node = def->load_chain;
+ def->load_chain = NULL;
+
+ while (node)
+ {
+ node->load(def);
+ next = node->chain;
+ vfree(node);
+
+ node = next;
+ }
+
+ if (def->flags.no_default_realm) {
+ return;
+ }
+
+ if (!def->create) {
+ return;
+ }
+
+ def->create(def, NULL);
+
+}
+
__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, sc_va_list, _args)
{
int errno = -1;
}
struct device* dev = resolve_device(fd_s->file->inode->data);
- if (!valid_device_subtype_ref(dev, DEV_STRUCT)) {
+ if (!dev) {
errno = ENODEV;
goto done;
}
done:
return DO_STATUS_OR_RETURN(errno);
-}
\ No newline at end of file
+}
+
+static void
+__device_subsys_init()
+{
+ device_mobj_root = changeling_spawn(NULL, "devices");
+}
+owloysius_fetch_init(__device_subsys_init, on_sysconf);
\ No newline at end of file
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/mm/valloc.h>
+
+struct potens_meta*
+alloc_potens(int cap, unsigned int size)
+{
+ struct potens_meta* cm = (struct potens_meta*)vzalloc(size);
+
+ cm->pot_type = cap;
+
+ return cm;
+}
+
+void
+device_grant_potens(struct device* dev, struct potens_meta* cap)
+{
+ llist_append(&dev->potentium, &cap->potentes);
+ cap->owner = dev;
+}
+
+struct potens_meta*
+device_get_potens(struct device* dev, unsigned int pot_type)
+{
+ struct potens_meta *pos, *n;
+
+ llist_for_each(pos, n, &dev->potentium, potentes) {
+ if (pos->pot_type == pot_type){
+ return pos;
+ }
+ }
+
+ return NULL;
+}
\ No newline at end of file
int,
options)
{
+ struct device* device = NULL;
struct v_dnode *dev = NULL, *mnt = NULL;
int errno = 0;
goto done;
}
- // By our convention.
- // XXX could we do better?
- struct device* device = NULL;
-
if (dev) {
if (!check_voldev_node(dev->inode)) {
errno = ENOTDEV;
goto done;
}
- device = (struct device*)dev->inode->data;
+
+ device = resolve_device(dev->inode->data);
+ assert(device);
}
errno = vfs_mount_at(fstype, device, mnt, options);
if (check_device_node(vino)) {
struct device* rdev = resolve_device(vino->data);
- if (!rdev || rdev->magic != DEV_STRUCT_MAGIC) {
+ if (!rdev) {
errno = EINVAL;
goto done;
}
stat->st_rdev = (dev_t){.meta = rdev->ident.fn_grp,
.unique = rdev->ident.unique,
- .index = rdev->dev_uid};
+ .index = dev_uid(rdev) };
}
if (fdev) {
stat->st_dev = (dev_t){.meta = fdev->ident.fn_grp,
.unique = fdev->ident.unique,
- .index = fdev->dev_uid};
+ .index = dev_uid(fdev) };
}
done:
/* Setup kernel memory layout and services */
kmem_init(bhctx);
- __remap_and_load_dtb(bhctx);
boot_parse_cmdline(bhctx);
device_scan_drivers();
+ initfn_invoke_sysconf();
+
+ __remap_and_load_dtb(bhctx);
device_sysconf_load();
- invoke_init_function(on_earlyboot);
+ // TODO register devtree hooks
+ // TODO re-scan devtree to bind devices.
clock_init();
timer_init();
- /*
- TODO autoload these init function that do not have dependency between
- them
- */
+ initfn_invoke_earlyboot();
- /* Let's get fs online as soon as possible, as things rely on them */
vfs_init();
fsm_init();
input_init();
must_success(vfs_mount_root("ramfs", NULL));
must_success(vfs_mount("/dev", "devfs", NULL, 0));
- invoke_init_function(on_boot);
+ initfn_invoke_boot();
/* Finish up bootstrapping sequence, we are ready to spawn the root process
* and start geting into uspace
clock_walltime(&dt);
twimap_printf(map,
"%.4d-%.2d-%.2d %.2d:%.2d:%.2d",
- dt.year,
- dt.month,
- dt.day,
- dt.hour,
- dt.minute,
- dt.second);
+ dt.year, dt.month, dt.day,
+ dt.hour, dt.minute, dt.second);
}
void
void
clock_walltime(datetime_t* datetime)
{
- sysrtc->get_walltime(sysrtc, datetime);
-}
-
-void
-clock_init()
-{
- int idx = 0;
- struct device_def* pos;
- foreach_exported_device_of(load_timedev, idx, pos)
- {
- if (pos->class.device != DEV_RTC) {
- continue;
- }
-
- pos->init(pos);
- }
+ sysrtc->ops->get_walltime(sysrtc, datetime);
}
\ No newline at end of file
static void
timer_update();
-static volatile struct lx_timer_context* timer_ctx = NULL;
+static DEFINE_LLIST(timers);
static volatile u32_t sched_ticks = 0;
static volatile u32_t sched_ticks_counter = 0;
timer_init_context()
{
timer_pile = cake_new_pile("timer", sizeof(struct lx_timer), 1, 0);
- timer_ctx =
- (struct lx_timer_context*)valloc(sizeof(struct lx_timer_context));
-
- assert_msg(timer_ctx, "Fail to initialize timer contex");
-
- timer_ctx->active_timers = (struct lx_timer*)cake_grab(timer_pile);
- llist_init_head(&timer_ctx->active_timers->link);
}
void
hwtimer_init(SYS_TIMER_FREQUENCY_HZ, timer_update);
- timer_ctx->base_frequency = hwtimer_base_frequency();
-
sched_ticks = (SYS_TIMER_FREQUENCY_HZ * SCHED_TIME_SLICE) / 1000;
sched_ticks_counter = 0;
}
timer->payload = payload;
timer->flags = flags;
- llist_append(&timer_ctx->active_timers->link, &timer->link);
+ llist_append(&timers, &timer->link);
return timer;
}
timer_update()
{
struct lx_timer *pos, *n;
- struct lx_timer* timer_list_head = timer_ctx->active_timers;
- llist_for_each(pos, n, &timer_list_head->link, link)
+ llist_for_each(pos, n, &timers, link)
{
if (--(pos->counter)) {
continue;
schedule();
}
}
-
-struct lx_timer_context*
-timer_context()
-{
- return (struct lx_timer_context*)timer_ctx;
-}
\ No newline at end of file
* @param size
* @return unsigned int
*/
-unsigned int weak
+unsigned int _weak
crc32b(unsigned char* data, unsigned int size)
{
unsigned int crc = (unsigned int)-1, i = 0;
* @param str
* @return unsigned int
*/
-u32_t weak
+u32_t _weak
strhash_32(const char* str, u32_t truncate_to)
{
if (!str)
#include <klibc/string.h>
#include <lunaix/types.h>
-void* weak
+void* _weak
memcpy(void* dest, const void* src, unsigned long num)
{
for (size_t i = 0; i < num; i++) {
return dest;
}
-void* weak
+void* _weak
memmove(void* dest, const void* src, unsigned long num)
{
u8_t* dest_ptr = (u8_t*)dest;
return dest;
}
-void* weak
+void* _weak
memset(void* ptr, int value, unsigned long num)
{
for (size_t i = 0; i < num; i++) {
return ptr;
}
-int weak
+int _weak
memcmp(const void* ptr1, const void* ptr2, unsigned long num)
{
u8_t* p1 = (u8_t*)ptr1;
#include <klibc/string.h>
#include <lunaix/types.h>
-const char* weak
+const char* _weak
strchr(const char* str, int character)
{
char c = (char)character;
#include <klibc/string.h>
#include <lunaix/compiler.h>
-int weak
+int _weak
streq(const char* a, const char* b)
{
while (*a == *b) {
#include <klibc/string.h>
#include <lunaix/compiler.h>
-char* weak
+char* _weak
strcpy(char* dest, const char* src)
{
char c;
* @param n
* @return char*
*/
-char* weak
+char* _weak
strncpy(char* dest, const char* src, unsigned long n)
{
char c;
#include <klibc/string.h>
#include <lunaix/compiler.h>
-unsigned long weak
+unsigned long _weak
strlen(const char *str)
{
unsigned long len = 0;
return len;
}
-unsigned long weak
+unsigned long _weak
strnlen(const char *str, unsigned long max_len)
{
unsigned long len = 0;
#define WS_CHAR(c) \
(c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\v' || c == '\r')
-void weak
+void _weak
strrtrim(char* str)
{
unsigned long l = strlen(str);
str[l + 1] = '\0';
}
-char* weak
+char* _weak
strltrim_safe(char* str)
{
unsigned long l = 0;
. = ALIGN(8);
- PROVIDE(__lga_dev_ld_timedev_start = .);
+ PROVIDE(__lga_dev_ld_post_start = .);
- KEEP(*(.lga.devdefs.ld_timedev));
+ KEEP(*(.lga.devdefs.ld_post));
- PROVIDE(__lga_dev_ld_timedev_end = .);
+ PROVIDE(__lga_dev_ld_post_end = .);
/* ---- */
. = ALIGN(8);
- PROVIDE(__lga_dev_ld_post_start = .);
+ PROVIDE(__lga_fs_start = .);
- KEEP(*(.lga.devdefs.ld_post));
+ KEEP(*(.lga.fs));
- PROVIDE(__lga_dev_ld_post_end = .);
+ PROVIDE(__lga_fs_end = .);
/* ---- */
. = ALIGN(8);
- PROVIDE(__lga_fs_start = .);
+ PROVIDE(__lga_lunainit_on_sysconf_start = .);
- KEEP(*(.lga.fs));
+ KEEP(*(.lga.lunainit.c_sysconf));
- PROVIDE(__lga_fs_end = .);
+ PROVIDE(__lga_lunainit_on_sysconf_end = .);
/* ---- */
gdb_port=1234
default_cmd="console=/dev/ttyS0"
-make CMDLINE=${default_cmd} ARCH=${ARCH} MODE=${MODE:-debug} all -j5 || exit -1
+make ARCH=${ARCH} MODE=${MODE:-debug} all -j5 || exit -1
./scripts/qemu.py \
scripts/qemus/qemu_x86_dev.json \
@$(MAKE) $(MKFLAGS) -C scripts all -I $(mkinc_dir)
.NOTPARALLEL:
-export KCMD=$(CMDLINE)
export LBUILD ARCH MODE
all: $(kbuild_dir) tool kernel
-Wno-discarded-qualifiers\
-Werror=incompatible-pointer-types
-OFLAGS := -fno-omit-frame-pointer
+OFLAGS := -fno-omit-frame-pointer \
+ -finline-small-functions
CFLAGS := -std=gnu99 $(OFLAGS) $(W) -g