mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-08-01 19:18:28 -04:00
90291bd627
ppd, and some things. Add a simple wpa_supplicant backend
168 lines
3.9 KiB
Go
168 lines
3.9 KiB
Go
package brightness
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"github.com/AvengeMedia/DankMaterialShell/core/internal/log"
|
|
"github.com/AvengeMedia/dankgo/syncmap"
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
// sys/sys/backlight.h: brightness is a 0-100 percent;
|
|
// BACKLIGHTGETSTATUS/BACKLIGHTUPDATESTATUS = _IOWR('G', 0/1, struct
|
|
// backlight_props{uint32 brightness; uint32 nlevels; uint32 levels[100]}).
|
|
const (
|
|
backlightDevDir = "/dev/backlight"
|
|
backlightGetStatus = 0xc1984700
|
|
backlightUpdateStatus = 0xc1984701
|
|
)
|
|
|
|
type backlightProps struct {
|
|
brightness uint32
|
|
nlevels uint32
|
|
levels [100]uint32
|
|
}
|
|
|
|
type BacklightBackend struct {
|
|
devices syncmap.Map[string, string]
|
|
}
|
|
|
|
func NewBacklightBackend() (*BacklightBackend, error) {
|
|
b := &BacklightBackend{}
|
|
if err := b.scanDevices(); err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
func isGenericBacklightName(name string) bool {
|
|
rest, ok := strings.CutPrefix(name, "backlight")
|
|
if !ok || rest == "" {
|
|
return false
|
|
}
|
|
for _, r := range rest {
|
|
if r < '0' || r > '9' {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (b *BacklightBackend) scanDevices() error {
|
|
entries, err := os.ReadDir(backlightDevDir)
|
|
if err != nil {
|
|
return fmt.Errorf("read %s: %w", backlightDevDir, err)
|
|
}
|
|
|
|
// backlight_register (sys/dev/backlight/backlight.c) publishes each unit
|
|
// as backlight/backlightN plus a driver-named alias for the same cdev;
|
|
// dedupe on the device number and keep the descriptive alias.
|
|
names := make(map[uint64]string)
|
|
for _, entry := range entries {
|
|
var st unix.Stat_t
|
|
if err := unix.Stat(filepath.Join(backlightDevDir, entry.Name()), &st); err != nil {
|
|
continue
|
|
}
|
|
rdev := uint64(st.Rdev)
|
|
current, exists := names[rdev]
|
|
if exists && !isGenericBacklightName(current) {
|
|
continue
|
|
}
|
|
names[rdev] = entry.Name()
|
|
}
|
|
|
|
for _, name := range names {
|
|
b.devices.Store("backlight:"+name, filepath.Join(backlightDevDir, name))
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func backlightIoctl(fd int, req uint, props *backlightProps) error {
|
|
_, _, errno := unix.Syscall(unix.SYS_IOCTL, uintptr(fd), uintptr(req), uintptr(unsafe.Pointer(props)))
|
|
if errno != 0 {
|
|
return errno
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func readBrightness(path string) (int, error) {
|
|
fd, err := unix.Open(path, unix.O_RDWR, 0)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer unix.Close(fd)
|
|
|
|
var props backlightProps
|
|
if err := backlightIoctl(fd, backlightGetStatus, &props); err != nil {
|
|
return 0, err
|
|
}
|
|
return int(props.brightness), nil
|
|
}
|
|
|
|
func (b *BacklightBackend) Rescan() error {
|
|
return b.scanDevices()
|
|
}
|
|
|
|
func (b *BacklightBackend) GetDevices() ([]Device, error) {
|
|
devices := make([]Device, 0)
|
|
|
|
b.devices.Range(func(id, path string) bool {
|
|
brightness, err := readBrightness(path)
|
|
if err != nil {
|
|
log.Debugf("failed to read brightness for %s: %v", id, err)
|
|
return true
|
|
}
|
|
|
|
devices = append(devices, Device{
|
|
Class: ClassBacklight,
|
|
ID: id,
|
|
Name: strings.TrimPrefix(id, "backlight:"),
|
|
Current: brightness,
|
|
Max: 100,
|
|
CurrentPercent: brightness,
|
|
Backend: "backlight",
|
|
})
|
|
return true
|
|
})
|
|
|
|
return devices, nil
|
|
}
|
|
|
|
func (b *BacklightBackend) SetBrightnessWithExponent(id string, percent int, exponential bool, exponent float64) error {
|
|
if percent < 0 || percent > 100 {
|
|
return fmt.Errorf("percent out of range: %d", percent)
|
|
}
|
|
|
|
path, ok := b.devices.Load(id)
|
|
if !ok {
|
|
return fmt.Errorf("device not found: %s", id)
|
|
}
|
|
|
|
value := percent
|
|
switch {
|
|
case percent == 0:
|
|
value = 1
|
|
case exponential:
|
|
value = 1 + int(math.Round(math.Pow(float64(percent-1)/99.0, exponent)*99.0))
|
|
}
|
|
|
|
fd, err := unix.Open(path, unix.O_RDWR, 0)
|
|
if err != nil {
|
|
return fmt.Errorf("open %s: %w", path, err)
|
|
}
|
|
defer unix.Close(fd)
|
|
|
|
props := backlightProps{brightness: uint32(value)}
|
|
if err := backlightIoctl(fd, backlightUpdateStatus, &props); err != nil {
|
|
return fmt.Errorf("set brightness: %w", err)
|
|
}
|
|
|
|
log.Debugf("set %s to %d%% (hw %d) via backlight(4)", id, percent, value)
|
|
return nil
|
|
}
|