2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
35 #include <sys/capsicum.h>
44 #include <capsicum_helpers.h>
46 #define PWM_ENABLE 0x0001
47 #define PWM_DISABLE 0x0002
48 #define PWM_SHOW_CONFIG 0x0004
49 #define PWM_PERIOD 0x0008
50 #define PWM_DUTY 0x0010
55 fprintf(stderr, "Usage:\n");
56 fprintf(stderr, "\tpwm [-f dev] -c channel -E\n");
57 fprintf(stderr, "\tpwm [-f dev] -c channel -D\n");
58 fprintf(stderr, "\tpwm [-f dev] -c channel -C\n");
59 fprintf(stderr, "\tpwm [-f dev] -c channel -p period\n");
60 fprintf(stderr, "\tpwm [-f dev] -c channel -d duty\n");
65 main(int argc, char *argv[])
67 struct pwm_state state;
69 int channel, nchannels;
72 cap_rights_t right_ioctl;
73 const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE, PWMMAXCHANNEL};
81 while ((ch = getopt(argc, argv, "f:c:EDCp:d:")) != -1) {
96 action = PWM_SHOW_CONFIG;
99 if (action & ~(PWM_PERIOD | PWM_DUTY))
102 period = strtol(optarg, NULL, 10);
105 if (action & ~(PWM_PERIOD | PWM_DUTY))
108 duty = strtol(optarg, &percent, 10);
109 if (*percent != '\0' && *percent != '%')
115 channel = strtol(optarg, NULL, 10);
118 if ((fd = open(optarg, O_RDWR)) < 0) {
119 fprintf(stderr, "pwm: cannot open %s %s\n",
120 optarg, strerror(errno));
127 if ((fd = open("/dev/pwmc0", O_RDWR)) < 0) {
128 fprintf(stderr, "pwm: cannot open %s %s\n",
129 optarg, strerror(errno));
134 if (action == 0 || fd == -1)
137 if (caph_limit_stdio() < 0) {
138 fprintf(stderr, "can't limit stdio rights");
141 caph_cache_catpages();
142 cap_rights_init(&right_ioctl, CAP_IOCTL);
143 if (caph_rights_limit(fd, &right_ioctl) < 0) {
144 fprintf(stderr, "cap_right_limit() failed\n");
147 if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) {
148 fprintf(stderr, "caph_ioctls_limit() failed\n");
151 if (caph_enter() < 0) {
152 fprintf(stderr, "failed to enter capability mode\n");
156 /* Check if the channel is correct */
157 if (ioctl(fd, PWMMAXCHANNEL, &nchannels) == -1) {
158 fprintf(stderr, "ioctl: %s\n", strerror(errno));
161 if (channel > nchannels) {
162 fprintf(stderr, "pwm controller only support %d channels\n",
167 /* Fill the common args */
168 state.channel = channel;
169 if (ioctl(fd, PWMGETSTATE, &state) == -1) {
170 fprintf(stderr, "Cannot get current state of the pwm controller\n");
176 if (state.enable == false) {
178 if (ioctl(fd, PWMSETSTATE, &state) == -1) {
180 "Cannot enable the pwm controller\n");
186 if (state.enable == true) {
187 state.enable = false;
188 if (ioctl(fd, PWMSETSTATE, &state) == -1) {
190 "Cannot disable the pwm controller\n");
195 case PWM_SHOW_CONFIG:
196 printf("period: %u\nduty: %u\nenabled:%d\n",
204 state.period = period;
206 if (*percent != '\0')
207 state.duty = state.period * duty / 100;
211 if (ioctl(fd, PWMSETSTATE, &state) == -1) {
213 "Cannot configure the pwm controller\n");