/* * Miscellaneous procedures for dealing with the PowerMac hardware. * Contains support for the backlight. * * Copyright (C) 2000 Benjamin Herrenschmidt * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include static struct backlight_controller *backlighter; static void* backlighter_data; static int backlight_autosave; static int backlight_level = BACKLIGHT_MAX; static int backlight_enabled = 1; static int backlight_req_level = -1; static int backlight_req_enable = -1; static void backlight_callback(void *); static DECLARE_WORK(backlight_work, backlight_callback, NULL); void __pmac register_backlight_controller(struct backlight_controller *ctrler, void *data, char *type) { struct device_node* bk_node; char *prop; int valid = 0; /* There's already a matching controller, bail out */ if (backlighter != NULL) return; bk_node = find_devices("backlight"); #ifdef CONFIG_ADB_PMU /* Special case for the old PowerBook since I can't test on it */ backlight_autosave = machine_is_compatible("AAPL,3400/2400") || machine_is_compatible("AAPL,3500"); if ((backlight_autosave || machine_is_compatible("AAPL,PowerBook1998") || machine_is_compatible("PowerBook1,1")) && !strcmp(type, "pmu")) valid = 1; #endif if (bk_node) { prop = get_property(bk_node, "backlight-control", NULL); if (prop && !strncmp(prop, type, strlen(type))) valid = 1; } if (!valid) return; backlighter = ctrler; backlighter_data = data; if (bk_node && !backlight_autosave) prop = get_property(bk_node, "bklt", NULL); else prop = NULL; if (prop) { backlight_level = ((*prop)+1) >> 1; if (backlight_level > BACKLIGHT_MAX) backlight_level = BACKLIGHT_MAX; } #ifdef CONFIG_ADB_PMU if (backlight_autosave) { struct adb_request req; pmu_request(&req, NULL, 2, 0xd9, 0); while (!req.complete) pmu_poll(); backlight_level = req.reply[0] >> 4; } #endif acquire_console_sem(); if (!backlighter->set_enable(1, backlight_level, data)) backlight_enabled = 1; release_console_sem(); printk(KERN_INFO "Registered \"%s\" backlight controller," "level: %d/15\n", type, backlight_level); } EXPORT_SYMBOL(register_backlight_controller); void __pmac unregister_backlight_controller(struct backlight_controller *ctrler, void *data) { /* We keep the current backlight level (for now) */ if (ctrler == backlighter && data == backlighter_data) backlighter = NULL; } EXPORT_SYMBOL(unregister_backlight_controller); static int __pmac __set_backlight_enable(int enable) { int rc; if (!backlighter) return -ENODEV; acquire_console_sem(); rc = backlighter->set_enable(enable, backlight_level, backlighter_data); if (!rc) backlight_enabled = enable; release_console_sem(); return rc; } int __pmac set_backlight_enable(int enable) { if (!backlighter) return -ENODEV; backlight_req_enable = enable; schedule_work(&backlight_work); return 0; } EXPORT_SYMBOL(set_backlight_enable); int __pmac get_backlight_enable(void) { if (!backlighter) return -ENODEV; return backlight_enabled; } EXPORT_SYMBOL(get_backlight_enable); static int __pmac __set_backlight_level(int level) { int rc = 0; if (!backlighter) return -ENODEV; if (level < BACKLIGHT_MIN) level = BACKLIGHT_OFF; if (level > BACKLIGHT_MAX) level = BACKLIGHT_MAX; acquire_console_sem(); if (backlight_enabled) rc = backlighter->set_level(level, backlighter_data); if (!rc) backlight_level = level; release_console_sem(); if (!rc && !backlight_autosave) { level <<=1; if (level & 0x10) level |= 0x01; // -- todo: save to property "bklt" } return rc; } int __pmac set_backlight_level(int level) { if (!backlighter) return -ENODEV; backlight_req_level = level; schedule_work(&backlight_work); return 0; } EXPORT_SYMBOL(set_backlight_level); int __pmac get_backlight_level(void) { if (!backlighter) return -ENODEV; return backlight_level; } EXPORT_SYMBOL(get_backlight_level); static void backlight_callback(void *dummy) { int level, enable; do { level = backlight_req_level; enable = backlight_req_enable; mb(); if (level >= 0) __set_backlight_level(level); if (enable >= 0) __set_backlight_enable(enable); } while(cmpxchg(&backlight_req_level, level, -1) != level || cmpxchg(&backlight_req_enable, enable, -1) != enable); }