| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| #include <string.h> |
| |
| #include "os/mynewt.h" |
| #include <sys/queue.h> |
| #include <battery/battery.h> |
| #include <battery/battery_prop.h> |
| #include <battery/battery_drv.h> |
| |
| #define BATTERY_MAX_COUNT 1 |
| |
| #define GET_BIT(arr, bit) ((arr)[(bit) / 32] & (1 << ((bit) % 32))) |
| |
| /* |
| * Structure holds information about listener and what is it listening for. |
| */ |
| struct listener_data |
| { |
| /* The properties to monitor for change */ |
| uint32_t ld_prop_change_mask[BATTERY_PROPERTY_MASK_SIZE]; |
| /* The properties to monitor for periodic read */ |
| uint32_t ld_prop_read_mask[BATTERY_PROPERTY_MASK_SIZE]; |
| /* Pointer to listener provided by the application. */ |
| struct battery_prop_listener *ld_listener; |
| }; |
| |
| struct battery_manager |
| { |
| /* The lock for battery object */ |
| struct os_mutex bm_lock; |
| |
| struct battery *bm_batteries[BATTERY_MAX_COUNT]; |
| |
| /** Event queue */ |
| struct os_eventq *bm_eventq; |
| |
| /** Manages poll rates of the batteries */ |
| struct os_callout bm_poll_callout; |
| |
| } battery_manager; |
| |
| struct os_eventq * |
| battery_mgr_evq_get(void) |
| { |
| return (battery_manager.bm_eventq); |
| } |
| |
| static void |
| battery_mgr_evq_set(struct os_eventq *evq) |
| { |
| assert(evq != NULL); |
| battery_manager.bm_eventq = evq; |
| } |
| |
| static void battery_mgr_poll_battery(struct battery *battery); |
| |
| static void |
| battery_poll_event_cb(struct os_event *ev) |
| { |
| int i; |
| int pflag; |
| os_time_t next_poll = 0; |
| os_time_t now = os_time_get(); |
| struct battery *bat; |
| os_stime_t ticks; |
| |
| pflag = 0; |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| bat = battery_manager.bm_batteries[i]; |
| if (bat) { |
| if (OS_TIME_TICK_GEQ(now, bat->b_next_run)) { |
| bat->b_last_read_time = now; |
| battery_mgr_poll_battery(battery_manager.bm_batteries[i]); |
| bat->b_next_run = now + os_time_ms_to_ticks32(bat->b_poll_rate); |
| } |
| if ((pflag == 0) || OS_TIME_TICK_LT(bat->b_next_run, next_poll)) { |
| pflag = 1; |
| next_poll = bat->b_next_run; |
| } |
| } |
| } |
| |
| if (pflag) { |
| ticks = (os_stime_t)(next_poll - os_time_get()); |
| if (ticks < 0) { |
| ticks = 1; |
| } |
| os_callout_reset(&battery_manager.bm_poll_callout, (os_time_t)ticks); |
| } |
| } |
| |
| void |
| battery_mgr_process_event(struct os_event *event) |
| { |
| os_eventq_put(battery_manager.bm_eventq, event); |
| } |
| |
| static void |
| battery_mgr_init(void) |
| { |
| #ifdef MYNEWT_VAL_BATTERY_MGR_EVQ |
| battery_mgr_evq_set(MYNEWT_VAL(BATTERY_MGR_EVQ)); |
| #else |
| battery_mgr_evq_set(os_eventq_dflt_get()); |
| #endif |
| |
| /** |
| * Initialize battery manager polling callout. |
| */ |
| os_callout_init(&battery_manager.bm_poll_callout, |
| battery_mgr_evq_get(), battery_poll_event_cb, |
| NULL); |
| |
| os_mutex_init(&battery_manager.bm_lock); |
| } |
| |
| /* ================================================================= |
| * ====================== PKG ====================================== |
| * ================================================================= |
| */ |
| |
| void |
| battery_pkg_init(void) |
| { |
| /* Ensure this function only gets called by sysinit. */ |
| SYSINIT_ASSERT_ACTIVE(); |
| |
| battery_mgr_init(); |
| |
| #if MYNEWT_VAL(BATTERY_SHELL) |
| battery_shell_register(); |
| #endif |
| } |
| |
| int |
| battery_mgr_register(struct battery *battery) |
| { |
| int i; |
| |
| os_mutex_pend(&battery_manager.bm_lock, OS_WAIT_FOREVER); |
| |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| if (battery_manager.bm_batteries[i] == NULL) { |
| battery_manager.bm_batteries[i] = battery; |
| } |
| } |
| os_mutex_release(&battery_manager.bm_lock); |
| |
| return 0; |
| } |
| |
| int |
| battery_mgr_get_battery_count(void) |
| { |
| int i; |
| |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| if (battery_manager.bm_batteries[i] == NULL) { |
| break; |
| } |
| } |
| |
| return i; |
| } |
| |
| struct os_dev * |
| battery_get_battery(int bat_num) |
| { |
| assert(bat_num < BATTERY_MAX_COUNT); |
| assert(battery_manager.bm_batteries[bat_num]); |
| |
| return &battery_manager.bm_batteries[bat_num]->b_dev; |
| } |
| |
| static int |
| battery_get_num(struct battery *battery) |
| { |
| int i; |
| |
| /* For one battery, there is no need to specify battery at all */ |
| if (battery == NULL) { |
| return 0; |
| } |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| if (battery_manager.bm_batteries[i] == battery) { |
| return i; |
| } |
| } |
| assert(0); |
| return 0; |
| } |
| |
| struct battery_driver * |
| battery_get_driver(struct os_dev *battery, |
| const char *dev_name) |
| { |
| int i; |
| assert(battery); |
| struct battery *bat = (struct battery *)battery; |
| for (i = 0; i < BATTERY_DRIVERS_MAX && bat->b_drivers[i]; ++i) { |
| if (strcmp(bat->b_drivers[i]->dev.od_name, dev_name) == 0) { |
| return bat->b_drivers[i]; |
| } |
| } |
| /* No device found */ |
| assert(0); |
| return NULL; |
| } |
| |
| static void |
| set_bit(uint32_t *mask, int bit) |
| { |
| mask[bit / (sizeof(*mask) * 8)] |= |
| 1 << (bit & ((sizeof(*mask) * 8) - 1)); |
| } |
| |
| static void |
| clear_bit(uint32_t *mask, int bit) |
| { |
| mask[bit / (sizeof(*mask) * 8)] &= |
| ~(1 << (bit & ((sizeof(*mask) * 8) - 1))); |
| } |
| |
| static struct battery_property * |
| find_driver_property(struct battery *bat, struct battery_driver *driver, |
| battery_property_type_t type, battery_property_flags_t flags) |
| { |
| struct battery_property *prop = bat->b_properties + driver->bd_first_property; |
| int i; |
| assert(driver); |
| |
| for (i = 0; driver->bd_property_count; ++i, ++prop) { |
| if (prop->bp_type == type && prop->bp_flags == flags) |
| return prop; |
| } |
| return NULL; |
| } |
| |
| static struct battery_property * |
| find_hardware_property(struct battery *battery, struct battery_driver *driver, |
| battery_property_type_t type, battery_property_flags_t flags) |
| { |
| struct battery_property *res = NULL; |
| int i; |
| |
| /* Search driver properties first */ |
| if (driver) { |
| res = find_driver_property(battery, driver, type, flags); |
| } else { |
| for (i = 0; res == NULL && i < BATTERY_DRIVERS_MAX; ++i) { |
| res = find_driver_property(battery, battery->b_drivers[i], |
| type, flags); |
| } |
| } |
| return res; |
| } |
| |
| struct battery_property * |
| battery_find_property(struct os_dev *battery, |
| battery_property_type_t type, battery_property_flags_t flags, |
| const char *dev_name) |
| { |
| struct battery_property *res = NULL; |
| struct battery_property *prop; |
| struct battery *bat = (struct battery *)battery; |
| int i; |
| struct battery_driver *driver = NULL; |
| |
| if (dev_name) { |
| driver = battery_get_driver(battery, dev_name); |
| assert(driver); |
| } |
| /* Search hardware properties first */ |
| res = find_hardware_property(bat, driver, type, flags); |
| if (!res) { |
| /* Search battery manager created properties */ |
| for (i = 0; i < bat->b_all_property_count; ++i) { |
| prop = &bat->b_properties[i]; |
| if (prop->bp_type == type && |
| prop->bp_flags == flags && |
| (driver == NULL || |
| bat->b_drivers[prop->bp_drv_num] == driver)) { |
| res = prop; |
| break; |
| } |
| } |
| } |
| if (!res) { |
| /* Create software threshold */ |
| if ((flags & BATTERY_PROPERTY_FLAGS_CREATE) != 0 && |
| (flags & BATTERY_PROPERTY_FLAGS_ALARM_THREASH) != 0) { |
| /* Find base property that threshold is for */ |
| prop = find_hardware_property(bat, driver, type, |
| BATTERY_PROPERTY_FLAGS_NONE); |
| /* Base property found, create derived one */ |
| if (prop) { |
| struct battery_property *p = |
| calloc(1, sizeof(struct battery_property)); |
| if (prop->bp_prop_num == 0) { |
| prop->bp_prop_num = ++bat->b_all_property_count; |
| assert(bat->b_all_property_count <= BATTERY_MAX_PROPERTY_COUNT); |
| } |
| /* Base property is marked as base for others |
| */ |
| prop->bp_base = 1; |
| p->bp_type = type; |
| p->bp_flags = flags; |
| p->bp_bat_num = prop->bp_bat_num; |
| p->bp_drv_num = prop->bp_drv_num; |
| p->bp_prop_num = ++bat->b_all_property_count; |
| assert(bat->b_all_property_count <= BATTERY_MAX_PROPERTY_COUNT); |
| res = p; |
| } |
| } |
| } |
| return res; |
| } |
| |
| int |
| battery_get_property_count(struct os_dev *battery, |
| struct battery_driver *driver) |
| { |
| struct battery *bat = (struct battery *)battery; |
| int i; |
| |
| if (driver == NULL) { |
| return bat->b_all_property_count; |
| } else { |
| for (i = 0; i < BATTERY_DRIVERS_MAX && bat->b_drivers[i]; ++i) { |
| if (bat->b_drivers[i] == driver) { |
| return bat->b_drivers[i]->bd_property_count; |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| struct battery_property * |
| battery_enum_property(struct os_dev *battery, struct battery_driver *driver, |
| uint8_t prop_num) |
| { |
| struct battery *bat = (struct battery *)battery; |
| struct battery_property *prop = NULL; |
| int i; |
| |
| if (driver == NULL) { |
| if (prop_num < bat->b_all_property_count) { |
| prop = &bat->b_properties[prop_num]; |
| } |
| } else { |
| for (i = 0; i < BATTERY_DRIVERS_MAX && bat->b_drivers[i]; ++i) { |
| if (bat->b_drivers[i] == driver) { |
| if (prop_num < driver->bd_property_count) { |
| prop = &bat->b_properties[prop_num + driver->bd_first_property]; |
| } |
| } |
| } |
| } |
| |
| return prop; |
| } |
| |
| char * |
| battery_prop_get_name(const struct battery_property *prop, char *buf, |
| size_t buf_size) |
| { |
| struct battery *bat = battery_manager.bm_batteries[prop->bp_bat_num]; |
| struct battery_driver *driver = bat->b_drivers[prop->bp_drv_num]; |
| const struct battery_driver_property *driver_prop = |
| &driver->bd_driver_properties[prop->bp_prop_num - driver->bd_first_property]; |
| |
| strncpy(buf, driver_prop->bdp_name, buf_size); |
| |
| return buf; |
| } |
| |
| struct battery_property * |
| battery_find_property_by_name(struct os_dev *battery, const char *name) |
| { |
| struct battery *bat = (struct battery *)battery; |
| char buf[20]; |
| int i; |
| |
| for (i = 0; i < bat->b_all_property_count; ++i) { |
| battery_prop_get_name(&bat->b_properties[i], buf, 20); |
| if (strcmp(buf, name) == 0) { |
| return &bat->b_properties[i]; |
| } |
| } |
| return NULL; |
| } |
| |
| static void |
| battery_mgr_poll_battery_driver(struct battery *bat, |
| struct battery_driver *drv, uint32_t changed[], uint32_t queried[]) |
| { |
| int i; |
| battery_property_value_t old_val; |
| struct battery_property *prop = &bat->b_properties[drv->bd_first_property]; |
| |
| /* Read requested properties */ |
| for (i = 0; i < drv->bd_property_count; ++i, ++prop) { |
| if (!GET_BIT(bat->b_polled_properties, i)) { |
| continue; |
| } |
| |
| if (!driver_property(prop)) { |
| continue; |
| } |
| |
| old_val = prop->bp_value; |
| if (drv->bd_funcs->bdf_property_get(drv, prop, 100)) { |
| prop->bp_valid = 0; |
| } else { |
| prop->bp_valid = 1; |
| if (memcmp(&old_val, &prop->bp_value, sizeof(old_val))) { |
| set_bit(changed, prop->bp_prop_num); |
| } |
| set_bit(queried, prop->bp_prop_num); |
| } |
| } |
| } |
| |
| static void |
| battery_mgr_poll_battery(struct battery *battery) |
| { |
| uint32_t changed[BATTERY_PROPERTY_MASK_SIZE] = {0}; |
| uint32_t queried[BATTERY_PROPERTY_MASK_SIZE] = {0}; |
| uint32_t masked; |
| int first_one; |
| struct listener_data *ld; |
| struct battery_driver *driver; |
| int i; |
| int j; |
| |
| /* Poll battery drivers */ |
| for(i = 0; i < BATTERY_DRIVERS_MAX; ++i) { |
| driver = battery->b_drivers[i]; |
| if (driver) { |
| battery_mgr_poll_battery_driver(battery, driver, changed, queried); |
| } |
| } |
| |
| /* Notify listeners about property changes */ |
| for (i = 0; i < battery->b_listener_count; ++i) { |
| ld = &battery->b_listeners[i]; |
| for (j = 0; j < BATTERY_PROPERTY_MASK_SIZE; ++j) { |
| masked = changed[j] & ld->ld_prop_change_mask[j]; |
| while (masked) { |
| /* Find first set bit */ |
| first_one = __builtin_ffs(masked) - 1; |
| /* Clear it for next loop */ |
| masked ^= (1 << first_one); |
| driver = battery->b_drivers[i]; |
| /* Notify listener */ |
| ld->ld_listener->bpl_prop_changed(ld->ld_listener, |
| battery->b_properties + |
| first_one + j * 32); |
| } |
| } |
| } |
| |
| /* Notify listeners about periodic reads */ |
| for (i = 0; i < battery->b_listener_count; ++i) { |
| ld = &battery->b_listeners[i]; |
| for (j = 0; j < BATTERY_PROPERTY_MASK_SIZE; ++j) { |
| masked = queried[j] & ld->ld_prop_read_mask[j]; |
| while (masked) { |
| /* Find first set bit */ |
| first_one = __builtin_ffs(masked) - 1; |
| /* Clear it for next loop */ |
| masked ^= (1 << first_one); |
| driver = battery->b_drivers[i]; |
| /* Notify listener */ |
| ld->ld_listener->bpl_prop_read(ld->ld_listener, |
| battery->b_properties + |
| first_one + j * 32); |
| } |
| } |
| } |
| } |
| |
| int |
| battery_set_poll_rate_ms(struct os_dev *battery, uint32_t poll_rate) |
| { |
| struct battery *bat = (struct battery *)battery; |
| |
| if ((poll_rate == 0) || (bat == NULL)) { |
| return -1; |
| } |
| |
| bat->b_poll_rate = poll_rate; |
| bat->b_next_run = os_time_get(); |
| os_callout_reset(&battery_manager.bm_poll_callout, 0); |
| |
| return 0; |
| } |
| |
| int |
| battery_add_driver(struct os_dev *battery, struct battery_driver *driver) |
| { |
| struct battery *bat = (struct battery *)battery; |
| const struct battery_driver_property *drv_prop; |
| struct battery_property *prop; |
| int bat_num; |
| int drv_num; |
| int i; |
| int j; |
| |
| assert(battery); |
| assert(driver); |
| |
| bat_num = battery_get_num(bat); |
| /* Find first slot */ |
| for (i = 0; i < BATTERY_DRIVERS_MAX; ++i) { |
| /* Just make sure that driver is not added twice */ |
| assert(bat->b_drivers[i] != driver); |
| if (bat->b_drivers[i] == NULL) { |
| break; |
| } |
| } |
| assert(i < BATTERY_DRIVERS_MAX); |
| drv_num = i; |
| bat->b_drivers[i] = driver; |
| |
| drv_prop = driver->bd_driver_properties; |
| for (i = 0; drv_prop->bdp_type; ++i) { |
| ++drv_prop; |
| } |
| driver->bd_property_count = i; |
| bat->b_properties = realloc(bat->b_properties, |
| ((i + bat->b_all_property_count) * |
| sizeof(struct battery_property))); |
| |
| j = bat->b_all_property_count; |
| driver->bd_first_property = (uint8_t)j; |
| /* Initialize driver properties with battery manager data */ |
| for (i = 0; i < driver->bd_property_count; ++i, ++j) { |
| prop = bat->b_properties + j; |
| prop->bp_type = driver->bd_driver_properties[i].bdp_type; |
| prop->bp_flags = driver->bd_driver_properties[i].bdp_flags; |
| prop->bp_valid = 0; |
| prop->bp_value.bpv_i32 = 0; |
| prop->bp_drv_prop_num = (uint8_t)i; |
| prop->bp_drv_num = drv_num; |
| prop->bp_bat_num = bat_num; |
| prop->bp_prop_num = j; |
| } |
| bat->b_all_property_count = j; |
| |
| return 0; |
| } |
| |
| static int |
| get_listener_index(struct battery *battery, |
| struct battery_prop_listener *listener) |
| { |
| int i; |
| |
| assert(listener); |
| assert(battery); |
| |
| /* Find existing listener */ |
| for (i = 0; i < battery->b_listener_count; ++i) { |
| if (battery->b_listeners[i].ld_listener == listener) { |
| break; |
| } |
| } |
| /* If listener was not yet added, create space for it and fill |
| * masks with zeros so they will be filled when listener is actually |
| * added to properties. |
| */ |
| if (i >= battery->b_listener_count) { |
| i = battery->b_listener_count++; |
| battery->b_listeners = realloc(battery->b_listeners, |
| sizeof(struct listener_data) * battery->b_listener_count); |
| if (battery->b_listeners == NULL) { |
| return -1; |
| } |
| battery->b_listeners[i].ld_listener = listener; |
| memset(battery->b_listeners[i].ld_prop_change_mask, 0, |
| sizeof(battery->b_listeners[i].ld_prop_change_mask)); |
| memset(battery->b_listeners[i].ld_prop_read_mask, 0, |
| sizeof(battery->b_listeners[i].ld_prop_read_mask)); |
| } |
| |
| return i; |
| } |
| |
| static int |
| battery_update_polled_properties(struct battery *battery) |
| { |
| struct listener_data *ld; |
| int i; |
| int j; |
| |
| for (i = 0; i < BATTERY_PROPERTY_MASK_SIZE; ++i) { |
| battery->b_polled_properties[i] = 0; |
| for (j = 0; j < battery->b_listener_count; ++j) { |
| ld = &battery->b_listeners[j]; |
| battery->b_polled_properties[i] |= ld->ld_prop_read_mask[i]; |
| battery->b_polled_properties[i] |= ld->ld_prop_change_mask[i]; |
| } |
| } |
| |
| return 0; |
| } |
| |
| int |
| battery_prop_change_subscribe(struct battery_prop_listener *listener, |
| struct battery_property *prop) |
| { |
| struct battery *battery; |
| int listener_index; |
| |
| assert(listener); |
| assert(prop); |
| |
| battery = (struct battery *)battery_get_battery(prop->bp_bat_num); |
| listener_index = get_listener_index(battery, listener); |
| |
| set_bit(battery->b_listeners[listener_index].ld_prop_change_mask, |
| prop->bp_prop_num); |
| |
| battery_update_polled_properties(battery); |
| |
| return 0; |
| } |
| |
| int |
| battery_prop_change_unsubscribe(struct battery_prop_listener *listener, |
| struct battery_property *prop) |
| { |
| struct battery *battery; |
| int i; |
| int j; |
| |
| if (prop) { |
| /* Single propety supplied */ |
| battery = (struct battery *)battery_get_battery(prop->bp_bat_num); |
| for (i = 0; i < battery->b_listener_count; ++i) { |
| if (listener == battery->b_listeners[i].ld_listener) { |
| break; |
| } |
| } |
| if (i >= battery->b_listener_count) { |
| return -1; |
| } |
| |
| clear_bit(battery->b_listeners[i].ld_prop_change_mask, |
| prop->bp_prop_num); |
| } else { |
| /* No property supplied, remove listener from all subscriptions */ |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| battery = battery_manager.bm_batteries[i]; |
| for (j = 0; j < battery->b_listener_count; ++i) { |
| if (battery->b_listeners[j].ld_listener == listener) { |
| /* Reduce number of listeners */ |
| battery->b_listener_count--; |
| if (j < battery->b_listener_count) { |
| /* It was not last listener, |
| * move last to emptied space */ |
| battery->b_listeners[j] = |
| battery->b_listeners[battery->b_listener_count]; |
| } |
| battery->b_listeners = |
| realloc(battery->b_listeners, |
| sizeof(struct listener_data) * |
| battery->b_listener_count); |
| break; |
| } |
| } |
| } |
| } |
| |
| battery_update_polled_properties(battery); |
| |
| return 0; |
| } |
| |
| int |
| battery_prop_poll_subscribe(struct battery_prop_listener *listener, |
| struct battery_property *prop) |
| { |
| struct battery *battery; |
| int listener_index; |
| |
| assert(listener); |
| assert(prop); |
| |
| battery = (struct battery *)battery_get_battery(prop->bp_bat_num); |
| listener_index = get_listener_index(battery, listener); |
| |
| set_bit(battery->b_listeners[listener_index].ld_prop_read_mask, |
| prop->bp_prop_num); |
| |
| battery_update_polled_properties(battery); |
| |
| return 0; |
| } |
| |
| int |
| battery_prop_poll_unsubscribe(struct battery_prop_listener *listener, |
| struct battery_property *prop) |
| { |
| struct battery *battery; |
| int i; |
| int j; |
| |
| if (prop) { |
| battery = (struct battery *)battery_get_battery(prop->bp_bat_num); |
| for (i = 0; i < battery->b_listener_count; ++i) { |
| if (listener == battery->b_listeners[i].ld_listener) { |
| break; |
| } |
| } |
| if (i >= battery->b_listener_count) { |
| return -1; |
| } |
| |
| clear_bit(battery->b_listeners[i].ld_prop_read_mask, |
| prop->bp_prop_num); |
| } else { |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| battery = battery_manager.bm_batteries[i]; |
| for (j = 0; j < battery->b_listener_count; ++i) { |
| if (battery->b_listeners[j].ld_listener == listener) { |
| battery->b_listener_count--; |
| if (j < battery->b_listener_count) { |
| battery->b_listeners[j] = |
| battery->b_listeners[battery->b_listener_count]; |
| } |
| battery->b_listeners = |
| realloc(battery->b_listeners, |
| sizeof(struct listener_data) * |
| battery->b_listener_count); |
| break; |
| } |
| } |
| } |
| } |
| |
| battery_update_polled_properties(battery); |
| |
| return 0; |
| } |
| |
| static int |
| battery_open(struct os_dev *dev, uint32_t timeout, void *arg) |
| { |
| struct battery *bat = (struct battery *)dev; |
| struct os_dev *drv_dev; |
| int rollback = -1; |
| int i; |
| int rc = 0; |
| |
| for (i = 0; i < BATTERY_DRIVERS_MAX && bat->b_drivers[i]; ++i) { |
| drv_dev = os_dev_open(bat->b_drivers[i]->dev.od_name, 0, NULL); |
| assert(drv_dev == &bat->b_drivers[i]->dev); |
| if (drv_dev != &bat->b_drivers[i]->dev) { |
| rollback = i - 1; |
| rc = -1; |
| break; |
| } |
| } |
| for (i = rollback; i >= 0; --i) { |
| os_dev_close(&bat->b_drivers[i]->dev); |
| } |
| return rc; |
| } |
| |
| static int |
| battery_close(struct os_dev *dev) |
| { |
| struct battery *bat = (struct battery *)dev; |
| int i; |
| |
| for (i = 0; i < BATTERY_DRIVERS_MAX && bat->b_drivers[i]; ++i) { |
| os_dev_close(&bat->b_drivers[i]->dev); |
| } |
| return 0; |
| } |
| |
| int |
| battery_init(struct os_dev *dev, void *arg) |
| { |
| int i; |
| struct battery *bat = (struct battery *)dev; |
| |
| OS_DEV_SETHANDLERS(dev, battery_open, battery_close); |
| |
| for (i = 0; i < BATTERY_MAX_COUNT; ++i) { |
| if (battery_manager.bm_batteries[i] == NULL) { |
| break; |
| } |
| } |
| assert(i < BATTERY_MAX_COUNT); |
| battery_manager.bm_batteries[i] = bat; |
| |
| memset(bat->b_drivers, 0, sizeof(bat->b_drivers)); |
| |
| return 0; |
| } |