Skip to content

Commit e0d1c34

Browse files
committed
Improve support for Raspberry Pi 4B and 5:
* Detect if we are running on Raspberry 4B or 5 * Add RPi 4B and 5 conditionals for RPi hacks * Relax some conditions which may vary depending on RPi hardware and/or OS (in particular Ubuntu hub numbering differs from Raspbian). * For RPi5, changed README to suggest using busses 2 and 4 instead of 1 and 3. This makes the same recipe work on both Raspbian and Ubuntu. This fixes mvp#587.
1 parent 153c5da commit e0d1c34

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,8 @@ to make power switching work on RPi 4B.
422422
##### Raspberry Pi 5
423423

424424
Raspberry Pi 5 has two USB2 ports and two USB3 ports (total 4).
425-
These ports are connected to 4 distinct USB hubs `1`,`2`,`3`,`4` in really weird configuration.
425+
These ports are connected to 4 distinct USB hubs `1`,`2`,`3`,`4` in really weird configuration
426+
(but depending on OS and HW revision hubs of interest can be `2`,`3`,`4`,`5`).
426427
If USB3 device is connected to blue socket, it will be detected on USB3 hub `2` or `4`.
427428
If USB2 device is connected to any socket or USB3 device connected to black socket,
428429
it will be detected on USB2 hub `1` or `3`.
@@ -436,15 +437,15 @@ despite belonging to 4 different logical USB hubs.
436437
To turn off VBUS power it has to be disabled across all onboard hubs and ports with:
437438

438439
```
439-
uhubctl -l 1 -a 0
440-
uhubctl -l 3 -a 0
440+
uhubctl -l 2 -a 0
441+
uhubctl -l 4 -a 0
441442
```
442443

443444
To turn it back on:
444445

445446
```
446-
uhubctl -l 1 -a 1
447-
uhubctl -l 3 -a 1
447+
uhubctl -l 2 -a 1
448+
uhubctl -l 4 -a 1
448449
```
449450

450451
Note that VBUS power goes down only if all ports are off -

uhubctl.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,9 @@ static int opt_nodesc = 0; /* skip querying device description */
227227
static int opt_nosysfs = 0; /* don't use the Linux sysfs port disable interface, even if available */
228228
#endif
229229

230+
/* For Raspberry Pi detection and workarounds: */
231+
static int is_rpi_4b = 0;
232+
static int is_rpi_5 = 0;
230233

231234
static const char short_options[] =
232235
"l:L:n:a:p:d:r:w:s:hvefRN"
@@ -361,6 +364,46 @@ static int ports2bitmap(char* const portlist)
361364
return ports;
362365
}
363366

367+
/*
368+
* Get model of the computer we are currently running on.
369+
* On success return 0 and fill model string (null terminated).
370+
* If model is not known or error occurred returns -1.
371+
*
372+
* Currently this can only return successfully on Linux,
373+
* but in the future we may need it on other operating systems too.
374+
*/
375+
376+
static int get_computer_model(char *model, int len)
377+
{
378+
int fd = open("/sys/firmware/devicetree/base/model", O_RDONLY);
379+
if (fd < 0) {
380+
return fd;
381+
}
382+
int bytes_read = read(fd, model, len-1);
383+
close(fd);
384+
if (bytes_read < 0) {
385+
return -1;
386+
}
387+
model[bytes_read] = 0;
388+
return 0;
389+
}
390+
391+
/*
392+
* Check if we are running on given computer model using substring match.
393+
* Returns 1 if yes and 0 otherwise.
394+
*/
395+
396+
static int check_computer_model(char *target)
397+
{
398+
char model[256] = "";
399+
if (get_computer_model(model, sizeof(model)) == 0) {
400+
if (strstr(model, target) != NULL) {
401+
return 1;
402+
}
403+
}
404+
return 0;
405+
}
406+
364407

365408
/*
366409
* Compatibility wrapper around libusb_get_port_numbers()
@@ -466,7 +509,8 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
466509
libusb_free_bos_descriptor(bos);
467510

468511
/* Raspberry Pi 4B hack for USB3 root hub: */
469-
if (strlen(info->container_id)==0 &&
512+
if (is_rpi_4b &&
513+
strlen(info->container_id)==0 &&
470514
strcasecmp(info->vendor, "1d6b:0003")==0 &&
471515
info->pn_len==0 &&
472516
info->nports==4 &&
@@ -483,32 +527,28 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
483527
lpsm = HUB_CHAR_INDV_PORT_LPSM;
484528
}
485529
/* Raspberry Pi 4B reports inconsistent descriptors, override: */
486-
if (lpsm == HUB_CHAR_COMMON_LPSM && strcasecmp(info->vendor, "2109:3431")==0) {
530+
if (is_rpi_4b && lpsm == HUB_CHAR_COMMON_LPSM && strcasecmp(info->vendor, "2109:3431")==0) {
487531
lpsm = HUB_CHAR_INDV_PORT_LPSM;
488532
}
489533
info->lpsm = lpsm;
490534

491535
/* Raspberry Pi 5 hack */
492-
493-
/* TODO: make this hack more reliable by querying Raspberry Pi model */
494-
495-
if (strlen(info->container_id)==0 &&
536+
if (is_rpi_5 &&
537+
strlen(info->container_id)==0 &&
496538
info->lpsm==HUB_CHAR_INDV_PORT_LPSM &&
497539
info->pn_len==0)
498540
{
499541
/* USB2 */
500542
if (strcasecmp(info->vendor, "1d6b:0002")==0 &&
501543
info->nports==2 &&
502-
!info->super_speed &&
503-
(info->bus==1 || info->bus==3))
544+
!info->super_speed)
504545
{
505546
strcpy(info->container_id, "Raspberry Pi 5 Fake Container Id");
506547
}
507548
/* USB3 */
508549
if (strcasecmp(info->vendor, "1d6b:0003")==0 &&
509550
info->nports==1 &&
510-
info->super_speed &&
511-
(info->bus==2 || info->bus==4))
551+
info->super_speed)
512552
{
513553
strcpy(info->container_id, "Raspberry Pi 5 Fake Container Id");
514554
}
@@ -1004,7 +1044,7 @@ static int usb_find_hubs(void)
10041044
}
10051045

10061046
/* Raspberry Pi 4B hack (USB2 hub is one level deeper than USB3): */
1007-
if (l1 + s1 == l2 + s2 && l1 >= s2 && memcmp(p1 + s2, p2 + s1, l1 - s2)==0) {
1047+
if (is_rpi_4b && l1 + s1 == l2 + s2 && l1 >= s2 && memcmp(p1 + s2, p2 + s1, l1 - s2)==0) {
10081048
if (best_score < 3) {
10091049
best_score = 3;
10101050
best_match = j;
@@ -1180,6 +1220,9 @@ int main(int argc, char *argv[])
11801220
goto cleanup;
11811221
}
11821222

1223+
is_rpi_4b = check_computer_model("Raspberry Pi 4 Model B");
1224+
is_rpi_5 = check_computer_model("Raspberry Pi 5");
1225+
11831226
rc = usb_find_hubs();
11841227
if (rc <= 0) {
11851228
fprintf(stderr,

0 commit comments

Comments
 (0)