📄 backlight.c
字号:
/* * Miscellaneous procedures for dealing with the PowerMac hardware. * Contains support for the backlight. * * Copyright (C) 2000 Benjamin Herrenschmidt * Copyright (C) 2006 Michael Hanselmann <linux-kernel@hansmi.ch> * */#include <linux/kernel.h>#include <linux/fb.h>#include <linux/backlight.h>#include <linux/adb.h>#include <linux/pmu.h>#include <asm/atomic.h>#include <asm/prom.h>#include <asm/backlight.h>#define OLD_BACKLIGHT_MAX 15static void pmac_backlight_key_worker(struct work_struct *work);static void pmac_backlight_set_legacy_worker(struct work_struct *work);static DECLARE_WORK(pmac_backlight_key_work, pmac_backlight_key_worker);static DECLARE_WORK(pmac_backlight_set_legacy_work, pmac_backlight_set_legacy_worker);/* Although these variables are used in interrupt context, it makes no sense to * protect them. No user is able to produce enough key events per second and * notice the errors that might happen. */static int pmac_backlight_key_queued;static int pmac_backlight_set_legacy_queued;/* The via-pmu code allows the backlight to be grabbed, in which case the * in-kernel control of the brightness needs to be disabled. This should * only be used by really old PowerBooks. */static atomic_t kernel_backlight_disabled = ATOMIC_INIT(0);/* Protect the pmac_backlight variable below. You should hold this lock when using the pmac_backlight pointer to prevent its potential removal. */DEFINE_MUTEX(pmac_backlight_mutex);/* Main backlight storage * * Backlight drivers in this variable are required to have the "ops" * attribute set and to have an update_status function. * * We can only store one backlight here, but since Apple laptops have only one * internal display, it doesn't matter. Other backlight drivers can be used * independently. * */struct backlight_device *pmac_backlight;int pmac_has_backlight_type(const char *type){ struct device_node* bk_node = of_find_node_by_name(NULL, "backlight"); if (bk_node) { const char *prop = of_get_property(bk_node, "backlight-control", NULL); if (prop && strncmp(prop, type, strlen(type)) == 0) { of_node_put(bk_node); return 1; } of_node_put(bk_node); } return 0;}int pmac_backlight_curve_lookup(struct fb_info *info, int value){ int level = (FB_BACKLIGHT_LEVELS - 1); if (info && info->bl_dev) { int i, max = 0; /* Look for biggest value */ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) max = max((int)info->bl_curve[i], max); /* Look for nearest value */ for (i = 0; i < FB_BACKLIGHT_LEVELS; i++) { int diff = abs(info->bl_curve[i] - value); if (diff < max) { max = diff; level = i; } } } return level;}static void pmac_backlight_key_worker(struct work_struct *work){ if (atomic_read(&kernel_backlight_disabled)) return; mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; int brightness; props = &pmac_backlight->props; brightness = props->brightness + ((pmac_backlight_key_queued?-1:1) * (props->max_brightness / 15)); if (brightness < 0) brightness = 0; else if (brightness > props->max_brightness) brightness = props->max_brightness; props->brightness = brightness; backlight_update_status(pmac_backlight); } mutex_unlock(&pmac_backlight_mutex);}/* This function is called in interrupt context */void pmac_backlight_key(int direction){ if (atomic_read(&kernel_backlight_disabled)) return; /* we can receive multiple interrupts here, but the scheduled work * will run only once, with the last value */ pmac_backlight_key_queued = direction; schedule_work(&pmac_backlight_key_work);}static int __pmac_backlight_set_legacy_brightness(int brightness){ int error = -ENXIO; mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; props = &pmac_backlight->props; props->brightness = brightness * (props->max_brightness + 1) / (OLD_BACKLIGHT_MAX + 1); if (props->brightness > props->max_brightness) props->brightness = props->max_brightness; else if (props->brightness < 0) props->brightness = 0; backlight_update_status(pmac_backlight); error = 0; } mutex_unlock(&pmac_backlight_mutex); return error;}static void pmac_backlight_set_legacy_worker(struct work_struct *work){ if (atomic_read(&kernel_backlight_disabled)) return; __pmac_backlight_set_legacy_brightness(pmac_backlight_set_legacy_queued);}/* This function is called in interrupt context */void pmac_backlight_set_legacy_brightness_pmu(int brightness) { if (atomic_read(&kernel_backlight_disabled)) return; pmac_backlight_set_legacy_queued = brightness; schedule_work(&pmac_backlight_set_legacy_work);}int pmac_backlight_set_legacy_brightness(int brightness){ return __pmac_backlight_set_legacy_brightness(brightness);}int pmac_backlight_get_legacy_brightness(){ int result = -ENXIO; mutex_lock(&pmac_backlight_mutex); if (pmac_backlight) { struct backlight_properties *props; props = &pmac_backlight->props; result = props->brightness * (OLD_BACKLIGHT_MAX + 1) / (props->max_brightness + 1); } mutex_unlock(&pmac_backlight_mutex); return result;}void pmac_backlight_disable(){ atomic_inc(&kernel_backlight_disabled);}void pmac_backlight_enable(){ atomic_dec(&kernel_backlight_disabled);}EXPORT_SYMBOL_GPL(pmac_backlight);EXPORT_SYMBOL_GPL(pmac_backlight_mutex);EXPORT_SYMBOL_GPL(pmac_has_backlight_type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -