📄 sony-laptop.c
字号:
return 0; ret = platform_driver_register(&sony_pf_driver); if (ret) goto out; sony_pf_device = platform_device_alloc("sony-laptop", -1); if (!sony_pf_device) { ret = -ENOMEM; goto out_platform_registered; } ret = platform_device_add(sony_pf_device); if (ret) goto out_platform_alloced; return 0; out_platform_alloced: platform_device_put(sony_pf_device); sony_pf_device = NULL; out_platform_registered: platform_driver_unregister(&sony_pf_driver); out: atomic_dec(&sony_pf_users); return ret;}static void sony_pf_remove(void){ /* deregister only after the last user has gone */ if (!atomic_dec_and_test(&sony_pf_users)) return; platform_device_del(sony_pf_device); platform_device_put(sony_pf_device); platform_driver_unregister(&sony_pf_driver);}/*********** SNC (SNY5001) Device ***********//* the device uses 1-based values, while the backlight subsystem uses 0-based values */#define SONY_MAX_BRIGHTNESS 8#define SNC_VALIDATE_IN 0#define SNC_VALIDATE_OUT 1static ssize_t sony_nc_sysfs_show(struct device *, struct device_attribute *, char *);static ssize_t sony_nc_sysfs_store(struct device *, struct device_attribute *, const char *, size_t);static int boolean_validate(const int, const int);static int brightness_default_validate(const int, const int);struct sony_nc_value { char *name; /* name of the entry */ char **acpiget; /* names of the ACPI get function */ char **acpiset; /* names of the ACPI set function */ int (*validate)(const int, const int); /* input/output validation */ int value; /* current setting */ int valid; /* Has ever been set */ int debug; /* active only in debug mode ? */ struct device_attribute devattr; /* sysfs atribute */};#define SNC_HANDLE_NAMES(_name, _values...) \ static char *snc_##_name[] = { _values, NULL }#define SNC_HANDLE(_name, _getters, _setters, _validate, _debug) \ { \ .name = __stringify(_name), \ .acpiget = _getters, \ .acpiset = _setters, \ .validate = _validate, \ .debug = _debug, \ .devattr = __ATTR(_name, 0, sony_nc_sysfs_show, sony_nc_sysfs_store), \ }#define SNC_HANDLE_NULL { .name = NULL }SNC_HANDLE_NAMES(fnkey_get, "GHKE");SNC_HANDLE_NAMES(brightness_def_get, "GPBR");SNC_HANDLE_NAMES(brightness_def_set, "SPBR");SNC_HANDLE_NAMES(cdpower_get, "GCDP");SNC_HANDLE_NAMES(cdpower_set, "SCDP", "CDPW");SNC_HANDLE_NAMES(audiopower_get, "GAZP");SNC_HANDLE_NAMES(audiopower_set, "AZPW");SNC_HANDLE_NAMES(lanpower_get, "GLNP");SNC_HANDLE_NAMES(lanpower_set, "LNPW");SNC_HANDLE_NAMES(lidstate_get, "GLID");SNC_HANDLE_NAMES(indicatorlamp_get, "GILS");SNC_HANDLE_NAMES(indicatorlamp_set, "SILS");SNC_HANDLE_NAMES(gainbass_get, "GMGB");SNC_HANDLE_NAMES(gainbass_set, "CMGB");SNC_HANDLE_NAMES(PID_get, "GPID");SNC_HANDLE_NAMES(CTR_get, "GCTR");SNC_HANDLE_NAMES(CTR_set, "SCTR");SNC_HANDLE_NAMES(PCR_get, "GPCR");SNC_HANDLE_NAMES(PCR_set, "SPCR");SNC_HANDLE_NAMES(CMI_get, "GCMI");SNC_HANDLE_NAMES(CMI_set, "SCMI");static struct sony_nc_value sony_nc_values[] = { SNC_HANDLE(brightness_default, snc_brightness_def_get, snc_brightness_def_set, brightness_default_validate, 0), SNC_HANDLE(fnkey, snc_fnkey_get, NULL, NULL, 0), SNC_HANDLE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), SNC_HANDLE(audiopower, snc_audiopower_get, snc_audiopower_set, boolean_validate, 0), SNC_HANDLE(lanpower, snc_lanpower_get, snc_lanpower_set, boolean_validate, 1), SNC_HANDLE(lidstate, snc_lidstate_get, NULL, boolean_validate, 0), SNC_HANDLE(indicatorlamp, snc_indicatorlamp_get, snc_indicatorlamp_set, boolean_validate, 0), SNC_HANDLE(gainbass, snc_gainbass_get, snc_gainbass_set, boolean_validate, 0), /* unknown methods */ SNC_HANDLE(PID, snc_PID_get, NULL, NULL, 1), SNC_HANDLE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), SNC_HANDLE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), SNC_HANDLE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), SNC_HANDLE_NULL};static acpi_handle sony_nc_acpi_handle;static struct acpi_device *sony_nc_acpi_device = NULL;/* * acpi_evaluate_object wrappers */static int acpi_callgetfunc(acpi_handle handle, char *name, int *result){ struct acpi_buffer output; union acpi_object out_obj; acpi_status status; output.length = sizeof(out_obj); output.pointer = &out_obj; status = acpi_evaluate_object(handle, name, NULL, &output); if ((status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER)) { *result = out_obj.integer.value; return 0; } printk(KERN_WARNING DRV_PFX "acpi_callreadfunc failed\n"); return -1;}static int acpi_callsetfunc(acpi_handle handle, char *name, int value, int *result){ struct acpi_object_list params; union acpi_object in_obj; struct acpi_buffer output; union acpi_object out_obj; acpi_status status; params.count = 1; params.pointer = &in_obj; in_obj.type = ACPI_TYPE_INTEGER; in_obj.integer.value = value; output.length = sizeof(out_obj); output.pointer = &out_obj; status = acpi_evaluate_object(handle, name, ¶ms, &output); if (status == AE_OK) { if (result != NULL) { if (out_obj.type != ACPI_TYPE_INTEGER) { printk(KERN_WARNING DRV_PFX "acpi_evaluate_object bad " "return type\n"); return -1; } *result = out_obj.integer.value; } return 0; } printk(KERN_WARNING DRV_PFX "acpi_evaluate_object failed\n"); return -1;}/* * sony_nc_values input/output validate functions *//* brightness_default_validate: * * manipulate input output values to keep consistency with the * backlight framework for which brightness values are 0-based. */static int brightness_default_validate(const int direction, const int value){ switch (direction) { case SNC_VALIDATE_OUT: return value - 1; case SNC_VALIDATE_IN: if (value >= 0 && value < SONY_MAX_BRIGHTNESS) return value + 1; } return -EINVAL;}/* boolean_validate: * * on input validate boolean values 0/1, on output just pass the * received value. */static int boolean_validate(const int direction, const int value){ if (direction == SNC_VALIDATE_IN) { if (value != 0 && value != 1) return -EINVAL; } return value;}/* * Sysfs show/store common to all sony_nc_values */static ssize_t sony_nc_sysfs_show(struct device *dev, struct device_attribute *attr, char *buffer){ int value; struct sony_nc_value *item = container_of(attr, struct sony_nc_value, devattr); if (!*item->acpiget) return -EIO; if (acpi_callgetfunc(sony_nc_acpi_handle, *item->acpiget, &value) < 0) return -EIO; if (item->validate) value = item->validate(SNC_VALIDATE_OUT, value); return snprintf(buffer, PAGE_SIZE, "%d\n", value);}static ssize_t sony_nc_sysfs_store(struct device *dev, struct device_attribute *attr, const char *buffer, size_t count){ int value; struct sony_nc_value *item = container_of(attr, struct sony_nc_value, devattr); if (!item->acpiset) return -EIO; if (count > 31) return -EINVAL; value = simple_strtoul(buffer, NULL, 10); if (item->validate) value = item->validate(SNC_VALIDATE_IN, value); if (value < 0) return value; if (acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, value, NULL) < 0) return -EIO; item->value = value; item->valid = 1; return count;}/* * Backlight device */static int sony_backlight_update_status(struct backlight_device *bd){ return acpi_callsetfunc(sony_nc_acpi_handle, "SBRT", bd->props.brightness + 1, NULL);}static int sony_backlight_get_brightness(struct backlight_device *bd){ int value; if (acpi_callgetfunc(sony_nc_acpi_handle, "GBRT", &value)) return 0; /* brightness levels are 1-based, while backlight ones are 0-based */ return value - 1;}static struct backlight_device *sony_backlight_device;static struct backlight_ops sony_backlight_ops = { .update_status = sony_backlight_update_status, .get_brightness = sony_backlight_get_brightness,};/* * New SNC-only Vaios event mapping to driver known keys */struct sony_nc_event { u8 data; u8 event;};static struct sony_nc_event *sony_nc_events;/* Vaio C* --maybe also FE*, N* and AR* ?-- special init sequence * for Fn keys */static int sony_nc_C_enable(const struct dmi_system_id *id){ int result = 0; printk(KERN_NOTICE DRV_PFX "detected %s\n", id->ident); sony_nc_events = id->driver_data; if (acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x4, &result) < 0 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x2, &result) < 0 || acpi_callsetfunc(sony_nc_acpi_handle, "SN02", 0x10, &result) < 0 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x0, &result) < 0 || acpi_callsetfunc(sony_nc_acpi_handle, "SN03", 0x2, &result) < 0 || acpi_callsetfunc(sony_nc_acpi_handle, "SN07", 0x101, &result) < 0) { printk(KERN_WARNING DRV_PFX "failed to initialize SNC, some " "functionalities may be missing\n"); return 1; } return 0;}static struct sony_nc_event sony_C_events[] = { { 0x81, SONYPI_EVENT_FNKEY_F1 }, { 0x01, SONYPI_EVENT_FNKEY_RELEASED }, { 0x85, SONYPI_EVENT_FNKEY_F5 }, { 0x05, SONYPI_EVENT_FNKEY_RELEASED }, { 0x86, SONYPI_EVENT_FNKEY_F6 }, { 0x06, SONYPI_EVENT_FNKEY_RELEASED }, { 0x87, SONYPI_EVENT_FNKEY_F7 }, { 0x07, SONYPI_EVENT_FNKEY_RELEASED }, { 0x8A, SONYPI_EVENT_FNKEY_F10 }, { 0x0A, SONYPI_EVENT_FNKEY_RELEASED }, { 0x8C, SONYPI_EVENT_FNKEY_F12 }, { 0x0C, SONYPI_EVENT_FNKEY_RELEASED }, { 0, 0 },};/* SNC-only model map */static const struct dmi_system_id sony_nc_ids[] = { { .ident = "Sony Vaio FE Series", .callback = sony_nc_C_enable, .driver_data = sony_C_events, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FE"), }, }, { .ident = "Sony Vaio FZ Series", .callback = sony_nc_C_enable, .driver_data = sony_C_events, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-FZ"), }, }, { .ident = "Sony Vaio C Series", .callback = sony_nc_C_enable, .driver_data = sony_C_events, .matches = { DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), DMI_MATCH(DMI_PRODUCT_NAME, "VGN-C"), }, }, { }};/* * ACPI callbacks */static void sony_acpi_notify(acpi_handle handle, u32 event, void *data){ struct sony_nc_event *evmap; u32 ev = event; int result; if (ev == 0x92) { /* read the key pressed from EC.GECR * A call to SN07 with 0x0202 will do it as well respecting * the current protocol on different OSes * * Note: the path for GECR may be * \_SB.PCI0.LPCB.EC (C, FE, AR, N and friends) * \_SB.PCI0.PIB.EC0 (VGN-FR notifications are sent directly, no GECR) * * TODO: we may want to do the same for the older GHKE -need * dmi list- so this snippet may become one more callback. */ if (acpi_callsetfunc(handle, "SN07", 0x0202, &result) < 0) dprintk("sony_acpi_notify, unable to decode event 0x%.2x\n", ev); else ev = result & 0xFF; } if (sony_nc_events) for (evmap = sony_nc_events; evmap->event; evmap++) { if (evmap->data == ev) { ev = evmap->event; break; } } dprintk("sony_acpi_notify, event: 0x%.2x\n", ev); sony_laptop_report_input_event(ev); acpi_bus_generate_proc_event(sony_nc_acpi_device, 1, ev);}static acpi_status sony_walk_callback(acpi_handle handle, u32 level, void *context, void **return_value){ struct acpi_namespace_node *node; union acpi_operand_object *operand; node = (struct acpi_namespace_node *)handle; operand = (union acpi_operand_object *)node->object; printk(KERN_WARNING DRV_PFX "method: name: %4.4s, args %X\n", node->name.ascii, (u32) operand->method.param_count); return AE_OK;}/* * ACPI device */static int sony_nc_resume(struct acpi_device *device){ struct sony_nc_value *item; for (item = sony_nc_values; item->name; item++) { int ret; if (!item->valid) continue; ret = acpi_callsetfunc(sony_nc_acpi_handle, *item->acpiset, item->value, NULL); if (ret < 0) { printk("%s: %d\n", __FUNCTION__, ret); break; } } /* set the last requested brightness level */ if (sony_backlight_device && !sony_backlight_update_status(sony_backlight_device)) printk(KERN_WARNING DRV_PFX "unable to restore brightness level"); /* re-initialize models with specific requirements */ dmi_check_system(sony_nc_ids); return 0;}static int sony_nc_add(struct acpi_device *device){ acpi_status status; int result = 0; acpi_handle handle; struct sony_nc_value *item; printk(KERN_INFO DRV_PFX "%s v%s.\n", SONY_NC_DRIVER_NAME, SONY_LAPTOP_DRIVER_VERSION);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -