]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pwm/pwm.c
stand: TARGET_ARCH is spelled MACHINE_ARCH in Makefiles
[FreeBSD/FreeBSD.git] / usr.sbin / pwm / pwm.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
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.
15  *
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
26  * SUCH DAMAGE.
27  *
28  * $FreeBSD$
29  */
30
31 #include <sys/types.h>
32 #include <sys/ioctl.h>
33 #include <stdbool.h>
34 #include <sys/pwm.h>
35 #include <sys/capsicum.h>
36
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <capsicum_helpers.h>
45
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
51
52 static void
53 usage(void)
54 {
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");
61         exit(1);
62 }
63
64 int
65 main(int argc, char *argv[])
66 {
67         struct pwm_state state;
68         int fd;
69         int channel, nchannels;
70         int period, duty;
71         int action, ch;
72         cap_rights_t right_ioctl;
73         const unsigned long pwm_ioctls[] = {PWMGETSTATE, PWMSETSTATE, PWMMAXCHANNEL};
74         char *percent;
75
76         action = 0;
77         fd = -1;
78         channel = -1;
79         period = duty = -1;
80
81         while ((ch = getopt(argc, argv, "f:c:EDCp:d:")) != -1) {
82                 switch (ch) {
83                 case 'E':
84                         if (action)
85                                 usage();
86                         action = PWM_ENABLE;
87                         break;
88                 case 'D':
89                         if (action)
90                                 usage();
91                         action = PWM_DISABLE;
92                         break;
93                 case 'C':
94                         if (action)
95                                 usage();
96                         action = PWM_SHOW_CONFIG;
97                         break;
98                 case 'p':
99                         if (action & ~(PWM_PERIOD | PWM_DUTY))
100                                 usage();
101                         action = PWM_PERIOD;
102                         period = strtol(optarg, NULL, 10);
103                         break;
104                 case 'd':
105                         if (action & ~(PWM_PERIOD | PWM_DUTY))
106                                 usage();
107                         action = PWM_DUTY;
108                         duty = strtol(optarg, &percent, 10);
109                         if (*percent != '\0' && *percent != '%')
110                                 usage();
111                         break;
112                 case 'c':
113                         if (channel != -1)
114                                 usage();
115                         channel = strtol(optarg, NULL, 10);
116                         break;
117                 case 'f':
118                         if ((fd = open(optarg, O_RDWR)) < 0) {
119                                 fprintf(stderr, "pwm: cannot open %s %s\n",
120                                   optarg, strerror(errno));
121                                 exit(1);
122                         }
123                 }
124         }
125
126         if (fd == -1) {
127                 if ((fd = open("/dev/pwmc0", O_RDWR)) < 0) {
128                         fprintf(stderr, "pwm: cannot open %s %s\n",
129                             optarg, strerror(errno));
130                         exit(1);
131                 }
132         }
133
134         if (action == 0 || fd == -1)
135                 usage();
136
137         if (caph_limit_stdio() < 0) {
138                 fprintf(stderr, "can't limit stdio rights");
139                 goto fail;
140         }
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");
145                 goto fail;
146         }
147         if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) {
148                 fprintf(stderr, "caph_ioctls_limit() failed\n");
149                 goto fail;
150         }
151         if (caph_enter() < 0) {
152                 fprintf(stderr, "failed to enter capability mode\n");
153                 goto fail;
154         }
155
156         /* Check if the channel is correct */
157         if (ioctl(fd, PWMMAXCHANNEL, &nchannels) == -1) {
158                 fprintf(stderr, "ioctl: %s\n", strerror(errno));
159                 goto fail;
160         }
161         if (channel > nchannels) {
162                 fprintf(stderr, "pwm controller only support %d channels\n",
163                     nchannels);
164                 goto fail;
165         }
166
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");
171                 goto fail;
172         }
173
174         switch (action) {
175         case PWM_ENABLE:
176                 if (state.enable == false) {
177                         state.enable = true;
178                         if (ioctl(fd, PWMSETSTATE, &state) == -1) {
179                                 fprintf(stderr,
180                                     "Cannot enable the pwm controller\n");
181                                 goto fail;
182                         }
183                 }
184                 break;
185         case PWM_DISABLE:
186                 if (state.enable == true) {
187                         state.enable = false;
188                         if (ioctl(fd, PWMSETSTATE, &state) == -1) {
189                                 fprintf(stderr,
190                                     "Cannot disable the pwm controller\n");
191                                 goto fail;
192                         }
193                 }
194                 break;
195         case PWM_SHOW_CONFIG:
196                 printf("period: %u\nduty: %u\nenabled:%d\n",
197                     state.period,
198                     state.duty,
199                     state.enable);
200                 break;
201         case PWM_PERIOD:
202         case PWM_DUTY:
203                 if (period != -1)
204                         state.period = period;
205                 if (duty != -1) {
206                         if (*percent != '\0')
207                                 state.duty = state.period * duty / 100;
208                         else
209                                 state.duty = duty;
210                 }
211                 if (ioctl(fd, PWMSETSTATE, &state) == -1) {
212                         fprintf(stderr,
213                           "Cannot configure the pwm controller\n");
214                         goto fail;
215                 }
216                 break;
217         }
218
219         close(fd);
220         return (0);
221
222 fail:
223         close(fd);
224         return (1);
225 }