mirror of
https://github.com/tailix/drivers.git
synced 2024-11-20 11:06:32 -05:00
Add existing drivers
This commit is contained in:
parent
b3dcc54312
commit
d0fc1ca09f
10 changed files with 339 additions and 2 deletions
16
Makefile.am
16
Makefile.am
|
@ -8,4 +8,18 @@ SUBDIRS = include
|
|||
lib_LTLIBRARIES = libdrivers.la
|
||||
|
||||
libdrivers_la_SOURCES = \
|
||||
src/foobar.c
|
||||
src/foobar.c \
|
||||
src/console.c \
|
||||
src/shutdown.c
|
||||
|
||||
# Intel 8253-compatible programmable interval timer
|
||||
|
||||
if ASM_I386
|
||||
libdrivers_la_SOURCES += src/intel_8253_pit.c
|
||||
endif
|
||||
|
||||
# Intel 8259-compatible programmable interrupt controller
|
||||
|
||||
if ASM_I386
|
||||
libdrivers_la_SOURCES += src/intel_8259_pic.c
|
||||
endif
|
||||
|
|
|
@ -1,2 +1,16 @@
|
|||
nobase_include_HEADERS = \
|
||||
drivers.h
|
||||
drivers.h \
|
||||
drivers/console.h \
|
||||
drivers/shutdown.h
|
||||
|
||||
# Intel 8253-compatible programmable interval timer
|
||||
|
||||
if ASM_I386
|
||||
nobase_include_HEADERS += drivers/intel_8253_pit.h
|
||||
endif
|
||||
|
||||
# Intel 8259-compatible programmable interrupt controller
|
||||
|
||||
if ASM_I386
|
||||
nobase_include_HEADERS += drivers/intel_8259_pic.h
|
||||
endif
|
||||
|
|
20
include/drivers/console.h
Normal file
20
include/drivers/console.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef INCLUDED_DRIVERS_CONSOLE
|
||||
#define INCLUDED_DRIVERS_CONSOLE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void drivers_console_putc(char c);
|
||||
|
||||
void drivers_console_print(const char *s);
|
||||
void drivers_console_puts(const char *s);
|
||||
void drivers_console_write(const char *data, size_t size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
21
include/drivers/intel_8253_pit.h
Normal file
21
include/drivers/intel_8253_pit.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* @brief A driver for Intel 8253-compatible programmable interval timer
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Intel_8253
|
||||
* @see https://wiki.osdev.org/PIT
|
||||
*/
|
||||
|
||||
#ifndef DRIVERS_INCLUDED_INTEL_8253_PIT
|
||||
#define DRIVERS_INCLUDED_INTEL_8253_PIT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void drivers_intel_8253_pit_initialize(unsigned int freq);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
57
include/drivers/intel_8259_pic.h
Normal file
57
include/drivers/intel_8259_pic.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/**
|
||||
* @brief A driver for Intel 8259-compatible programmable interrupt controller
|
||||
*
|
||||
* @details
|
||||
* This is not a driver for a random Intel 8259-compatible PIC, but only for a
|
||||
* typical configuration of it that can be found in most PCs.
|
||||
*
|
||||
* @see https://en.wikipedia.org/wiki/Intel_8259
|
||||
* @see https://wiki.osdev.org/8259_PIC
|
||||
* @see https://pdos.csail.mit.edu/6.828/2005/readings/hardware/8259A.pdf
|
||||
*/
|
||||
|
||||
#ifndef DRIVERS_INCLUDED_INTEL_8259_PIC
|
||||
#define DRIVERS_INCLUDED_INTEL_8259_PIC
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Enable PIC
|
||||
*/
|
||||
void drivers_intel_8259_pic_enable_all();
|
||||
|
||||
/**
|
||||
* @brief Disable PIC
|
||||
*/
|
||||
void drivers_intel_8259_pic_disable_all();
|
||||
|
||||
/**
|
||||
* @brief Enable single IRQ line
|
||||
*/
|
||||
void drivers_intel_8259_pic_enable(unsigned char number);
|
||||
|
||||
/**
|
||||
* @brief Disable single IRQ line
|
||||
*/
|
||||
void drivers_intel_8259_pic_disable(unsigned char number);
|
||||
|
||||
/**
|
||||
* @brief Remap PIC
|
||||
*/
|
||||
void drivers_intel_8259_pic_remap(
|
||||
unsigned char new_master_start,
|
||||
unsigned char new_slave_start
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Signal end of interrupt
|
||||
*/
|
||||
void drivers_intel_8259_pic_eoi(unsigned char number);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
15
include/drivers/shutdown.h
Normal file
15
include/drivers/shutdown.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef DRIVERS_INCLUDED_SHUTDOWN
|
||||
#define DRIVERS_INCLUDED_SHUTDOWN
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
__attribute__((noreturn)) void drivers_shutdown_halt();
|
||||
__attribute__((noreturn)) void drivers_shutdown_poweroff();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
36
src/console.c
Normal file
36
src/console.c
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <drivers/console.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
void drivers_console_putc(const char c)
|
||||
{
|
||||
#if defined(ASM_X86)
|
||||
__asm__ __volatile__("outb %1, %0" : : "dN" (0x3f8), "a" (c));
|
||||
#else
|
||||
(void)c;
|
||||
#endif
|
||||
}
|
||||
|
||||
void drivers_console_print(const char *const s)
|
||||
{
|
||||
for (const char *c = s; *c; ++c) {
|
||||
drivers_console_putc(*c);
|
||||
}
|
||||
}
|
||||
|
||||
void drivers_console_puts(const char *const s)
|
||||
{
|
||||
drivers_console_print(s);
|
||||
drivers_console_putc('\n');
|
||||
}
|
||||
|
||||
void drivers_console_write(const char *const data, const size_t size)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
drivers_console_putc(data[i]);
|
||||
}
|
||||
}
|
19
src/intel_8253_pit.c
Normal file
19
src/intel_8253_pit.c
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <drivers/intel_8253_pit.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
void drivers_intel_8253_pit_initialize(const unsigned int freq)
|
||||
{
|
||||
const unsigned int divisor = 1193180 / freq;
|
||||
|
||||
const uint8_t l = divisor & 0xff;
|
||||
const uint8_t h = (divisor >> 8) & 0xff;
|
||||
|
||||
__asm__ __volatile__("outb %1, %0" : : "dN" (0x43), "a" (0x36));
|
||||
__asm__ __volatile__("outb %1, %0" : : "dN" (0x40), "a" (l));
|
||||
__asm__ __volatile__("outb %1, %0" : : "dN" (0x40), "a" (h));
|
||||
}
|
112
src/intel_8259_pic.c
Normal file
112
src/intel_8259_pic.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <drivers/intel_8259_pic.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BITS8(n) ((uint8_t )(((uint8_t )1) << (n)))
|
||||
|
||||
#define MASTER_COMMAND_PORT 0x20
|
||||
#define SLAVE_COMMAND_PORT 0xA0
|
||||
|
||||
#define MASTER_DATA_PORT 0x21
|
||||
#define SLAVE_DATA_PORT 0xA1
|
||||
|
||||
#define IRQS_COUNT 8
|
||||
#define IRQS_TOTAL 16
|
||||
|
||||
static unsigned char master_start = 0;
|
||||
static unsigned char slave_start = 8;
|
||||
|
||||
static uint8_t inportb(const uint16_t port)
|
||||
{
|
||||
register uint8_t result;
|
||||
__asm__ __volatile__("inb %1, %0" : "=a" (result) : "dN" (port));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static void outportb(const uint16_t port, const uint8_t value)
|
||||
{
|
||||
__asm__ __volatile__("outb %1, %0" : : "dN" (port), "a" (value));
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_enable_all()
|
||||
{
|
||||
outportb(MASTER_DATA_PORT, 0);
|
||||
outportb(SLAVE_DATA_PORT, 0);
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_disable_all()
|
||||
{
|
||||
outportb(MASTER_DATA_PORT, 0xFF);
|
||||
outportb(SLAVE_DATA_PORT, 0xFF);
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_enable(const unsigned char number)
|
||||
{
|
||||
if (number < IRQS_COUNT) {
|
||||
const uint8_t mask = inportb(MASTER_DATA_PORT);
|
||||
outportb(MASTER_DATA_PORT, mask & ~BITS8(number));
|
||||
} else {
|
||||
const uint8_t mask = inportb(SLAVE_DATA_PORT);
|
||||
outportb(SLAVE_DATA_PORT, mask & ~BITS8((number - IRQS_COUNT)));
|
||||
}
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_disable(const unsigned char number)
|
||||
{
|
||||
if (number < IRQS_COUNT) {
|
||||
const uint8_t mask = inportb(MASTER_DATA_PORT);
|
||||
outportb(MASTER_DATA_PORT, mask | BITS8(number));
|
||||
} else {
|
||||
const uint8_t mask = inportb(SLAVE_DATA_PORT);
|
||||
outportb(SLAVE_DATA_PORT, mask | BITS8((number - IRQS_COUNT)));
|
||||
}
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_remap(
|
||||
const unsigned char new_master_start,
|
||||
const unsigned char new_slave_start
|
||||
) {
|
||||
master_start = new_master_start;
|
||||
slave_start = new_slave_start;
|
||||
|
||||
// Save masks
|
||||
const uint8_t master_mask = inportb(MASTER_DATA_PORT);
|
||||
const uint8_t slave_mask = inportb(SLAVE_DATA_PORT);
|
||||
|
||||
// Start the initialization sequence
|
||||
outportb(MASTER_COMMAND_PORT, 0x11);
|
||||
outportb(SLAVE_COMMAND_PORT, 0x11);
|
||||
|
||||
// Set IRQ vectors
|
||||
outportb(MASTER_DATA_PORT, new_master_start);
|
||||
outportb(SLAVE_DATA_PORT, new_slave_start);
|
||||
|
||||
// Connect master and slave with each other
|
||||
outportb(MASTER_DATA_PORT, 0x04);
|
||||
outportb(SLAVE_DATA_PORT, 0x02);
|
||||
|
||||
// 8086/88 (MCS-80/85) mode
|
||||
outportb(MASTER_DATA_PORT, 0x01);
|
||||
outportb(SLAVE_DATA_PORT, 0x01);
|
||||
|
||||
// Restore masks
|
||||
outportb(MASTER_DATA_PORT, master_mask);
|
||||
outportb(SLAVE_DATA_PORT, slave_mask);
|
||||
}
|
||||
|
||||
void drivers_intel_8259_pic_eoi(const unsigned char number)
|
||||
{
|
||||
const bool to_slave =
|
||||
number >= slave_start && number < slave_start + IRQS_COUNT;
|
||||
const bool to_master = to_slave ||
|
||||
(number >= master_start && number < master_start + IRQS_COUNT);
|
||||
|
||||
if (to_slave) outportb(SLAVE_COMMAND_PORT, 0x20);
|
||||
if (to_master) outportb(MASTER_COMMAND_PORT, 0x20);
|
||||
}
|
29
src/shutdown.c
Normal file
29
src/shutdown.c
Normal file
|
@ -0,0 +1,29 @@
|
|||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <drivers/shutdown.h>
|
||||
|
||||
void drivers_shutdown_halt()
|
||||
{
|
||||
#ifdef ASM_X86
|
||||
// Disable interrupts
|
||||
__asm__ __volatile__("cli");
|
||||
#endif
|
||||
|
||||
volatile int x = 0;
|
||||
for (;;) ++x;
|
||||
}
|
||||
|
||||
void drivers_shutdown_poweroff()
|
||||
{
|
||||
#ifdef ASM_X86
|
||||
// QEMU >= 2.0
|
||||
__asm__ __volatile__("outw %1, %0" : : "dN" (0x604), "a" (0x2000));
|
||||
// QEMU < 2.0
|
||||
__asm__ __volatile__("outw %1, %0" : : "dN" (0xB004), "a" (0x2000));
|
||||
#endif
|
||||
|
||||
// If we can't poweroff then we halt
|
||||
drivers_shutdown_halt();
|
||||
}
|
Loading…
Reference in a new issue