1
0
mirror of https://github.com/taigrr/gopher-os synced 2025-01-18 04:43:13 -08:00

Detect hw and wire active console and TTY

This commit is contained in:
Achilleas Anagnostopoulos 2017-07-06 09:24:41 +01:00
parent eca1f6c26e
commit 562fae2028
10 changed files with 186 additions and 22 deletions

View File

@ -13,3 +13,7 @@ type Driver interface {
// DriverInit initializes the device driver.
DriverInit() *kernel.Error
}
// ProbeFn is a function that scans for the presence of a particular
// piece of hardware and returns a driver for it.
type ProbeFn func() Driver

View File

@ -5,6 +5,14 @@ import (
"io"
)
const (
// DefaultScrollback defines the terminal scrollback in lines.
DefaultScrollback = 80
// DefaultTabWidth defines the number of spaces that tabs expand to.
DefaultTabWidth = 4
)
// State defines the supported terminal state values.
type State uint8

View File

@ -0,0 +1,11 @@
package tty
import "gopheros/device"
// HWProbes returns a slice of device.ProbeFn that can be used by the hal
// package to probe for TTY device hardware.
func HWProbes() []device.ProbeFn {
return []device.ProbeFn{
probeForVT,
}
}

View File

@ -1,6 +1,7 @@
package tty
import (
"gopheros/device"
"gopheros/device/video/console"
"gopheros/kernel"
"io"
@ -258,3 +259,7 @@ func (t *VT) DriverVersion() (uint16, uint16, uint16) {
// DriverInit initializes this driver.
func (t *VT) DriverInit() *kernel.Error { return nil }
func probeForVT() device.Driver {
return NewVT(DefaultTabWidth, DefaultScrollback)
}

View File

@ -5,6 +5,7 @@ import (
"gopheros/device/video/console"
"image/color"
"io"
"reflect"
"testing"
)
@ -337,6 +338,28 @@ func TestVTDriverInterface(t *testing.T) {
}
}
func TestVTProbe(t *testing.T) {
var (
expProbePtr = reflect.ValueOf(probeForVT).Pointer()
foundProbe bool
)
for _, probeFn := range HWProbes() {
if reflect.ValueOf(probeFn).Pointer() == expProbePtr {
foundProbe = true
break
}
}
if !foundProbe {
t.Fatal("expected probeForVT to be part of the probes returned by HWProbes")
}
if drv := probeForVT(); drv == nil {
t.Fatal("expected probeForVT to return a driver")
}
}
type mockConsole struct {
width, height uint16
fg, bg uint8

View File

@ -0,0 +1,16 @@
package console
import "gopheros/device"
import "gopheros/kernel/hal/multiboot"
var (
getFramebufferInfoFn = multiboot.GetFramebufferInfo
)
// HWProbes returns a slice of device.ProbeFn that can be used by the hal
// package to probe for console device hardware.
func HWProbes() []device.ProbeFn {
return []device.ProbeFn{
probeForVgaTextConsole,
}
}

View File

@ -1,8 +1,10 @@
package console
import (
"gopheros/device"
"gopheros/kernel"
"gopheros/kernel/cpu"
"gopheros/kernel/hal/multiboot"
"image/color"
"reflect"
"unsafe"
@ -196,3 +198,15 @@ func (cons *VgaTextConsole) DriverVersion() (uint16, uint16, uint16) {
// DriverInit initializes this driver.
func (cons *VgaTextConsole) DriverInit() *kernel.Error { return nil }
// probeForVgaTextConsole checks for the presence of a vga text console.
func probeForVgaTextConsole() device.Driver {
var drv device.Driver
fbInfo := getFramebufferInfoFn()
if fbInfo.Type == multiboot.FramebufferTypeEGA {
drv = NewVgaTextConsole(uint16(fbInfo.Width), uint16(fbInfo.Height), uintptr(fbInfo.PhysAddr))
}
return drv
}

View File

@ -3,7 +3,9 @@ package console
import (
"gopheros/device"
"gopheros/kernel/cpu"
"gopheros/kernel/hal/multiboot"
"image/color"
"reflect"
"testing"
"unsafe"
)
@ -318,3 +320,39 @@ func TestVgaTextDriverInterface(t *testing.T) {
t.Fatal("DriverVersion() returned an invalid version number")
}
}
func TestVgaTextProbe(t *testing.T) {
defer func() {
getFramebufferInfoFn = multiboot.GetFramebufferInfo
}()
var (
expProbePtr = reflect.ValueOf(probeForVgaTextConsole).Pointer()
foundProbe bool
)
for _, probeFn := range HWProbes() {
if reflect.ValueOf(probeFn).Pointer() == expProbePtr {
foundProbe = true
break
}
}
if !foundProbe {
t.Fatal("expected probeForVgaTextConsole to be part of the probes returned by HWProbes")
}
getFramebufferInfoFn = func() *multiboot.FramebufferInfo {
return &multiboot.FramebufferInfo{
Width: 80,
Height: 25,
Pitch: 160,
PhysAddr: 0xb80000,
Type: multiboot.FramebufferTypeEGA,
}
}
if drv := probeForVgaTextConsole(); drv == nil {
t.Fatal("expected probeForVgaTextConsole to return a driver")
}
}

View File

@ -1,23 +1,67 @@
package hal
import (
"gopheros/kernel/driver/tty"
"gopheros/kernel/driver/video/console"
"gopheros/kernel/hal/multiboot"
"gopheros/device"
"gopheros/device/tty"
"gopheros/device/video/console"
"gopheros/kernel/kfmt"
)
var (
egaConsole = &console.Ega{}
// ActiveTerminal points to the currently active terminal.
ActiveTerminal = &tty.Vt{}
)
// InitTerminal provides a basic terminal to allow the kernel to emit some output
// till everything is properly setup
func InitTerminal() {
fbInfo := multiboot.GetFramebufferInfo()
egaConsole.Init(uint16(fbInfo.Width), uint16(fbInfo.Height), uintptr(fbInfo.PhysAddr))
ActiveTerminal.AttachTo(egaConsole)
// managedDevices contains the devices discovered by the HAL.
type managedDevices struct {
activeConsole console.Device
activeTTY tty.Device
}
var devices managedDevices
// ActiveTTY returns the currently active TTY
func ActiveTTY() tty.Device {
return devices.activeTTY
}
// DetectHardware probes for hardware devices and initializes the appropriate
// drivers.
func DetectHardware() {
consoles := probe(console.HWProbes())
if len(consoles) != 0 {
devices.activeConsole = consoles[0].(console.Device)
}
ttys := probe(tty.HWProbes())
if len(ttys) != 0 {
devices.activeTTY = ttys[0].(tty.Device)
devices.activeTTY.AttachTo(devices.activeConsole)
kfmt.SetOutputSink(devices.activeTTY)
// Sync terminal contents with console
devices.activeTTY.SetState(tty.StateActive)
}
}
// probe executes the supplied hw probe functions and attempts to initialize
// each detected device. The function returns a list of device drivers that
// were successfully initialized.
func probe(hwProbeFns []device.ProbeFn) []device.Driver {
var drivers []device.Driver
for _, probeFn := range hwProbeFns {
drv := probeFn()
if drv == nil {
continue
}
major, minor, patch := drv.DriverVersion()
kfmt.Printf("[hal] %s(%d.%d.%d): ", drv.DriverName(), major, minor, patch)
if err := drv.DriverInit(); err != nil {
kfmt.Printf("init failed: %s\n", err.Message)
continue
}
drivers = append(drivers, drv)
kfmt.Printf("initialized\n")
}
return drivers
}

View File

@ -5,6 +5,7 @@ import (
"gopheros/kernel/goruntime"
"gopheros/kernel/hal"
"gopheros/kernel/hal/multiboot"
"gopheros/kernel/kfmt"
"gopheros/kernel/mem/pmm/allocator"
"gopheros/kernel/mem/vmm"
)
@ -27,9 +28,6 @@ var (
func Kmain(multibootInfoPtr, kernelStart, kernelEnd uintptr) {
multiboot.SetInfoPtr(multibootInfoPtr)
hal.InitTerminal()
hal.ActiveTerminal.Clear()
var err *kernel.Error
if err = allocator.Init(kernelStart, kernelEnd); err != nil {
panic(err)
@ -39,7 +37,10 @@ func Kmain(multibootInfoPtr, kernelStart, kernelEnd uintptr) {
panic(err)
}
// Use kernel.Panic instead of panic to prevent the compiler from
// Detect and initialize hardware
hal.DetectHardware()
// Use kfmt.Panic instead of panic to prevent the compiler from
// treating kernel.Panic as dead-code and eliminating it.
kernel.Panic(errKmainReturned)
kfmt.Panic(errKmainReturned)
}