19312900fSEmmanuel Vadot /*- 29312900fSEmmanuel Vadot * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 39312900fSEmmanuel Vadot * 49312900fSEmmanuel Vadot * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org> 59312900fSEmmanuel Vadot * 69312900fSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 79312900fSEmmanuel Vadot * modification, are permitted provided that the following conditions 89312900fSEmmanuel Vadot * are met: 99312900fSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 109312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 119312900fSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 129312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 139312900fSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 149312900fSEmmanuel Vadot * 159312900fSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 169312900fSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 179312900fSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 189312900fSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 199312900fSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 209312900fSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 219312900fSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 229312900fSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 239312900fSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 249312900fSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 259312900fSEmmanuel Vadot * SUCH DAMAGE. 269312900fSEmmanuel Vadot * 279312900fSEmmanuel Vadot * $FreeBSD$ 289312900fSEmmanuel Vadot */ 299312900fSEmmanuel Vadot 309312900fSEmmanuel Vadot #include <sys/types.h> 319312900fSEmmanuel Vadot #include <sys/ioctl.h> 329312900fSEmmanuel Vadot #include <stdbool.h> 339312900fSEmmanuel Vadot #include <sys/capsicum.h> 3471fb3739SIan Lepore #include <dev/pwm/pwmc.h> 359312900fSEmmanuel Vadot 369312900fSEmmanuel Vadot #include <err.h> 379312900fSEmmanuel Vadot #include <errno.h> 389312900fSEmmanuel Vadot #include <fcntl.h> 397d763870SIan Lepore #include <limits.h> 409312900fSEmmanuel Vadot #include <stdio.h> 419312900fSEmmanuel Vadot #include <stdlib.h> 429312900fSEmmanuel Vadot #include <string.h> 439312900fSEmmanuel Vadot #include <unistd.h> 449312900fSEmmanuel Vadot #include <capsicum_helpers.h> 459312900fSEmmanuel Vadot 469312900fSEmmanuel Vadot #define PWM_ENABLE 0x0001 479312900fSEmmanuel Vadot #define PWM_DISABLE 0x0002 489312900fSEmmanuel Vadot #define PWM_SHOW_CONFIG 0x0004 499312900fSEmmanuel Vadot #define PWM_PERIOD 0x0008 509312900fSEmmanuel Vadot #define PWM_DUTY 0x0010 51*17b14d8fSOskar Holmund #define PWM_INVERTED 0x0020 529312900fSEmmanuel Vadot 537d763870SIan Lepore static char device_name[PATH_MAX] = "/dev/pwm/pwmc0.0"; 547d763870SIan Lepore 557d763870SIan Lepore static void 567d763870SIan Lepore set_device_name(const char *name) 577d763870SIan Lepore { 587d763870SIan Lepore 597d763870SIan Lepore if (name[0] == '/') 607d763870SIan Lepore strlcpy(device_name, name, sizeof(device_name)); 617d763870SIan Lepore else 627d763870SIan Lepore snprintf(device_name, sizeof(device_name), "/dev/pwm/%s", name); 637d763870SIan Lepore } 647d763870SIan Lepore 659312900fSEmmanuel Vadot static void 669312900fSEmmanuel Vadot usage(void) 679312900fSEmmanuel Vadot { 689312900fSEmmanuel Vadot fprintf(stderr, "Usage:\n"); 69780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -C\n"); 70*17b14d8fSOskar Holmund fprintf(stderr, "\tpwm [-f dev] [-D | -E] [-I] [-p period] [-d duty[%%]]\n"); 719312900fSEmmanuel Vadot exit(1); 729312900fSEmmanuel Vadot } 739312900fSEmmanuel Vadot 749312900fSEmmanuel Vadot int 759312900fSEmmanuel Vadot main(int argc, char *argv[]) 769312900fSEmmanuel Vadot { 779312900fSEmmanuel Vadot struct pwm_state state; 789312900fSEmmanuel Vadot int fd; 79a4f28d42SAndriy Gapon u_int period, duty; 809312900fSEmmanuel Vadot int action, ch; 819312900fSEmmanuel Vadot cap_rights_t right_ioctl; 82780c3de8SIan Lepore const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE}; 8350a123aaSEmmanuel Vadot char *percent; 847d763870SIan Lepore bool setname; 859312900fSEmmanuel Vadot 869312900fSEmmanuel Vadot action = 0; 877d763870SIan Lepore setname = false; 889312900fSEmmanuel Vadot fd = -1; 899312900fSEmmanuel Vadot period = duty = -1; 909312900fSEmmanuel Vadot 91*17b14d8fSOskar Holmund while ((ch = getopt(argc, argv, "f:EDCIp:d:")) != -1) { 929312900fSEmmanuel Vadot switch (ch) { 939312900fSEmmanuel Vadot case 'E': 9426f3ca61SIan Lepore if (action & (PWM_DISABLE | PWM_SHOW_CONFIG)) 959312900fSEmmanuel Vadot usage(); 9626f3ca61SIan Lepore action |= PWM_ENABLE; 979312900fSEmmanuel Vadot break; 989312900fSEmmanuel Vadot case 'D': 9926f3ca61SIan Lepore if (action & (PWM_ENABLE | PWM_SHOW_CONFIG)) 1009312900fSEmmanuel Vadot usage(); 10126f3ca61SIan Lepore action |= PWM_DISABLE; 1029312900fSEmmanuel Vadot break; 1039312900fSEmmanuel Vadot case 'C': 1049312900fSEmmanuel Vadot if (action) 1059312900fSEmmanuel Vadot usage(); 1069312900fSEmmanuel Vadot action = PWM_SHOW_CONFIG; 1079312900fSEmmanuel Vadot break; 108*17b14d8fSOskar Holmund case 'I': 109*17b14d8fSOskar Holmund if (action & PWM_SHOW_CONFIG) 110*17b14d8fSOskar Holmund usage(); 111*17b14d8fSOskar Holmund action |= PWM_INVERTED; 112*17b14d8fSOskar Holmund break; 1139312900fSEmmanuel Vadot case 'p': 11426f3ca61SIan Lepore if (action & PWM_SHOW_CONFIG) 1159312900fSEmmanuel Vadot usage(); 11626f3ca61SIan Lepore action |= PWM_PERIOD; 117a4f28d42SAndriy Gapon period = strtoul(optarg, NULL, 10); 1189312900fSEmmanuel Vadot break; 1199312900fSEmmanuel Vadot case 'd': 12026f3ca61SIan Lepore if (action & PWM_SHOW_CONFIG) 1219312900fSEmmanuel Vadot usage(); 12226f3ca61SIan Lepore action |= PWM_DUTY; 123a4f28d42SAndriy Gapon duty = strtoul(optarg, &percent, 10); 12426f3ca61SIan Lepore if (*percent == '%') { 125a4f28d42SAndriy Gapon if (duty > 100) { 12626f3ca61SIan Lepore fprintf(stderr, 12726f3ca61SIan Lepore "Invalid duty percentage\n"); 12826f3ca61SIan Lepore usage(); 12926f3ca61SIan Lepore } 13026f3ca61SIan Lepore } else if (*percent != '\0') 13150a123aaSEmmanuel Vadot usage(); 1329312900fSEmmanuel Vadot break; 1339312900fSEmmanuel Vadot case 'f': 1347d763870SIan Lepore setname = true; 1357d763870SIan Lepore set_device_name(optarg); 1367d763870SIan Lepore break; 137780c3de8SIan Lepore case '?': 138780c3de8SIan Lepore usage(); 139780c3de8SIan Lepore break; 1409312900fSEmmanuel Vadot } 1419312900fSEmmanuel Vadot } 1429312900fSEmmanuel Vadot 1437d763870SIan Lepore if (action == 0) 1449312900fSEmmanuel Vadot usage(); 1459312900fSEmmanuel Vadot 1467d763870SIan Lepore if ((fd = open(device_name, O_RDWR)) == -1) { 1477d763870SIan Lepore fprintf(stderr, "pwm: cannot open %s: %s\n", 1487d763870SIan Lepore device_name, strerror(errno)); 1497d763870SIan Lepore if (setname) 1507d763870SIan Lepore exit(1); 1517d763870SIan Lepore else 1527d763870SIan Lepore usage(); 1537d763870SIan Lepore } 1547d763870SIan Lepore 1559312900fSEmmanuel Vadot if (caph_limit_stdio() < 0) { 1569312900fSEmmanuel Vadot fprintf(stderr, "can't limit stdio rights"); 1579312900fSEmmanuel Vadot goto fail; 1589312900fSEmmanuel Vadot } 1599312900fSEmmanuel Vadot caph_cache_catpages(); 1609312900fSEmmanuel Vadot cap_rights_init(&right_ioctl, CAP_IOCTL); 1619312900fSEmmanuel Vadot if (caph_rights_limit(fd, &right_ioctl) < 0) { 1629312900fSEmmanuel Vadot fprintf(stderr, "cap_right_limit() failed\n"); 1639312900fSEmmanuel Vadot goto fail; 1649312900fSEmmanuel Vadot } 1659312900fSEmmanuel Vadot if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) { 1669312900fSEmmanuel Vadot fprintf(stderr, "caph_ioctls_limit() failed\n"); 1679312900fSEmmanuel Vadot goto fail; 1689312900fSEmmanuel Vadot } 1699312900fSEmmanuel Vadot if (caph_enter() < 0) { 1709312900fSEmmanuel Vadot fprintf(stderr, "failed to enter capability mode\n"); 1719312900fSEmmanuel Vadot goto fail; 1729312900fSEmmanuel Vadot } 1739312900fSEmmanuel Vadot 1749312900fSEmmanuel Vadot /* Fill the common args */ 1759312900fSEmmanuel Vadot if (ioctl(fd, PWMGETSTATE, &state) == -1) { 1769312900fSEmmanuel Vadot fprintf(stderr, "Cannot get current state of the pwm controller\n"); 1779312900fSEmmanuel Vadot goto fail; 1789312900fSEmmanuel Vadot } 1799312900fSEmmanuel Vadot 18026f3ca61SIan Lepore if (action == PWM_SHOW_CONFIG) { 181*17b14d8fSOskar Holmund printf("period: %u\nduty: %u\nenabled:%d\ninverted:%d\n", 1826a9997edSEmmanuel Vadot state.period, 1836a9997edSEmmanuel Vadot state.duty, 184*17b14d8fSOskar Holmund state.enable, 185*17b14d8fSOskar Holmund state.flags & PWM_POLARITY_INVERTED); 18626f3ca61SIan Lepore } else { 18726f3ca61SIan Lepore if (action & PWM_ENABLE) 18826f3ca61SIan Lepore state.enable = true; 18926f3ca61SIan Lepore if (action & PWM_DISABLE) 19026f3ca61SIan Lepore state.enable = false; 19126f3ca61SIan Lepore if (action & PWM_PERIOD) 1929312900fSEmmanuel Vadot state.period = period; 193*17b14d8fSOskar Holmund if (action & PWM_INVERTED) 194*17b14d8fSOskar Holmund state.flags |= PWM_POLARITY_INVERTED; 195*17b14d8fSOskar Holmund else 196*17b14d8fSOskar Holmund state.flags &= ~PWM_POLARITY_INVERTED; 19726f3ca61SIan Lepore if (action & PWM_DUTY) { 19850a123aaSEmmanuel Vadot if (*percent != '\0') 199a4f28d42SAndriy Gapon state.duty = (uint64_t)state.period * duty / 100; 20050a123aaSEmmanuel Vadot else 2019312900fSEmmanuel Vadot state.duty = duty; 20250a123aaSEmmanuel Vadot } 20326f3ca61SIan Lepore 2049312900fSEmmanuel Vadot if (ioctl(fd, PWMSETSTATE, &state) == -1) { 2059312900fSEmmanuel Vadot fprintf(stderr, 2069312900fSEmmanuel Vadot "Cannot configure the pwm controller\n"); 2079312900fSEmmanuel Vadot goto fail; 2089312900fSEmmanuel Vadot } 2099312900fSEmmanuel Vadot } 2109312900fSEmmanuel Vadot 2119312900fSEmmanuel Vadot close(fd); 2129312900fSEmmanuel Vadot return (0); 2139312900fSEmmanuel Vadot 2149312900fSEmmanuel Vadot fail: 2159312900fSEmmanuel Vadot close(fd); 2169312900fSEmmanuel Vadot return (1); 2179312900fSEmmanuel Vadot } 218