RUN+="/bin/chmod 0660 /sys%p/edge",\
RUN+="/bin/chsmack -a * /sys%p/edge"
+SUBSYSTEM=="pwm", KERNEL=="pwm*", ACTION=="change",\
+ RUN+="/bin/chown root:root /sys%p/%E{EXPORT}/period",\
+ RUN+="/bin/chmod 0660 /sys%p/%E{EXPORT}/period",\
+ RUN+="/bin/chsmack -a * /sys%p/%E{EXPORT}/period"
+SUBSYSTEM=="pwm", KERNEL=="pwm*", ACTION=="change",\
+ RUN+="/bin/chown root:root /sys%p/%E{EXPORT}/duty_cycle",\
+ RUN+="/bin/chmod 0660 /sys%p/%E{EXPORT}/duty_cycle",\
+ RUN+="/bin/chsmack -a * /sys%p/%E{EXPORT}/duty_cycle"
+SUBSYSTEM=="pwm", KERNEL=="pwm*", ACTION=="change",\
+ RUN+="/bin/chown root:root /sys%p/%E{EXPORT}/polarity",\
+ RUN+="/bin/chmod 0660 /sys%p/%E{EXPORT}/polarity",\
+ RUN+="/bin/chsmack -a * /sys%p/%E{EXPORT}/polarity"
+SUBSYSTEM=="pwm", KERNEL=="pwm*", ACTION=="change",\
+ RUN+="/bin/chown root:root /sys%p/%E{EXPORT}/enable",\
+ RUN+="/bin/chmod 0660 /sys%p/%E{EXPORT}/enable",\
+ RUN+="/bin/chsmack -a * /sys%p/%E{EXPORT}/enable"
+
SUBSYSTEM=="i2c-dev", KERNEL=="i2c-*", ACTION=="add", \
MODE="0660", OWNER="root", GROUP="root", SECLABEL{smack}="*"
*/
#include <stdlib.h>
+#include <libudev.h>
+#include <poll.h>
+
#include "peripheral_interface_pwm.h"
#include "peripheral_interface_common.h"
+static int __pwm_create_udev_monitor(struct udev **udev, struct udev_monitor **monitor)
+{
+ struct udev *_udev = NULL;
+ struct udev_monitor *_monitor = NULL;
+ int ret = -EIO;
+
+ _udev = udev_new();
+ if (!_udev) {
+ _E("Cannot create udev");
+ goto error;
+ }
+
+ _monitor = udev_monitor_new_from_netlink(_udev, "udev");
+ if (!_monitor) {
+ _E("Cannot create udev monitor");
+ goto error;
+ }
+
+ ret = udev_monitor_filter_add_match_subsystem_devtype(_monitor, "pwm", NULL);
+ if (ret < 0) {
+ _E("Failed to add monitor filter");
+ goto error;
+ }
+
+ ret = udev_monitor_enable_receiving(_monitor);
+ if (ret < 0) {
+ _E("Failed to enable udev receiving");
+ goto error;
+ }
+
+ *udev = _udev;
+ *monitor = _monitor;
+
+ return 0;
+
+error:
+ udev_monitor_unref(_monitor);
+ udev_unref(_udev);
+ return ret;
+}
+
+static int __pwm_wait_for_udev(struct udev_monitor *monitor, int chip, int pin)
+{
+ struct udev_device *dev = NULL;
+ struct pollfd pfd;
+ char pwmchip_name[MAX_BUF_LEN];
+ char pwm_name[MAX_BUF_LEN];
+
+ pfd.fd = udev_monitor_get_fd(monitor);
+ pfd.events = POLLIN;
+
+ snprintf(pwmchip_name, MAX_BUF_LEN, "pwmchip%d", chip);
+ snprintf(pwm_name, MAX_BUF_LEN, "pwm%d", pin);
+
+ for (int cnt = 0; cnt < 10; cnt++) {
+ _D("poll iteration");
+ if (poll(&pfd, 1, 100) < 0) {
+ _E("Failed to watch udev monitor");
+ return -EIO;
+ }
+
+ dev = udev_monitor_receive_device(monitor);
+ if (dev) {
+ if (strcmp(udev_device_get_sysname(dev), pwmchip_name) == 0 &&
+ strcmp(udev_device_get_property_value(dev, "EXPORT"), pwm_name) == 0) {
+ _D("udev for %s is initialized", pwm_name);
+ udev_device_unref(dev);
+ return 0;
+ }
+ udev_device_unref(dev);
+ }
+ }
+ _E("Time out");
+
+ return 0;
+}
+
int peripheral_interface_pwm_export(int chip, int pin)
{
RETVM_IF(chip < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid pwm chip");
RETVM_IF(pin < 0, PERIPHERAL_ERROR_INVALID_PARAMETER, "Invalid pwm pin");
int ret;
- int fd;
+ int fd = -1;
int length;
char path[MAX_BUF_LEN] = {0, };
char buf[MAX_BUF_LEN] = {0, };
+ struct udev *udev = NULL;
+ struct udev_monitor *monitor = NULL;
+
+ ret = __pwm_create_udev_monitor(&udev, &monitor);
+ if (ret != 0) {
+ _E("Failed to create udev monitor");
+ goto out;
+ };
snprintf(path, MAX_BUF_LEN, "/sys/class/pwm/pwmchip%d/export", chip);
fd = open(path, O_WRONLY);
- IF_ERROR_RETURN(fd < 0);
+ if (fd < 0) {
+ _E("open() failed: %m");
+ ret = PERIPHERAL_ERROR_IO_ERROR;
+ goto out;
+ }
length = snprintf(buf, MAX_BUF_LEN, "%d", pin);
ret = write(fd, buf, length);
- IF_ERROR_RETURN(ret != length, close(fd));
+ if (ret != length) {
+ _E("write() failed: %m");
+ ret = PERIPHERAL_ERROR_IO_ERROR;
+ goto out;
+ }
ret = close(fd);
- IF_ERROR_RETURN(ret != 0);
-
- snprintf(buf, MAX_BUF_LEN, "chsmack -a \"*\" /sys/class/pwm/pwmchip%d/pwm%d/period", chip, pin);
- ret = system(buf);
if (ret != 0) {
- _E("Failed to change period security label to read/write.");
- return PERIPHERAL_ERROR_IO_ERROR;
+ _E("close() failed: %m");
+ ret = PERIPHERAL_ERROR_IO_ERROR;
+ goto out;
}
- snprintf(buf, MAX_BUF_LEN, "chsmack -a \"*\" /sys/class/pwm/pwmchip%d/pwm%d/duty_cycle", chip, pin);
- ret = system(buf);
- if (ret != 0) {
- _E("Failed to change duty_cycle security label to read/write.");
- return PERIPHERAL_ERROR_IO_ERROR;
+ ret = __pwm_wait_for_udev(monitor, chip, pin);
+ if (ret < 0) {
+ _E("device nodes are not writable");
+ ret = PERIPHERAL_ERROR_IO_ERROR;
+ goto out;
}
- snprintf(buf, MAX_BUF_LEN, "chsmack -a \"*\" /sys/class/pwm/pwmchip%d/pwm%d/polarity", chip, pin);
- ret = system(buf);
- if (ret != 0) {
- _E("Failed to change polarity security label to read/write.");
- return PERIPHERAL_ERROR_IO_ERROR;
- }
+out:
+ if (fd != -1)
+ close(fd);
- snprintf(buf, MAX_BUF_LEN, "chsmack -a \"*\" /sys/class/pwm/pwmchip%d/pwm%d/enable", chip, pin);
- ret = system(buf);
- if (ret != 0) {
- _E("Failed to change enable security label to read/write.");
- return PERIPHERAL_ERROR_IO_ERROR;
- }
+ udev_monitor_unref(monitor);
+ udev_unref(udev);
- return PERIPHERAL_ERROR_NONE;
+ return ret;
}
int peripheral_interface_pwm_unexport(int chip, int pin)