Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ boot.img.
== Device configuration
The list of attached devices is read from $HOME/.cdba and is YAML formatted.

== Custom reset sequence

For devices where power-control is nontrivial, a workaround is to use the soft-reset
feature built into the board, this usually involves pressing some button combination.
A custom reset sequence can be specified with the "reset_sequence" YAML key.

=== Example
devices:
- board: db2k
Expand All @@ -54,3 +60,11 @@ devices:
fastboot: 91671140
fastboot_set_active: true
fastboot_key_timeout: 2

- board: sdm845-enchilada
qcomlt_debug_board: /dev/serial/by-id/usb-postmarketOS_Test_Device_E6604430430-if00
console: /dev/serial/by-id/usb-postmarketOS_Test_Device_E6604430430-if02
name: "OnePlus 6"
fastboot: 5725c671
# Press power; sleep 10.5 seconds; press vol+; sleep 1 second; release power
reset_sequence: "B;10500;R;0;b;0;"
6 changes: 6 additions & 0 deletions cdba-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ static void fastboot_opened(struct fastboot *fb, void *data)

warnx("fastboot connection opened");

device_fastboot_open(data);

msg = alloca(sizeof(*msg) + 1);
msg->type = MSG_FASTBOOT_PRESENT;
msg->len = 1;
Expand Down Expand Up @@ -415,6 +417,10 @@ int main(int argc, char **argv)

done:

close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);

if (selected_device)
device_close(selected_device);

Expand Down
72 changes: 68 additions & 4 deletions device.c
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ struct device *device_open(const char *board,
if (device->usb_always_on)
device_usb(device, true);

device->fastboot = fastboot_open(device->serial, fastboot_ops, NULL);
device->fastboot = fastboot_open(device->serial, fastboot_ops, device);

return device;
}
Expand Down Expand Up @@ -141,6 +141,8 @@ static void device_tick(void *data)
{
struct device *device = data;

fprintf(stderr, "rst %d\n", device->state);

switch (device->state) {
case DEVICE_STATE_START:
/* Make sure power key is not engaged */
Expand Down Expand Up @@ -192,13 +194,34 @@ static void device_tick(void *data)
}
}

static void device_tick_custom(void *data)
{
struct device *device = data;
int step = device->state++;

// fprintf(stderr, "rst %d: %8s %d %d\n", step,
// device->reset_sequence[step].key ? "power" : "fastboot",
// device->reset_sequence[step].asserted,
// device->reset_sequence[step].sleep_ms);

device_key(device, device->reset_sequence[step].key, device->reset_sequence[step].asserted);
if (device->state < device->reset_sequence_count)
watch_timer_add(device->reset_sequence[step].sleep_ms, device_tick_custom, device);
else
device->state = DEVICE_STATE_RUNNING;
}

static int device_power_on(struct device *device)
{
if (!device || !device->power)
if (!device || !device->power || device->in_fastboot)
return 0;

device->state = DEVICE_STATE_START;
device_tick(device);
if (device->custom_reset_sequence) {
device_key(device, DEVICE_KEY_FASTBOOT, false);
device_tick_custom(device);
} else
device_tick(device);

return 0;
}
Expand All @@ -208,6 +231,8 @@ static int device_power_off(struct device *device)
if (!device || !device->power)
return 0;

device->in_fastboot = false;

device->power(device, false);

return 0;
Expand Down Expand Up @@ -243,19 +268,39 @@ int device_write(struct device *device, const void *buf, size_t len)
return device->write(device, buf, len);
}

void device_fastboot_open(struct device *device)
{
/*
* udev might trigger preemptively or if we're already in fastboot
* in that case just ignore
*/
if (!device)
return;

device->in_fastboot = true;
// fprintf(stderr, "fastboot opened: %s\n", device->serial);

/* Release fastboot key if being held */
if (device->release_key_on_fastboot_detect)
device_key(device, DEVICE_KEY_FASTBOOT, false);
}

void device_fastboot_boot(struct device *device)
{
device->in_fastboot = false;
fastboot_boot(device->fastboot);
}

void device_fastboot_flash_reboot(struct device *device)
{
device->in_fastboot = false;
fastboot_flash(device->fastboot, "boot");
fastboot_reboot(device->fastboot);
}

void device_boot(struct device *device, const void *data, size_t len)
{
device->in_fastboot = false;
warnx("booting the board...");
if (device->set_active)
fastboot_set_active(device->fastboot, "a");
Expand Down Expand Up @@ -319,7 +364,26 @@ void device_close(struct device *dev)
{
if (!dev->usb_always_on)
device_usb(dev, false);
device_power(dev, false);

/* Can't use the watch timer because the loop isn't running */
if (dev->custom_reset_sequence && dev->power_off_to_fastboot) {
/* Fork and return parent to prevent the cdba client from
* blocking
*/
if (fork()) {
return;
}

for (int i = 0; i < dev->reset_sequence_count; i++) {
device_key(dev, dev->reset_sequence[i].key, dev->reset_sequence[i].asserted);
usleep(dev->reset_sequence[i].sleep_ms * 1000);
}
/* Release all the keys */
usleep(1500 * 1000);
device_key(dev, DEVICE_KEY_FASTBOOT, false);
} else {
device_power(dev, false);
}

if (dev->close)
dev->close(dev);
Expand Down
23 changes: 18 additions & 5 deletions device.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ struct cdb_assist;
struct fastboot;
struct fastboot_ops;

enum device_key {
DEVICE_KEY_FASTBOOT,
DEVICE_KEY_POWER,
};

#define MAX_RESET_SEQUENCE 6

struct device {
char *board;
char *control_dev;
Expand All @@ -18,10 +25,19 @@ struct device {
unsigned voltage;
bool tickle_mmc;
bool usb_always_on;
bool release_key_on_fastboot_detect;
bool power_off_to_fastboot;
struct fastboot *fastboot;
unsigned int fastboot_key_timeout;
int state;
bool has_power_key;
bool custom_reset_sequence;
int reset_sequence_count;
struct {
enum device_key key;
bool asserted;
unsigned short sleep_ms;
} reset_sequence[MAX_RESET_SEQUENCE];

void (*boot)(struct device *);

Expand All @@ -36,6 +52,7 @@ struct device {

void (*send_break)(struct device *dev);
bool set_active;
bool in_fastboot;

void *cdb;

Expand All @@ -57,15 +74,11 @@ int device_write(struct device *device, const void *buf, size_t len);

void device_boot(struct device *device, const void *data, size_t len);

void device_fastboot_open(struct device *device);
void device_fastboot_boot(struct device *device);
void device_fastboot_flash_reboot(struct device *device);
void device_send_break(struct device *device);
void device_list_devices(void);
void device_info(const void *data, size_t dlen);

enum {
DEVICE_KEY_FASTBOOT,
DEVICE_KEY_POWER,
};

#endif
60 changes: 60 additions & 0 deletions device_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,60 @@ static bool expect(struct device_parser *dp, int type, char *scalar)
exit(1);
}

static void parse_reset_sequence(struct device *dev, char *seq)
{
char *p, *pp = seq;
int i = 0;

dev->custom_reset_sequence = true;

/* Parse a sequence of "<btn>;time_ms" pairs */
while(i < MAX_RESET_SEQUENCE) {
p = strstr(pp, ";");
if (!p)
break;
*p = '\0';

switch (*pp) {
case 'B':
dev->reset_sequence[i].asserted = true;
__attribute__ ((fallthrough));
case 'b':
dev->reset_sequence[i].key = DEVICE_KEY_POWER;
break;
case 'R':
dev->reset_sequence[i].asserted = true;
__attribute__ ((fallthrough));
case 'r':
dev->reset_sequence[i].key = DEVICE_KEY_FASTBOOT;
break;
default:
dev->reset_sequence[i].sleep_ms = strtol(pp, &p, 10);
if (*p == *pp) {
fprintf(stderr, "device parser: invalid reset sequence: '%s'\n", seq);
exit(1);
}
i++;
}

pp += strlen(pp) + 1;
}

if (i == MAX_RESET_SEQUENCE) {
fprintf(stderr, "device parser: too many reset sequence steps\n");
exit(1);
}

dev->reset_sequence_count = i;

// for(i = 0; i < dev->reset_sequence_count; i++) {
// fprintf(stderr, "rst %d: %8s %d %d\n", i,
// dev->reset_sequence[i].key ? "power" : "fastboot",
// dev->reset_sequence[i].asserted,
// dev->reset_sequence[i].sleep_ms);
// }
}

static void parse_board(struct device_parser *dp)
{
struct device *dev;
Expand Down Expand Up @@ -154,6 +208,12 @@ static void parse_board(struct device_parser *dp)
dev->fastboot_key_timeout = strtoul(value, NULL, 10);
} else if (!strcmp(key, "usb_always_on")) {
dev->usb_always_on = !strcmp(value, "true");
} else if (!strcmp(key, "reset_sequence")) {
parse_reset_sequence(dev, value);
} else if (!strcmp(key, "release_key_on_fastboot_detect")) {
dev->release_key_on_fastboot_detect = true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Main question: shouldn't this be a default behaviour? IOW, is there a reason to hold fastboot key longer than necessary?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so no, currently it just holds the fastboot key for 1 second which is enough for dev boards but on some production devices they haven't actually reached the fastboot detection point yet.

I'll make it the default.

} else if (!strcmp(key, "power_off_to_fastboot")) {
dev->power_off_to_fastboot = true;
} else {
fprintf(stderr, "device parser: unknown key \"%s\"\n", key);
exit(1);
Expand Down
2 changes: 1 addition & 1 deletion qcomlt_dbg.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ void qcomlt_dbg_key(struct device *dev, int key, bool asserted)
{
struct qcomlt_dbg *dbg = dev->cdb;

// fprintf(stderr, "qcomlt_dbg_key(%d, %d)\n", key, asserted);
fprintf(stderr, "qcomlt_dbg_key(%d, %d)\n", key, asserted);

switch (key) {
case DEVICE_KEY_FASTBOOT:
Expand Down