Root/
Source at commit 9e223f77e699c294818ca9cc5ad6d62f8da013e8 created 10 years 22 days ago. By Werner Almesberger, ubbctl/: also support decoding and setting of interrupts and alternate functions | |
---|---|
1 | /* |
2 | * ubbctl.c - Set and query UBB signals |
3 | * |
4 | * Written 2013-2014 by Werner Almesberger |
5 | * Copyright 2013-2014 Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | #include <stddef.h> |
14 | #include <stdint.h> |
15 | #include <stdlib.h> |
16 | #include <stdio.h> |
17 | #include <unistd.h> |
18 | #include <string.h> |
19 | #include <strings.h> /* for strcasecmp, strncasecmp */ |
20 | |
21 | #include <ubb/ubb.h> |
22 | |
23 | |
24 | static struct pin { |
25 | const char *name; |
26 | uint32_t mask; |
27 | } pins[] = { |
28 | { "nPWR", UBB_nPWR }, |
29 | { "DAT2", UBB_DAT2 }, |
30 | { "DAT3", UBB_DAT3 }, |
31 | { "CMD", UBB_CMD }, |
32 | { "CLK", UBB_CLK }, |
33 | { "DAT0", UBB_DAT0 }, |
34 | { "DAT1", UBB_DAT1 }, |
35 | { NULL } |
36 | }; |
37 | |
38 | |
39 | static void show_pins(void) |
40 | { |
41 | const struct pin *p; |
42 | int pin, set; |
43 | |
44 | for (p = pins; p->name; p++) { |
45 | printf("%s%s=", p == pins ? "" : " ", p->name); |
46 | pin = PIN(p->mask); |
47 | if (PDFUN & p->mask) { |
48 | putchar('F'); |
49 | if (PDSEL & p->mask) |
50 | putchar('b'); |
51 | } else if (PDSEL & p->mask) { |
52 | putchar('I'); |
53 | if (PDTRG & p->mask) { |
54 | if (PDDIR & p->mask) |
55 | putchar('r'); |
56 | else |
57 | putchar('f'); |
58 | } else { |
59 | if (PDDIR & p->mask) |
60 | putchar('h'); |
61 | else |
62 | putchar('l'); |
63 | } |
64 | if (!(PDPULL & p->mask)) |
65 | putchar('R'); |
66 | } else if (PDDIR & p->mask) { |
67 | set = !!(PDDAT & p->mask); |
68 | if (pin != set) |
69 | printf("%d!", set); |
70 | |
71 | } else { |
72 | putchar(PDPULL & p->mask ? 'Z' : 'R'); |
73 | } |
74 | printf("%d", pin); |
75 | } |
76 | } |
77 | |
78 | |
79 | /* |
80 | * The order of the IO operations below is important to avoid glitches. |
81 | */ |
82 | |
83 | static int setup_pin(const char *s, int doit) |
84 | { |
85 | static const char trigger[] = "lhfrLHFR"; |
86 | const struct pin *p; |
87 | const char *eq, *t; |
88 | uint8_t trig; |
89 | |
90 | if (!strcasecmp(s, "on")) |
91 | s = "nPWR=0"; |
92 | else if (!strcasecmp(s, "off")) |
93 | s = "nPWR=1"; |
94 | |
95 | eq = strchr(s, '='); |
96 | if (!eq) |
97 | return 0; |
98 | |
99 | for (p = pins; p->name; p++) |
100 | if (strlen(p->name) == eq-s && !strncasecmp(p->name, s, eq-s)) |
101 | break; |
102 | if (!p->name) |
103 | return 0; |
104 | |
105 | if (!strcasecmp(eq+1, "f") || !strcasecmp(eq+1, "fa")) { |
106 | if (doit) { |
107 | PDFUNS = p->mask; |
108 | PDSELC = p->mask; |
109 | } |
110 | return 1; |
111 | } |
112 | if (!strcasecmp(eq+1, "fb")) { |
113 | if (doit) { |
114 | PDFUNS = p->mask; |
115 | PDSELS = p->mask; |
116 | } |
117 | return 1; |
118 | } |
119 | if (!strcmp(eq+1, "0")) { |
120 | if (doit) { |
121 | PDDATC = p->mask; |
122 | PDDIRS = p->mask; |
123 | PDFUNC = p->mask; |
124 | } |
125 | return 1; |
126 | } |
127 | if (!strcmp(eq+1, "1")) { |
128 | if (doit) { |
129 | PDDATS = p->mask; |
130 | PDDIRS = p->mask; |
131 | PDFUNC = p->mask; |
132 | } |
133 | return 1; |
134 | } |
135 | if (!strcasecmp(eq+1, "r")) { |
136 | if (doit) { |
137 | PDPULLC = p->mask; |
138 | PDDIRC = p->mask; |
139 | PDFUNC = p->mask; |
140 | PDSELC = p->mask; |
141 | } |
142 | return 1; |
143 | } |
144 | if (!strcasecmp(eq+1, "z")) { |
145 | if (doit) { |
146 | PDPULLS = p->mask; |
147 | PDDIRC = p->mask; |
148 | PDFUNC = p->mask; |
149 | PDSELC = p->mask; |
150 | } |
151 | return 1; |
152 | } |
153 | if (eq[1] != 'i' && eq[1] != 'I') |
154 | return 0; |
155 | |
156 | t = strchr(trigger, eq[2]); |
157 | if (!t || !*t) |
158 | return 0; |
159 | |
160 | if (!eq[3] || eq[3] == 'z' || eq[3] == 'Z') { |
161 | if (doit) |
162 | PDPULLS = p->mask; |
163 | } else if (eq[3] == 'r' || eq[3] == 'R') { |
164 | if (doit) |
165 | PDPULLC = p->mask; |
166 | } else { |
167 | return 0; |
168 | } |
169 | |
170 | if (!doit) |
171 | return 1; |
172 | |
173 | PDFUNC = p->mask; |
174 | PDSELS = p->mask; |
175 | trig = (t-trigger) & 3; |
176 | if (trig & 1) |
177 | PDDIRS = p->mask; |
178 | else |
179 | PDDIRC = p->mask; |
180 | if (trig & 2) |
181 | PDTRGS = p->mask; |
182 | else |
183 | PDTRGC = p->mask; |
184 | |
185 | return 1; |
186 | } |
187 | |
188 | |
189 | static void usage(const char *name) |
190 | { |
191 | fprintf(stderr, |
192 | "usage: %s [-c]\n" |
193 | " %s name=value|action ...\n\n" |
194 | " -c continously update the pin status (until user interrupts)\n\n" |
195 | "Names: nPWR, CMD, CLK, DAT0, DAT1, DAT2, DAT3\n" |
196 | "Values: F, Fa, Fb, 0, 1, Z, R, Ir[R|Z], If[R|Z], Ih[R|Z], Il[R|Z]\n" |
197 | "Actions: ON, OFF\n" |
198 | , name, name); |
199 | exit(1); |
200 | } |
201 | |
202 | |
203 | int main(int argc, char **argv) |
204 | { |
205 | int continuous = 0; |
206 | int c, i; |
207 | |
208 | while ((c = getopt(argc, argv, "c")) != EOF) |
209 | switch (c) { |
210 | case 'c': |
211 | continuous = 1; |
212 | break; |
213 | default: |
214 | usage(*argv); |
215 | } |
216 | |
217 | if (argc != optind && continuous) |
218 | usage(*argv); |
219 | |
220 | for (i = optind; i != argc; i++) |
221 | if (!setup_pin(argv[i], 0)) |
222 | usage(*argv); |
223 | |
224 | ubb_open(UBB_ALL); |
225 | if (argc == optind) { |
226 | if (continuous) { |
227 | while (1) { |
228 | show_pins(); |
229 | printf("%*s\r", sizeof(pins)/sizeof(*pins)*2, |
230 | ""); |
231 | fflush(stdout); |
232 | usleep(200*1000); |
233 | } |
234 | } else { |
235 | show_pins(); |
236 | putchar('\n'); |
237 | } |
238 | } else { |
239 | for (i = optind; i != argc; i++) |
240 | setup_pin(argv[i], 1); |
241 | } |
242 | return 0; |
243 | } |
244 |
Branches:
master