mirror of
https://github.com/taigrr/gopher-os
synced 2025-01-18 04:43:13 -08:00
Merge pull request #47 from achilleasa/order-based-driver-probing
Order based driver detection/loading
This commit is contained in:
commit
4b25971cef
@ -22,3 +22,68 @@ type Driver interface {
|
||||
// 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
|
||||
|
||||
// DetectOrder specifies when each driver's probe function will be invoked
|
||||
// by the hal package.
|
||||
type DetectOrder int8
|
||||
|
||||
const (
|
||||
// DetectOrderEarly specifies that the driver's probe function should
|
||||
// be executed at the beginning of the HW detection phase. It is used
|
||||
// by some of the console and TTY device drivers.
|
||||
DetectOrderEarly DetectOrder = -128
|
||||
|
||||
// DetectOrderBeforeACPI specifies that the driver's probe function
|
||||
// should be executed before attempting any ACPI-based HW detection but
|
||||
// after any drivers with DetectOrderEarly.
|
||||
DetectOrderBeforeACPI = -127
|
||||
|
||||
// DetectOrderACPI specifies that the driver's probe function should
|
||||
// be executed after parsing the ACPI tables. This is the default (zero
|
||||
// value) for all drivers.
|
||||
DetectOrderACPI = 0
|
||||
|
||||
// DetectOrderLast specifies that the driver's probe function should
|
||||
// be executed at the end of the HW detection phase.
|
||||
DetectOrderLast = 127
|
||||
)
|
||||
|
||||
// DriverInfo is a driver-defined struct that is passed to calls to RegisterDriver.
|
||||
type DriverInfo struct {
|
||||
// Order specifies at which stage of the HW detection step should
|
||||
// the probe function be invoked.
|
||||
Order DetectOrder
|
||||
|
||||
// Probe is a function that checks for the presence of a particular
|
||||
// piece of hardware and returns back a driver for it.
|
||||
Probe ProbeFn
|
||||
}
|
||||
|
||||
// DriverInfoList is a list of registered drivers that implements sort.Sort.
|
||||
type DriverInfoList []*DriverInfo
|
||||
|
||||
// Len returns the length of the driver info list.
|
||||
func (l DriverInfoList) Len() int { return len(l) }
|
||||
|
||||
// Swap exchanges 2 elements in the driver info list.
|
||||
func (l DriverInfoList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
|
||||
|
||||
// Less compares 2 elements of the driver info list.
|
||||
func (l DriverInfoList) Less(i, j int) bool { return l[i].Order < l[j].Order }
|
||||
|
||||
var (
|
||||
// registeredDrivers tracks the drivers registered via a call to
|
||||
// RegisterDriver.
|
||||
registeredDrivers DriverInfoList
|
||||
)
|
||||
|
||||
// RegisterDriver adds the supplied driver info to the list of registered
|
||||
// drivers. The list can be retrieved by a call to DriverList().
|
||||
func RegisterDriver(info *DriverInfo) {
|
||||
registeredDrivers = append(registeredDrivers, info)
|
||||
}
|
||||
|
||||
// DriverList returns the list of registered drivers.
|
||||
func DriverList() DriverInfoList {
|
||||
return registeredDrivers
|
||||
}
|
||||
|
36
src/gopheros/device/driver_test.go
Normal file
36
src/gopheros/device/driver_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package device
|
||||
|
||||
import (
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDriverInfoListSorting(t *testing.T) {
|
||||
defer func() {
|
||||
registeredDrivers = nil
|
||||
}()
|
||||
|
||||
origlist := []*DriverInfo{
|
||||
&DriverInfo{Order: DetectOrderACPI},
|
||||
&DriverInfo{Order: DetectOrderLast},
|
||||
&DriverInfo{Order: DetectOrderBeforeACPI},
|
||||
&DriverInfo{Order: DetectOrderEarly},
|
||||
}
|
||||
|
||||
for _, drv := range origlist {
|
||||
RegisterDriver(drv)
|
||||
}
|
||||
|
||||
registeredList := DriverList()
|
||||
if exp, got := len(origlist), len(registeredList); got != exp {
|
||||
t.Fatalf("expected DriverList() to return %d entries; got %d", exp, got)
|
||||
}
|
||||
|
||||
sort.Sort(registeredList)
|
||||
expOrder := []int{3, 2, 0, 1}
|
||||
for i, exp := range expOrder {
|
||||
if registeredList[i] != origlist[exp] {
|
||||
t.Errorf("expected sorted entry %d to be %v; got %v", i, registeredList[exp], origlist[i])
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
package tty
|
||||
|
||||
import "gopheros/device"
|
||||
|
||||
var (
|
||||
// ProbeFuncs is a slice of device probe functions
|
||||
// that is used by the hal package to probe for TTY
|
||||
// hardware. Each driver should use an init() block
|
||||
// to append its probe function to this list.
|
||||
ProbeFuncs []device.ProbeFn
|
||||
)
|
@ -265,5 +265,8 @@ func probeForVT() device.Driver {
|
||||
}
|
||||
|
||||
func init() {
|
||||
ProbeFuncs = append(ProbeFuncs, probeForVT)
|
||||
device.RegisterDriver(&device.DriverInfo{
|
||||
Order: device.DetectOrderEarly,
|
||||
Probe: probeForVT,
|
||||
})
|
||||
}
|
||||
|
@ -3,9 +3,18 @@ package console
|
||||
import (
|
||||
"gopheros/device/video/console/font"
|
||||
"gopheros/device/video/console/logo"
|
||||
"gopheros/kernel/cpu"
|
||||
"gopheros/kernel/hal/multiboot"
|
||||
"gopheros/kernel/mem/vmm"
|
||||
"image/color"
|
||||
)
|
||||
|
||||
var (
|
||||
mapRegionFn = vmm.MapRegion
|
||||
portWriteByteFn = cpu.PortWriteByte
|
||||
getFramebufferInfoFn = multiboot.GetFramebufferInfo
|
||||
)
|
||||
|
||||
// ScrollDir defines a scroll direction.
|
||||
type ScrollDir uint8
|
||||
|
||||
|
@ -1,19 +0,0 @@
|
||||
package console
|
||||
|
||||
import (
|
||||
"gopheros/device"
|
||||
"gopheros/kernel/cpu"
|
||||
"gopheros/kernel/hal/multiboot"
|
||||
"gopheros/kernel/mem/vmm"
|
||||
)
|
||||
|
||||
var (
|
||||
mapRegionFn = vmm.MapRegion
|
||||
portWriteByteFn = cpu.PortWriteByte
|
||||
getFramebufferInfoFn = multiboot.GetFramebufferInfo
|
||||
|
||||
// ProbeFuncs is a slice of device probe functions that is used by
|
||||
// the hal package to probe for console device hardware. Each driver
|
||||
// should use an init() block to append its probe function to this list.
|
||||
ProbeFuncs []device.ProbeFn
|
||||
)
|
@ -603,5 +603,8 @@ func probeForVesaFbConsole() device.Driver {
|
||||
}
|
||||
|
||||
func init() {
|
||||
ProbeFuncs = append(ProbeFuncs, probeForVesaFbConsole)
|
||||
device.RegisterDriver(&device.DriverInfo{
|
||||
Order: device.DetectOrderEarly,
|
||||
Probe: probeForVesaFbConsole,
|
||||
})
|
||||
}
|
||||
|
@ -236,5 +236,8 @@ func probeForVgaTextConsole() device.Driver {
|
||||
}
|
||||
|
||||
func init() {
|
||||
ProbeFuncs = append(ProbeFuncs, probeForVgaTextConsole)
|
||||
device.RegisterDriver(&device.DriverInfo{
|
||||
Order: device.DetectOrderEarly,
|
||||
Probe: probeForVgaTextConsole,
|
||||
})
|
||||
}
|
||||
|
@ -9,12 +9,16 @@ import (
|
||||
"gopheros/device/video/console/logo"
|
||||
"gopheros/kernel/hal/multiboot"
|
||||
"gopheros/kernel/kfmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// managedDevices contains the devices discovered by the HAL.
|
||||
type managedDevices struct {
|
||||
activeConsole console.Device
|
||||
activeTTY tty.Device
|
||||
|
||||
// activeDrivers tracks all initialized device drivers.
|
||||
activeDrivers []device.Driver
|
||||
}
|
||||
|
||||
var (
|
||||
@ -30,70 +34,20 @@ func ActiveTTY() tty.Device {
|
||||
// DetectHardware probes for hardware devices and initializes the appropriate
|
||||
// drivers.
|
||||
func DetectHardware() {
|
||||
consoles := probe(console.ProbeFuncs)
|
||||
if len(consoles) != 0 {
|
||||
devices.activeConsole = consoles[0].(console.Device)
|
||||
// Get driver list and sort by detection priority
|
||||
drivers := device.DriverList()
|
||||
sort.Sort(drivers)
|
||||
|
||||
if logoSetter, ok := (devices.activeConsole).(console.LogoSetter); ok {
|
||||
disableLogo := false
|
||||
for k, v := range multiboot.GetBootCmdLine() {
|
||||
if k == "consoleLogo" && v == "off" {
|
||||
disableLogo = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !disableLogo {
|
||||
consW, consH := devices.activeConsole.Dimensions(console.Pixels)
|
||||
logoSetter.SetLogo(logo.BestFit(consW, consH))
|
||||
}
|
||||
}
|
||||
|
||||
if fontSetter, ok := (devices.activeConsole).(console.FontSetter); ok {
|
||||
consW, consH := devices.activeConsole.Dimensions(console.Pixels)
|
||||
|
||||
// Check boot cmdline for a font request
|
||||
var selFont *font.Font
|
||||
for k, v := range multiboot.GetBootCmdLine() {
|
||||
if k != "consoleFont" {
|
||||
continue
|
||||
}
|
||||
|
||||
if selFont = font.FindByName(v); selFont != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if selFont == nil {
|
||||
selFont = font.BestFit(consW, consH)
|
||||
}
|
||||
|
||||
fontSetter.SetFont(selFont)
|
||||
}
|
||||
}
|
||||
|
||||
ttys := probe(tty.ProbeFuncs)
|
||||
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(drivers)
|
||||
}
|
||||
|
||||
// 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
|
||||
w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()}
|
||||
)
|
||||
// probe executes the probe function for each driver and invokes
|
||||
// onDriverInit for each successfully initialized driver.
|
||||
func probe(driverInfoList device.DriverInfoList) {
|
||||
var w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()}
|
||||
|
||||
for _, probeFn := range hwProbeFns {
|
||||
drv := probeFn()
|
||||
for _, info := range driverInfoList {
|
||||
drv := info.Probe()
|
||||
if drv == nil {
|
||||
continue
|
||||
}
|
||||
@ -109,8 +63,91 @@ func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
||||
}
|
||||
|
||||
kfmt.Fprintf(&w, "initialized\n")
|
||||
drivers = append(drivers, drv)
|
||||
onDriverInit(info, drv)
|
||||
devices.activeDrivers = append(devices.activeDrivers, drv)
|
||||
}
|
||||
}
|
||||
|
||||
// onDriverInit is invoked by probe() whenever a piece of hardware is detected
|
||||
// and successfully initialized.
|
||||
func onDriverInit(info *device.DriverInfo, drv device.Driver) {
|
||||
switch drvImpl := drv.(type) {
|
||||
case console.Device:
|
||||
onConsoleInit(drvImpl)
|
||||
case tty.Device:
|
||||
if devices.activeTTY != nil {
|
||||
return
|
||||
}
|
||||
|
||||
devices.activeTTY = drvImpl
|
||||
if devices.activeConsole != nil {
|
||||
linkTTYToConsole()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// onConsoleInit is invoked whenever a console is initialized. If this is the
|
||||
// first found console it automatically becomes the active console. In
|
||||
// addition, if the console supports fonts and/or logos this function ensures
|
||||
// that they are loaded and attached to the console. Finally, if an active TTY
|
||||
// device is present, it will be automatically linked to the first active
|
||||
// console via a call to linkTTYToConsole.
|
||||
func onConsoleInit(cons console.Device) {
|
||||
if devices.activeConsole != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return drivers
|
||||
devices.activeConsole = cons
|
||||
|
||||
if logoSetter, ok := (devices.activeConsole).(console.LogoSetter); ok {
|
||||
disableLogo := false
|
||||
for k, v := range multiboot.GetBootCmdLine() {
|
||||
if k == "consoleLogo" && v == "off" {
|
||||
disableLogo = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !disableLogo {
|
||||
consW, consH := devices.activeConsole.Dimensions(console.Pixels)
|
||||
logoSetter.SetLogo(logo.BestFit(consW, consH))
|
||||
}
|
||||
}
|
||||
|
||||
if fontSetter, ok := (devices.activeConsole).(console.FontSetter); ok {
|
||||
consW, consH := devices.activeConsole.Dimensions(console.Pixels)
|
||||
|
||||
// Check boot cmdline for a font request
|
||||
var selFont *font.Font
|
||||
for k, v := range multiboot.GetBootCmdLine() {
|
||||
if k != "consoleFont" {
|
||||
continue
|
||||
}
|
||||
|
||||
if selFont = font.FindByName(v); selFont != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if selFont == nil {
|
||||
selFont = font.BestFit(consW, consH)
|
||||
}
|
||||
|
||||
fontSetter.SetFont(selFont)
|
||||
}
|
||||
|
||||
if devices.activeTTY != nil {
|
||||
linkTTYToConsole()
|
||||
}
|
||||
}
|
||||
|
||||
// linkTTYToConsole connects the active TTY device to the active console device
|
||||
// and syncs their contents.
|
||||
func linkTTYToConsole() {
|
||||
devices.activeTTY.AttachTo(devices.activeConsole)
|
||||
kfmt.SetOutputSink(devices.activeTTY)
|
||||
|
||||
// Sync terminal contents with console
|
||||
devices.activeTTY.SetState(tty.StateActive)
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user