/
hal.go
157 lines (129 loc) · 3.79 KB
/
hal.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package hal
import (
"bytes"
"gopheros/device"
"gopheros/device/tty"
"gopheros/device/video/console"
"gopheros/device/video/console/font"
"gopheros/device/video/console/logo"
"gopheros/kernel/kfmt"
"gopheros/multiboot"
"sort"
// import and register acpi driver
_ "gopheros/device/acpi"
)
// 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 (
devices managedDevices
strBuf bytes.Buffer
)
// 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() {
// Get driver list and sort by detection priority
drivers := device.DriverList()
sort.Sort(drivers)
probe(drivers)
}
// 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
for _, info := range driverInfoList {
drv := info.Probe()
if drv == nil {
continue
}
strBuf.Reset()
major, minor, patch := drv.DriverVersion()
kfmt.Fprintf(&strBuf, "[hal] %s(%d.%d.%d): ", drv.DriverName(), major, minor, patch)
w.Prefix = strBuf.Bytes()
w.Sink = kfmt.GetOutputSink()
if err := drv.DriverInit(&w); err != nil {
kfmt.Fprintf(&w, "init failed: %s\n", err.Message)
continue
}
kfmt.Fprintf(&w, "initialized\n")
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
}
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)
}