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 * All rights reserved. 69312900fSEmmanuel Vadot * 79312900fSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 89312900fSEmmanuel Vadot * modification, are permitted provided that the following conditions 99312900fSEmmanuel Vadot * are met: 109312900fSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 119312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 129312900fSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 139312900fSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 149312900fSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 159312900fSEmmanuel Vadot * 169312900fSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 179312900fSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 189312900fSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 199312900fSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 209312900fSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 219312900fSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 229312900fSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 239312900fSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 249312900fSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 259312900fSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 269312900fSEmmanuel Vadot * SUCH DAMAGE. 279312900fSEmmanuel Vadot * 289312900fSEmmanuel Vadot * $FreeBSD$ 299312900fSEmmanuel Vadot */ 309312900fSEmmanuel Vadot 319312900fSEmmanuel Vadot #include <sys/types.h> 329312900fSEmmanuel Vadot #include <sys/ioctl.h> 339312900fSEmmanuel Vadot #include <stdbool.h> 349312900fSEmmanuel Vadot #include <sys/capsicum.h> 3571fb3739SIan Lepore #include <dev/pwm/pwmc.h> 369312900fSEmmanuel Vadot 379312900fSEmmanuel Vadot #include <err.h> 389312900fSEmmanuel Vadot #include <errno.h> 399312900fSEmmanuel Vadot #include <fcntl.h> 407d763870SIan Lepore #include <limits.h> 419312900fSEmmanuel Vadot #include <stdio.h> 429312900fSEmmanuel Vadot #include <stdlib.h> 439312900fSEmmanuel Vadot #include <string.h> 449312900fSEmmanuel Vadot #include <unistd.h> 459312900fSEmmanuel Vadot #include <capsicum_helpers.h> 469312900fSEmmanuel Vadot 479312900fSEmmanuel Vadot #define PWM_ENABLE 0x0001 489312900fSEmmanuel Vadot #define PWM_DISABLE 0x0002 499312900fSEmmanuel Vadot #define PWM_SHOW_CONFIG 0x0004 509312900fSEmmanuel Vadot #define PWM_PERIOD 0x0008 519312900fSEmmanuel Vadot #define PWM_DUTY 0x0010 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"); 69*780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -E\n"); 70*780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -D\n"); 71*780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -C\n"); 72*780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -p period\n"); 73*780c3de8SIan Lepore fprintf(stderr, "\tpwm [-f dev] -d duty\n"); 749312900fSEmmanuel Vadot exit(1); 759312900fSEmmanuel Vadot } 769312900fSEmmanuel Vadot 779312900fSEmmanuel Vadot int 789312900fSEmmanuel Vadot main(int argc, char *argv[]) 799312900fSEmmanuel Vadot { 809312900fSEmmanuel Vadot struct pwm_state state; 819312900fSEmmanuel Vadot int fd; 829312900fSEmmanuel Vadot int period, duty; 839312900fSEmmanuel Vadot int action, ch; 849312900fSEmmanuel Vadot cap_rights_t right_ioctl; 85*780c3de8SIan Lepore const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE}; 8650a123aaSEmmanuel Vadot char *percent; 877d763870SIan Lepore bool setname; 889312900fSEmmanuel Vadot 899312900fSEmmanuel Vadot action = 0; 907d763870SIan Lepore setname = false; 919312900fSEmmanuel Vadot fd = -1; 929312900fSEmmanuel Vadot period = duty = -1; 939312900fSEmmanuel Vadot 94*780c3de8SIan Lepore while ((ch = getopt(argc, argv, "f:EDCp:d:")) != -1) { 959312900fSEmmanuel Vadot switch (ch) { 969312900fSEmmanuel Vadot case 'E': 979312900fSEmmanuel Vadot if (action) 989312900fSEmmanuel Vadot usage(); 999312900fSEmmanuel Vadot action = PWM_ENABLE; 1009312900fSEmmanuel Vadot break; 1019312900fSEmmanuel Vadot case 'D': 1029312900fSEmmanuel Vadot if (action) 1039312900fSEmmanuel Vadot usage(); 1049312900fSEmmanuel Vadot action = PWM_DISABLE; 1059312900fSEmmanuel Vadot break; 1069312900fSEmmanuel Vadot case 'C': 1079312900fSEmmanuel Vadot if (action) 1089312900fSEmmanuel Vadot usage(); 1099312900fSEmmanuel Vadot action = PWM_SHOW_CONFIG; 1109312900fSEmmanuel Vadot break; 1119312900fSEmmanuel Vadot case 'p': 1129312900fSEmmanuel Vadot if (action & ~(PWM_PERIOD | PWM_DUTY)) 1139312900fSEmmanuel Vadot usage(); 1149312900fSEmmanuel Vadot action = PWM_PERIOD; 1159312900fSEmmanuel Vadot period = strtol(optarg, NULL, 10); 1169312900fSEmmanuel Vadot break; 1179312900fSEmmanuel Vadot case 'd': 1189312900fSEmmanuel Vadot if (action & ~(PWM_PERIOD | PWM_DUTY)) 1199312900fSEmmanuel Vadot usage(); 1209312900fSEmmanuel Vadot action = PWM_DUTY; 12150a123aaSEmmanuel Vadot duty = strtol(optarg, &percent, 10); 12250a123aaSEmmanuel Vadot if (*percent != '\0' && *percent != '%') 12350a123aaSEmmanuel Vadot usage(); 1249312900fSEmmanuel Vadot break; 1259312900fSEmmanuel Vadot case 'f': 1267d763870SIan Lepore setname = true; 1277d763870SIan Lepore set_device_name(optarg); 1287d763870SIan Lepore break; 129*780c3de8SIan Lepore case '?': 130*780c3de8SIan Lepore usage(); 131*780c3de8SIan Lepore break; 1329312900fSEmmanuel Vadot } 1339312900fSEmmanuel Vadot } 1349312900fSEmmanuel Vadot 1357d763870SIan Lepore if (action == 0) 1369312900fSEmmanuel Vadot usage(); 1379312900fSEmmanuel Vadot 1387d763870SIan Lepore if ((fd = open(device_name, O_RDWR)) == -1) { 1397d763870SIan Lepore fprintf(stderr, "pwm: cannot open %s: %s\n", 1407d763870SIan Lepore device_name, strerror(errno)); 1417d763870SIan Lepore if (setname) 1427d763870SIan Lepore exit(1); 1437d763870SIan Lepore else 1447d763870SIan Lepore usage(); 1457d763870SIan Lepore } 1467d763870SIan Lepore 1479312900fSEmmanuel Vadot if (caph_limit_stdio() < 0) { 1489312900fSEmmanuel Vadot fprintf(stderr, "can't limit stdio rights"); 1499312900fSEmmanuel Vadot goto fail; 1509312900fSEmmanuel Vadot } 1519312900fSEmmanuel Vadot caph_cache_catpages(); 1529312900fSEmmanuel Vadot cap_rights_init(&right_ioctl, CAP_IOCTL); 1539312900fSEmmanuel Vadot if (caph_rights_limit(fd, &right_ioctl) < 0) { 1549312900fSEmmanuel Vadot fprintf(stderr, "cap_right_limit() failed\n"); 1559312900fSEmmanuel Vadot goto fail; 1569312900fSEmmanuel Vadot } 1579312900fSEmmanuel Vadot if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) { 1589312900fSEmmanuel Vadot fprintf(stderr, "caph_ioctls_limit() failed\n"); 1599312900fSEmmanuel Vadot goto fail; 1609312900fSEmmanuel Vadot } 1619312900fSEmmanuel Vadot if (caph_enter() < 0) { 1629312900fSEmmanuel Vadot fprintf(stderr, "failed to enter capability mode\n"); 1639312900fSEmmanuel Vadot goto fail; 1649312900fSEmmanuel Vadot } 1659312900fSEmmanuel Vadot 1669312900fSEmmanuel Vadot /* Fill the common args */ 1679312900fSEmmanuel Vadot if (ioctl(fd, PWMGETSTATE, &state) == -1) { 1689312900fSEmmanuel Vadot fprintf(stderr, "Cannot get current state of the pwm controller\n"); 1699312900fSEmmanuel Vadot goto fail; 1709312900fSEmmanuel Vadot } 1719312900fSEmmanuel Vadot 1729312900fSEmmanuel Vadot switch (action) { 1739312900fSEmmanuel Vadot case PWM_ENABLE: 1749312900fSEmmanuel Vadot if (state.enable == false) { 1759312900fSEmmanuel Vadot state.enable = true; 1769312900fSEmmanuel Vadot if (ioctl(fd, PWMSETSTATE, &state) == -1) { 1779312900fSEmmanuel Vadot fprintf(stderr, 1789312900fSEmmanuel Vadot "Cannot enable the pwm controller\n"); 1799312900fSEmmanuel Vadot goto fail; 1809312900fSEmmanuel Vadot } 1819312900fSEmmanuel Vadot } 1829312900fSEmmanuel Vadot break; 1839312900fSEmmanuel Vadot case PWM_DISABLE: 1849312900fSEmmanuel Vadot if (state.enable == true) { 1859312900fSEmmanuel Vadot state.enable = false; 1869312900fSEmmanuel Vadot if (ioctl(fd, PWMSETSTATE, &state) == -1) { 1879312900fSEmmanuel Vadot fprintf(stderr, 1889312900fSEmmanuel Vadot "Cannot disable the pwm controller\n"); 1899312900fSEmmanuel Vadot goto fail; 1909312900fSEmmanuel Vadot } 1919312900fSEmmanuel Vadot } 1929312900fSEmmanuel Vadot break; 1939312900fSEmmanuel Vadot case PWM_SHOW_CONFIG: 1946a9997edSEmmanuel Vadot printf("period: %u\nduty: %u\nenabled:%d\n", 1956a9997edSEmmanuel Vadot state.period, 1966a9997edSEmmanuel Vadot state.duty, 1979312900fSEmmanuel Vadot state.enable); 1989312900fSEmmanuel Vadot break; 1999312900fSEmmanuel Vadot case PWM_PERIOD: 2009312900fSEmmanuel Vadot case PWM_DUTY: 2019312900fSEmmanuel Vadot if (period != -1) 2029312900fSEmmanuel Vadot state.period = period; 20350a123aaSEmmanuel Vadot if (duty != -1) { 20450a123aaSEmmanuel Vadot if (*percent != '\0') 20550a123aaSEmmanuel Vadot state.duty = state.period * duty / 100; 20650a123aaSEmmanuel Vadot else 2079312900fSEmmanuel Vadot state.duty = duty; 20850a123aaSEmmanuel Vadot } 2099312900fSEmmanuel Vadot if (ioctl(fd, PWMSETSTATE, &state) == -1) { 2109312900fSEmmanuel Vadot fprintf(stderr, 2119312900fSEmmanuel Vadot "Cannot configure the pwm controller\n"); 2129312900fSEmmanuel Vadot goto fail; 2139312900fSEmmanuel Vadot } 2149312900fSEmmanuel Vadot break; 2159312900fSEmmanuel Vadot } 2169312900fSEmmanuel Vadot 2179312900fSEmmanuel Vadot close(fd); 2189312900fSEmmanuel Vadot return (0); 2199312900fSEmmanuel Vadot 2209312900fSEmmanuel Vadot fail: 2219312900fSEmmanuel Vadot close(fd); 2229312900fSEmmanuel Vadot return (1); 2239312900fSEmmanuel Vadot } 224