📄 battery.c
字号:
return result; return device_create_file(battery->bat.dev, &alarm_attr);}static void sysfs_remove_battery(struct acpi_battery *battery){ if (!battery->bat.dev) return; device_remove_file(battery->bat.dev, &alarm_attr); power_supply_unregister(&battery->bat); battery->bat.dev = NULL;}#endifstatic int acpi_battery_update(struct acpi_battery *battery){ int result; result = acpi_battery_get_status(battery); if (result) return result;#ifdef CONFIG_ACPI_SYSFS_POWER if (!acpi_battery_present(battery)) { sysfs_remove_battery(battery); battery->update_time = 0; return 0; }#endif if (!battery->update_time) { result = acpi_battery_get_info(battery); if (result) return result; acpi_battery_init_alarm(battery); }#ifdef CONFIG_ACPI_SYSFS_POWER if (!battery->bat.dev) sysfs_add_battery(battery);#endif return acpi_battery_get_state(battery);}/* -------------------------------------------------------------------------- FS Interface (/proc) -------------------------------------------------------------------------- */#ifdef CONFIG_ACPI_PROCFS_POWERstatic struct proc_dir_entry *acpi_battery_dir;static int acpi_battery_print_info(struct seq_file *seq, int result){ struct acpi_battery *battery = seq->private; if (result) goto end; seq_printf(seq, "present: %s\n", acpi_battery_present(battery)?"yes":"no"); if (!acpi_battery_present(battery)) goto end; if (battery->design_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design capacity: unknown\n"); else seq_printf(seq, "design capacity: %d %sh\n", battery->design_capacity, acpi_battery_units(battery)); if (battery->full_charge_capacity == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "last full capacity: unknown\n"); else seq_printf(seq, "last full capacity: %d %sh\n", battery->full_charge_capacity, acpi_battery_units(battery)); seq_printf(seq, "battery technology: %srechargeable\n", (!battery->technology)?"non-":""); if (battery->design_voltage == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "design voltage: unknown\n"); else seq_printf(seq, "design voltage: %d mV\n", battery->design_voltage); seq_printf(seq, "design capacity warning: %d %sh\n", battery->design_capacity_warning, acpi_battery_units(battery)); seq_printf(seq, "design capacity low: %d %sh\n", battery->design_capacity_low, acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 1: %d %sh\n", battery->capacity_granularity_1, acpi_battery_units(battery)); seq_printf(seq, "capacity granularity 2: %d %sh\n", battery->capacity_granularity_2, acpi_battery_units(battery)); seq_printf(seq, "model number: %s\n", battery->model_number); seq_printf(seq, "serial number: %s\n", battery->serial_number); seq_printf(seq, "battery type: %s\n", battery->type); seq_printf(seq, "OEM info: %s\n", battery->oem_info); end: if (result) seq_printf(seq, "ERROR: Unable to read battery info\n"); return result;}static int acpi_battery_print_state(struct seq_file *seq, int result){ struct acpi_battery *battery = seq->private; if (result) goto end; seq_printf(seq, "present: %s\n", acpi_battery_present(battery)?"yes":"no"); if (!acpi_battery_present(battery)) goto end; seq_printf(seq, "capacity state: %s\n", (battery->state & 0x04)?"critical":"ok"); if ((battery->state & 0x01) && (battery->state & 0x02)) seq_printf(seq, "charging state: charging/discharging\n"); else if (battery->state & 0x01) seq_printf(seq, "charging state: discharging\n"); else if (battery->state & 0x02) seq_printf(seq, "charging state: charging\n"); else seq_printf(seq, "charging state: charged\n"); if (battery->current_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present rate: unknown\n"); else seq_printf(seq, "present rate: %d %s\n", battery->current_now, acpi_battery_units(battery)); if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "remaining capacity: unknown\n"); else seq_printf(seq, "remaining capacity: %d %sh\n", battery->capacity_now, acpi_battery_units(battery)); if (battery->voltage_now == ACPI_BATTERY_VALUE_UNKNOWN) seq_printf(seq, "present voltage: unknown\n"); else seq_printf(seq, "present voltage: %d mV\n", battery->voltage_now); end: if (result) seq_printf(seq, "ERROR: Unable to read battery state\n"); return result;}static int acpi_battery_print_alarm(struct seq_file *seq, int result){ struct acpi_battery *battery = seq->private; if (result) goto end; if (!acpi_battery_present(battery)) { seq_printf(seq, "present: no\n"); goto end; } seq_printf(seq, "alarm: "); if (!battery->alarm) seq_printf(seq, "unsupported\n"); else seq_printf(seq, "%u %sh\n", battery->alarm, acpi_battery_units(battery)); end: if (result) seq_printf(seq, "ERROR: Unable to read battery alarm\n"); return result;}static ssize_t acpi_battery_write_alarm(struct file *file, const char __user * buffer, size_t count, loff_t * ppos){ int result = 0; char alarm_string[12] = { '\0' }; struct seq_file *m = file->private_data; struct acpi_battery *battery = m->private; if (!battery || (count > sizeof(alarm_string) - 1)) return -EINVAL; if (!acpi_battery_present(battery)) { result = -ENODEV; goto end; } if (copy_from_user(alarm_string, buffer, count)) { result = -EFAULT; goto end; } alarm_string[count] = '\0'; battery->alarm = simple_strtol(alarm_string, NULL, 0); result = acpi_battery_set_alarm(battery); end: if (!result) return count; return result;}typedef int(*print_func)(struct seq_file *seq, int result);static print_func acpi_print_funcs[ACPI_BATTERY_NUMFILES] = { acpi_battery_print_info, acpi_battery_print_state, acpi_battery_print_alarm,};static int acpi_battery_read(int fid, struct seq_file *seq){ struct acpi_battery *battery = seq->private; int result = acpi_battery_update(battery); return acpi_print_funcs[fid](seq, result);}#define DECLARE_FILE_FUNCTIONS(_name) \static int acpi_battery_read_##_name(struct seq_file *seq, void *offset) \{ \ return acpi_battery_read(_name##_tag, seq); \} \static int acpi_battery_##_name##_open_fs(struct inode *inode, struct file *file) \{ \ return single_open(file, acpi_battery_read_##_name, PDE(inode)->data); \}DECLARE_FILE_FUNCTIONS(info);DECLARE_FILE_FUNCTIONS(state);DECLARE_FILE_FUNCTIONS(alarm);#undef DECLARE_FILE_FUNCTIONS#define FILE_DESCRIPTION_RO(_name) \ { \ .name = __stringify(_name), \ .mode = S_IRUGO, \ .ops = { \ .open = acpi_battery_##_name##_open_fs, \ .read = seq_read, \ .llseek = seq_lseek, \ .release = single_release, \ .owner = THIS_MODULE, \ }, \ }#define FILE_DESCRIPTION_RW(_name) \ { \ .name = __stringify(_name), \ .mode = S_IFREG | S_IRUGO | S_IWUSR, \ .ops = { \ .open = acpi_battery_##_name##_open_fs, \ .read = seq_read, \ .llseek = seq_lseek, \ .write = acpi_battery_write_##_name, \ .release = single_release, \ .owner = THIS_MODULE, \ }, \ }static struct battery_file { struct file_operations ops; mode_t mode; char *name;} acpi_battery_file[] = { FILE_DESCRIPTION_RO(info), FILE_DESCRIPTION_RO(state), FILE_DESCRIPTION_RW(alarm),};#undef FILE_DESCRIPTION_RO#undef FILE_DESCRIPTION_RWstatic int acpi_battery_add_fs(struct acpi_device *device){ struct proc_dir_entry *entry = NULL; int i; if (!acpi_device_dir(device)) { acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), acpi_battery_dir); if (!acpi_device_dir(device)) return -ENODEV; acpi_device_dir(device)->owner = THIS_MODULE; } for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) { entry = create_proc_entry(acpi_battery_file[i].name, acpi_battery_file[i].mode, acpi_device_dir(device)); if (!entry) return -ENODEV; else { entry->proc_fops = &acpi_battery_file[i].ops; entry->data = acpi_driver_data(device); entry->owner = THIS_MODULE; } } return 0;}static void acpi_battery_remove_fs(struct acpi_device *device){ int i; if (!acpi_device_dir(device)) return; for (i = 0; i < ACPI_BATTERY_NUMFILES; ++i) remove_proc_entry(acpi_battery_file[i].name, acpi_device_dir(device)); remove_proc_entry(acpi_device_bid(device), acpi_battery_dir); acpi_device_dir(device) = NULL;}#endif/* -------------------------------------------------------------------------- Driver Interface -------------------------------------------------------------------------- */static void acpi_battery_notify(acpi_handle handle, u32 event, void *data){ struct acpi_battery *battery = data; struct acpi_device *device; if (!battery) return; device = battery->device; acpi_battery_update(battery); acpi_bus_generate_proc_event(device, event, acpi_battery_present(battery)); acpi_bus_generate_netlink_event(device->pnp.device_class, device->dev.bus_id, event, acpi_battery_present(battery));#ifdef CONFIG_ACPI_SYSFS_POWER /* acpi_batter_update could remove power_supply object */ if (battery->bat.dev) kobject_uevent(&battery->bat.dev->kobj, KOBJ_CHANGE);#endif}static int acpi_battery_add(struct acpi_device *device){ int result = 0; acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device) return -EINVAL; battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); if (!battery) return -ENOMEM; battery->device = device; strcpy(acpi_device_name(device), ACPI_BATTERY_DEVICE_NAME); strcpy(acpi_device_class(device), ACPI_BATTERY_CLASS); acpi_driver_data(device) = battery; mutex_init(&battery->lock); acpi_battery_update(battery);#ifdef CONFIG_ACPI_PROCFS_POWER result = acpi_battery_add_fs(device); if (result) goto end;#endif status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify, battery); if (ACPI_FAILURE(status)) { ACPI_EXCEPTION((AE_INFO, status, "Installing notify handler")); result = -ENODEV; goto end; } printk(KERN_INFO PREFIX "%s Slot [%s] (battery %s)\n", ACPI_BATTERY_DEVICE_NAME, acpi_device_bid(device), device->status.battery_present ? "present" : "absent"); end: if (result) {#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device);#endif kfree(battery); } return result;}static int acpi_battery_remove(struct acpi_device *device, int type){ acpi_status status = 0; struct acpi_battery *battery = NULL; if (!device || !acpi_driver_data(device)) return -EINVAL; battery = acpi_driver_data(device); status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY, acpi_battery_notify);#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_remove_fs(device);#endif#ifdef CONFIG_ACPI_SYSFS_POWER sysfs_remove_battery(battery);#endif mutex_destroy(&battery->lock); kfree(battery); return 0;}/* this is needed to learn about changes made in suspended state */static int acpi_battery_resume(struct acpi_device *device){ struct acpi_battery *battery; if (!device) return -EINVAL; battery = acpi_driver_data(device); battery->update_time = 0; acpi_battery_update(battery); return 0;}static struct acpi_driver acpi_battery_driver = { .name = "battery", .class = ACPI_BATTERY_CLASS, .ids = battery_device_ids, .ops = { .add = acpi_battery_add, .resume = acpi_battery_resume, .remove = acpi_battery_remove, },};static int __init acpi_battery_init(void){ if (acpi_disabled) return -ENODEV;#ifdef CONFIG_ACPI_PROCFS_POWER acpi_battery_dir = acpi_lock_battery_dir(); if (!acpi_battery_dir) return -ENODEV;#endif if (acpi_bus_register_driver(&acpi_battery_driver) < 0) {#ifdef CONFIG_ACPI_PROCFS_POWER acpi_unlock_battery_dir(acpi_battery_dir);#endif return -ENODEV; } return 0;}static void __exit acpi_battery_exit(void){ acpi_bus_unregister_driver(&acpi_battery_driver);#ifdef CONFIG_ACPI_PROCFS_POWER acpi_unlock_battery_dir(acpi_battery_dir);#endif}module_init(acpi_battery_init);module_exit(acpi_battery_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -