/* * battery.c * * Universal battery monitor class * * (c) 2003 Ian Molton * * Modified: 2004, Oct Szabolcs Gyurko * * You may use this code as per GPL version 2 * * Note: the battery class is NOT the place to put code to detect * ac line status- this should be in a seperate 'power' class. -Spyro * * All volatges, currents, charges, and temperatures in mV, mA, mJ and * tenths of a degree unless otherwise stated. * */ #include #include #include #include #include #define to_battery(obj) container_of(obj, struct battery, class_dev) static ssize_t battery_show_id(struct class_device *cdev, char *buf) { struct battery *bat = to_battery(cdev); return sprintf(buf, "%s\n", bat->id); } static char *status_text[] = {"Unknown", "Charging", "Discharging", "Not charging"}; static ssize_t battery_show_status(struct class_device *cdev, char *buf) { struct battery *bat = to_battery(cdev); int status = 0; if (bat->get_status) { status = bat->get_status(bat); if(status > 3) status = 0; return sprintf(buf, "%s\n", status_text[status]); } return 0; } #define show_int_val(name) \ static ssize_t battery_show_##name(struct class_device *cdev, char *buf) { \ struct battery *bat = to_battery(cdev); \ if (bat->get_##name) \ return sprintf(buf, "%d\n", bat->get_##name(bat)); \ return 0; \ } show_int_val(min_voltage); // in mV show_int_val(min_current); // in mA show_int_val(min_charge); // in mJ show_int_val(max_voltage); show_int_val(max_current); show_int_val(max_charge); show_int_val(temp); // in tenths of a deg *C* (we dont do fahrenheight) show_int_val(voltage); show_int_val(current); show_int_val(charge); /* * This is because the name "current" breaks the device attr macro. * The "current" word resolvs to "(get_current())" so instead of "current" "(get_current())" * appears in the sysfs. * * The source of this definition is the device.h which calls __ATTR macro in sysfs.h * which calls the __stringify macro. * * Only modification that the name is not tried to be resolved (as a macro let's say) */ #define BATTERY_CLS_DEV_ATTR(_name, _mode, _show, _store) \ struct class_device_attribute class_device_attr_##_name = { \ .attr = { .name = #_name, .mode = _mode, .owner = THIS_MODULE }, \ .show = _show, \ .store = _store, \ } static BATTERY_CLS_DEV_ATTR (id, 0444, battery_show_id, NULL); static BATTERY_CLS_DEV_ATTR (status, 0444, battery_show_status, NULL); static BATTERY_CLS_DEV_ATTR (min_voltage, 0444, battery_show_min_voltage, NULL); static BATTERY_CLS_DEV_ATTR (min_current, 0444, battery_show_min_current, NULL); static BATTERY_CLS_DEV_ATTR (min_charge, 0444, battery_show_min_charge, NULL); static BATTERY_CLS_DEV_ATTR (max_voltage, 0444, battery_show_max_voltage, NULL); static BATTERY_CLS_DEV_ATTR (max_current, 0444, battery_show_max_current, NULL); static BATTERY_CLS_DEV_ATTR (max_charge, 0444, battery_show_max_charge, NULL); static BATTERY_CLS_DEV_ATTR (temp, 0444, battery_show_temp, NULL); static BATTERY_CLS_DEV_ATTR (voltage, 0444, battery_show_voltage, NULL); static BATTERY_CLS_DEV_ATTR (current, 0444, battery_show_current, NULL); static BATTERY_CLS_DEV_ATTR (charge, 0444, battery_show_charge, NULL); /*--------------------------------------------------------------*/ /* hotplug stuff */ #if 0 static int battery_class_hotplug(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size) { struct battery *bat = to_battery(dev); return 0; } #endif static struct class battery_class = { .name = "battery", // .hotplug = battery_class_hotplug, // .release = battery_class_release, }; /*--------------------------------------------------------------*/ /* Register new batteries */ #define create_entry_conditional(name) \ if(bat->get_##name) { \ rc = class_device_create_file(&bat->class_dev, &class_device_attr_##name); \ if (rc) goto out; \ } int battery_class_register(struct battery *bat) { int rc = 0; WARN_ON(!bat->name); bat->class_dev.class = &battery_class; strcpy(bat->class_dev.class_id, bat->name); rc = class_device_register(&bat->class_dev); if(rc) goto out; if(bat->id) { rc = class_device_create_file(&bat->class_dev, &class_device_attr_id); if (rc) goto out; } create_entry_conditional(status); create_entry_conditional(min_voltage); create_entry_conditional(min_current); create_entry_conditional(min_charge); create_entry_conditional(max_voltage); create_entry_conditional(max_current); create_entry_conditional(max_charge); create_entry_conditional(temp); create_entry_conditional(voltage); create_entry_conditional(current); create_entry_conditional(charge); out: return rc; } EXPORT_SYMBOL (battery_class_register); void battery_class_unregister (struct battery *bat) { class_device_unregister(&bat->class_dev); } EXPORT_SYMBOL (battery_class_unregister); /*--------------------------------------------------------------*/ /* Init */ static int __init battery_class_init(void) { return class_register(&battery_class); } static void __exit battery_class_exit(void) { class_unregister(&battery_class); } #ifdef MODULE module_init(battery_class_init); #else /* start early */ subsys_initcall(battery_class_init); #endif module_exit(battery_class_exit); MODULE_DESCRIPTION("Battery driver"); MODULE_AUTHOR("Ian Molton"); MODULE_LICENSE("GPL");