forked from linux-msm/cdba
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
bad: Add initial cdba backend implementation
Signed-off-by: Bjorn Andersson <[email protected]>
- Loading branch information
Showing
12 changed files
with
1,699 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
CDBA := bad | ||
|
||
.PHONY: all | ||
|
||
all: $(CDBA) | ||
|
||
CFLAGS := -Wall -g -O2 | ||
LDFLAGS := -ludev | ||
|
||
CDBA_SRCS := bad.c cdb_assist.c circ_buf.c device.c fastboot.c | ||
CDBA_OBJS := $(CDBA_SRCS:.c=.o) | ||
|
||
$(CDBA): $(CDBA_OBJS) | ||
$(CC) $(LDFLAGS) -o $@ $^ | ||
|
||
clean: | ||
rm -f $(CDBA_OBJS) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,231 @@ | ||
#include <alloca.h> | ||
#include <err.h> | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <stdint.h> | ||
#include <stdio.h> | ||
#include <string.h> | ||
#include <unistd.h> | ||
|
||
#include "bad.h" | ||
#include "circ_buf.h" | ||
#include "device.h" | ||
#include "fastboot.h" | ||
#include "list.h" | ||
|
||
struct device *selected_device; | ||
|
||
static void fastboot_opened(struct fastboot *fb, void *data) | ||
{ | ||
const uint8_t one = 1; | ||
struct msg *msg; | ||
|
||
msg = alloca(sizeof(*msg) + 1); | ||
msg->type = MSG_FASTBOOT_PRESENT; | ||
msg->len = 1; | ||
memcpy(msg->data, &one, 1); | ||
|
||
write(STDOUT_FILENO, msg, sizeof(*msg) + 1); | ||
} | ||
|
||
static void fastboot_info(struct fastboot *fb, const void *buf, size_t len) | ||
{ | ||
fprintf(stderr, "%s\n", (char *)buf); | ||
} | ||
|
||
static void fastboot_disconnect(void *data) | ||
{ | ||
const uint8_t zero = 0; | ||
struct msg *msg; | ||
|
||
msg = alloca(sizeof(*msg) + 1); | ||
msg->type = MSG_FASTBOOT_PRESENT; | ||
msg->len = 1; | ||
memcpy(msg->data, &zero, 1); | ||
|
||
write(STDOUT_FILENO, msg, sizeof(*msg) + 1); | ||
} | ||
|
||
static struct fastboot_ops fastboot_ops = { | ||
.opened = fastboot_opened, | ||
.disconnect = fastboot_disconnect, | ||
.info = fastboot_info, | ||
}; | ||
|
||
static void msg_select_board(const void *param) | ||
{ | ||
struct msg reply = { MSG_SELECT_BOARD, 0 }; | ||
|
||
selected_device = device_open(param, &fastboot_ops); | ||
if (!selected_device) | ||
fprintf(stderr, "failed to open %s\n", (const char *)param); | ||
|
||
write(STDOUT_FILENO, &reply, sizeof(reply)); | ||
} | ||
|
||
static void *fastboot_payload; | ||
static size_t fastboot_size; | ||
|
||
static void msg_fastboot_download(const void *data, size_t len) | ||
{ | ||
struct msg reply = { MSG_FASTBOOT_DOWNLOAD, }; | ||
size_t new_size = fastboot_size + len; | ||
void *newp; | ||
|
||
newp = realloc(fastboot_payload, new_size); | ||
if (!newp) | ||
err(1, "failed too expant fastboot scratch area"); | ||
|
||
memcpy(newp + fastboot_size, data, len); | ||
|
||
fastboot_payload = newp; | ||
fastboot_size = new_size; | ||
|
||
if (!len) { | ||
device_boot(selected_device, fastboot_payload, fastboot_size); | ||
|
||
write(STDOUT_FILENO, &reply, sizeof(reply)); | ||
free(fastboot_payload); | ||
fastboot_payload = NULL; | ||
fastboot_size = 0; | ||
} | ||
} | ||
|
||
static int handle_stdin(int fd, void *buf) | ||
{ | ||
static struct circ_buf recv_buf = { 0 }; | ||
struct msg *msg; | ||
struct msg hdr; | ||
size_t n; | ||
int ret; | ||
|
||
ret = circ_fill(STDIN_FILENO, &recv_buf); | ||
if (ret < 0 && errno != EAGAIN) { | ||
fprintf(stderr, "read %d\n", ret); | ||
return -1; | ||
} | ||
|
||
for (;;) { | ||
n = circ_peak(&recv_buf, &hdr, sizeof(hdr)); | ||
if (n != sizeof(hdr)) | ||
return 0; | ||
|
||
if (CIRC_AVAIL(&recv_buf) < sizeof(*msg) + hdr.len) | ||
return 0; | ||
|
||
msg = malloc(sizeof(*msg) + hdr.len); | ||
circ_read(&recv_buf, msg, sizeof(*msg) + hdr.len); | ||
|
||
switch (msg->type) { | ||
case MSG_CONSOLE: | ||
device_write(selected_device, msg->data, msg->len); | ||
break; | ||
case MSG_FASTBOOT_PRESENT: | ||
break; | ||
case MSG_SELECT_BOARD: | ||
msg_select_board(msg->data); | ||
break; | ||
case MSG_HARDRESET: | ||
// fprintf(stderr, "hard reset\n"); | ||
break; | ||
case MSG_POWER_ON: | ||
device_power_on(selected_device); | ||
break; | ||
case MSG_POWER_OFF: | ||
device_power_off(selected_device); | ||
break; | ||
case MSG_FASTBOOT_DOWNLOAD: | ||
msg_fastboot_download(msg->data, msg->len); | ||
break; | ||
case MSG_FASTBOOT_BOOT: | ||
// fprintf(stderr, "fastboot boot\n"); | ||
break; | ||
case MSG_STATUS_UPDATE: | ||
device_print_status(selected_device); | ||
break; | ||
case MSG_VBUS_ON: | ||
device_vbus(selected_device, true); | ||
break; | ||
case MSG_VBUS_OFF: | ||
device_vbus(selected_device, false); | ||
break; | ||
default: | ||
fprintf(stderr, "unk %d len %d\n", msg->type, msg->len); | ||
exit(1); | ||
} | ||
|
||
free(msg); | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
struct watch { | ||
struct list_head node; | ||
|
||
int fd; | ||
int (*cb)(int, void*); | ||
void *data; | ||
}; | ||
|
||
static struct list_head read_watches = LIST_INIT(read_watches); | ||
|
||
void watch_add_readfd(int fd, int (*cb)(int, void*), void *data) | ||
{ | ||
struct watch *w; | ||
|
||
w = calloc(1, sizeof(*w)); | ||
w->fd = fd; | ||
w->cb = cb; | ||
w->data = data; | ||
|
||
list_add(&read_watches, &w->node); | ||
} | ||
|
||
int main(int argc, char **argv) | ||
{ | ||
struct watch *w; | ||
fd_set rfds; | ||
int flags; | ||
int nfds; | ||
int ret; | ||
|
||
watch_add_readfd(STDIN_FILENO, handle_stdin, NULL); | ||
|
||
flags = fcntl(STDIN_FILENO, F_GETFL, 0); | ||
fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); | ||
|
||
for (;;) { | ||
nfds = 0; | ||
|
||
list_for_each_entry(w, &read_watches, node) { | ||
nfds = MAX(nfds, w->fd); | ||
FD_SET(w->fd, &rfds); | ||
} | ||
|
||
if (!FD_ISSET(STDIN_FILENO, &rfds)) { | ||
fprintf(stderr, "rfds is trash!\n"); | ||
goto done; | ||
} | ||
|
||
ret = select(nfds + 1, &rfds, NULL, NULL, NULL); | ||
if (ret < 0) | ||
continue; | ||
|
||
list_for_each_entry(w, &read_watches, node) { | ||
if (FD_ISSET(w->fd, &rfds)) { | ||
ret = w->cb(w->fd, w->data); | ||
if (ret < 0) { | ||
fprintf(stderr, "cb returned %d\n", ret); | ||
goto done; | ||
} | ||
} | ||
} | ||
} | ||
|
||
done: | ||
|
||
device_power_off(selected_device); | ||
|
||
return 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
#ifndef __BAD_H__ | ||
#define __BAD_H__ | ||
|
||
#include <stdbool.h> | ||
#include <stdint.h> | ||
|
||
#define __packed __attribute__((packed)) | ||
|
||
#define MIN(x, y) ((x) < (y) ? (x) : (y)) | ||
#define MAX(x, y) ((x) > (y) ? (x) : (y)) | ||
|
||
struct msg { | ||
uint8_t type; | ||
uint16_t len; | ||
uint8_t data[]; | ||
} __packed; | ||
|
||
enum { | ||
MSG_SELECT_BOARD = 1, | ||
MSG_CONSOLE, | ||
MSG_HARDRESET, | ||
MSG_POWER_ON, | ||
MSG_POWER_OFF, | ||
MSG_FASTBOOT_PRESENT, | ||
MSG_FASTBOOT_DOWNLOAD, | ||
MSG_FASTBOOT_BOOT, | ||
MSG_STATUS_UPDATE, | ||
MSG_VBUS_ON, | ||
MSG_VBUS_OFF, | ||
MSG_FASTBOOT_REBOOT, | ||
}; | ||
|
||
void watch_add_readfd(int fd, int (*cb)(int, void*), void *data); | ||
int watch_add_quit(int (*cb)(int, void*), void *data); | ||
int watch_add_timer(void (*cb)(void*), void *data, unsigned interval, bool repeat); | ||
void watch_quit(void); | ||
int watch_run(void); | ||
|
||
#endif |
Oops, something went wrong.