}
ptr_t
-isrm_get_payload(int iv)
+isrm_get_payload(const isr_param* param)
{
+ int iv = param->execp->vector;
assert(iv < 256);
return ivhand_payload[iv];
void
ahci_register_device(struct hba_device* hbadev);
-void*
-ahci_driver_init(struct pci_device* ahci_dev);
-
void
__hba_reset_port(hba_reg_t* port_reg)
{
port_reg[HBA_RPxSCTL] &= ~0xf;
}
-void*
-ahci_driver_init(struct pci_device* ahci_dev)
+int
+ahci_driver_init(struct device_def* def, struct device* dev)
{
+ struct pci_device* ahci_dev = container_of(dev, struct pci_device, dev);
+
struct pci_base_addr* bar6 = &ahci_dev->bar[5];
assert_msg(bar6->type & BAR_TYPE_MMIO, "AHCI: BAR#6 is not MMIO.");
int iv = isrm_ivexalloc(__ahci_hba_isr);
pci_setup_msi(ahci_dev, iv);
+ isrm_set_payload(iv, (ptr_t)&ahcis);
struct ahci_driver* ahci_drv = vzalloc(sizeof(*ahci_drv));
struct ahci_hba* hba = &ahci_drv->hba;
ahci_register_device(hbadev);
}
- return ahci_drv;
+ dev->underlay = ahci_drv;
+ return 0;
}
-EXPORT_PCI_DEVICE(pci_ahci, AHCI_HBA_CLASS, 0, 0, ahci_driver_init);
void
ahci_register_device(struct hba_device* hbadev)
} else {
port->device->ops.submit = scsi_submit;
}
-}
\ No newline at end of file
+}
+
+static struct pci_device_def ahcidef = {
+ .dev_class = AHCI_HBA_CLASS,
+ .dev_vendor = PCI_ID_ANY,
+ .dev_id = PCI_ID_ANY,
+ .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_STORAGE, DEV_SATA, 0),
+ .name = "SATA AHCI",
+ .init_for = ahci_driver_init }
+};
+EXPORT_DEVICE(ahci, &ahcidef.devdef, load_on_demand);
\ No newline at end of file
LOG_MODULE("io_evt")
-extern struct llist_header ahcis;
-
void
__ahci_hba_isr(const isr_param* param)
{
struct ahci_hba* hba;
struct ahci_driver *pos, *n;
- llist_for_each(pos, n, &ahcis, ahci_drvs)
+ struct llist_header* ahcis = (struct llist_header*)isrm_get_payload(param);
+
+ llist_for_each(pos, n, ahcis, ahci_drvs)
{
if (pos->id == (int)param->execp->vector) {
hba = &pos->hba;
return 0;
}
-void
-pdev_nulldev_init()
+static int
+pdev_nulldev_init(struct device_def*)
{
struct device* devnull = device_addseq(NULL, NULL, "null");
devnull->ops.write_page = __null_wr_pg;
devnull->ops.write = __null_wr;
devnull->ops.read_page = __null_rd_pg;
devnull->ops.read = __null_rd;
+
+ return 0;
}
-EXPORT_PSEUDODEV(nulldev, pdev_nulldev_init);
\ No newline at end of file
+
+static struct device_def devnull_def = {
+ .name = "null",
+ .class = DEVCLASS(DEVIF_NON, DEVFN_PSEUDO, 0, 0),
+ .init = pdev_nulldev_init
+};
+EXPORT_DEVICE(nulldev, &devnull_def, load_earlystage);
static void
ps2_device_post_cmd(char cmd, char arg);
-static void
-ps2_kbd_init();
-
static void
ps2_process_cmd(void* arg);
mutex_unlock(&cmd_q.mutex);
}
-void
-ps2_kbd_init()
+static int
+ps2_kbd_init(struct device_def* devdef)
{
memset(&cmd_q, 0, sizeof(cmd_q));
result = ps2_issue_cmd_wretry(PS2_CMD_SELFTEST, PS2_NO_ARG);
if (result != PS2_RESULT_TEST_OK) {
kprintf(KWARN "controller self-test failed. (%x)\n", result);
- // goto done;
+ goto done;
}
// 5、设备自检(端口1自检,通常是我们的键盘)
result = ps2_issue_cmd_wretry(PS2_CMD_SELFTEST_PORT1, PS2_NO_ARG);
if (result != 0) {
kprintf(KERROR "interface test on port 1 failed. (%x)\n", result);
- // goto done;
+ goto done;
}
ps2_post_cmd(PS2_PORT_CTRL_CMDREG, PS2_CMD_PORT2_DISABLE, PS2_NO_ARG);
isrm_bindirq(PC_AT_IRQ_KBD, intr_ps2_kbd_handler);
cpu_enable_interrupt();
+ return 0;
+
+done:
+ return 1;
}
-EXPORT_INPUT_DEV(i8042_keyboard, ps2_kbd_init);
static void
ps2_process_cmd(void* arg)
;
return port_rdbyte(PS2_PORT_ENC_CMDREG);
-}
\ No newline at end of file
+}
+
+static struct device_def devrtc_i8042kbd = {
+ .name = "ps2 keyboard",
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_INPUT, DEV_X86LEGACY, 0),
+ .init = ps2_kbd_init
+};
+EXPORT_DEVICE(i8042_kbd, &devrtc_i8042kbd, load_timerstage);
LOG_MODULE("PCI")
static DEFINE_LLIST(pci_devices);
-static DEFINE_LLIST(pci_drivers);
void
pci_probe_msi_info(struct pci_device* device);
+static struct pci_device*
+pci_create_device(ptr_t pci_base, int devinfo)
+{
+ pci_reg_t class = pci_read_cspace(pci_base, 0x8);
+ struct hbucket* bucket = device_definitions_byif(DEVIF_PCI);
+
+ u32_t devid = PCI_DEV_DEVID(devinfo);
+ u32_t vendor = PCI_DEV_VENDOR(devinfo);
+
+ kappendf(".%x:%x, ", vendor, devid);
+
+ struct pci_device_def *pos, *n;
+ hashtable_bucket_foreach(bucket, pos, n, devdef.hlist_if)
+ {
+ if (pos->dev_class != PCI_DEV_CLASS(class)) {
+ continue;
+ }
+
+ int result = (pos->dev_vendor & vendor) == vendor &&
+ (pos->dev_id & devid) == devid;
+
+ if (result) {
+ goto found;
+ }
+ }
+
+ kappendf(KWARN "unknown device\n");
+
+ return NULL;
+
+found:
+ pci_reg_t intr = pci_read_cspace(pci_base, 0x3c);
+
+ 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;
+
+ device_prepare(&device->dev);
+
+ pci_probe_msi_info(device);
+ pci_probe_bar_info(device);
+
+ kappendf("%s (dev.%x:%x:%x) \n",
+ pos->devdef.name,
+ pos->devdef.class.meta,
+ pos->devdef.class.device,
+ pos->devdef.class.variant);
+
+ if (!pos->devdef.init_for) {
+ kappendf(KERROR "bad def\n");
+ goto fail;
+ }
+
+ int errno = pos->devdef.init_for(&pos->devdef, &device->dev);
+ if (errno) {
+ kappendf(KERROR "failed (e=%d)\n", errno);
+ goto fail;
+ }
+
+ llist_append(&pci_devices, &device->dev_chain);
+
+ return device;
+
+fail:
+ vfree(device);
+ return NULL;
+}
+
void
pci_probe_device(int bus, int dev, int funct)
{
return;
}
- pci_reg_t intr = pci_read_cspace(base, 0x3c);
- pci_reg_t class = pci_read_cspace(base, 0x8);
-
- struct pci_device* device = vzalloc(sizeof(struct pci_device));
- *device = (struct pci_device){ .cspace_base = base,
- .class_info = class,
- .device_info = reg1,
- .intr_info = intr };
-
- pci_probe_msi_info(device);
- pci_probe_bar_info(device);
-
- llist_append(&pci_devices, &device->dev_chain);
+ kprintf("pci.%d:%d:%d", bus, dev, funct);
- if (!pci_bind_driver(device)) {
- kprintf(KWARN "dev.%d:%d:%d %x:%x unknown device\n",
- bus,
- dev,
- funct,
- PCI_DEV_VENDOR(reg1),
- PCI_DEV_DEVID(reg1));
- } else {
- kprintf("dev.%d:%d:%d %x:%x %s\n",
- bus,
- dev,
- funct,
- PCI_DEV_VENDOR(reg1),
- PCI_DEV_DEVID(reg1),
- device->driver.type->name);
- }
+ pci_create_device(base, reg1);
}
void
-pci_probe()
+pci_scan()
{
- // 暴力扫描所有PCI设备
- // XXX: 尽管最多会有256条PCI总线,但就目前而言,只考虑bus #0就足够了
for (int bus = 0; bus < 256; bus++) {
for (int dev = 0; dev < 32; dev++) {
pci_probe_device(bus, dev, 0);
}
}
+size_t
+pci_bar_sizing(struct pci_device* dev, u32_t* bar_out, u32_t bar_num)
+{
+ pci_reg_t bar = pci_read_cspace(dev->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;
+ 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);
+ 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;
+}
+
static void
__pci_read_cspace(struct twimap* map)
{
map->size_acc = 256;
}
+/*---------- TwiFS interface definition ----------*/
+
static void
__pci_read_revid(struct twimap* map)
{
}
EXPORT_TWIFS_PLUGIN(pci_devs, pci_build_fsmapping);
-size_t
-pci_bar_sizing(struct pci_device* dev, u32_t* bar_out, u32_t bar_num)
-{
- pci_reg_t bar = pci_read_cspace(dev->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;
- 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);
- 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;
- }
- }
+/*---------- PCI 3.0 HBA device definition ----------*/
- return NULL;
-}
-
-void
-pci_add_driver(const char* name,
- u32_t class,
- u32_t vendor,
- u32_t devid,
- pci_drv_init init)
+static int
+pci_load_devices(struct device_def* def)
{
- struct pci_driver* pci_drv = valloc(sizeof(*pci_drv));
- *pci_drv = (struct pci_driver){ .create_driver = init,
- .dev_info = (vendor << 16) | devid,
- .dev_class = class };
- if (name) {
- strncpy(pci_drv->name, name, PCI_DRV_NAME_LEN);
- }
-
- llist_append(&pci_drivers, &pci_drv->drivers);
-}
+ pci_scan();
-int
-pci_bind_driver(struct pci_device* pci_dev)
-{
- struct pci_driver *pos, *n;
- llist_for_each(pos, n, &pci_drivers, drivers)
- {
- if (pos->dev_info) {
- if (pos->dev_info == pci_dev->device_info) {
- goto check_type;
- }
- continue;
- }
- check_type:
- if (pos->dev_class) {
- if (pos->dev_class == PCI_DEV_CLASS(pci_dev->class_info)) {
- pci_dev->driver.type = pos;
- pci_dev->driver.instance = pos->create_driver(pci_dev);
- return 1;
- }
- }
- }
return 0;
}
-void
-pci_load_devices()
-{
- int i = 0;
- struct pci_driver* dev;
- ldga_foreach(pci_dev_drivers, struct pci_driver*, i, dev)
- {
- llist_append(&pci_drivers, &dev->drivers);
- }
-
- pci_probe();
-}
\ No newline at end of file
+static struct device_def pci_def = {
+ .name = "pci3.0-hba",
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_BUSIF, DEV_BUS, 0),
+ .init = pci_load_devices
+};
+EXPORT_DEVICE(pci3hba, &pci_def, load_poststage);
return len;
}
-void
-pdev_randdev_init()
+int
+pdev_randdev_init(struct device_def* devdef)
{
struct device* devrand = device_addseq(NULL, NULL, "rand");
devrand->ops.read = __rand_rd;
devrand->ops.read_page = __rand_rd_pg;
+
+ return 0;
}
-EXPORT_PSEUDODEV(randdev, pdev_randdev_init);
\ No newline at end of file
+
+static struct device_def devrandx86_def = {
+ .name = "null",
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_CHAR, DEV_RNG, 0),
+ .init = pdev_randdev_init
+};
+EXPORT_DEVICE(randdev, &devrandx86_def, load_earlystage);
\ No newline at end of file
DEFINE_LLIST(rtcs);
-void
-hwrtc_init()
-{
- ptr_t init;
- int index;
- ldga_foreach(rtcdev, ptr_t, index, init)
- {
- ((void (*)())init)();
- }
-}
+// void
+// hwrtc_init()
+// {
+// ldga_invoke_fn0(rtcdev);
+// }
void
hwrtc_walltime(datetime_t* dt)
static void
__rtc_tick(const isr_param* param)
{
- struct mc146818* state =
- (struct mc146818*)isrm_get_payload(param->execp->vector);
+ struct mc146818* state = (struct mc146818*)isrm_get_payload(param);
state->tick_counts++;
return state->tick_counts;
}
-static void
-rtc_init()
+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->cls_mask = rtc_cls_mask;
rtc->get_counts = rtc_getcnt;
rtc->chfreq = rtc_chfreq;
+
+ return 0;
}
-EXPORT_RTC_DEVICE(mc146818, rtc_init);
\ No newline at end of file
+
+static struct device_def devrtc_mc146818 = {
+ .name = "rtc_mc146818",
+ .class = DEVCLASS(DEVIF_SOC, DEVFN_TIME, DEV_RTC, 1),
+ .init = rtc_init
+};
+EXPORT_DEVICE(mc146818, &devrtc_mc146818, load_earlystage);
\ No newline at end of file
ticks_t
hwtimer_base_frequency()
{
+ assert(current_timer);
return current_timer->base_freq;
}
ticks_t
hwtimer_current_systicks()
{
+ assert(current_timer);
return current_timer->systicks();
}
ticks_t
hwtimer_to_ticks(u32_t value, int unit)
{
+ assert(current_timer);
// in case system frequency is less than 1000Hz
if (unit != TIME_MS) {
return current_timer->running_freq * unit * value;
#ifndef __LUNAIX_PCI_H
#define __LUNAIX_PCI_H
+#include <lunaix/device.h>
#include <lunaix/ds/ldga.h>
#include <lunaix/ds/llist.h>
#include <lunaix/types.h>
#define PCI_REG_BAR(num) (0x10 + (num - 1) * 4)
#define PCI_DEV_VENDOR(x) ((x)&0xffff)
-#define PCI_DEV_DEVID(x) ((x) >> 16)
+#define PCI_DEV_DEVID(x) (((x)&0xffff0000) >> 16)
#define PCI_INTR_IRQ(x) ((x)&0xff)
#define PCI_INTR_PIN(x) (((x)&0xff00) >> 8)
#define PCI_DEV_CLASS(x) ((x) >> 8)
(((bus)&0xff) << 16) | (((dev)&0xff) << 11) | (((funct)&0xff) << 8) | \
0x80000000
+#define PCI_ID_ANY (-1)
+
typedef unsigned int pci_reg_t;
// PCI device header format
#define BAR_TYPE_CACHABLE 0x2
#define PCI_DRV_NAME_LEN 32
-#define EXPORT_PCI_DEVICE(name_, class, vendor_id, dev_id, init_fn) \
- static struct pci_driver pcidev_##name_ = \
- (struct pci_driver){ .name = #name_, \
- .create_driver = (init_fn), \
- .dev_info = ((vendor_id) << 16) | (dev_id), \
- .dev_class = (class) }; \
- export_ldga_el(pci_dev_drivers, name_, ptr_t, &pcidev_##name_)
-
-struct pci_driver;
-
struct pci_base_addr
{
u32_t start;
struct pci_device
{
+ struct device dev;
struct llist_header dev_chain;
u32_t device_info;
u32_t class_info;
u32_t cspace_base;
u32_t msi_loc;
u16_t intr_info;
- struct
- {
- struct pci_driver* type;
- void* instance;
- } driver;
struct pci_base_addr bar[6];
};
typedef void* (*pci_drv_init)(struct pci_device*);
-struct pci_driver
+struct pci_device_def
{
- struct llist_header drivers;
- u32_t dev_info;
u32_t dev_class;
- pci_drv_init create_driver;
- char name[PCI_DRV_NAME_LEN];
+ u32_t dev_vendor;
+ u32_t dev_id;
+ struct device_def devdef;
};
-/**
- * @brief 初始化PCI。这主要是通过扫描PCI总线进行拓扑重建。注意,该
- * 初始化不包括针对每个设备的初始化,因为那是设备驱动的事情。
- *
- */
-void
-pci_load_devices();
-
/**
* @brief 根据类型代码(Class Code)去在拓扑中寻找一个设备
* 类型代码请参阅: PCI LB Spec. Appendix D.
#define DEVICE_NAME_SIZE 32
+#include <lunaix/device_num.h>
+#include <lunaix/ds/hashtable.h>
#include <lunaix/ds/hstr.h>
#include <lunaix/ds/ldga.h>
#include <lunaix/ds/llist.h>
#include <lunaix/types.h>
/**
- * @brief Export pseudo device
+ * @brief Export a device definition
*
*/
-#define EXPORT_PSEUDODEV(id, init_fn) \
- export_ldga_el(pseudo_dev, id, ptr_t, init_fn)
+#define EXPORT_DEVICE(id, devdef, load_order) \
+ export_ldga_el(devdefs, id, ptr_t, devdef); \
+ export_ldga_el_sfx(devdefs, id##_ldorder, ptr_t, devdef, load_order);
+
+#define load_on_demand ld_ondemand
+
+/**
+ * @brief Mark the device definition should be loaded automatically as earlier
+ * as possible in the kernel bootstrapping stage (before initialization of file
+ * systems). Load here if your driver is standalone and require no other than
+ * basic memory allocation services
+ *
+ */
+#define load_earlystage ld_early
+
+/**
+ * @brief Mark the device definition should be loaded automatically after timer
+ * is ready. Load here if your driver require a basic timing service
+ *
+ */
+#define load_timerstage ld_aftertimer
+
+/**
+ * @brief Mark the device definition should be loaded automatically in
+ * the post boostrapping stage (i.e., the start up of proc0). Load here if your
+ * driver involves async mechanism
+ *
+ */
+#define load_poststage ld_post
+
+/**
+ * @brief Declare a device class
+ *
+ */
+#define DEVCLASS(devif, devfn, devkind, devvar) \
+ (struct devclass) \
+ { \
+ .meta = DEV_META(devif, devfn), .device = (devkind), \
+ .variant = (devvar) \
+ }
#define DEV_STRUCT_MAGIC 0x5645444c
typedef unsigned int dev_t;
+struct devclass
+{
+ u32_t meta;
+ u32_t device;
+ u32_t variant;
+ u32_t hash;
+};
+
struct device
{
u32_t magic;
// TODO investigate event polling
struct hstr name;
+ struct devclass class;
dev_t dev_id;
int dev_type;
char name_val[DEVICE_NAME_SIZE];
} ops;
};
+struct device_def
+{
+ struct llist_header dev_list;
+ struct hlist_node hlist;
+ struct hlist_node hlist_if;
+ char* name;
+
+ struct devclass class;
+
+ int (*init)(struct device_def*);
+ int (*init_for)(struct device_def*, struct device*);
+};
+
+static inline u32_t devclass_hash(struct devclass class)
+{
+ return (((class.device & 0xffff) << 16) | (class.variant & 0xffff)) ^
+ ~class.meta;
+}
+
+void
+device_register_all();
+
+void
+device_prepare(struct device* dev);
+
+void
+device_setname(struct device* dev, char* fmt, ...);
+
+void
+device_setname(struct device* dev, char* fmt, ...);
+
+struct device*
+device_add_vargs(struct device* parent,
+ void* underlay,
+ char* name_fmt,
+ u32_t type,
+ va_list args);
+
struct device*
device_add(struct device* parent,
void* underlay,
- char* name_fmt,
u32_t type,
- va_list args);
+ char* name_fmt,
+ ...);
struct device*
device_addsys(struct device* parent, void* underlay, char* name_fmt, ...);
struct device*
device_getbyoffset(struct device* root_dev, int pos);
+struct device*
+device_create_byclass(struct devclass* class,
+ u32_t type,
+ char* name,
+ int* err_code);
+
+struct hbucket*
+device_definitions_byif(int if_type);
+
+void
+device_register_all();
+
+/*------ Load hooks ------*/
+
+void
+device_earlystage();
+
+void
+device_poststage();
+
void
-device_install_pseudo();
+device_timerstage();
#endif /* __LUNAIX_DEVICE_H */
--- /dev/null
+#ifndef __LUNAIX_DEVICE_NUM_H
+#define __LUNAIX_DEVICE_NUM_H
+
+/*
+ Device metadata field (device_def::meta)
+
+ 31 16 15 0
+ | interface | function |
+
+ Where the interface identify how the device is connected with the processor
+ Lunaix identify the following values:
+
+ NON: device do not have hardware interfacing
+
+ SOC: device conntected through some System-on-Chip interconnect bus
+ for example, southbridge on x86 platform, AMBA for ARM's series.
+
+ PCI: device connected through the peripheral component interconnect bus
+ (PCI)
+
+ USB: device connected through the universal serial bus (USB)
+
+ SPI: device connected through the serial peripheral interface (SPI)
+
+ I2C: device connected through the IIC protocol
+
+ The function defines the functionality that the device is designated to
+ serve. Lunaix identify the following values:
+
+ PSEDUO: a pseudo device which does not backed by any hardware. (e.g.
+ /dev/null)
+
+ CHAR: a character device, which support read/write and dealing with
+ characters. Backed hardware might exist.
+
+ SERIAL: a serial interface which talks
+
+ STORAGE: a device that is used for storage of data
+
+ INPUT: a device that accept external input.
+
+ TIME: a device that provides time related services, for example, timing
+ and clocking
+
+ BUSIF: a device that is the interface or HBAs for accessing interconnect
+ bus.
+
+ TTY: a device which can be called as teletypewriter, system can use such
+ device for output into external environment
+*/
+
+#define DEV_META(if_, function) (((if_)&0xffff) << 16) | ((function)&0xffff)
+#define DEV_IF(meta) ((meta) >> 16)
+#define DEV_FN(meta) (((meta)&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 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 DEV_BUILTIN 0x0
+#define DEV_X86LEGACY 0x1
+#define DEV_RNG 0x2
+#define DEV_RTC 0x3
+#define DEV_SATA 0x4
+#define DEV_NVME 0x5
+#define DEV_BUS 0x5
+
+#endif /* __LUNAIX_DEVICE_NUM_H */
struct hlist_node* head;
};
-#define __hashkey(table, hash) (hash % (sizeof(table) / sizeof(table[0])))
+#define __hashkey(table, hash) ((hash) % (sizeof(table) / sizeof(table[0])))
-#define DECLARE_HASHTABLE(name, bucket_num) struct hbucket name[bucket_num];
+#define DECLARE_HASHTABLE(name, bucket_num) struct hbucket name[(bucket_num)];
#define hashtable_bucket_foreach(bucket, pos, n, member) \
for (pos = list_entry((bucket)->head, typeof(*pos), member); \
#include <lunaix/types.h>
+#define ldga_el_id(ga_name, el_name) __lga_##ga_name##_##el_name
+#define ldga_section(ga_name) __attribute__((section(".lga." ga_name)))
+
#define export_ldga_el(ga_name, el_name, type, val) \
- type __attribute__((section(".lga." #ga_name))) \
- __lga_##ga_name##_##el_name = (type)(val)
+ type ldga_section(#ga_name) ldga_el_id(ga_name, el_name) = (type)(val)
+
+#define export_ldga_el_sfx(ga_name, el_name, type, val, suffix) \
+ type ldga_section(#ga_name "." #suffix) ldga_el_id(ga_name, el_name) = \
+ (type)(val)
+
+#define export_ldga_el_idx(ga_name, i, type, val) \
+ export_ldga_el(ga_name, i, type, val)
+#define export_ldga_el_anon(ga_name, type, val) \
+ export_ldga_el_idx(ga_name, __COUNTER__, type, val)
#define ldga_foreach(ga_name, el_type, index, el) \
extern el_type __lga_##ga_name##_start[], __lga_##ga_name##_end; \
(ptr_t)&__lga_##ga_name##_end; \
el = __lga_##ga_name##_start[++index])
+/**
+ * @brief Invoke all elements in the array named `ga_name` of parameterless
+ * function pointers
+ *
+ */
+#define ldga_invoke_fn0(ga_name) \
+ ({ \
+ int i = 0; \
+ ptr_t fn0; \
+ ldga_foreach(ga_name, ptr_t, i, fn0) \
+ { \
+ ((void (*)())fn0)(); \
+ } \
+ })
+
#endif /* __LUNAIX_LDGA_H */
#include <lunaix/ds/btrie.h>
#include <lunaix/ds/hashtable.h>
#include <lunaix/ds/hstr.h>
+#include <lunaix/ds/ldga.h>
#include <lunaix/ds/llist.h>
#include <lunaix/ds/lru.h>
#include <lunaix/ds/mutex.h>
#define TEST_FD(fd) (fd >= 0 && fd < VFS_MAX_FD)
+#define EXPORT_FILE_SYSTEM(fs_id, init_fn) \
+ export_ldga_el(fs, fs_id, ptr_t, init_fn)
+
#define VFS_VALID_CHAR(chr) \
(('A' <= (chr) && (chr) <= 'Z') || ('a' <= (chr) && (chr) <= 'z') || \
('0' <= (chr) && (chr) <= '9') || (chr) == '.' || (chr) == '_' || \
isrm_get(int iv);
ptr_t
-isrm_get_payload(int iv);
+isrm_get_payload(const isr_param*);
void
isrm_set_payload(int iv, ptr_t);
void
lxconsole_init();
-void
-lxconsole_spawn_ttydev();
-
void
console_write_str(char* str);
void
kprint_dbg(const char* fmt, ...);
+void
+kappendf(const char* fmt, ...);
+
#endif /* __LUNAIX_SYSLOG_H */
--- /dev/null
+#include <lunaix/device.h>
+#include <lunaix/fs/twifs.h>
+#include <lunaix/status.h>
+
+#include <klibc/stdio.h>
+
+static DECLARE_HASHTABLE(dev_registry, 32);
+static DECLARE_HASHTABLE(dev_byif, 8);
+static DEFINE_LLIST(dev_registry_flat);
+
+static struct device* adhoc_devcat;
+
+void
+device_register_all()
+{
+ adhoc_devcat = device_addcat(NULL, "adhoc");
+
+ hashtable_init(dev_registry);
+ hashtable_init(dev_byif);
+
+ int idx = 0;
+ struct device_def* devdef;
+ ldga_foreach(devdefs, struct device_def*, idx, devdef)
+ {
+ u32_t hash = devclass_hash(devdef->class);
+ devdef->class.hash = hash;
+
+ hashtable_hash_in(dev_registry, &devdef->hlist, hash);
+ hashtable_hash_in(
+ dev_byif, &devdef->hlist_if, DEV_IF(devdef->class.meta));
+
+ llist_append(&dev_registry_flat, &devdef->dev_list);
+ }
+}
+
+static int
+devclass_eq(struct devclass* c1, struct devclass* c2)
+{
+ return c1->meta == c2->meta && c1->variant == c2->variant &&
+ c1->device == c2->device;
+}
+
+struct device_def*
+devdef_byclass(struct devclass* class)
+{
+ u32_t hash = devclass_hash(*class);
+ int errno;
+
+ struct device_def *pos, *n;
+ hashtable_hash_foreach(dev_registry, hash, pos, n, hlist)
+ {
+ if (pos->class.hash != hash) {
+ continue;
+ }
+ if (devclass_eq(class, &pos->class)) {
+ break;
+ }
+ }
+
+ return pos;
+}
+
+struct device*
+device_create_byclass(struct devclass* class,
+ u32_t type,
+ char* name,
+ int* err_code)
+{
+ int errno;
+ struct device_def* devdef = devdef_byclass(class);
+
+ if (!devdef) {
+ *err_code = ENOENT;
+ return NULL;
+ }
+
+ if (!devdef->init_for) {
+ if (err_code) {
+ *err_code = ENOTSUP;
+ }
+ return NULL;
+ }
+
+ struct device* dev = device_add(adhoc_devcat, NULL, type, NULL);
+
+ errno = devdef->init_for(devdef, dev);
+ if (err_code && !errno) {
+ *err_code = errno;
+ device_remove(dev);
+ return NULL;
+ }
+
+ device_setname(dev,
+ "%s_%d:%d:%d_%d",
+ name,
+ class->meta,
+ class->device,
+ class->device,
+ dev->dev_id);
+
+ return dev;
+}
+
+struct hbucket*
+device_definitions_byif(int if_type)
+{
+ return &dev_byif[__hashkey(dev_byif, if_type)];
+}
+
+#define device_load_on_stage(stage) \
+ ({ \
+ int idx = 0; \
+ struct device_def* devdef; \
+ ldga_foreach(dev_ld_##stage, struct device_def*, idx, devdef) \
+ { \
+ devdef->init(devdef); \
+ } \
+ })
+
+void
+device_earlystage()
+{
+ device_load_on_stage(early);
+}
+
+void
+device_timerstage()
+{
+ device_load_on_stage(aftertimer);
+}
+
+void
+device_poststage()
+{
+ device_load_on_stage(post);
+}
+
+static int
+__devdb_db_gonext(struct twimap* mapping)
+{
+ struct device_def* current = twimap_index(mapping, struct device_def*);
+ if (current->dev_list.next == &dev_registry_flat) {
+ return 0;
+ }
+ mapping->index =
+ list_entry(current->dev_list.next, struct device_def, dev_list);
+ return 1;
+}
+
+static void
+__devdb_twifs_lsdb(struct twimap* mapping)
+{
+ char flags[32];
+ struct device_def* def = twimap_index(mapping, struct device_def*);
+
+ int meta = def->class.meta;
+ ksnprintf(flags, 32, "if=%x,fn=%x", DEV_IF(meta), DEV_FN(meta));
+
+ twimap_printf(mapping,
+ "%d:%d:%d %s (%s)\n",
+ def->class.meta,
+ def->class.device,
+ def->class.variant,
+ def->name,
+ flags);
+}
+
+static void
+devdb_twifs_plugin()
+{
+ struct twimap* map = twifs_mapping(NULL, NULL, "devtab");
+ map->read = __devdb_twifs_lsdb;
+ map->go_next = __devdb_db_gonext;
+}
+EXPORT_TWIFS_PLUGIN(devdb, devdb_twifs_plugin);
\ No newline at end of file
fs->mount = devfs_mount;
fs->unmount = devfs_unmount;
}
+EXPORT_FILE_SYSTEM(devfs, devfs_init);
struct v_inode_ops devfs_inode_ops = { .dir_lookup = devfs_dirlookup,
.open = default_inode_open,
static volatile dev_t devid = 0;
+void
+device_prepare(struct device* dev)
+{
+ dev->magic = DEV_STRUCT_MAGIC;
+ dev->dev_id = devid++;
+
+ llist_init_head(&dev->children);
+}
+
+static void
+device_setname_vargs(struct device* dev, char* fmt, va_list args)
+{
+ size_t strlen =
+ __ksprintf_internal(dev->name_val, fmt, DEVICE_NAME_SIZE, args);
+
+ dev->name = HSTR(dev->name_val, strlen);
+
+ hstr_rehash(&dev->name, HSTR_FULL_HASH);
+}
+
+void
+device_setname(struct device* dev, char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+
+ device_setname_vargs(dev, fmt, args);
+
+ va_end(args);
+}
+
struct device*
-device_add(struct device* parent,
- void* underlay,
- char* name_fmt,
- u32_t type,
- va_list args)
+device_add_vargs(struct device* parent,
+ void* underlay,
+ char* name_fmt,
+ u32_t type,
+ va_list args)
{
struct device* dev = vzalloc(sizeof(struct device));
+ device_prepare(dev);
+
if (parent) {
assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT);
llist_append(&parent->children, &dev->siblings);
llist_append(&root_list, &dev->siblings);
}
- size_t strlen =
- __ksprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
+ if (name_fmt) {
+ device_setname_vargs(dev, name_fmt, args);
+ }
- dev->magic = DEV_STRUCT_MAGIC;
- dev->dev_id = devid++;
- dev->name = HSTR(dev->name_val, strlen);
dev->parent = parent;
dev->underlay = underlay;
dev->dev_type = type;
- hstr_rehash(&dev->name, HSTR_FULL_HASH);
- llist_init_head(&dev->children);
+ return dev;
+}
+struct device*
+device_add(struct device* parent,
+ void* underlay,
+ u32_t type,
+ char* name_fmt,
+ ...)
+{
+ va_list args;
+ va_start(args, name_fmt);
+
+ struct device* dev =
+ device_add_vargs(parent, underlay, name_fmt, type, args);
+
+ va_end(args);
return dev;
}
va_start(args, name_fmt);
struct device* dev =
- device_add(parent, underlay, name_fmt, DEV_IFSEQ, args);
+ device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
va_end(args);
return dev;
va_start(args, name_fmt);
struct device* dev =
- device_add(parent, underlay, name_fmt, DEV_IFSEQ, args);
+ device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args);
va_end(args);
return dev;
va_start(args, name_fmt);
struct device* dev =
- device_add(parent, underlay, name_fmt, DEV_IFVOL, args);
+ device_add_vargs(parent, underlay, name_fmt, DEV_IFVOL, args);
va_end(args);
return dev;
va_list args;
va_start(args, name_fmt);
- struct device* dev = device_add(parent, NULL, name_fmt, DEV_IFCAT, args);
+ struct device* dev =
+ device_add_vargs(parent, NULL, name_fmt, DEV_IFCAT, args);
va_end(args);
return dev;
input_init()
{
input_devcat = device_addcat(NULL, "input");
-
- int i;
- ptr_t input_dev_init;
- ldga_foreach(inputdev, ptr_t, i, input_dev_init)
- {
- ((void (*)())input_dev_init)();
- }
}
void
va_start(args, name_fmt);
struct device* dev =
- device_add(input_devcat, idev, name_fmt, DEV_IFSEQ, args);
+ device_add_vargs(input_devcat, idev, name_fmt, DEV_IFSEQ, args);
idev->dev_if = dev;
dev->ops.read = __input_dev_read;
+++ /dev/null
-#include <lunaix/device.h>
-
-extern void
-devbuiltin_init_rand();
-
-extern void
-devbuiltin_init_null();
-
-void
-device_install_pseudo()
-{
- ptr_t pdev_init_fn;
- int index;
- ldga_foreach(pseudo_dev, ptr_t, index, pdev_init_fn)
- {
- ((void (*)())pdev_init_fn)();
- }
-}
\ No newline at end of file
+++ /dev/null
-#include <lunaix/fs.h>
-#include <lunaix/fs/devfs.h>
-#include <lunaix/fs/iso9660.h>
-#include <lunaix/fs/ramfs.h>
-#include <lunaix/fs/taskfs.h>
-#include <lunaix/fs/twifs.h>
-
-void
-fsm_register_all()
-{
- ramfs_init();
- twifs_init();
- devfs_init();
- taskfs_init();
- iso9660_init();
-
- // ... more fs implementation
-}
\ No newline at end of file
{
hashtable_init(fs_registry);
- fsm_register_all();
+ ldga_invoke_fn0(fs);
}
void
fs->unmount = iso9660_unmount;
fsm_register(fs);
-}
\ No newline at end of file
+}
+EXPORT_FILE_SYSTEM(iso9660, iso9660_init);
\ No newline at end of file
fsm_register(ramfs);
}
+EXPORT_FILE_SYSTEM(ramfs, ramfs_init);
int
ramfs_mksymlink(struct v_inode* this, const char* target)
fs_root = twifs_dir_node(NULL, NULL, 0, 0);
}
+EXPORT_FILE_SYSTEM(twifs, twifs_init);
void
twifs_register_plugins()
{
- int i = 0;
- ptr_t init_twifs_plugin_fn;
- ldga_foreach(twiplugin_inits, ptr_t, i, init_twifs_plugin_fn)
- {
- ((void (*)())init_twifs_plugin_fn)();
- }
+ ldga_invoke_fn0(twiplugin_inits);
}
int
#include <hal/acpi/acpi.h>
#include <hal/intc.h>
-#include <hal/pci.h>
#include <sys/abi.h>
#include <sys/interrupts.h>
/* Prepare stack trace environment */
trace_modksyms_init(bhctx);
+ device_register_all();
+
// crt
tty_init(ioremap(0xB8000, PG_SIZE));
tty_set_theme(VGA_COLOR_WHITE, VGA_COLOR_BLACK);
/* Get intc online, this is the cornerstone when initing devices */
intc_init();
+ input_init();
+ device_earlystage();
+
/* System timing and clock support */
clock_init();
timer_init();
- input_init();
+ device_timerstage();
+
block_init();
/* the bare metal are now happy, let's get software over with */
vfs_mount("/sys", "twifs", NULL, MNT_RO);
vfs_mount("/task", "taskfs", NULL, MNT_RO);
- lxconsole_spawn_ttydev();
- device_install_pseudo();
-
/* Finish up bootstrapping sequence, we are ready to spawn the root process
* and start geting into uspace
*/
#define MAX_KPRINTF_BUF_SIZE 512
#define MAX_XFMT_SIZE 512
+static char* log_prefix[] = { "- ", "W ", "E ", "D " };
+static char* color_code[] = { "", "\033[6;0m", "\033[12;0m", "\033[9;0m" };
+
void
__kprintf_internal(const char* component,
int log_level,
+ const char* prefix,
const char* fmt,
va_list args)
{
char buf[MAX_KPRINTF_BUF_SIZE];
char expanded_fmt[MAX_XFMT_SIZE];
-
- switch (log_level) {
- case 1:
- // tty_set_theme(VGA_COLOR_BROWN, current_theme >> 12);
- ksnprintf(expanded_fmt,
- MAX_XFMT_SIZE,
- "\033[6;0mW %s: %s\033[39;49m",
- component,
- fmt);
- break;
- case 2:
- // tty_set_theme(VGA_COLOR_LIGHT_RED, current_theme >> 12);
- ksnprintf(expanded_fmt,
- MAX_XFMT_SIZE,
- "\033[12;0mE %s: %s\033[39;49m",
- component,
- fmt);
- break;
- case 3:
- // tty_set_theme(VGA_COLOR_LIGHT_BLUE, current_theme >> 12);
- ksnprintf(expanded_fmt,
- MAX_XFMT_SIZE,
- "\033[9;0mD %s: %s\033[39;49m",
- component,
- fmt);
- break;
- default:
- ksnprintf(expanded_fmt, MAX_XFMT_SIZE, "- %s: %s", component, fmt);
- break;
+ char* color = color_code[log_level];
+
+ if (component) {
+ ksnprintf(expanded_fmt,
+ MAX_XFMT_SIZE,
+ "%s%s%s: %s\033[39;49m",
+ color,
+ prefix,
+ component,
+ fmt);
+ } else {
+ ksnprintf(
+ expanded_fmt, MAX_XFMT_SIZE, "%s%s%s\033[39;49m", color, prefix, fmt);
}
__ksprintf_internal(buf, expanded_fmt, MAX_KPRINTF_BUF_SIZE, args);
console_write_str(buf);
}
+char*
+__get_loglevel(char* fmt, int* log_level_out)
+{
+ char l = '0';
+ if (*fmt == '\x1b') {
+ l = *(++fmt);
+ fmt++;
+ }
+ l -= '0';
+
+ if (l > 3) {
+ l = 0;
+ }
+
+ *log_level_out = (int)l;
+ return fmt;
+}
+
+void
+kappendf(const char* fmt, ...)
+{
+ char buf[MAX_KPRINTF_BUF_SIZE];
+
+ va_list args;
+ va_start(args, fmt);
+
+ int log_level;
+ fmt = __get_loglevel(fmt, &log_level);
+
+ __kprintf_internal(NULL, log_level, "", fmt, args);
+
+ va_end(args);
+}
+
void
__kprintf(const char* component, const char* fmt, va_list args)
{
if (!fmt)
return;
- char log_level = '0';
- if (*fmt == '\x1b') {
- log_level = *(++fmt);
- fmt++;
- }
-
- __kprintf_internal(component, log_level - '0', fmt, args);
+ int log_level;
+ fmt = __get_loglevel(fmt, &log_level);
+ __kprintf_internal(component, log_level, log_prefix[log_level], fmt, args);
}
void
tty_put_str_at(buf, 0, 24);
va_end(args);
+
+ spin();
}
void
__DEFINE_LXSYSCALL3(void, syslog, int, level, const char*, fmt, va_list, args)
{
- __kprintf_internal("syslog", level, fmt, args);
+ __kprintf_internal("syslog", level, "", fmt, args);
}
\ No newline at end of file
#include <sdbg/protocol.h>
-#include <hal/pci.h>
-
#include <klibc/string.h>
LOG_MODULE("PROC0")
__VERSION__,
__TIME__);
+ device_poststage();
+
twifs_register_plugins();
- /*
- * all device registering and loading must defered to here!
- * due to limited stack size and partial scheduling context
- */
- pci_load_devices();
+ // FIXME This 8025 serial should integrated into device layer
+ serial_init();
// debugger
- serial_init();
sdbg_init();
// console
attr_export_table = vcalloc(ATTR_TABLE_LEN, sizeof(struct hbucket));
export_task_attr();
-}
\ No newline at end of file
+}
+EXPORT_FILE_SYSTEM(taskfs, taskfs_init);
\ No newline at end of file
void
clock_init()
{
- hwrtc_init();
+ // hwrtc_init();
}
time_t
return __tty_read(dev, buf, offset, PG_SIZE);
}
-void
-lxconsole_spawn_ttydev()
-{
- struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
- tty_dev->ops.write = __tty_write;
- tty_dev->ops.write_page = __tty_write_pg;
- tty_dev->ops.read = __tty_read;
- tty_dev->ops.read_page = __tty_read_pg;
- tty_dev->ops.exec_cmd = __tty_exec_cmd;
-
- waitq_init(&lx_reader);
- input_add_listener(__lxconsole_listener);
-}
-
int
__tty_write(struct device* dev, void* buf, size_t offset, size_t len)
{
struct lx_timer* timer =
timer_run_ms(20, console_flush, NULL, TIMER_MODE_PERIODIC);
lx_console.flush_timer = timer;
-}
\ No newline at end of file
+}
+
+static int
+lxconsole_spawn_ttydev(struct device_def* devdef)
+{
+ struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
+ tty_dev->ops.write = __tty_write;
+ tty_dev->ops.write_page = __tty_write_pg;
+ tty_dev->ops.read = __tty_read;
+ tty_dev->ops.read_page = __tty_read_pg;
+ tty_dev->ops.exec_cmd = __tty_exec_cmd;
+
+ waitq_init(&lx_reader);
+ input_add_listener(__lxconsole_listener);
+
+ return 0;
+}
+
+static struct device_def lxconsole_def = {
+ .class = DEVCLASS(DEVIF_NON, DEVFN_TTY, DEV_BUILTIN, 0),
+ .init = lxconsole_spawn_ttydev
+};
+EXPORT_DEVICE(lxconsole, &lxconsole_def, load_earlystage);
\ No newline at end of file
/* align to 8 bytes, so it can cover both 32 and 64 bits address line*/
. = ALIGN(8);
- PROVIDE(__lga_pci_dev_drivers_start = .);
+ PROVIDE(__lga_devdefs_start = .);
- KEEP(*(.lga.pci_dev_drivers));
+ KEEP(*(.lga.devdefs));
- PROVIDE(__lga_pci_dev_drivers_end = .);
+ PROVIDE(__lga_devdefs_end = .);
/* ---- */
. = ALIGN(8);
- PROVIDE(__lga_rtcdev_start = .);
+ PROVIDE(__lga_dev_ld_early_start = .);
- KEEP(*(.lga.rtcdev));
+ KEEP(*(.lga.devdefs.ld_early));
- PROVIDE(__lga_rtcdev_end = .);
+ PROVIDE(__lga_dev_ld_early_end = .);
/* ---- */
. = ALIGN(8);
- PROVIDE(__lga_inputdev_start = .);
+ PROVIDE(__lga_dev_ld_aftertimer_start = .);
- KEEP(*(.lga.inputdev));
+ KEEP(*(.lga.devdefs.ld_aftertimer));
- PROVIDE(__lga_inputdev_end = .);
+ PROVIDE(__lga_dev_ld_aftertimer_end = .);
/* ---- */
. = ALIGN(8);
- PROVIDE(__lga_pseudo_dev_start = .);
+ PROVIDE(__lga_dev_ld_post_start = .);
- KEEP(*(.lga.pseudo_dev));
+ KEEP(*(.lga.devdefs.ld_post));
+
+ PROVIDE(__lga_dev_ld_post_end = .);
+
+ /* ---- */
+
+ . = ALIGN(8);
+
+ PROVIDE(__lga_fs_start = .);
+
+ KEEP(*(.lga.fs));
+
+ PROVIDE(__lga_fs_end = .);
- PROVIDE(__lga_pseudo_dev_end = .);
}
.bss BLOCK(4K) : AT ( ADDR(.bss) - 0xC0000000 ) {