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
|
// ProbeFn is a function that scans for the presence of a particular
|
||||||
// piece of hardware and returns a driver for it.
|
// piece of hardware and returns a driver for it.
|
||||||
type ProbeFn func() Driver
|
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() {
|
func init() {
|
||||||
ProbeFuncs = append(ProbeFuncs, probeForVT)
|
device.RegisterDriver(&device.DriverInfo{
|
||||||
|
Order: device.DetectOrderEarly,
|
||||||
|
Probe: probeForVT,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,18 @@ package console
|
|||||||
import (
|
import (
|
||||||
"gopheros/device/video/console/font"
|
"gopheros/device/video/console/font"
|
||||||
"gopheros/device/video/console/logo"
|
"gopheros/device/video/console/logo"
|
||||||
|
"gopheros/kernel/cpu"
|
||||||
|
"gopheros/kernel/hal/multiboot"
|
||||||
|
"gopheros/kernel/mem/vmm"
|
||||||
"image/color"
|
"image/color"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mapRegionFn = vmm.MapRegion
|
||||||
|
portWriteByteFn = cpu.PortWriteByte
|
||||||
|
getFramebufferInfoFn = multiboot.GetFramebufferInfo
|
||||||
|
)
|
||||||
|
|
||||||
// ScrollDir defines a scroll direction.
|
// ScrollDir defines a scroll direction.
|
||||||
type ScrollDir uint8
|
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() {
|
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() {
|
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/device/video/console/logo"
|
||||||
"gopheros/kernel/hal/multiboot"
|
"gopheros/kernel/hal/multiboot"
|
||||||
"gopheros/kernel/kfmt"
|
"gopheros/kernel/kfmt"
|
||||||
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// managedDevices contains the devices discovered by the HAL.
|
// managedDevices contains the devices discovered by the HAL.
|
||||||
type managedDevices struct {
|
type managedDevices struct {
|
||||||
activeConsole console.Device
|
activeConsole console.Device
|
||||||
activeTTY tty.Device
|
activeTTY tty.Device
|
||||||
|
|
||||||
|
// activeDrivers tracks all initialized device drivers.
|
||||||
|
activeDrivers []device.Driver
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -30,70 +34,20 @@ func ActiveTTY() tty.Device {
|
|||||||
// DetectHardware probes for hardware devices and initializes the appropriate
|
// DetectHardware probes for hardware devices and initializes the appropriate
|
||||||
// drivers.
|
// drivers.
|
||||||
func DetectHardware() {
|
func DetectHardware() {
|
||||||
consoles := probe(console.ProbeFuncs)
|
// Get driver list and sort by detection priority
|
||||||
if len(consoles) != 0 {
|
drivers := device.DriverList()
|
||||||
devices.activeConsole = consoles[0].(console.Device)
|
sort.Sort(drivers)
|
||||||
|
|
||||||
if logoSetter, ok := (devices.activeConsole).(console.LogoSetter); ok {
|
probe(drivers)
|
||||||
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 executes the supplied hw probe functions and attempts to initialize
|
// probe executes the probe function for each driver and invokes
|
||||||
// each detected device. The function returns a list of device drivers that
|
// onDriverInit for each successfully initialized driver.
|
||||||
// were successfully initialized.
|
func probe(driverInfoList device.DriverInfoList) {
|
||||||
func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
var w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()}
|
||||||
var (
|
|
||||||
drivers []device.Driver
|
|
||||||
w = kfmt.PrefixWriter{Sink: kfmt.GetOutputSink()}
|
|
||||||
)
|
|
||||||
|
|
||||||
for _, probeFn := range hwProbeFns {
|
for _, info := range driverInfoList {
|
||||||
drv := probeFn()
|
drv := info.Probe()
|
||||||
if drv == nil {
|
if drv == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@ -109,8 +63,91 @@ func probe(hwProbeFns []device.ProbeFn) []device.Driver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
kfmt.Fprintf(&w, "initialized\n")
|
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