37
37
#include <unistd.h>
38
38
#include <fcntl.h>
39
39
#include <linux/input.h>
40
+ #include <dirent.h>
41
+ #include <string.h>
42
+ #include <stdlib.h>
40
43
41
44
#include "vmmapi.h"
42
45
#include "acpi.h"
46
49
#include "lpc.h"
47
50
#include "monitor.h"
48
51
49
- #define POWER_BUTTON_EVENT 116
50
52
#define POWER_BUTTON_NAME "power_button"
53
+ #define POWER_BUTTON_ACPI_DRV "/sys/bus/acpi/drivers/button/LNXPWRBN:00/"
54
+ #define POWER_BUTTON_INPUT_DIR POWER_BUTTON_ACPI_DRV"input"
51
55
static pthread_mutex_t pm_lock = PTHREAD_MUTEX_INITIALIZER ;
52
56
static struct mevent * power_button ;
53
57
static sig_t old_power_handler ;
@@ -242,6 +246,7 @@ INOUT_PORT(pm1_enable, PM1A_EVT_ADDR + 2, IOPORT_F_INOUT, pm1_enable_handler);
242
246
static void
243
247
power_button_press_emulation (struct vmctx * ctx )
244
248
{
249
+ printf ("%s" , "press power button\n" );
245
250
pthread_mutex_lock (& pm_lock );
246
251
if (!(pm1_status & PM1_PWRBTN_STS )) {
247
252
pm1_status |= PM1_PWRBTN_STS ;
@@ -267,7 +272,11 @@ input_event0_handler(int fd, enum ev_type type, void *arg)
267
272
if (rc < 0 || rc != sizeof (ev ))
268
273
return ;
269
274
270
- if (ev .code == POWER_BUTTON_EVENT && ev .value == 1 )
275
+ /*
276
+ * The input key defines in input-event-codes.h
277
+ * KEY_POWER 116 SC System Power Down
278
+ */
279
+ if (ev .code == KEY_POWER && ev .value == 1 )
271
280
power_button_press_emulation (arg );
272
281
}
273
282
@@ -336,6 +345,109 @@ static struct monitor_vm_ops vm_ops = {
336
345
.suspend = vm_suspend_handler ,
337
346
};
338
347
348
+ static int
349
+ input_dir_filter (const struct dirent * dir )
350
+ {
351
+ return !strncmp (dir -> d_name , "input" , 5 );
352
+ }
353
+
354
+ static int
355
+ event_dir_filter (const struct dirent * dir )
356
+ {
357
+ return !strncmp (dir -> d_name , "event" , 5 );
358
+ }
359
+
360
+ static int
361
+ open_power_button_input_device ()
362
+ {
363
+ struct dirent * * input_dirs = NULL ;
364
+ struct dirent * * event_dirs = NULL ;
365
+ int ninput = 0 ;
366
+ int nevent = 0 ;
367
+ char path [256 ] = {0 };
368
+ char name [256 ] = {0 };
369
+ int rc , fd ;
370
+
371
+ if (access (POWER_BUTTON_ACPI_DRV , F_OK ) != 0 ) {
372
+ fprintf (stderr , "failed to detect power button driver\n" );
373
+ return -1 ;
374
+ }
375
+
376
+ /*
377
+ * Scan path to get inputN
378
+ * path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input
379
+ */
380
+ ninput = scandir (POWER_BUTTON_INPUT_DIR , & input_dirs , input_dir_filter ,
381
+ alphasort );
382
+ if (ninput < 0 ) {
383
+ fprintf (stderr , "failed to scan power button %s\n" ,
384
+ POWER_BUTTON_INPUT_DIR );
385
+ goto err ;
386
+ } else if (ninput == 1 ) {
387
+ rc = snprintf (path , sizeof (path ), "%s/%s" ,
388
+ POWER_BUTTON_INPUT_DIR , input_dirs [0 ]-> d_name );
389
+ if (rc < 0 || rc >= sizeof (path )) {
390
+ fprintf (stderr , "failed to set power button path %d\n" ,
391
+ rc );
392
+ goto err_input ;
393
+ }
394
+
395
+ /*
396
+ * Scan path to get eventN
397
+ * path is /sys/bus/acpi/drivers/button/LNXPWRBN:00/input/inputN
398
+ */
399
+ nevent = scandir (path , & event_dirs , event_dir_filter ,
400
+ alphasort );
401
+ if (nevent < 0 ) {
402
+ fprintf (stderr , "failed to get power button event %s\n" ,
403
+ path );
404
+ goto err_input ;
405
+ } else if (nevent == 1 ) {
406
+
407
+ /* Get the power button input event name */
408
+ rc = snprintf (name , sizeof (name ), "/dev/input/%s" ,
409
+ event_dirs [0 ]-> d_name );
410
+ if (rc < 0 || rc >= sizeof (name )) {
411
+ fprintf (stderr , "power button error %d\n" , rc );
412
+ goto err_input ;
413
+ }
414
+ } else {
415
+ fprintf (stderr , "power button event number error %d\n" ,
416
+ nevent );
417
+ goto err_event ;
418
+ }
419
+ } else {
420
+ fprintf (stderr , "power button input number error %d\n" , nevent );
421
+ goto err_input ;
422
+ }
423
+
424
+ /* Open the input device */
425
+ fd = open (name , O_RDONLY );
426
+ if (fd > 0 )
427
+ printf ("Watching power button on %s\n" , name );
428
+
429
+ while (nevent -- )
430
+ free (event_dirs [nevent ]);
431
+ free (event_dirs );
432
+ while (ninput -- )
433
+ free (input_dirs [ninput ]);
434
+ free (input_dirs );
435
+ return fd ;
436
+
437
+ err_event :
438
+ while (nevent -- )
439
+ free (event_dirs [nevent ]);
440
+ free (event_dirs );
441
+
442
+ err_input :
443
+ while (ninput -- )
444
+ free (input_dirs [ninput ]);
445
+ free (input_dirs );
446
+
447
+ err :
448
+ return -1 ;
449
+ }
450
+
339
451
/*
340
452
* ACPI SMI Command Register
341
453
*
@@ -371,11 +483,8 @@ smi_cmd_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes,
371
483
old_power_handler = signal (SIGTERM , SIG_IGN );
372
484
}
373
485
if (input_evt0 == NULL ) {
374
- /*
375
- * FIXME: check /sys/bus/acpi/devices/LNXPWRBN\:00/input to
376
- * get input event node instead hardcode in here.
377
- */
378
- pwrbtn_fd = open ("/dev/input/event0" , O_RDONLY );
486
+
487
+ pwrbtn_fd = open_power_button_input_device ();
379
488
if (pwrbtn_fd < 0 )
380
489
fprintf (stderr , "open input event0 error=%d\n" ,
381
490
errno );
0 commit comments