Skip to content

Commit 0432087

Browse files
committed
Add support for comma separated list of ranges to port list parser
* Add support for comma separated list of ports, and possibly ranges, e.g. it is possible to use syntax like `1,3-5,9-12`. * Increase MAX_HUB_PORTS to 14. WARNING: this will break your scripts if you used syntax like `-p 1234` before. Replace that syntax with `1,2,3,4` or `1-4` instead.
1 parent 2de7def commit 0432087

File tree

2 files changed

+57
-18
lines changed

2 files changed

+57
-18
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ You can control the power on a USB port(s) like this:
122122
This means operate on default smart hub and turn power off (`-a off`, or `-a 0`)
123123
on port 2 (`-p 2`). Supported actions are `off`/`on`/`cycle` (or `0`/`1`/`2`).
124124
`cycle` means turn power off, wait some delay (configurable with `-d`) and turn it back on.
125+
Ports can be comma separated list, and may use `-` for ranges e.g. `2`, or `2,4`, or `2-5`, or `1-2,5-8`.
125126

126127
On Linux, you may need to run it with `sudo`, or to configure `udev` USB permissions.
127128

uhubctl.c

+56-18
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,8 @@ void sleep_ms(int milliseconds)
5959
#endif
6060
}
6161

62-
/* Max number of hub ports supported.
63-
* This is somewhat artificially limited by "-p" option parser.
64-
* If "-p" parser is improved, we can support up to 32 ports.
65-
* However, biggest number of ports on smart hub I've seen was 8.
66-
* I've also observed onboard USB hub with whopping 14 ports,
67-
* but that hub did not support per-port power switching.
68-
*/
69-
#define MAX_HUB_PORTS 9
62+
/* Max number of hub ports supported */
63+
#define MAX_HUB_PORTS 14
7064
#define ALL_HUB_PORTS ((1 << MAX_HUB_PORTS) - 1) /* bitmask */
7165

7266
#define USB_CTRL_GET_TIMEOUT 5000
@@ -266,6 +260,59 @@ static char* rtrim(char* str)
266260
return str;
267261
}
268262

263+
/*
264+
* Convert port list into bitmap.
265+
* Following port list specifications are equivalent:
266+
* 1,3,4,5,11,12,13
267+
* 1,3-5,11-13
268+
* Returns: bitmap of specified ports, max port is MAX_HUB_PORTS.
269+
*/
270+
271+
static int ports2bitmap(char* const portlist)
272+
{
273+
int ports = 0;
274+
char* position = portlist;
275+
char* comma;
276+
char* dash;
277+
int len;
278+
int i;
279+
while (position) {
280+
char buf[8] = {0};
281+
comma = strchr(position, ',');
282+
len = sizeof(buf) - 1;
283+
if (comma) {
284+
if (len > comma - position)
285+
len = comma - position;
286+
strncpy(buf, position, len);
287+
position = comma + 1;
288+
} else {
289+
strncpy(buf, position, len);
290+
position = NULL;
291+
}
292+
/* Check if we have port range, e.g.: a-b */
293+
int a=0, b=0;
294+
a = atoi(buf);
295+
dash = strchr(buf, '-');
296+
if (dash) {
297+
b = atoi(dash+1);
298+
} else {
299+
b = a;
300+
}
301+
if (a > b) {
302+
fprintf(stderr, "Bad port spec %d-%d, first port must be less than last\n", a, b);
303+
exit(1);
304+
}
305+
if (a <= 0 || a > MAX_HUB_PORTS || b <= 0 || b > MAX_HUB_PORTS) {
306+
fprintf(stderr, "Bad port spec %d-%d, port numbers must be from 1 to %d\n", a, b, MAX_HUB_PORTS);
307+
exit(1);
308+
}
309+
for (i=a; i<=b; i++) {
310+
ports |= (1 << (i-1));
311+
}
312+
}
313+
return ports;
314+
}
315+
269316

270317
/*
271318
* get USB hub properties.
@@ -694,16 +741,7 @@ int main(int argc, char *argv[])
694741
break;
695742
}
696743
if (strlen(optarg)) {
697-
/* parse port list */
698-
opt_ports = 0;
699-
size_t i;
700-
for (i=0; i<strlen(optarg); i++) {
701-
if (!isdigit(optarg[i]) || optarg[i] == '0') {
702-
printf("%s must be list of ports 1 to %d\n", optarg, MAX_HUB_PORTS);
703-
}
704-
int d = optarg[i]-'1';
705-
opt_ports |= (1 << d);
706-
}
744+
opt_ports = ports2bitmap(optarg);
707745
}
708746
break;
709747
case 'a':

0 commit comments

Comments
 (0)