140a360c2SBrad Bishop #include <stdio.h>
240a360c2SBrad Bishop #include <stdlib.h>
340a360c2SBrad Bishop #include <errno.h>
440a360c2SBrad Bishop #include <string.h>
540a360c2SBrad Bishop #include <dirent.h>
640a360c2SBrad Bishop #include <systemd/sd-bus.h>
740a360c2SBrad Bishop
840a360c2SBrad Bishop static int led_stable_state_function(const char *, const char *);
940a360c2SBrad Bishop static int led_default_blink(const char *, const char *);
1040a360c2SBrad Bishop static int read_led(const char *, const char *, void *, const size_t);
1140a360c2SBrad Bishop static int led_custom_blink(const char *, sd_bus_message *);
1240a360c2SBrad Bishop
1340a360c2SBrad Bishop /*
1440a360c2SBrad Bishop * These are control files that are present for each led under
1540a360c2SBrad Bishop *'/sys/class/leds/<led_name>/' which are used to trigger action
1640a360c2SBrad Bishop * on the respective leds by writing predefined data.
1740a360c2SBrad Bishop */
1840a360c2SBrad Bishop const char *power_ctrl = "brightness";
1940a360c2SBrad Bishop const char *blink_ctrl = "trigger";
2040a360c2SBrad Bishop const char *duty_on = "delay_on";
2140a360c2SBrad Bishop const char *duty_off = "delay_off";
2240a360c2SBrad Bishop
2340a360c2SBrad Bishop /*
2440a360c2SBrad Bishop * --------------------------------------------------
2540a360c2SBrad Bishop * Given the dbus path, returns the name of the LED
2640a360c2SBrad Bishop * --------------------------------------------------
2740a360c2SBrad Bishop */
2840a360c2SBrad Bishop char *
get_led_name(const char * dbus_path)2940a360c2SBrad Bishop get_led_name(const char *dbus_path)
3040a360c2SBrad Bishop {
3140a360c2SBrad Bishop char *led_name = NULL;
3240a360c2SBrad Bishop
3340a360c2SBrad Bishop /* Get the led name from /org/openbmc/control/led/<name> */
3440a360c2SBrad Bishop led_name = strrchr(dbus_path, '/');
3540a360c2SBrad Bishop if(led_name)
3640a360c2SBrad Bishop {
3740a360c2SBrad Bishop led_name++;
3840a360c2SBrad Bishop }
3940a360c2SBrad Bishop
4040a360c2SBrad Bishop return led_name;
4140a360c2SBrad Bishop }
4240a360c2SBrad Bishop
4340a360c2SBrad Bishop /*
4440a360c2SBrad Bishop * -------------------------------------------------------------------------
4540a360c2SBrad Bishop * Writes the 'on / off / blink' trigger to leds.
4640a360c2SBrad Bishop * -------------------------------------------------------------------------
4740a360c2SBrad Bishop */
4840a360c2SBrad Bishop int
write_to_led(const char * name,const char * ctrl_file,const char * value)4940a360c2SBrad Bishop write_to_led(const char *name, const char *ctrl_file, const char *value)
5040a360c2SBrad Bishop {
5140a360c2SBrad Bishop /* Generic error reporter. */
5240a360c2SBrad Bishop int rc = -1;
5340a360c2SBrad Bishop
5440a360c2SBrad Bishop /* To get /sys/class/leds/<name>/<control file> */
5540a360c2SBrad Bishop char led_path[128] = {0};
5640a360c2SBrad Bishop
5740a360c2SBrad Bishop int len = 0;
5840a360c2SBrad Bishop len = snprintf(led_path, sizeof(led_path),
5940a360c2SBrad Bishop "/sys/class/leds/%s/%s",name, ctrl_file);
6040a360c2SBrad Bishop if(len >= sizeof(led_path))
6140a360c2SBrad Bishop {
6240a360c2SBrad Bishop fprintf(stderr, "Error. LED path is too long. :[%d]\n",len);
6340a360c2SBrad Bishop return rc;
6440a360c2SBrad Bishop }
6540a360c2SBrad Bishop
6640a360c2SBrad Bishop FILE *fp = fopen(led_path,"w");
6740a360c2SBrad Bishop if(fp == NULL)
6840a360c2SBrad Bishop {
6940a360c2SBrad Bishop fprintf(stderr,"Error:[%s] opening:[%s]\n",strerror(errno),led_path);
7040a360c2SBrad Bishop return rc;
7140a360c2SBrad Bishop }
7240a360c2SBrad Bishop
7340a360c2SBrad Bishop rc = fwrite(value, strlen(value), 1, fp);
7440a360c2SBrad Bishop if(rc != 1)
7540a360c2SBrad Bishop {
7640a360c2SBrad Bishop fprintf(stderr, "Error:[%s] writing to :[%s]\n",strerror(errno),led_path);
7740a360c2SBrad Bishop }
7840a360c2SBrad Bishop
7940a360c2SBrad Bishop fclose(fp);
8040a360c2SBrad Bishop
8140a360c2SBrad Bishop /* When we get here, rc would be what it was from writing to the file */
8240a360c2SBrad Bishop return (rc == 1) ? 0 : -1;
8340a360c2SBrad Bishop }
8440a360c2SBrad Bishop
8540a360c2SBrad Bishop /*
8640a360c2SBrad Bishop * ----------------------------------------------------------------
8740a360c2SBrad Bishop * Router function for any LED operations that come via dbus
8840a360c2SBrad Bishop *----------------------------------------------------------------
8940a360c2SBrad Bishop */
9040a360c2SBrad Bishop static int
led_function_router(sd_bus_message * msg,void * user_data,sd_bus_error * ret_error)9140a360c2SBrad Bishop led_function_router(sd_bus_message *msg, void *user_data,
9240a360c2SBrad Bishop sd_bus_error *ret_error)
9340a360c2SBrad Bishop {
9440a360c2SBrad Bishop /* Generic error reporter. */
9540a360c2SBrad Bishop int rc = -1;
9640a360c2SBrad Bishop
9740a360c2SBrad Bishop /* Extract the led name from the full dbus path */
9840a360c2SBrad Bishop const char *led_path = sd_bus_message_get_path(msg);
9940a360c2SBrad Bishop if(led_path == NULL)
10040a360c2SBrad Bishop {
10140a360c2SBrad Bishop fprintf(stderr, "Error. LED path is empty");
10240a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
10340a360c2SBrad Bishop }
10440a360c2SBrad Bishop
10540a360c2SBrad Bishop char *led_name = get_led_name(led_path);
10640a360c2SBrad Bishop if(led_name == NULL)
10740a360c2SBrad Bishop {
10840a360c2SBrad Bishop fprintf(stderr, "Invalid LED name for path :[%s]\n",led_path);
10940a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
11040a360c2SBrad Bishop }
11140a360c2SBrad Bishop
11240a360c2SBrad Bishop /* Now that we have the LED name, get the Operation. */
11340a360c2SBrad Bishop const char *led_function = sd_bus_message_get_member(msg);
11440a360c2SBrad Bishop if(led_function == NULL)
11540a360c2SBrad Bishop {
116*9d572eb3SGunnar Mills fprintf(stderr, "Null LED function specified for : [%s]\n",led_name);
11740a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
11840a360c2SBrad Bishop }
11940a360c2SBrad Bishop
12040a360c2SBrad Bishop /* Route the user action to appropriate handlers. */
12140a360c2SBrad Bishop if( (strcmp(led_function, "setOn") == 0) ||
12240a360c2SBrad Bishop (strcmp(led_function, "setOff") == 0))
12340a360c2SBrad Bishop {
12440a360c2SBrad Bishop rc = led_stable_state_function(led_name, led_function);
12540a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
12640a360c2SBrad Bishop }
12740a360c2SBrad Bishop else if( (strcmp(led_function, "setBlinkFast") == 0) ||
12840a360c2SBrad Bishop (strcmp(led_function, "setBlinkSlow") == 0))
12940a360c2SBrad Bishop {
13040a360c2SBrad Bishop rc = led_default_blink(led_name, led_function);
13140a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
13240a360c2SBrad Bishop }
13340a360c2SBrad Bishop else if(strcmp(led_function, "BlinkCustom") == 0)
13440a360c2SBrad Bishop {
13540a360c2SBrad Bishop rc = led_custom_blink(led_name, msg);
13640a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
13740a360c2SBrad Bishop }
13840a360c2SBrad Bishop else if(strcmp(led_function, "GetLedState") == 0)
13940a360c2SBrad Bishop {
14040a360c2SBrad Bishop char value_str[10] = {0};
14140a360c2SBrad Bishop const char *led_state = NULL;
14240a360c2SBrad Bishop
14340a360c2SBrad Bishop rc = read_led(led_name, power_ctrl, value_str, sizeof(value_str)-1);
14440a360c2SBrad Bishop if(rc >= 0)
14540a360c2SBrad Bishop {
14640a360c2SBrad Bishop /* LED is active HI */
14740a360c2SBrad Bishop led_state = strtoul(value_str, NULL, 0) ? "On" : "Off";
14840a360c2SBrad Bishop }
14940a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "is", rc, led_state);
15040a360c2SBrad Bishop }
15140a360c2SBrad Bishop else
15240a360c2SBrad Bishop {
15340a360c2SBrad Bishop fprintf(stderr,"Invalid LED function:[%s]\n",led_function);
15440a360c2SBrad Bishop }
15540a360c2SBrad Bishop
15640a360c2SBrad Bishop return sd_bus_reply_method_return(msg, "i", rc);
15740a360c2SBrad Bishop }
15840a360c2SBrad Bishop
15940a360c2SBrad Bishop /*
16040a360c2SBrad Bishop * --------------------------------------------------------------
16140a360c2SBrad Bishop * Turn On or Turn Off the LED
16240a360c2SBrad Bishop * --------------------------------------------------------------
16340a360c2SBrad Bishop */
16440a360c2SBrad Bishop static int
led_stable_state_function(const char * led_name,const char * led_function)16540a360c2SBrad Bishop led_stable_state_function(const char *led_name, const char *led_function)
16640a360c2SBrad Bishop {
16740a360c2SBrad Bishop /* Generic error reporter. */
16840a360c2SBrad Bishop int rc = -1;
16940a360c2SBrad Bishop
17040a360c2SBrad Bishop const char *value = NULL;
17140a360c2SBrad Bishop if(strcmp(led_function, "setOff") == 0)
17240a360c2SBrad Bishop {
17340a360c2SBrad Bishop /* LED active low */
17440a360c2SBrad Bishop value = "0";
17540a360c2SBrad Bishop }
17640a360c2SBrad Bishop else if(strcmp(led_function, "setOn") == 0)
17740a360c2SBrad Bishop {
17840a360c2SBrad Bishop value = "255";
17940a360c2SBrad Bishop }
18040a360c2SBrad Bishop else
18140a360c2SBrad Bishop {
18240a360c2SBrad Bishop fprintf(stderr,"Invalid LED stable state operation:[%s] \n",led_function);
18340a360c2SBrad Bishop return rc;
18440a360c2SBrad Bishop }
18540a360c2SBrad Bishop
18640a360c2SBrad Bishop /*
18740a360c2SBrad Bishop * Before doing anything, need to turn off the blinking
18840a360c2SBrad Bishop * if there is one in progress by writing 'none' to trigger
18940a360c2SBrad Bishop */
19040a360c2SBrad Bishop rc = write_to_led(led_name, blink_ctrl, "none");
19140a360c2SBrad Bishop if(rc < 0)
19240a360c2SBrad Bishop {
19340a360c2SBrad Bishop fprintf(stderr,"Error disabling blink. Function:[%s]\n", led_function);
19440a360c2SBrad Bishop return rc;
19540a360c2SBrad Bishop }
19640a360c2SBrad Bishop
19740a360c2SBrad Bishop /*
19840a360c2SBrad Bishop * Open the brightness file and write corresponding values.
19940a360c2SBrad Bishop */
20040a360c2SBrad Bishop rc = write_to_led(led_name, power_ctrl, value);
20140a360c2SBrad Bishop if(rc < 0)
20240a360c2SBrad Bishop {
20340a360c2SBrad Bishop fprintf(stderr,"Error driving LED. Function:[%s]\n", led_function);
20440a360c2SBrad Bishop }
20540a360c2SBrad Bishop
20640a360c2SBrad Bishop return rc;
20740a360c2SBrad Bishop }
20840a360c2SBrad Bishop
20940a360c2SBrad Bishop //-----------------------------------------------------------------------------------
21040a360c2SBrad Bishop // Given the on and off duration, applies the action on the specified LED.
21140a360c2SBrad Bishop //-----------------------------------------------------------------------------------
21240a360c2SBrad Bishop int
blink_led(const char * led_name,const char * on_duration,const char * off_duration)21340a360c2SBrad Bishop blink_led(const char *led_name, const char *on_duration, const char *off_duration)
21440a360c2SBrad Bishop {
21540a360c2SBrad Bishop /* Generic error reporter */
21640a360c2SBrad Bishop int rc = -1;
21740a360c2SBrad Bishop
21840a360c2SBrad Bishop /* Protocol demands that 'timer' be echoed to 'trigger' */
21940a360c2SBrad Bishop rc = write_to_led(led_name, blink_ctrl, "timer");
22040a360c2SBrad Bishop if(rc < 0)
22140a360c2SBrad Bishop {
22240a360c2SBrad Bishop fprintf(stderr,"Error writing timer to Led:[%s]\n", led_name);
22340a360c2SBrad Bishop return rc;
22440a360c2SBrad Bishop }
22540a360c2SBrad Bishop
22640a360c2SBrad Bishop /*
22740a360c2SBrad Bishop * After writing 'timer to 'trigger', 2 new files get generated namely
22840a360c2SBrad Bishop *'delay_on' and 'delay_off' which are telling the time duration for a
22940a360c2SBrad Bishop * particular LED on and off.
23040a360c2SBrad Bishop */
23140a360c2SBrad Bishop rc = write_to_led(led_name, duty_on, on_duration);
23240a360c2SBrad Bishop if(rc < 0)
23340a360c2SBrad Bishop {
23440a360c2SBrad Bishop fprintf(stderr,"Error writing [%s] to delay_on:[%s]\n",on_duration,led_name);
23540a360c2SBrad Bishop return rc;
23640a360c2SBrad Bishop }
23740a360c2SBrad Bishop
23840a360c2SBrad Bishop rc = write_to_led(led_name, duty_off, off_duration);
23940a360c2SBrad Bishop if(rc < 0)
24040a360c2SBrad Bishop {
24140a360c2SBrad Bishop fprintf(stderr,"Error writing [%s] to delay_off:[%s]\n",off_duration,led_name);
24240a360c2SBrad Bishop }
24340a360c2SBrad Bishop
24440a360c2SBrad Bishop return rc;
24540a360c2SBrad Bishop }
24640a360c2SBrad Bishop
24740a360c2SBrad Bishop /*
24840a360c2SBrad Bishop * ----------------------------------------------------
24940a360c2SBrad Bishop * Default blink action on the LED.
25040a360c2SBrad Bishop * ----------------------------------------------------
25140a360c2SBrad Bishop */
25240a360c2SBrad Bishop static int
led_default_blink(const char * led_name,const char * blink_type)25340a360c2SBrad Bishop led_default_blink(const char *led_name, const char *blink_type)
25440a360c2SBrad Bishop {
25540a360c2SBrad Bishop /* Generic error reporter */
25640a360c2SBrad Bishop int rc = -1;
25740a360c2SBrad Bishop
25840a360c2SBrad Bishop /* How long the LED needs to be in on and off state while blinking */
25940a360c2SBrad Bishop const char *on_duration = NULL;
26040a360c2SBrad Bishop const char *off_duration = NULL;
26140a360c2SBrad Bishop if(strcmp(blink_type, "setBlinkSlow") == 0)
26240a360c2SBrad Bishop {
26340a360c2SBrad Bishop //*Delay 900 millisec before 'on' and delay 900 millisec before off */
26440a360c2SBrad Bishop on_duration = "900";
26540a360c2SBrad Bishop off_duration = "900";
26640a360c2SBrad Bishop }
26740a360c2SBrad Bishop else if(strcmp(blink_type, "setBlinkFast") == 0)
26840a360c2SBrad Bishop {
26940a360c2SBrad Bishop /* Delay 200 millisec before 'on' and delay 200 millisec before off */
27040a360c2SBrad Bishop on_duration = "200";
27140a360c2SBrad Bishop off_duration = "200";
27240a360c2SBrad Bishop }
27340a360c2SBrad Bishop else
27440a360c2SBrad Bishop {
27540a360c2SBrad Bishop fprintf(stderr,"Invalid blink operation:[%s]\n",blink_type);
27640a360c2SBrad Bishop return rc;
27740a360c2SBrad Bishop }
27840a360c2SBrad Bishop
27940a360c2SBrad Bishop rc = blink_led(led_name, on_duration, off_duration);
28040a360c2SBrad Bishop
28140a360c2SBrad Bishop return rc;
28240a360c2SBrad Bishop }
28340a360c2SBrad Bishop
28440a360c2SBrad Bishop /*
28540a360c2SBrad Bishop * -------------------------------------------------
28640a360c2SBrad Bishop * Blinks at user defined 'on' and 'off' intervals.
28740a360c2SBrad Bishop * -------------------------------------------------
28840a360c2SBrad Bishop */
28940a360c2SBrad Bishop static int
led_custom_blink(const char * led_name,sd_bus_message * msg)29040a360c2SBrad Bishop led_custom_blink(const char *led_name, sd_bus_message *msg)
29140a360c2SBrad Bishop {
29240a360c2SBrad Bishop /* Generic error reporter. */
29340a360c2SBrad Bishop int rc = -1;
29440a360c2SBrad Bishop int led_len = 0;
29540a360c2SBrad Bishop
29640a360c2SBrad Bishop /* User supplied 'on' and 'off' duration converted into string */
29740a360c2SBrad Bishop char on_duration[32] = {0};
29840a360c2SBrad Bishop char off_duration[32] = {0};
29940a360c2SBrad Bishop
30040a360c2SBrad Bishop /* User supplied 'on' and 'off' duration */
30140a360c2SBrad Bishop uint32_t user_input_on = 0;
30240a360c2SBrad Bishop uint32_t user_input_off = 0;
30340a360c2SBrad Bishop
30440a360c2SBrad Bishop /* Extract values into 'ss' ( string, string) */
30540a360c2SBrad Bishop rc = sd_bus_message_read(msg, "uu", &user_input_on, &user_input_off);
30640a360c2SBrad Bishop if(rc < 0)
30740a360c2SBrad Bishop {
30840a360c2SBrad Bishop fprintf(stderr, "Failed to read 'on' and 'off' duration.[%s]\n", strerror(-rc));
30940a360c2SBrad Bishop }
31040a360c2SBrad Bishop else
31140a360c2SBrad Bishop {
31240a360c2SBrad Bishop /*
31340a360c2SBrad Bishop * Converting user supplied integer arguments into string as required by
31440a360c2SBrad Bishop * sys interface. The top level REST will make sure that an error is
31540a360c2SBrad Bishop * thrown right away on invalid inputs. However, REST is allowing the
31640a360c2SBrad Bishop * unsigned decimal and floating numbers but when its received here, its
31740a360c2SBrad Bishop * received as decimal so no input validation needed.
31840a360c2SBrad Bishop */
31940a360c2SBrad Bishop led_len = snprintf(on_duration, sizeof(on_duration),
32040a360c2SBrad Bishop "%d",user_input_on);
32140a360c2SBrad Bishop if(led_len >= sizeof(on_duration))
32240a360c2SBrad Bishop {
32340a360c2SBrad Bishop fprintf(stderr, "Error. Blink ON duration is too long. :[%d]\n",led_len);
32440a360c2SBrad Bishop return rc;
32540a360c2SBrad Bishop }
32640a360c2SBrad Bishop
32740a360c2SBrad Bishop led_len = snprintf(off_duration, sizeof(off_duration),
32840a360c2SBrad Bishop "%d",user_input_off);
32940a360c2SBrad Bishop if(led_len >= sizeof(off_duration))
33040a360c2SBrad Bishop {
33140a360c2SBrad Bishop fprintf(stderr, "Error. Blink OFF duration is too long. :[%d]\n",led_len);
33240a360c2SBrad Bishop return rc;
33340a360c2SBrad Bishop }
33440a360c2SBrad Bishop
33540a360c2SBrad Bishop /* We are good here.*/
33640a360c2SBrad Bishop rc = blink_led(led_name, on_duration, off_duration);
33740a360c2SBrad Bishop }
33840a360c2SBrad Bishop return rc;
33940a360c2SBrad Bishop }
34040a360c2SBrad Bishop
34140a360c2SBrad Bishop /*
34240a360c2SBrad Bishop * ---------------------------------------------------------------
34340a360c2SBrad Bishop * Gets the current value of passed in LED file
34440a360c2SBrad Bishop * Mainly used for reading 'brightness'
34540a360c2SBrad Bishop * NOTE : It is the responsibility of the caller to allocate
34640a360c2SBrad Bishop * sufficient space for buffer. This will read up to user supplied
34740a360c2SBrad Bishop * size -or- entire contents of file whichever is smaller
34840a360c2SBrad Bishop * ----------------------------------------------------------------
34940a360c2SBrad Bishop */
35040a360c2SBrad Bishop static int
read_led(const char * name,const char * ctrl_file,void * value,const size_t len)35140a360c2SBrad Bishop read_led(const char *name, const char *ctrl_file,
35240a360c2SBrad Bishop void *value, const size_t len)
35340a360c2SBrad Bishop {
35440a360c2SBrad Bishop /* Generic error reporter. */
35540a360c2SBrad Bishop int rc = -1;
35640a360c2SBrad Bishop int count = 0;
35740a360c2SBrad Bishop
35840a360c2SBrad Bishop if(value == NULL || len <= 0)
35940a360c2SBrad Bishop {
36040a360c2SBrad Bishop fprintf(stderr, "Invalid buffer passed to LED read\n");
36140a360c2SBrad Bishop return rc;
36240a360c2SBrad Bishop }
36340a360c2SBrad Bishop
36440a360c2SBrad Bishop /* To get /sys/class/leds/<name>/<control file> */
36540a360c2SBrad Bishop char led_path[128] = {0};
36640a360c2SBrad Bishop
36740a360c2SBrad Bishop int led_len = 0;
36840a360c2SBrad Bishop led_len = snprintf(led_path, sizeof(led_path),
36940a360c2SBrad Bishop "/sys/class/leds/%s/%s",name, ctrl_file);
37040a360c2SBrad Bishop if(led_len >= sizeof(led_path))
37140a360c2SBrad Bishop {
37240a360c2SBrad Bishop fprintf(stderr, "Error. LED path is too long. :[%d]\n",led_len);
37340a360c2SBrad Bishop return rc;
37440a360c2SBrad Bishop }
37540a360c2SBrad Bishop
37640a360c2SBrad Bishop FILE *fp = fopen(led_path,"rb");
37740a360c2SBrad Bishop if(fp == NULL)
37840a360c2SBrad Bishop {
37940a360c2SBrad Bishop fprintf(stderr,"Error:[%s] opening:[%s]\n",strerror(errno),led_path);
38040a360c2SBrad Bishop return rc;
38140a360c2SBrad Bishop }
38240a360c2SBrad Bishop
38340a360c2SBrad Bishop char *sysfs_value = (char *)value;
38440a360c2SBrad Bishop while(!feof(fp) && (count < len))
38540a360c2SBrad Bishop {
38640a360c2SBrad Bishop sysfs_value[count++] = fgetc(fp);
38740a360c2SBrad Bishop }
38840a360c2SBrad Bishop
38940a360c2SBrad Bishop fclose(fp);
39040a360c2SBrad Bishop return 0;
39140a360c2SBrad Bishop }
39240a360c2SBrad Bishop
39340a360c2SBrad Bishop /*
39440a360c2SBrad Bishop * -----------------------------------------------
39540a360c2SBrad Bishop * Dbus Services offered by this LED controller
39640a360c2SBrad Bishop * -----------------------------------------------
39740a360c2SBrad Bishop */
39840a360c2SBrad Bishop static const sd_bus_vtable led_control_vtable[] =
39940a360c2SBrad Bishop {
40040a360c2SBrad Bishop SD_BUS_VTABLE_START(0),
40140a360c2SBrad Bishop SD_BUS_METHOD("setOn", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40240a360c2SBrad Bishop SD_BUS_METHOD("setOff", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40340a360c2SBrad Bishop SD_BUS_METHOD("setBlinkFast", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40440a360c2SBrad Bishop SD_BUS_METHOD("setBlinkSlow", "", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40540a360c2SBrad Bishop SD_BUS_METHOD("GetLedState", "", "is", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40640a360c2SBrad Bishop SD_BUS_METHOD("BlinkCustom", "uu", "i", &led_function_router, SD_BUS_VTABLE_UNPRIVILEGED),
40740a360c2SBrad Bishop SD_BUS_VTABLE_END,
40840a360c2SBrad Bishop };
40940a360c2SBrad Bishop
41040a360c2SBrad Bishop /*
41140a360c2SBrad Bishop * ---------------------------------------------
41240a360c2SBrad Bishop * Interested in all files except standard ones
41340a360c2SBrad Bishop * ---------------------------------------------
41440a360c2SBrad Bishop */
41540a360c2SBrad Bishop int
led_select(const struct dirent * entry)41640a360c2SBrad Bishop led_select(const struct dirent *entry)
41740a360c2SBrad Bishop {
41840a360c2SBrad Bishop if( (strcmp(entry->d_name, ".") == 0) ||
41940a360c2SBrad Bishop (strcmp(entry->d_name, "..") == 0))
42040a360c2SBrad Bishop {
42140a360c2SBrad Bishop return 0;
42240a360c2SBrad Bishop }
42340a360c2SBrad Bishop return 1;
42440a360c2SBrad Bishop }
42540a360c2SBrad Bishop
42640a360c2SBrad Bishop /*
42740a360c2SBrad Bishop * ------------------------------------------------
42840a360c2SBrad Bishop * Called as part of setting up skeleton services.
42940a360c2SBrad Bishop * -----------------------------------------------
43040a360c2SBrad Bishop */
43140a360c2SBrad Bishop int
start_led_services()43240a360c2SBrad Bishop start_led_services()
43340a360c2SBrad Bishop {
43440a360c2SBrad Bishop static const char *led_dbus_root = "/org/openbmc/control/led";
43540a360c2SBrad Bishop
43640a360c2SBrad Bishop /* Generic error reporter. */
43740a360c2SBrad Bishop int rc = -1;
43840a360c2SBrad Bishop int num_leds = 0;
43940a360c2SBrad Bishop int count_leds = 0;
44040a360c2SBrad Bishop
44140a360c2SBrad Bishop /* Bus and slot where we are offering the LED dbus service. */
44240a360c2SBrad Bishop sd_bus *bus_type = NULL;
44340a360c2SBrad Bishop sd_bus_slot *led_slot = NULL;
44440a360c2SBrad Bishop
44540a360c2SBrad Bishop /* For walking '/sys/class/leds/' looking for names of LED.*/
44640a360c2SBrad Bishop struct dirent **led_list;
44740a360c2SBrad Bishop
44840a360c2SBrad Bishop /* Get a hook onto system bus. */
44940a360c2SBrad Bishop rc = sd_bus_open_system(&bus_type);
45040a360c2SBrad Bishop if(rc < 0)
45140a360c2SBrad Bishop {
45240a360c2SBrad Bishop fprintf(stderr,"Error opening system bus.\n");
45340a360c2SBrad Bishop return rc;
45440a360c2SBrad Bishop }
45540a360c2SBrad Bishop
45640a360c2SBrad Bishop count_leds = num_leds = scandir("/sys/class/leds/",
45740a360c2SBrad Bishop &led_list, led_select, alphasort);
45840a360c2SBrad Bishop if(num_leds <= 0)
45940a360c2SBrad Bishop {
46040a360c2SBrad Bishop fprintf(stderr,"No LEDs present in the system\n");
46140a360c2SBrad Bishop
46240a360c2SBrad Bishop sd_bus_slot_unref(led_slot);
46340a360c2SBrad Bishop sd_bus_unref(bus_type);
46440a360c2SBrad Bishop return rc;
46540a360c2SBrad Bishop }
46640a360c2SBrad Bishop
46740a360c2SBrad Bishop /* Install a freedesktop object manager */
46840a360c2SBrad Bishop rc = sd_bus_add_object_manager(bus_type, NULL, led_dbus_root);
46940a360c2SBrad Bishop if(rc < 0) {
47040a360c2SBrad Bishop fprintf(stderr, "Failed to add object to dbus: %s\n",
47140a360c2SBrad Bishop strerror(-rc));
47240a360c2SBrad Bishop
47340a360c2SBrad Bishop sd_bus_slot_unref(led_slot);
47440a360c2SBrad Bishop sd_bus_unref(bus_type);
47540a360c2SBrad Bishop return rc;
47640a360c2SBrad Bishop }
47740a360c2SBrad Bishop
47840a360c2SBrad Bishop /* Fully qualified Dbus object for a particular LED */
47940a360c2SBrad Bishop char led_object[128] = {0};
48040a360c2SBrad Bishop int len = 0;
48140a360c2SBrad Bishop
48240a360c2SBrad Bishop /* For each led present, announce the service on dbus. */
48340a360c2SBrad Bishop while(num_leds--)
48440a360c2SBrad Bishop {
48540a360c2SBrad Bishop memset(led_object, 0x0, sizeof(led_object));
48640a360c2SBrad Bishop
48740a360c2SBrad Bishop len = snprintf(led_object, sizeof(led_object), "%s%s%s",
48840a360c2SBrad Bishop led_dbus_root, "/", led_list[num_leds]->d_name);
48940a360c2SBrad Bishop
49040a360c2SBrad Bishop if(len >= sizeof(led_object))
49140a360c2SBrad Bishop {
49240a360c2SBrad Bishop fprintf(stderr, "Error. LED object is too long:[%d]\n",len);
49340a360c2SBrad Bishop rc = -1;
49440a360c2SBrad Bishop break;
49540a360c2SBrad Bishop }
49640a360c2SBrad Bishop
49740a360c2SBrad Bishop /* Install the object */
49840a360c2SBrad Bishop rc = sd_bus_add_object_vtable(bus_type,
49940a360c2SBrad Bishop &led_slot,
50040a360c2SBrad Bishop led_object, /* object path */
50140a360c2SBrad Bishop "org.openbmc.Led", /* interface name */
50240a360c2SBrad Bishop led_control_vtable,
50340a360c2SBrad Bishop NULL);
50440a360c2SBrad Bishop
50540a360c2SBrad Bishop if(rc < 0)
50640a360c2SBrad Bishop {
50740a360c2SBrad Bishop fprintf(stderr, "Failed to add object to dbus: %s\n", strerror(-rc));
50840a360c2SBrad Bishop break;
50940a360c2SBrad Bishop }
51040a360c2SBrad Bishop
51140a360c2SBrad Bishop rc = sd_bus_emit_object_added(bus_type, led_object);
51240a360c2SBrad Bishop
51340a360c2SBrad Bishop if(rc < 0)
51440a360c2SBrad Bishop {
51540a360c2SBrad Bishop fprintf(stderr, "Failed to emit InterfacesAdded "
51640a360c2SBrad Bishop "signal: %s\n", strerror(-rc));
51740a360c2SBrad Bishop break;
51840a360c2SBrad Bishop }
51940a360c2SBrad Bishop }
52040a360c2SBrad Bishop
52140a360c2SBrad Bishop /* Done with all registration. */
52240a360c2SBrad Bishop while(count_leds > 0)
52340a360c2SBrad Bishop {
52440a360c2SBrad Bishop free(led_list[--count_leds]);
52540a360c2SBrad Bishop }
52640a360c2SBrad Bishop free(led_list);
52740a360c2SBrad Bishop
52840a360c2SBrad Bishop /* If we had success in adding the providers, request for a bus name. */
52940a360c2SBrad Bishop if(rc >= 0)
53040a360c2SBrad Bishop {
53140a360c2SBrad Bishop /* Take one in OpenBmc */
53240a360c2SBrad Bishop rc = sd_bus_request_name(bus_type, "org.openbmc.control.led", 0);
53340a360c2SBrad Bishop if(rc < 0)
53440a360c2SBrad Bishop {
53540a360c2SBrad Bishop fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-rc));
53640a360c2SBrad Bishop }
53740a360c2SBrad Bishop else
53840a360c2SBrad Bishop {
53940a360c2SBrad Bishop for(;;)
54040a360c2SBrad Bishop {
54140a360c2SBrad Bishop /* Process requests */
54240a360c2SBrad Bishop rc = sd_bus_process(bus_type, NULL);
54340a360c2SBrad Bishop if(rc < 0)
54440a360c2SBrad Bishop {
54540a360c2SBrad Bishop fprintf(stderr, "Failed to process bus: %s\n", strerror(-rc));
54640a360c2SBrad Bishop break;
54740a360c2SBrad Bishop }
54840a360c2SBrad Bishop if(rc > 0)
54940a360c2SBrad Bishop {
55040a360c2SBrad Bishop continue;
55140a360c2SBrad Bishop }
55240a360c2SBrad Bishop
55340a360c2SBrad Bishop rc = sd_bus_wait(bus_type, (uint64_t) - 1);
55440a360c2SBrad Bishop if(rc < 0)
55540a360c2SBrad Bishop {
55640a360c2SBrad Bishop fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-rc));
55740a360c2SBrad Bishop break;
55840a360c2SBrad Bishop }
55940a360c2SBrad Bishop }
56040a360c2SBrad Bishop }
56140a360c2SBrad Bishop }
56240a360c2SBrad Bishop sd_bus_slot_unref(led_slot);
56340a360c2SBrad Bishop sd_bus_unref(bus_type);
56440a360c2SBrad Bishop
56540a360c2SBrad Bishop return rc;
56640a360c2SBrad Bishop }
56740a360c2SBrad Bishop
56840a360c2SBrad Bishop int
main(void)56940a360c2SBrad Bishop main(void)
57040a360c2SBrad Bishop {
57140a360c2SBrad Bishop int rc = 0;
57240a360c2SBrad Bishop
57340a360c2SBrad Bishop /* This call is not supposed to return. If it does, then an error */
57440a360c2SBrad Bishop rc = start_led_services();
57540a360c2SBrad Bishop if(rc < 0)
57640a360c2SBrad Bishop {
57740a360c2SBrad Bishop fprintf(stderr, "Error starting LED Services. Exiting");
57840a360c2SBrad Bishop }
57940a360c2SBrad Bishop
58040a360c2SBrad Bishop return rc;
58140a360c2SBrad Bishop }
582