49 static gboolean umudev_cable_state_timer_cb (gpointer aptr);
50 static void umudev_cable_state_stop_timer (
void);
51 static void umudev_cable_state_start_timer(gint delay);
52 static bool umudev_cable_state_connected (
void);
53 static cable_state_t umudev_cable_state_get (
void);
54 static void umudev_cable_state_set (cable_state_t state);
55 static void umudev_cable_state_changed (
void);
56 static void umudev_cable_state_from_udev (cable_state_t curr);
57 static void umudev_io_error_cb (gpointer data);
58 static gboolean umudev_io_input_cb (GIOChannel *iochannel, GIOCondition cond, gpointer data);
59 static void umudev_parse_properties (
struct udev_device *dev,
bool initial);
60 static int umudev_score_as_power_supply (
const char *syspath);
61 gboolean umudev_init (
void);
62 void umudev_quit (
void);
69 static struct udev *umudev_object = 0;
70 static struct udev_monitor *umudev_monitor = 0;
71 static gchar *umudev_sysname = 0;
72 static guint umudev_watch_id = 0;
73 static bool umudev_in_cleanup =
false;
76 static cable_state_t umudev_cable_state_current = CABLE_STATE_UNKNOWN;
79 static cable_state_t umudev_cable_state_active = CABLE_STATE_UNKNOWN;
82 static cable_state_t umudev_cable_state_previous = CABLE_STATE_UNKNOWN;
85 static guint umudev_cable_state_timer_id = 0;
86 static gint umudev_cable_state_timer_delay = -1;
92 static gboolean umudev_cable_state_timer_cb(gpointer aptr)
97 umudev_cable_state_timer_id = 0;
98 umudev_cable_state_timer_delay = -1;
100 log_debug(
"trigger delayed transfer to: %s",
101 cable_state_repr(umudev_cable_state_current));
102 umudev_cable_state_set(umudev_cable_state_current);
106 static void umudev_cable_state_stop_timer(
void)
108 LOG_REGISTER_CONTEXT;
110 if( umudev_cable_state_timer_id ) {
111 log_debug(
"cancel delayed transfer to: %s",
112 cable_state_repr(umudev_cable_state_current));
113 g_source_remove(umudev_cable_state_timer_id),
114 umudev_cable_state_timer_id = 0;
115 umudev_cable_state_timer_delay = -1;
119 static void umudev_cable_state_start_timer(gint delay)
121 LOG_REGISTER_CONTEXT;
123 if( umudev_cable_state_timer_delay != delay ) {
124 umudev_cable_state_stop_timer();
127 if( !umudev_cable_state_timer_id ) {
128 log_debug(
"schedule delayed transfer to: %s",
129 cable_state_repr(umudev_cable_state_current));
130 umudev_cable_state_timer_id =
132 umudev_cable_state_timer_cb, 0);
133 umudev_cable_state_timer_delay = delay;
138 umudev_cable_state_connected(
void)
140 LOG_REGISTER_CONTEXT;
142 bool connected =
false;
143 switch( umudev_cable_state_get() ) {
146 case CABLE_STATE_CHARGER_CONNECTED:
147 case CABLE_STATE_PC_CONNECTED:
154 static cable_state_t umudev_cable_state_get(
void)
156 LOG_REGISTER_CONTEXT;
158 return umudev_cable_state_active;
161 static void umudev_cable_state_set(cable_state_t state)
163 LOG_REGISTER_CONTEXT;
165 umudev_cable_state_stop_timer();
167 if( umudev_cable_state_active == state )
170 umudev_cable_state_previous = umudev_cable_state_active;
171 umudev_cable_state_active = state;
173 log_debug(
"cable_state: %s -> %s",
174 cable_state_repr(umudev_cable_state_previous),
175 cable_state_repr(umudev_cable_state_active));
177 umudev_cable_state_changed();
183 static void umudev_cable_state_changed(
void)
185 LOG_REGISTER_CONTEXT;
194 switch( umudev_cable_state_previous ) {
196 case CABLE_STATE_DISCONNECTED:
199 case CABLE_STATE_CHARGER_CONNECTED:
202 case CABLE_STATE_PC_CONNECTED:
211 switch( umudev_cable_state_active ) {
213 case CABLE_STATE_DISCONNECTED:
216 case CABLE_STATE_CHARGER_CONNECTED:
219 case CABLE_STATE_PC_CONNECTED:
228 static void umudev_cable_state_from_udev(cable_state_t curr)
230 LOG_REGISTER_CONTEXT;
232 cable_state_t prev = umudev_cable_state_current;
233 umudev_cable_state_current = curr;
238 log_debug(
"reported cable state: %s -> %s",
239 cable_state_repr(prev),
240 cable_state_repr(curr));
249 if( curr == CABLE_STATE_DISCONNECTED ) {
253 umudev_cable_state_set(curr);
262 if( curr == CABLE_STATE_PC_CONNECTED && prev != CABLE_STATE_UNKNOWN ) {
267 umudev_cable_state_start_timer(delay);
278 static void umudev_io_error_cb(gpointer data)
280 LOG_REGISTER_CONTEXT;
285 if( !umudev_in_cleanup ) {
286 log_debug(
"USB connection watch destroyed, restarting it\n!");
293 static gboolean umudev_io_input_cb(GIOChannel *iochannel, GIOCondition cond, gpointer data)
295 LOG_REGISTER_CONTEXT;
300 gboolean continue_watching = TRUE;
308 struct udev_device *dev = udev_monitor_receive_device(umudev_monitor);
312 continue_watching = FALSE;
317 if( !strcmp(umudev_sysname, udev_device_get_sysname(dev)) )
319 if( !strcmp(udev_device_get_action(dev),
"change") )
321 umudev_parse_properties(dev,
false);
325 udev_device_unref(dev);
329 if( cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL) )
332 continue_watching = FALSE;
335 if( !continue_watching && umudev_watch_id )
338 log_crit(
"udev io watch disabled");
343 return continue_watching;
346 static void umudev_parse_properties(
struct udev_device *dev,
bool initial)
348 LOG_REGISTER_CONTEXT;
353 const char *power_supply_present = 0;
354 const char *power_supply_online = 0;
355 const char *power_supply_type = 0;
358 bool connected =
false;
366 bool warnings =
log_p(LOG_DEBUG);
372 power_supply_present = udev_device_get_property_value(dev,
"POWER_SUPPLY_PRESENT");
373 if( !power_supply_present ) {
374 power_supply_present =
375 power_supply_online = udev_device_get_property_value(dev,
"POWER_SUPPLY_ONLINE");
378 if( power_supply_present && !strcmp(power_supply_present,
"1") )
393 if( warnings && !power_supply_present )
394 log_err(
"No usable power supply indicator\n");
395 umudev_cable_state_from_udev(CABLE_STATE_DISCONNECTED);
398 if( warnings && power_supply_online )
399 log_warning(
"Using online property\n");
405 power_supply_type = udev_device_get_property_value(dev,
"POWER_SUPPLY_REAL_TYPE");
406 if( !power_supply_type )
407 power_supply_type = udev_device_get_property_value(dev,
"POWER_SUPPLY_TYPE");
413 if( !power_supply_type ) {
415 log_warning(
"Fallback since cable detection might not be accurate. "
416 "Will connect on any voltage on charger.\n");
417 umudev_cable_state_from_udev(CABLE_STATE_PC_CONNECTED);
421 log_debug(
"CONNECTED - POWER_SUPPLY_TYPE = %s", power_supply_type);
423 if( !strcmp(power_supply_type,
"USB") ||
424 !strcmp(power_supply_type,
"USB_CDP") ) {
425 umudev_cable_state_from_udev(CABLE_STATE_PC_CONNECTED);
427 else if( !strcmp(power_supply_type,
"USB_DCP") ||
428 !strcmp(power_supply_type,
"USB_HVDCP") ||
429 !strcmp(power_supply_type,
"USB_HVDCP_3") ) {
430 umudev_cable_state_from_udev(CABLE_STATE_CHARGER_CONNECTED);
432 else if( !strcmp(power_supply_type,
"USB_FLOAT")) {
433 if( !umudev_cable_state_connected() )
434 log_warning(
"connection type detection failed, assuming charger");
435 umudev_cable_state_from_udev(CABLE_STATE_CHARGER_CONNECTED);
437 else if( !strcmp(power_supply_type,
"Unknown")) {
439 log_warning(
"unknown connection type reported, assuming disconnected");
440 umudev_cable_state_from_udev(CABLE_STATE_DISCONNECTED);
444 log_warning(
"unhandled power supply type: %s", power_supply_type);
445 umudev_cable_state_from_udev(CABLE_STATE_DISCONNECTED);
453 static int umudev_score_as_power_supply(
const char *syspath)
455 LOG_REGISTER_CONTEXT;
458 struct udev_device *dev = 0;
459 const char *sysname = 0;
464 if( !(dev = udev_device_new_from_syspath(umudev_object, syspath)) )
467 if( !(sysname = udev_device_get_sysname(dev)) )
473 if(strstr(sysname,
"battery") || strstr(sysname,
"BAT"))
477 if(strstr(sysname,
"usb"))
481 if(strstr(sysname,
"charger"))
485 if(udev_device_get_property_value(dev,
"POWER_SUPPLY_PRESENT"))
488 if(udev_device_get_property_value(dev,
"POWER_SUPPLY_ONLINE"))
493 if(udev_device_get_property_value(dev,
"POWER_SUPPLY_TYPE"))
499 udev_device_unref(dev);
504 gboolean umudev_init(
void)
506 LOG_REGISTER_CONTEXT;
508 gboolean success = FALSE;
510 char *configured_device = NULL;
511 char *configured_subsystem = NULL;
512 struct udev_device *dev = 0;
513 GIOChannel *iochannel = 0;
518 umudev_in_cleanup =
false;
521 if( !(umudev_object = udev_new()) ) {
522 log_err(
"Can't create umudev_object\n");
526 if( !(configured_device = config_find_udev_path()) )
527 configured_device = g_strdup(
"/sys/class/power_supply/usb");
529 if( !(configured_subsystem = config_find_udev_subsystem()) )
530 configured_subsystem = g_strdup(
"power_supply");
533 dev = udev_device_new_from_syspath(umudev_object, configured_device);
537 log_debug(
"Trying to guess $power_supply device.\n");
539 int current_score = 0;
540 gchar *current_name = 0;
542 struct udev_enumerate *list;
543 struct udev_list_entry *list_entry;
544 struct udev_list_entry *first_entry;
546 list = udev_enumerate_new(umudev_object);
547 udev_enumerate_add_match_subsystem(list,
"power_supply");
548 udev_enumerate_scan_devices(list);
549 first_entry = udev_enumerate_get_list_entry(list);
550 udev_list_entry_foreach(list_entry, first_entry) {
551 const char *name = udev_list_entry_get_name(list_entry);
552 int score = umudev_score_as_power_supply(name);
553 if( current_score < score ) {
554 g_free(current_name);
555 current_name = g_strdup(name);
556 current_score = score;
560 if(current_score > 0) {
561 dev = udev_device_new_from_syspath(umudev_object, current_name);
563 g_free(current_name);
568 log_err(
"Unable to find $power_supply device.");
574 umudev_sysname = g_strdup(udev_device_get_sysname(dev));
575 log_debug(
"device name = %s\n", umudev_sysname);
578 umudev_monitor = udev_monitor_new_from_netlink(umudev_object,
"udev");
579 if( !umudev_monitor )
581 log_err(
"Unable to monitor the netlink\n");
586 ret = udev_monitor_filter_add_match_subsystem_devtype(umudev_monitor,
587 configured_subsystem,
591 log_err(
"Udev match failed.\n");
595 ret = udev_monitor_enable_receiving(umudev_monitor);
598 log_err(
"Failed to enable monitor recieving.\n");
602 iochannel = g_io_channel_unix_new(udev_monitor_get_fd(umudev_monitor));
606 umudev_watch_id = g_io_add_watch_full(iochannel, 0, G_IO_IN, umudev_io_input_cb, NULL, umudev_io_error_cb);
607 if( !umudev_watch_id )
614 umudev_parse_properties(dev,
true);
619 g_io_channel_unref(iochannel);
622 udev_device_unref(dev);
624 g_free(configured_subsystem);
625 g_free(configured_device);
634 void umudev_quit(
void)
636 LOG_REGISTER_CONTEXT;
638 umudev_in_cleanup =
true;
640 log_debug(
"HWhal cleanup\n");
642 if( umudev_watch_id )
644 g_source_remove(umudev_watch_id),
648 if( umudev_monitor ) {
649 udev_monitor_unref(umudev_monitor),
653 if( umudev_object ) {
654 udev_unref(umudev_object),
658 g_free(umudev_sysname),
661 umudev_cable_state_stop_timer();