summaryrefslogtreecommitdiff
path: root/drivers/console.cc
blob: f741dd2b1354479021889841820ff1d57d184c3a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */

/*
 * console.cc — Console character device (/dev/console)
 *
 * Wraps the existing early_putc() UART driver as a file_operations
 * chardev.  read() is a stub for now (returns 0 = EOF).
 * write() sends each byte through early_putc().
 */

#include <lume/file.h>
#include <lume/chardev.h>
#include <lume/types.h>

extern "C" void early_putc(char c);

/* ================================================================== */
/*  console_write                                                     */
/* ================================================================== */

static int64 console_write(file* fp, const char* buf, uint64 count, int64* pos)
{
    (void)fp;
    (void)pos;

    for (uint64 i = 0; i < count; i++) {
        early_putc(buf[i]);
    }

    return static_cast<int64>(count);
}

/* ================================================================== */
/*  console_read — stub (returns 0 = EOF for now)                     */
/* ================================================================== */

static int64 console_read(file* fp, char* buf, uint64 count, int64* pos)
{
    (void)fp;
    (void)buf;
    (void)count;
    (void)pos;
    /* TODO: implement UART RX polling/IRQ-based blocking read */
    return 0;
}

/* ================================================================== */
/*  null device — /dev/null                                           */
/* ================================================================== */

static int64 null_read(file* /*fp*/, char* /*buf*/, uint64 /*count*/, int64* /*pos*/)
{
    return 0;  /* EOF */
}

static int64 null_write(file* /*fp*/, const char* /*buf*/, uint64 count, int64* /*pos*/)
{
    return static_cast<int64>(count);  /* discard */
}

/* ================================================================== */
/*  zero device — /dev/zero                                           */
/* ================================================================== */

static int64 zero_read(file* /*fp*/, char* buf, uint64 count, int64* /*pos*/)
{
    for (uint64 i = 0; i < count; i++) {
        buf[i] = 0;
    }
    return static_cast<int64>(count);
}

static int64 zero_write(file* /*fp*/, const char* /*buf*/, uint64 count, int64* /*pos*/)
{
    return static_cast<int64>(count);  /* discard */
}

/* ================================================================== */
/*  Registration — runtime init (no static initializers!)             */
/* ================================================================== */

static file_operations console_fops;
static file_operations null_fops;
static file_operations zero_fops;

static cdev console_cdev;
static cdev null_cdev;
static cdev zero_cdev;

void console_cdev_init()
{
    /* Console: major=5, minor=1 */
    console_fops.read  = console_read;
    console_fops.write = console_write;

    console_cdev.name = "console";
    console_cdev.dev  = MKDEV(5, 1);
    console_cdev.fops = &console_fops;
    cdev_register(&console_cdev);

    /* /dev/null: major=1, minor=3 */
    null_fops.read  = null_read;
    null_fops.write = null_write;

    null_cdev.name = "null";
    null_cdev.dev  = MKDEV(1, 3);
    null_cdev.fops = &null_fops;
    cdev_register(&null_cdev);

    /* /dev/zero: major=1, minor=5 */
    zero_fops.read  = zero_read;
    zero_fops.write = zero_write;

    zero_cdev.name = "zero";
    zero_cdev.dev  = MKDEV(1, 5);
    zero_cdev.fops = &zero_fops;
    cdev_register(&zero_cdev);
}