diff --git a/arch/at91sam3x8e/serial.c b/arch/at91sam3x8e/serial.c index d540fe1..629233d 100644 --- a/arch/at91sam3x8e/serial.c +++ b/arch/at91sam3x8e/serial.c @@ -16,20 +16,20 @@ #include #include -struct arch_serial_interface arch_serial_default_interface = { +struct arch_serial_device arch_serial_default_device = { .tx_current = NULL, .tx_next = NULL, - .interface = { + .device = { .rx = NULL, .id = 0, .baud = 0, }, }; -struct serial_interface *serial_default_interface = &arch_serial_default_interface.interface; +struct serial_device *serial_default_device = &arch_serial_default_device.device; -int arch_serial_init(struct serial_interface *interface) +int arch_serial_init(struct serial_device *dev) { - if (interface->baud <= 0 || interface->id != 0) + if (dev->baud <= 0 || dev->id != 0) return -1; /* enable peripheral clock for UART (which has peripheral id 8) */ @@ -49,7 +49,7 @@ int arch_serial_init(struct serial_interface *interface) REG_UART_MR = REG_UART_MR_PAR_NO | REG_UART_MR_CHMODE_NORMAL; /* From Atmel Datasheet: baud rate = MCK / (REG_UART_BRGR * 16) */ - REG_UART_BRGR = (uint16_t)(( sys_core_clock / (uint32_t)interface->baud ) >> 4); + REG_UART_BRGR = (uint16_t)(( sys_core_clock / (uint32_t)dev->baud ) >> 4); /* choose the events we want an interrupt on */ REG_UART_IDR = 0xFFFFFFFF; /* make sure all interrupts are disabled first */ @@ -65,9 +65,9 @@ int arch_serial_init(struct serial_interface *interface) return 0; } -void arch_serial_exit(struct serial_interface *interface) +void arch_serial_exit(struct serial_device *dev) { - if (interface->id != 0) + if (dev->id != 0) return; /* disable receiver and transmitter */ @@ -78,15 +78,15 @@ void arch_serial_exit(struct serial_interface *interface) /* disable peripheral clock for UART (PID is taken from Atmel Datasheet, Section 9.1 */ REG_PMC_PCDR0 = REG_PMC_PCDR0_PID(8); - interface->id = -1; + dev->id = -1; } -ssize_t arch_serial_write(struct serial_interface *interface, const void *buf, size_t len) +ssize_t arch_serial_write(struct serial_device *dev, const void *buf, size_t len) { struct arch_serial_buffer *arch_buf = NULL; - struct arch_serial_interface *arch_iface = to_arch_serial_interface(interface); + struct arch_serial_device *arch_dev = to_arch_serial_device(dev); - if (arch_iface->tx_next != NULL) + if (arch_dev->tx_next != NULL) return -EBUSY; if (len >= (1 << 16)) /* DMA uses 16-bit counters */ @@ -99,14 +99,14 @@ ssize_t arch_serial_write(struct serial_interface *interface, const void *buf, s memcpy(&arch_buf->data[0], buf, len); arch_buf->len = (uint16_t)len; - if (arch_iface->tx_current == NULL) { - arch_iface->tx_current = arch_buf; + if (arch_dev->tx_current == NULL) { + arch_dev->tx_current = arch_buf; REG_UART_PDC_TPR = (uint32_t)&arch_buf->data[0]; REG_UART_PDC_TCR = arch_buf->len; /* we weren't transmitting, so the interrupt was masked */ REG_UART_IER = REG_UART_IER_ENDTX_MASK; } else { - arch_iface->tx_next = arch_buf; + arch_dev->tx_next = arch_buf; REG_UART_PDC_TNPR = (uint32_t)&arch_buf->data[0]; REG_UART_PDC_TNCR = arch_buf->len; } @@ -122,19 +122,19 @@ void irq_uart(void) /* RX has received a byte, store it into the ring buffer */ if (state & REG_UART_SR_RXRDY_MASK) { tmp = REG_UART_RHR; - ringbuf_write(arch_serial_default_interface.interface.rx, &tmp, sizeof(tmp)); + ringbuf_write(arch_serial_default_device.device.rx, &tmp, sizeof(tmp)); } /* REG_UART_PDC_TCR has reached zero */ if (state & REG_UART_SR_ENDTX_MASK) { /* this might be NULL but that's ok because free() tolerates that */ - free(arch_serial_default_interface.tx_current); + free(arch_serial_default_device.tx_current); /* DMA automatically does this to the actual hardware registers */ - arch_serial_default_interface.tx_current = arch_serial_default_interface.tx_next; - arch_serial_default_interface.tx_next = NULL; + arch_serial_default_device.tx_current = arch_serial_default_device.tx_next; + arch_serial_default_device.tx_next = NULL; - if (arch_serial_default_interface.tx_current == NULL) + if (arch_serial_default_device.tx_current == NULL) REG_UART_IDR = REG_UART_IDR_ENDTX_MASK; } diff --git a/include/arch/at91sam3x8e/serial.h b/include/arch/at91sam3x8e/serial.h index cb96294..9cd529f 100644 --- a/include/arch/at91sam3x8e/serial.h +++ b/include/arch/at91sam3x8e/serial.h @@ -18,23 +18,23 @@ struct arch_serial_buffer { uint8_t data[]; }; -/** Architecture-specific extension of `struct serial_interface` */ -struct arch_serial_interface { +/** Architecture-specific extension of `struct serial_device` */ +struct arch_serial_device { /** should always match REG_UART_PDC_TPR */ struct arch_serial_buffer *tx_current; /** should always match REG_UART_PDC_TNPR */ struct arch_serial_buffer *tx_next; - struct serial_interface interface; + struct serial_device device; }; /** - * Cast a `struct serial_interface` out to a `struct arch_serial_interface`. + * Cast a `struct serial_device` out to a `struct arch_serialdevice`. * - * @param ptr: The `struct serial_interface *` to cast out from. - * @returns The containing `struct arch_serial_interface *`. + * @param ptr: The `struct serial_device *` to cast out from. + * @returns The containing `struct arch_serialdevice *`. */ -#define to_arch_serial_interface(ptr) container_of(ptr, struct arch_serial_interface, interface) +#define to_arch_serial_device(ptr) container_of(ptr, struct arch_serial_device, device) /* * Copyright (c) 2020 Felix Kopp diff --git a/include/arch/serial.h b/include/arch/serial.h index f7c848a..2591d03 100644 --- a/include/arch/serial.h +++ b/include/arch/serial.h @@ -7,19 +7,19 @@ #include -int arch_serial_init(struct serial_interface *interface); -void arch_serial_exit(struct serial_interface *interface); +int arch_serial_init(struct serial_device *dev); +void arch_serial_exit(struct serial_device *dev); /** * Copy `buf` to a hardware buffer in the TX queue. * The transmission is performed asynchronously. * - * @param interface: serial interface to enqueue the buffer for + * @param dev: serial device to enqueue the buffer for * @param buf: raw buffer data * @param len: length of `buf` * @returns actual amount of bytes enqueued, or a negative error code on failure */ -ssize_t arch_serial_write(struct serial_interface *interface, const void *buf, size_t len); +ssize_t arch_serial_write(struct serial_device *dev, const void *buf, size_t len); #include ARCH_INCLUDE(serial.h) diff --git a/include/ardix/device.h b/include/ardix/device.h new file mode 100644 index 0000000..9975834 --- /dev/null +++ b/include/ardix/device.h @@ -0,0 +1,70 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* See the end of this file for copyright, licensing, and warranty information. */ + +#pragma once + +#include +#include +#include +#include + +#include + +/** Top-level abstraction for any device connected to the system. */ +struct device { + struct kent kent; +}; + +/** Cast a kent out to its containing struct device */ +#define to_device(ptr) container_of(ptr, struct device, kent) + +extern struct kent *devices_kent; + +/** Initialize the devices subsystem. */ +int devices_init(void); + +/** + * Initialize a device and add it to the device tree. + * + * @param dev: device to initialze + * @param parent: parent device (may me `NULL` if unapplicable) + * @returns 0 on success, or a negative error code on failure + */ +int device_init(struct device *dev, struct device *parent); + +/** Increment a device's reference counter. */ +inline void device_get(struct device *dev) +{ + kent_get(&dev->kent); +} + +/** Decrement a device's referece counter. */ +inline void device_put(struct device *dev) +{ + kent_put(&dev->kent); +} + +/* + * Copyright (c) 2021 Felix Kopp + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/include/ardix/serial.h b/include/ardix/serial.h index eeb7c99..3027a8f 100644 --- a/include/ardix/serial.h +++ b/include/ardix/serial.h @@ -3,6 +3,7 @@ #pragma once +#include #include #include @@ -18,50 +19,47 @@ #define SERIAL_BUFSZ 256 #endif -struct serial_interface { +struct serial_device { + struct device device; struct ringbuf *rx; long int baud; int id; }; /** The default serial console (this is where printk outputs to) */ -extern struct serial_interface *serial_default_interface; +extern struct serial_device *serial_default_device; /** - * Initialize a serial interface. + * Initialize a serial device. * - * @param interface: The serial interface. - * @param baud: The baud rate (bits/second). + * @param dev: serial device + * @param baud: baud rate (bits/sec) * @returns 0 on success, a negative number otherwise. */ -int serial_init(struct serial_interface *interface, long int baud); +int serial_init(struct serial_device *dev, long int baud); -/** - * Flush all buffers (if possible) and close the serial interface. - * - * @param interface: The serial interface. - */ -void serial_exit(struct serial_interface *interface); +/** Flush all buffers (if possible) and close the serial device. */ +void serial_exit(struct serial_device *dev); /** * Read from the serial buffer. * - * @param dest: Where to store the received data. - * @param interface: The serial interface to read data from. - * @param len: The maximum amount of bytes to read. - * @returns The actual amount of bytes read. + * @param dest: where to write received data + * @param dev: serial device to read from + * @param len: amount of bytes to read + * @returns actual amount of bytes read */ -ssize_t serial_read(void *dest, struct serial_interface *interface, size_t len); +ssize_t serial_read(void *dest, struct serial_device *dev, size_t len); /** * Write data to the serial buffer. * - * @param interface: The serial interface to write data to. - * @param data: The data to write. - * @param len: The length of `data`. - * @returns The actual amount of bytes written. + * @param dev: serial device to write to + * @param data: where to read data from + * @param len: amount of bytes to write + * @returns actual amount of bytes written */ -ssize_t serial_write(struct serial_interface *interface, const void *data, size_t len); +ssize_t serial_write(struct serial_device *dev, const void *data, size_t len); /* * Copyright (c) 2020 Felix Kopp diff --git a/include/ardix/util.h b/include/ardix/util.h index b2320ba..aaa28e3 100644 --- a/include/ardix/util.h +++ b/include/ardix/util.h @@ -5,6 +5,8 @@ #include +#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) + /** * Cast a pointer to a member of a struct out to the containing structure. * diff --git a/init/main.c b/init/main.c index da9d4b3..4e415d0 100644 --- a/init/main.c +++ b/init/main.c @@ -6,10 +6,10 @@ #include #include #include -#include #include #include +#include #define REG_PIOB_PER (*(uint32_t *)0x400E1000U) #define REG_PIOB_PDR (*(uint32_t *)0x400E1004U) @@ -34,9 +34,12 @@ void do_bootstrap(void) REG_PIOB_CODR = 1 << 27; sched_init(); + + devices_init(); + io_init(); - printk("hello, world\n"); + write(1, "hello, world\n", 13); while (true) { if (count++ != 1000000) @@ -47,7 +50,6 @@ void do_bootstrap(void) REG_PIOB_CODR = 1 << 27; else REG_PIOB_SODR = 1 << 27; - printk("endless loop iteration #%u\n", print_count); count = 0; } diff --git a/kernel/Makefile b/kernel/Makefile index 4132f4c..a91ae3b 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -29,6 +29,7 @@ include $(ARDIX_KERNEL_PWD)/fs/Makefile include $(ARDIX_KERNEL_PWD)/io/Makefile ARDIX_SOURCES += \ + $(ARDIX_KERNEL_PWD)/device.c \ $(ARDIX_KERNEL_PWD)/kent.c \ $(ARDIX_KERNEL_PWD)/printk.c \ $(ARDIX_KERNEL_PWD)/ringbuf.c \ diff --git a/kernel/device.c b/kernel/device.c new file mode 100644 index 0000000..89c1b42 --- /dev/null +++ b/kernel/device.c @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: BSD-3-Clause */ +/* See the end of this file for copyright, licensing, and warranty information. */ + +#include +#include +#include +#include +#include + +#include +#include + +struct kent *devices_kent = NULL; + +/** Initialize the devices subsystem. */ +int devices_init(void) +{ + if (devices_kent != NULL) + return -EEXIST; + + devices_kent = malloc(sizeof(*devices_kent)); + if (devices_kent == NULL) + return -ENOMEM; + + return kent_init(NULL, devices_kent); +} + +int device_init(struct device *dev, struct device *parent) +{ + if (devices_kent == NULL) + return -ENOENT; + + return kent_init(devices_kent, &dev->kent); +} + +/* + * Copyright (c) 2021 Felix Kopp + * + * Redistribution and use in source and binary forms, with or without modification, are permitted + * provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, this list of + * conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors may be + * used to endorse or promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY + * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/kernel/fs/read.c b/kernel/fs/read.c index 193ba3d..0053100 100644 --- a/kernel/fs/read.c +++ b/kernel/fs/read.c @@ -22,7 +22,7 @@ ssize_t sys_read(int fd, __user void *buf, size_t len) if (copy == NULL) return -ENOMEM; - ret = serial_read(copy, serial_default_interface, len); + ret = serial_read(copy, serial_default_device, len); if (ret > 0) copy_to_user(buf, copy, (size_t)ret); diff --git a/kernel/fs/write.c b/kernel/fs/write.c index 13bbd19..daf53aa 100644 --- a/kernel/fs/write.c +++ b/kernel/fs/write.c @@ -24,7 +24,7 @@ ssize_t sys_write(int fd, __user const void *buf, size_t len) ret = (ssize_t)copy_from_user(copy, buf, len); /* TODO: reschedule if blocking */ - ret = serial_write(serial_default_interface, copy, (size_t)ret); + ret = serial_write(serial_default_device, copy, (size_t)ret); free(copy); diff --git a/kernel/io/io.c b/kernel/io/io.c index b2a6e32..9e77d07 100644 --- a/kernel/io/io.c +++ b/kernel/io/io.c @@ -8,7 +8,7 @@ int io_init(void) { int ret; - ret = serial_init(serial_default_interface, CONFIG_SERIAL_BAUD); + ret = serial_init(serial_default_device, CONFIG_SERIAL_BAUD); return ret; } diff --git a/kernel/printk.c b/kernel/printk.c index 884e9bd..327a877 100644 --- a/kernel/printk.c +++ b/kernel/printk.c @@ -17,8 +17,8 @@ * TODO: THIS CAUSES A STACK BUFFER OVERFLOW ON SYSTEMS WHERE INT IS 64 BITS */ -/* 10 decimal digits (2 ** 32 - 1) + ASCII NUL */ -#define PRINTK_UINT_BUFSZ 11 +/* 10 decimal digits of 4294967295 (2 ** 32 - 1) */ +#define PRINTK_UINT_BUFSZ 10 __rodata static const char fmt_hex_table[] = { '0', '1', '2', '3', @@ -42,7 +42,7 @@ static int fmt_handle_ptr(uintptr_t ptr) ptr >>= 4; } while (pos != &buf[2]); - ret = serial_write(serial_default_interface, &buf[0], 2 * sizeof(uintptr_t) + 2); + ret = serial_write(serial_default_device, &buf[0], 2 * sizeof(uintptr_t) + 2); return ret; } @@ -59,7 +59,7 @@ static int fmt_handle_uint(unsigned int u) } while (u != 0); pos++; - ret = serial_write(serial_default_interface, pos, + ret = serial_write(serial_default_device, pos, PRINTK_UINT_BUFSZ - ( (size_t)pos - (size_t)&buf[0] )); return ret; } @@ -70,7 +70,7 @@ static inline int fmt_handle_int(int i) char minus = '-'; if (i < 0) { - ret = serial_write(serial_default_interface, &minus, sizeof(minus)); + ret = serial_write(serial_default_device, &minus, sizeof(minus)); i = -i; } @@ -102,12 +102,12 @@ static inline int fmt_handle(const char **pos, va_list args) switch (**pos) { case '%': /* literal percent sign */ - ret = serial_write(serial_default_interface, *pos, sizeof(**pos)); + ret = serial_write(serial_default_device, *pos, sizeof(**pos)); break; case 'c': /* char */ val.c = va_arg(args, typeof(val.c)); - ret = serial_write(serial_default_interface, &val.c, sizeof(val.c)); + ret = serial_write(serial_default_device, &val.c, sizeof(val.c)); break; case 'd': /* int */ @@ -123,7 +123,7 @@ static inline int fmt_handle(const char **pos, va_list args) case 's': /* string */ val.s = va_arg(args, typeof(val.s)); ret = (int)strlen(val.s); - ret = serial_write(serial_default_interface, val.s, (size_t)ret); + ret = serial_write(serial_default_device, val.s, (size_t)ret); break; case 'u': /* unsigned int */ @@ -149,7 +149,7 @@ int printk(const char *fmt, ...) while (*tmp != '\0') { if (*tmp++ == '%') { /* flush out everything we have so far (minus one char for %) */ - ret += (int)serial_write(serial_default_interface, fmt, + ret += (int)serial_write(serial_default_device, fmt, (size_t)tmp - (size_t)fmt - 1); tmpret = fmt_handle(&tmp, args); @@ -166,9 +166,10 @@ int printk(const char *fmt, ...) } if (tmp != fmt && ret >= 0) - ret += serial_write(serial_default_interface, fmt, (size_t)tmp - (size_t)fmt); + ret += serial_write(serial_default_device, fmt, (size_t)tmp - (size_t)fmt); va_end(args); + return ret; } diff --git a/kernel/serial.c b/kernel/serial.c index 8cab586..697d649 100644 --- a/kernel/serial.c +++ b/kernel/serial.c @@ -2,6 +2,7 @@ /* See the end of this file for copyright, licensing, and warranty information. */ #include +#include #include #include #include @@ -10,50 +11,52 @@ #include -int serial_init(struct serial_interface *interface, long int baud) +int serial_init(struct serial_device *dev, long int baud) { int err = -1; - if (interface->id < 0) - return -1; /* invalid interface */ + if (dev->id < 0) + return -1; /* invalid dev */ - interface->baud = baud; + err = device_init(&dev->device, NULL); - interface->rx = ringbuf_create(SERIAL_BUFSZ); - if (interface->rx == NULL) + dev->baud = baud; + + dev->rx = ringbuf_create(SERIAL_BUFSZ); + if (dev->rx == NULL) return -1; - err = arch_serial_init(interface); + err = arch_serial_init(dev); if (err) - ringbuf_destroy(interface->rx); + ringbuf_destroy(dev->rx); return err; } -void serial_exit(struct serial_interface *interface) +void serial_exit(struct serial_device *dev) { - arch_serial_exit(interface); - ringbuf_destroy(interface->rx); - interface->id = -1; + arch_serial_exit(dev); + ringbuf_destroy(dev->rx); + dev->id = -1; } -ssize_t serial_read(void *dest, struct serial_interface *interface, size_t len) +ssize_t serial_read(void *dest, struct serial_device *dev, size_t len) { ssize_t ret; atomic_enter(); - ret = (ssize_t)ringbuf_read(dest, interface->rx, len); + ret = (ssize_t)ringbuf_read(dest, dev->rx, len); atomic_leave(); return ret; } -ssize_t serial_write(struct serial_interface *interface, const void *data, size_t len) +ssize_t serial_write(struct serial_device *dev, const void *data, size_t len) { ssize_t ret; atomic_enter(); - ret = arch_serial_write(interface, data, len); + ret = arch_serial_write(dev, data, len); atomic_leave(); return ret;