]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/pwm/pwm.c
pwm: Convert period and duty to unsigned int
[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
75         action = 0;
76         fd = -1;
77         channel = -1;
78         period = duty = -1;
79
80         while ((ch = getopt(argc, argv, "f:c:EDCp:d:")) != -1) {
81                 switch (ch) {
82                 case 'E':
83                         if (action)
84                                 usage();
85                         action = PWM_ENABLE;
86                         break;
87                 case 'D':
88                         if (action)
89                                 usage();
90                         action = PWM_DISABLE;
91                         break;
92                 case 'C':
93                         if (action)
94                                 usage();
95                         action = PWM_SHOW_CONFIG;
96                         break;
97                 case 'p':
98                         if (action & ~(PWM_PERIOD | PWM_DUTY))
99                                 usage();
100                         action = PWM_PERIOD;
101                         period = strtol(optarg, NULL, 10);
102                         break;
103                 case 'd':
104                         if (action & ~(PWM_PERIOD | PWM_DUTY))
105                                 usage();
106                         action = PWM_DUTY;
107                         duty = strtol(optarg, NULL, 10);
108                         break;
109                 case 'c':
110                         if (channel != -1)
111                                 usage();
112                         channel = strtol(optarg, NULL, 10);
113                         break;
114                 case 'f':
115                         if ((fd = open(optarg, O_RDWR)) < 0) {
116                                 fprintf(stderr, "pwm: cannot open %s %s\n",
117                                   optarg, strerror(errno));
118                                 exit(1);
119                         }
120                 }
121         }
122
123         if (fd == -1) {
124                 if ((fd = open("/dev/pwmc0", O_RDWR)) < 0) {
125                         fprintf(stderr, "pwm: cannot open %s %s\n",
126                             optarg, strerror(errno));
127                         exit(1);
128                 }
129         }
130
131         if (action == 0 || fd == -1)
132                 usage();
133
134         if (caph_limit_stdio() < 0) {
135                 fprintf(stderr, "can't limit stdio rights");
136                 goto fail;
137         }
138         caph_cache_catpages();
139         cap_rights_init(&right_ioctl, CAP_IOCTL);
140         if (caph_rights_limit(fd, &right_ioctl) < 0) {
141                 fprintf(stderr, "cap_right_limit() failed\n");
142                 goto fail;
143         }
144         if (caph_ioctls_limit(fd, pwm_ioctls, nitems(pwm_ioctls)) < 0) {
145                 fprintf(stderr, "caph_ioctls_limit() failed\n");
146                 goto fail;
147         }
148         if (caph_enter() < 0) {
149                 fprintf(stderr, "failed to enter capability mode\n");
150                 goto fail;
151         }
152
153         /* Check if the channel is correct */
154         if (ioctl(fd, PWMMAXCHANNEL, &nchannels) == -1) {
155                 fprintf(stderr, "ioctl: %s\n", strerror(errno));
156                 goto fail;
157         }
158         if (channel > nchannels) {
159                 fprintf(stderr, "pwm controller only support %d channels\n",
160                     nchannels);
161                 goto fail;
162         }
163
164         /* Fill the common args */
165         state.channel = channel;
166         if (ioctl(fd, PWMGETSTATE, &state) == -1) {
167                 fprintf(stderr, "Cannot get current state of the pwm controller\n");
168                 goto fail;
169         }
170
171         switch (action) {
172         case PWM_ENABLE:
173                 if (state.enable == false) {
174                         state.enable = true;
175                         if (ioctl(fd, PWMSETSTATE, &state) == -1) {
176                                 fprintf(stderr,
177                                     "Cannot enable the pwm controller\n");
178                                 goto fail;
179                         }
180                 }
181                 break;
182         case PWM_DISABLE:
183                 if (state.enable == true) {
184                         state.enable = false;
185                         if (ioctl(fd, PWMSETSTATE, &state) == -1) {
186                                 fprintf(stderr,
187                                     "Cannot disable the pwm controller\n");
188                                 goto fail;
189                         }
190                 }
191                 break;
192         case PWM_SHOW_CONFIG:
193                 printf("period: %u\nduty: %u\nenabled:%d\n",
194                     state.period,
195                     state.duty,
196                     state.enable);
197                 break;
198         case PWM_PERIOD:
199         case PWM_DUTY:
200                 if (period != -1)
201                         state.period = period;
202                 if (duty != -1)
203                         state.duty = duty;
204                 if (ioctl(fd, PWMSETSTATE, &state) == -1) {
205                         fprintf(stderr,
206                           "Cannot configure the pwm controller\n");
207                         goto fail;
208                 }
209                 break;
210         }
211
212         close(fd);
213         return (0);
214
215 fail:
216         close(fd);
217         return (1);
218 }