diff options
author | Dongwoo Lee <dwoo08.lee@samsung.com> | 2017-09-26 10:50:41 +0900 |
---|---|---|
committer | Seung-Woo Kim <sw0312.kim@samsung.com> | 2018-05-31 15:35:48 +0900 |
commit | c34bb09c195829235f6921812b4d85c30cc44f2b (patch) | |
tree | 93f364791187eec32af0665f913da4fe2297efb3 /libthor | |
parent | 644503bbf4cd6d429b84955feb06fb1aebc7396f (diff) | |
download | lthor-c34bb09c195829235f6921812b4d85c30cc44f2b.tar.gz lthor-c34bb09c195829235f6921812b4d85c30cc44f2b.tar.bz2 lthor-c34bb09c195829235f6921812b4d85c30cc44f2b.zip |
Re-structure lthor to extend its transfer methods
Currently, thor has very specific code structure for considering only
usb transfer, thus it is too hard to add other transfer methods. This
patch makes lthor to be extendable by just implementing few operations:
open, close, send, recv, and send_data.
Change-Id: If455a9d7a5c7fd86cf6e8808f29c643456e80166
Signed-off-by: Dongwoo Lee <dwoo08.lee@samsung.com>
Signed-off-by: Seung-Woo Kim <sw0312.kim@samsung.com>
Diffstat (limited to 'libthor')
-rw-r--r-- | libthor/thor.c | 465 | ||||
-rw-r--r-- | libthor/thor.h | 21 | ||||
-rw-r--r-- | libthor/thor_acm.c | 21 | ||||
-rw-r--r-- | libthor/thor_internal.h | 125 | ||||
-rw-r--r-- | libthor/thor_transport.c | 95 | ||||
-rw-r--r-- | libthor/thor_transport.h | 48 | ||||
-rw-r--r-- | libthor/thor_usb.c | 696 |
7 files changed, 835 insertions, 636 deletions
diff --git a/libthor/thor.c b/libthor/thor.c index 6dc37e4..37c4b24 100644 --- a/libthor/thor.c +++ b/libthor/thor.c @@ -14,69 +14,58 @@ * limitations under the License. */ +#include <assert.h> #include <errno.h> #include <stdlib.h> #include <string.h> #include "thor.h" #include "thor_internal.h" +#include "thor_transport.h" -int thor_init() +thor_device_handle *thor_init(enum thor_transport_type type) { - return libusb_init(NULL); -} + thor_device_handle *th; + int ret; -void thor_cleanup() -{ - libusb_exit(NULL); -} + th = calloc(1, sizeof(*th)); + if (!th) + return NULL; -int thor_check_proto(struct thor_device_id *dev_id) -{ - struct thor_device_handle *th; - int ret; + th->type = type; - ret = thor_open(dev_id, 0, &th); - if (!ret) - thor_close(th); + ret = t_thor_init(th); + if (ret < 0) { + free(th); + th = NULL; + } - return ret; + return th; } -static struct thor_device_id * thor_choose_id( - struct thor_device_id *user_dev_id) +void thor_cleanup(thor_device_handle *th) { - static struct thor_device_id default_id = { - .busid = NULL, - .vid = 0x04e8, - .pid = 0x685d, - .serial = NULL, - }; - - if (user_dev_id->busid == NULL - && user_dev_id->vid < 0 - && user_dev_id->pid < 0 - && user_dev_id->serial == NULL) - user_dev_id = &default_id; - - return user_dev_id; + if (!th) + return; + t_thor_cleanup(th); + free(th); } -static int t_thor_do_handshake(struct thor_device_handle *th) +static int thor_do_handshake(thor_device_handle *th) { char challenge[] = "THOR"; char response[] = "ROHT"; char buffer[sizeof(response)]; int ret; - ret = t_usb_send(th, (unsigned char *)challenge, sizeof(challenge) - 1, - DEFAULT_TIMEOUT); + ret = t_thor_send(th, (unsigned char *)challenge, sizeof(challenge) - 1, + DEFAULT_TIMEOUT); if (ret < 0) return ret; - ret = t_usb_recv(th, (unsigned char *)buffer, sizeof(buffer) - 1, - DEFAULT_TIMEOUT); + ret = t_thor_recv(th, (unsigned char *)buffer, sizeof(buffer) - 1, + DEFAULT_TIMEOUT); if (ret < 0) return ret; @@ -88,49 +77,77 @@ static int t_thor_do_handshake(struct thor_device_handle *th) return 0; } -int thor_open(struct thor_device_id *user_dev_id, int wait, - thor_device_handle **handle) +int thor_open(thor_device_handle *th, struct thor_device_id *dev_id, int wait) { - struct thor_device_id *dev_id = thor_choose_id(user_dev_id); - struct thor_device_handle *th; - int found, ret; + int ret; - th = calloc(sizeof(*th), 1); if (!th) - return -ENOMEM; + return -ENOENT; - found = t_usb_find_device(dev_id, wait, th); - if (found <= 0) { - ret = -ENODEV; - goto close_dev; - } - - ret = t_acm_prepare_device(th); + ret = t_thor_open(th, dev_id, wait); if (ret) - goto close_dev; + return ret; - ret = t_thor_do_handshake(th); + ret = thor_do_handshake(th); if (ret) { - ret = -EINVAL; - goto close_dev; + thor_close(th); + return ret; } - *handle = th; return 0; -close_dev: - thor_close(th); - return ret; } void thor_close(thor_device_handle *th) { - t_usb_close_device(th); - free(th); + if (!th) + return; + + t_thor_close(th); } -static int t_thor_exec_cmd_full(thor_device_handle *th, request_type req_id, - int req_sub_id, int *idata, int icnt, - char **sdata, int scnt, struct res_pkt *res) +static int thor_send_req(thor_device_handle *th, request_type req_id, + int req_sub_id, int *idata, int icnt, + char **sdata, int scnt) +{ + struct rqt_pkt req; + int i; + int ret; + + assert(icnt <= ARRAY_SIZE(req.int_data)); + assert(icnt >= 0); + assert(scnt <= ARRAY_SIZE(req.str_data)); + assert(scnt >= 0); + + memset(&req, 0, sizeof(req)); + + req.id = req_id; + req.sub_id = req_sub_id; + + if (idata) { + for (i = 0; i < icnt; i++) + req.int_data[i] = idata[i]; + } + + if (sdata) { + for (i = 0; i < scnt; i++) + strncpy(req.str_data[i], sdata[i], 32); + } + + ret = t_thor_send(th, (unsigned char *)&req, RQT_PKT_SIZE, + DEFAULT_TIMEOUT); + + return ret; +} + +static inline int thor_recv_req(thor_device_handle *th, struct res_pkt *resp) +{ + return t_thor_recv(th, (unsigned char *)resp, sizeof(*resp), + DEFAULT_TIMEOUT); +} + +static int thor_exec_cmd_full(thor_device_handle *th, request_type req_id, + int req_sub_id, int *idata, int icnt, + char **sdata, int scnt, struct res_pkt *res) { int ret; struct res_pkt resp; @@ -138,23 +155,23 @@ static int t_thor_exec_cmd_full(thor_device_handle *th, request_type req_id, if (!res) res = &resp; - ret = t_usb_send_req(th, req_id, req_sub_id, idata, icnt, - sdata, scnt); + ret = thor_send_req(th, req_id, req_sub_id, idata, icnt, + sdata, scnt); if (ret < 0) return ret; - ret = t_usb_recv_req(th, res); + ret = thor_recv_req(th, res); if (ret < 0) return ret; return res->ack; } -static int t_thor_exec_cmd(thor_device_handle *th, request_type req_id, - int req_sub_id, int *idata, int icnt) +static inline int thor_exec_cmd(thor_device_handle *th, request_type req_id, + int req_sub_id, int *idata, int icnt) { - return t_thor_exec_cmd_full(th, req_id, req_sub_id, idata, icnt, - NULL, 0, NULL); + return thor_exec_cmd_full(th, req_id, req_sub_id, idata, icnt, + NULL, 0, NULL); } int thor_get_proto_ver(thor_device_handle *th) @@ -162,8 +179,11 @@ int thor_get_proto_ver(thor_device_handle *th) int ret; struct res_pkt resp; - ret = t_thor_exec_cmd_full(th, RQT_INFO, RQT_INFO_VER_PROTOCOL, - NULL, 0, NULL, 0, &resp); + if (!th) + return -ENOENT; + + ret = thor_exec_cmd_full(th, RQT_INFO, RQT_INFO_VER_PROTOCOL, + NULL, 0, NULL, 0, &resp); if (!ret) ret = (resp.int_data[0] << 8) | resp.int_data[1]; @@ -178,8 +198,8 @@ int thor_start_session(thor_device_handle *th, off_t total) int_data[0] = (uint32_t)(total & 0xffffffff); int_data[1] = (uint32_t)((total >> 32) & 0xffffffff); - ret = t_thor_exec_cmd(th, RQT_DL, RQT_DL_INIT, int_data, - ARRAY_SIZE(int_data)); + ret = thor_exec_cmd(th, RQT_DL, RQT_DL_INIT, int_data, + ARRAY_SIZE(int_data)); return ret; } @@ -188,273 +208,10 @@ int thor_end_session(thor_device_handle *th) { int ret; - ret = t_thor_exec_cmd(th, RQT_DL, RQT_DL_EXIT, NULL, 0); - - return ret; -} - -static int t_thor_submit_chunk(struct t_thor_data_chunk *chunk) -{ - int ret; - - chunk->data_finished = chunk->resp_finished = 0; - - ret = t_usb_submit_transfer(&chunk->data_transfer); - if (ret) - goto out; - - memset(&chunk->resp, 0, DATA_RES_PKT_SIZE); - ret = t_usb_submit_transfer(&chunk->resp_transfer); - if (ret) - goto cancel_data_transfer; - - return 0; -cancel_data_transfer: - t_usb_cancel_transfer(&chunk->data_transfer); -out: - return ret; -} - -static int t_thor_prep_next_chunk(struct t_thor_data_chunk *chunk, - struct t_thor_data_transfer *transfer_data) -{ - off_t to_read; - int ret; - - to_read = transfer_data->data_left - transfer_data->data_in_progress; - if (to_read <= 0) { - printf("to big data in progress\n"); - fflush(stdout); - return -EINVAL; - } - - chunk->useful_size = to_read > chunk->trans_unit_size ? - chunk->trans_unit_size : to_read; - - ret = transfer_data->data->get_block(transfer_data->data, - chunk->buf, chunk->useful_size); - if (ret < 0 || ret != chunk->useful_size) - return ret; - - memset(chunk->buf + chunk->useful_size, 0, - chunk->trans_unit_size - chunk->useful_size); - chunk->chunk_number = transfer_data->chunk_number++; - - ret = t_thor_submit_chunk(chunk); - if (!ret) - transfer_data->data_in_progress += chunk->useful_size; - - return ret; -} - -static void check_next_chunk(struct t_thor_data_chunk *chunk, - struct t_thor_data_transfer *transfer_data) -{ - /* If there is some more data to be queued */ - if (transfer_data->data_left - transfer_data->data_in_progress) { - int ret; - - ret = t_thor_prep_next_chunk(chunk, transfer_data); - if (ret) { - transfer_data->ret = ret; - transfer_data->completed = 1; - } - } else { - /* Last one turns the light off */ - if (transfer_data->data_in_progress == 0) - transfer_data->completed = 1; - } -} - -static void data_transfer_finished(struct t_usb_transfer *_data_transfer) -{ - struct t_thor_data_chunk *chunk = container_of(_data_transfer, - struct t_thor_data_chunk, - data_transfer); - struct t_thor_data_transfer *transfer_data = chunk->user_data; - - chunk->data_finished = 1; - - if (_data_transfer->cancelled || transfer_data->ret) - return; - - if (_data_transfer->ret) { - transfer_data->ret = _data_transfer->ret; - transfer_data->completed = 1; - } - - if (chunk->resp_finished) - check_next_chunk(chunk, transfer_data); -} - -static void resp_transfer_finished(struct t_usb_transfer *_resp_transfer) -{ - struct t_thor_data_chunk *chunk = container_of(_resp_transfer, - struct t_thor_data_chunk, - resp_transfer); - struct t_thor_data_transfer *transfer_data = chunk->user_data; - - chunk->resp_finished = 1; - transfer_data->data_in_progress -= chunk->useful_size; - - if (_resp_transfer->cancelled || transfer_data->ret) { - if (transfer_data->data_in_progress == 0) - transfer_data->completed = 1; - return; - } - - if (_resp_transfer->ret) { - transfer_data->ret = _resp_transfer->ret; - goto complete_all; - } - - if (chunk->resp.cnt != chunk->chunk_number) { - printf ("chunk number mismatch: %d != %d\n", - chunk->resp.cnt, chunk->chunk_number); - fflush(stdout); - transfer_data->ret = -EINVAL; - goto complete_all; - } - - transfer_data->data_sent += chunk->useful_size; - transfer_data->data_left -= chunk->useful_size; - if (transfer_data->report_progress) - transfer_data->report_progress(transfer_data->th, - transfer_data->data, - transfer_data->data_sent, - transfer_data->data_left, - chunk->chunk_number, - transfer_data->user_data); - - if (chunk->data_finished) - check_next_chunk(chunk, transfer_data); - - return; -complete_all: - transfer_data->completed = 1; - return; -} - -static int t_thor_init_chunk(struct t_thor_data_chunk *chunk, - thor_device_handle *th, - off_t trans_unit_size, - void *user_data) -{ - int ret; - - chunk->user_data = user_data; - chunk->useful_size = 0; - chunk->trans_unit_size = trans_unit_size; - - chunk->buf = malloc(trans_unit_size); - if (!chunk->buf) - return -ENOMEM; - - ret = t_usb_init_out_transfer(&chunk->data_transfer, th, chunk->buf, - trans_unit_size, data_transfer_finished, - DEFAULT_TIMEOUT); - if (ret) - goto free_buf; - - ret = t_usb_init_in_transfer(&chunk->resp_transfer, th, - (unsigned char *)&chunk->resp, - DATA_RES_PKT_SIZE, - resp_transfer_finished, - 2*DEFAULT_TIMEOUT); - if (ret) - goto cleanup_data_transfer; - - return 0; -cleanup_data_transfer: - t_usb_cleanup_transfer(&chunk->data_transfer); -free_buf: - free(chunk->buf); - - return ret; -} - -static void t_thor_cleanup_chunk(struct t_thor_data_chunk *chunk) -{ - t_usb_cleanup_transfer(&chunk->data_transfer); - t_usb_cleanup_transfer(&chunk->resp_transfer); - free(chunk->buf); -} - -static inline int -t_thor_handle_events(struct t_thor_data_transfer *transfer_data) -{ - return t_usb_handle_events_completed(&transfer_data->completed); -} - -static inline void t_thor_cancel_chunk(struct t_thor_data_chunk *chunk) -{ - t_usb_cancel_transfer(&chunk->data_transfer); - t_usb_cancel_transfer(&chunk->resp_transfer); -} - -static int t_thor_send_raw_data(thor_device_handle *th, - struct thor_data_src *data, - off_t trans_unit_size, - thor_progress_cb report_progress, - void *user_data) -{ - struct t_thor_data_chunk chunk[3]; - struct t_thor_data_transfer transfer_data; - int i, j; - int ret; - - for (i = 0; i < ARRAY_SIZE(chunk); ++i) { - ret = t_thor_init_chunk(chunk + i, th, trans_unit_size, - &transfer_data); - if (ret) - goto cleanup_chunks; - } - - transfer_data.data = data; - transfer_data.report_progress = report_progress; - transfer_data.user_data = user_data; - transfer_data.data_left = data->get_file_length(data); - transfer_data.data_sent = 0; - transfer_data.chunk_number = 1; - transfer_data.completed = 0; - transfer_data.data_in_progress = 0; - transfer_data.ret = 0; - - for (i = 0; - i < ARRAY_SIZE(chunk) - && (transfer_data.data_left - transfer_data.data_in_progress > 0); - ++i) { - ret = t_thor_prep_next_chunk(chunk + i, &transfer_data); - if (ret) - goto cancel_chunks; - } - - t_thor_handle_events(&transfer_data); - - if (transfer_data.data_in_progress) { - ret = transfer_data.ret; - goto cancel_chunks; - } - - for (i = 0; i < ARRAY_SIZE(chunk); ++i) - t_thor_cleanup_chunk(chunk + i); - - return transfer_data.ret; - -cancel_chunks: - for (j = 0; j < i; ++j) - t_thor_cancel_chunk(chunk + j); - if (i) { - transfer_data.completed = 0; - t_thor_handle_events(&transfer_data); - } - - i = ARRAY_SIZE(chunk); -cleanup_chunks: - for (j = 0; j < i; ++j) - t_thor_cleanup_chunk(chunk + j); + if (!th) + return -ENOENT; - return ret; + return thor_exec_cmd(th, RQT_DL, RQT_DL_EXIT, NULL, 0); } int thor_send_data(thor_device_handle *th, struct thor_data_src *data, @@ -508,20 +265,18 @@ int thor_send_data(thor_device_handle *th, struct thor_data_src *data, if (!th) continue; - ret = t_thor_exec_cmd_full(th, RQT_DL, RQT_DL_FILE_INFO, - int_data, ARRAY_SIZE(int_data), - (char **)str_data, scnt, &resp); + ret = thor_exec_cmd_full(th, RQT_DL, RQT_DL_FILE_INFO, + int_data, ARRAY_SIZE(int_data), + (char **)str_data, scnt, &resp); if (ret < 0) return ret; trans_unit_size = resp.int_data[0]; - if (th) { - ret = t_thor_exec_cmd(th, RQT_DL, RQT_DL_FILE_START, - NULL, 0); - if (ret < 0) - return ret; - } + ret = thor_exec_cmd(th, RQT_DL, RQT_DL_FILE_START, + NULL, 0); + if (ret < 0) + return ret; ret = t_thor_send_raw_data(th, data, trans_unit_size, report_progress, user_data); @@ -529,8 +284,8 @@ int thor_send_data(thor_device_handle *th, struct thor_data_src *data, return ret; if (th) { - ret = t_thor_exec_cmd(th, RQT_DL, RQT_DL_FILE_END, - NULL, 0); + ret = thor_exec_cmd(th, RQT_DL, RQT_DL_FILE_END, + NULL, 0); if (ret < 0) return ret; } @@ -541,11 +296,10 @@ int thor_send_data(thor_device_handle *th, struct thor_data_src *data, int thor_reboot(thor_device_handle *th) { - int ret; - - ret = t_thor_exec_cmd(th, RQT_CMD, RQT_CMD_REBOOT, NULL, 0); + if (!th) + return -ENOENT; - return ret; + return thor_exec_cmd(th, RQT_CMD, RQT_CMD_REBOOT, NULL, 0); } int thor_get_data_src(const char *path, enum thor_data_src_format format, @@ -572,4 +326,3 @@ void thor_release_data_src(struct thor_data_src *data) if (data->release) data->release(data); } - diff --git a/libthor/thor.h b/libthor/thor.h index c9a432d..75c918b 100644 --- a/libthor/thor.h +++ b/libthor/thor.h @@ -21,13 +21,17 @@ #include <stdio.h> #include <stddef.h> -struct thor_device_id { +struct usb_device_id { const char *busid; int vid; int pid; const char *serial; }; +struct thor_device_id { + struct usb_device_id usb_dev; +}; + struct thor_device_handle; typedef struct thor_device_handle thor_device_handle; @@ -65,18 +69,19 @@ typedef void (*thor_next_entry_cb)(thor_device_handle *th, struct thor_data_src *data, void *user_data); +enum thor_transport_type { + THOR_TRANSPORT_USB = 0, + THOR_TRANSPORT_MAX, +}; + /* Init the Thor library */ -int thor_init(); +thor_device_handle *thor_init(enum thor_transport_type type); /* Cleanup the thor library */ -void thor_cleanup(); - -/* Check if device is thor compatible */ -int thor_check_proto(struct thor_device_id *dev_id); +void thor_cleanup(thor_device_handle *th); /* Open the device and prepare it for thor communication */ -int thor_open(struct thor_device_id *dev_id, int wait, - thor_device_handle **handle); +int thor_open(thor_device_handle *th, struct thor_device_id *dev_id, int wait); /* Close the device */ void thor_close(thor_device_handle *th); diff --git a/libthor/thor_acm.c b/libthor/thor_acm.c index 69eae53..d27b890 100644 --- a/libthor/thor_acm.c +++ b/libthor/thor_acm.c @@ -46,17 +46,18 @@ struct usb_cdc_line_coding { #include <libusb-1.0/libusb.h> #include "thor_internal.h" +#include "thor_transport.h" -static int acm_set_control_line_state(struct thor_device_handle *th, int state) +static int acm_set_control_line_state(struct usb_device_handle *uh, int state) { int ret; - ret = libusb_control_transfer(th->devh, + ret = libusb_control_transfer(uh->devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, USB_CDC_REQ_SET_CONTROL_LINE_STATE, state ? 0x3 : 0, - (uint16_t)th->control_interface_id, + (uint16_t)uh->control_interface_id, NULL, 0, DEFAULT_TIMEOUT); @@ -67,7 +68,7 @@ static int acm_set_control_line_state(struct thor_device_handle *th, int state) return 0; } -static int acm_set_line_coding(struct thor_device_handle *th) +static int acm_set_line_coding(struct usb_device_handle *uh) { struct usb_cdc_line_coding default_thor_line_coding = { .dwDTERate = htole32(9600), @@ -77,12 +78,12 @@ static int acm_set_line_coding(struct thor_device_handle *th) }; int ret; - ret = libusb_control_transfer(th->devh, + ret = libusb_control_transfer(uh->devh, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, USB_CDC_REQ_SET_LINE_CODING, 0, - (uint16_t)th->control_interface_id, + (uint16_t)uh->control_interface_id, (unsigned char *)&default_thor_line_coding, sizeof(default_thor_line_coding), DEFAULT_TIMEOUT); @@ -94,19 +95,19 @@ static int acm_set_line_coding(struct thor_device_handle *th) } -int t_acm_prepare_device(struct thor_device_handle *th) +int t_acm_prepare_device(struct usb_device_handle *uh) { int ret; - ret = acm_set_control_line_state(th, 0); + ret = acm_set_control_line_state(uh, 0); if (ret < 0) return ret; - ret = acm_set_line_coding(th); + ret = acm_set_line_coding(uh); if (ret < 0) return ret; - ret = acm_set_control_line_state(th, 1); + ret = acm_set_control_line_state(uh, 1); return ret; } diff --git a/libthor/thor_internal.h b/libthor/thor_internal.h index ec3d80f..de515e3 100644 --- a/libthor/thor_internal.h +++ b/libthor/thor_internal.h @@ -34,121 +34,30 @@ #define ARRAY_SIZE(_a) (sizeof(_a)/sizeof(_a[0])) -struct thor_device_handle { - libusb_device_handle *devh; - int control_interface; - int control_interface_id; - int data_interface; - int data_interface_id; - int data_ep_in; - int data_ep_out; -}; - -struct t_usb_transfer; - -typedef void (*t_usb_transfer_cb)(struct t_usb_transfer *); - -struct t_usb_transfer { - struct libusb_transfer *ltransfer; - t_usb_transfer_cb transfer_finished; - off_t size; - int ret; - int cancelled; -}; - -struct t_thor_data_chunk { - struct t_usb_transfer data_transfer; - struct t_usb_transfer resp_transfer; - void *user_data; - off_t useful_size; - struct data_res_pkt resp; - unsigned char *buf; - off_t trans_unit_size; - int chunk_number; - int data_finished; - int resp_finished; +struct thor_transport_ops { + int (*open)(thor_device_handle *th, struct thor_device_id *dev_id, + int wait); + void (*close)(thor_device_handle *th); + int (*send)(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout); + int (*recv)(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout); + int (*send_data)(thor_device_handle *th, + struct thor_data_src *data, + off_t trans_unit_size, + thor_progress_cb report_progress, + void *user_data); }; -struct t_thor_data_transfer { - struct thor_device_handle *th; - struct thor_data_src *data; - thor_progress_cb report_progress; - void *user_data; - off_t data_left; - off_t data_sent; - off_t data_in_progress; - int chunk_number; - int completed; - int ret; +struct thor_device_handle { + enum thor_transport_type type; + struct thor_transport_ops *ops; + void *dev_priv; }; - -int t_usb_handle_events_completed(int *completed); - -int t_usb_init_transfer(struct t_usb_transfer *t, - libusb_device_handle *devh, - unsigned char ep, - unsigned char *buf, off_t size, - t_usb_transfer_cb transfer_finished, - unsigned int timeout); - -static inline void t_usb_cleanup_transfer(struct t_usb_transfer *t) -{ - libusb_free_transfer(t->ltransfer); -} - -static inline int t_usb_init_in_transfer(struct t_usb_transfer *t, - struct thor_device_handle *th, - unsigned char *buf, off_t size, - t_usb_transfer_cb transfer_finished, - unsigned int timeout) -{ - return t_usb_init_transfer(t, th->devh, th->data_ep_in, buf, size, - transfer_finished, timeout); -} - -static inline int t_usb_init_out_transfer(struct t_usb_transfer *t, - struct thor_device_handle *th, - unsigned char *buf, off_t size, - t_usb_transfer_cb transfer_finished, - unsigned int timeout) -{ - return t_usb_init_transfer(t, th->devh, th->data_ep_out, buf, size, - transfer_finished, timeout); -} - -static inline int t_usb_submit_transfer(struct t_usb_transfer *t) -{ - return libusb_submit_transfer(t->ltransfer); -} - -static inline int t_usb_cancel_transfer(struct t_usb_transfer *t) -{ - return libusb_cancel_transfer(t->ltransfer); -} - int t_file_get_data_src(const char *path, struct thor_data_src **data); int t_tar_get_data_src(const char *path, struct thor_data_src **data); -int t_usb_send(struct thor_device_handle *th, unsigned char *buf, - off_t count, int timeout); - -int t_usb_recv(struct thor_device_handle *th, unsigned char *buf, - off_t count, int timeout); - -int t_usb_send_req(struct thor_device_handle *th, request_type req_id, - int req_sub_id, int *idata, int icnt, char **sdata, - int scnt); - -int t_usb_recv_req(struct thor_device_handle *th, struct res_pkt *resp); - -int t_usb_find_device(struct thor_device_id *dev_id, int wait, - struct thor_device_handle *th); - -void t_usb_close_device(struct thor_device_handle *th); - -int t_acm_prepare_device(struct thor_device_handle *th); - #endif /* THOR_INTERNAL_H__ */ diff --git a/libthor/thor_transport.c b/libthor/thor_transport.c new file mode 100644 index 0000000..ae8b642 --- /dev/null +++ b/libthor/thor_transport.c @@ -0,0 +1,95 @@ +/* + * libthor - Tizen Thor communication protocol + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <sys/types.h> +#include <errno.h> +#include <string.h> + +#include "thor.h" +#include "thor_internal.h" +#include "thor_transport.h" + + +int t_thor_init(thor_device_handle *th) +{ + switch (th->type) { + case THOR_TRANSPORT_USB: + return thor_usb_init(th); + default: + break; + } + + return -ENODEV; +} + +void t_thor_cleanup(thor_device_handle *th) +{ + switch (th->type) { + case THOR_TRANSPORT_USB: + thor_usb_cleanup(th); + break; + default: + break; + } +} + +int t_thor_open(thor_device_handle *th, struct thor_device_id *dev_id, int wait) +{ + if (!th->ops || !th->ops->open) + return -ENOENT; + + return th->ops->open(th, dev_id, wait); +} + +void t_thor_close(thor_device_handle *th) +{ + if (!th->ops || !th->ops->close) + return; + + th->ops->close(th); +} + +int t_thor_send(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + if (!th->ops || !th->ops->send) + return -ENOENT; + + return th->ops->send(th, buf, count, timeout); + +} + +int t_thor_recv(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + if (!th->ops || !th->ops->recv) + return -ENOENT; + + return th->ops->recv(th, buf, count, timeout); +} + +int t_thor_send_raw_data(thor_device_handle *th, + struct thor_data_src *data, + off_t trans_unit_size, + thor_progress_cb report_progress, + void *user_data) +{ + if (!th->ops || !th->ops->send_data) + return -EIO; + + return th->ops->send_data(th, data, trans_unit_size, + report_progress, user_data); +} diff --git a/libthor/thor_transport.h b/libthor/thor_transport.h new file mode 100644 index 0000000..daddc9e --- /dev/null +++ b/libthor/thor_transport.h @@ -0,0 +1,48 @@ +/* + * libthor - Tizen Thor communication protocol + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef THOR_TRNASPORT_H__ +#define THOR_TRANSPORT_H__ + +#include "thor.h" +#include "thor_internal.h" + +int t_thor_init(thor_device_handle *th); +int t_thor_open(thor_device_handle *th, struct thor_device_id *dev_id, + int wait); +void thor_close(thor_device_handle *th); +int t_thor_send_raw_data(thor_device_handle *th, + struct thor_data_src *data, + off_t trans_unit_size, + thor_progress_cb report_progress, + void *user_data); + +/* USB transport */ +struct usb_device_handle { + libusb_device_handle *devh; + int control_interface; + int control_interface_id; + int data_interface; + int data_interface_id; + int data_ep_in; + int data_ep_out; +}; + +int thor_usb_init(thor_device_handle *th); +void thor_usb_cleanup(thor_device_handle *th); +int t_acm_prepare_device(struct usb_device_handle *uh); + +#endif /* THOR_TRANSPORT_H__ */ diff --git a/libthor/thor_usb.c b/libthor/thor_usb.c index b43870b..74e0ab2 100644 --- a/libthor/thor_usb.c +++ b/libthor/thor_usb.c @@ -1,9 +1,6 @@ -#include <sys/types.h> -#include <stdio.h> -#include <endian.h> #include <errno.h> #include <string.h> -#include <assert.h> +#include <stdlib.h> #ifdef __linux__ #include <linux/usb/cdc.h> #else @@ -43,15 +40,73 @@ struct usb_interface_assoc_descriptor { #include "thor.h" #include "thor_internal.h" +#include "thor_transport.h" #define MAX_SERIAL_LEN 256 struct hotplug_helper { - struct thor_device_handle *th; - struct thor_device_id *dev_id; + struct usb_device_handle *uh; + struct usb_device_id *dev_id; int completed; }; +struct t_usb_transfer; + +typedef void (*t_usb_transfer_cb)(struct t_usb_transfer *); + +struct t_usb_transfer { + struct libusb_transfer *ltransfer; + t_usb_transfer_cb transfer_finished; + off_t size; + int ret; + int cancelled; +}; + +struct t_thor_usb_chunk { + struct t_usb_transfer data_transfer; + struct t_usb_transfer resp_transfer; + void *user_data; + off_t useful_size; + struct data_res_pkt resp; + unsigned char *buf; + off_t trans_unit_size; + int chunk_number; + int data_finished; + int resp_finished; +}; + +struct t_thor_usb_transfer { + thor_device_handle *th; + struct thor_data_src *data; + thor_progress_cb report_progress; + void *user_data; + off_t data_left; + off_t data_sent; + off_t data_in_progress; + int chunk_number; + int completed; + int ret; +}; + +static struct usb_device_id *thor_choose_id(struct thor_device_id *dev_id) +{ + static struct usb_device_id default_id = { + .busid = NULL, + .vid = 0x04e8, + .pid = 0x685d, + .serial = NULL, + }; + struct usb_device_id *usb_dev_id = &dev_id->usb_dev; + + if (usb_dev_id->busid == NULL + && usb_dev_id->vid < 0 + && usb_dev_id->pid < 0 + && usb_dev_id->serial == NULL) + usb_dev_id = &default_id; + + return usb_dev_id; +} + static int check_busid_match(const char *expected, libusb_device *dev) { /* Max USB depth is 7 */ @@ -175,7 +230,7 @@ static int find_idesc_by_id(struct libusb_config_descriptor *cdesc, int id) static int check_assoc(struct libusb_config_descriptor *cdesc, struct usb_interface_assoc_descriptor *assoc_desc, - struct thor_device_handle *th) + struct usb_device_handle *uh) { int intf_a, intf_b; @@ -190,16 +245,16 @@ static int check_assoc(struct libusb_config_descriptor *cdesc, if (is_data_interface(cdesc->interface[intf_a].altsetting + 0) && is_control_interface(cdesc->interface[intf_b].altsetting + 0)) { - th->data_interface = intf_a; - th->data_interface_id = assoc_desc->bFirstInterface; - th->control_interface = intf_b; - th->control_interface_id = assoc_desc->bFirstInterface + 1; + uh->data_interface = intf_a; + uh->data_interface_id = assoc_desc->bFirstInterface; + uh->control_interface = intf_b; + uh->control_interface_id = assoc_desc->bFirstInterface + 1; } else if (is_control_interface(cdesc->interface[intf_a].altsetting + 0) && is_data_interface(cdesc->interface[intf_b].altsetting + 0)) { - th->data_interface = intf_b; - th->data_interface_id = assoc_desc->bFirstInterface + 1; - th->control_interface = intf_a; - th->control_interface_id = assoc_desc->bFirstInterface; + uh->data_interface = intf_b; + uh->data_interface_id = assoc_desc->bFirstInterface + 1; + uh->control_interface = intf_a; + uh->control_interface_id = assoc_desc->bFirstInterface; } else { return -ENODEV; } @@ -208,7 +263,7 @@ static int check_assoc(struct libusb_config_descriptor *cdesc, } static int find_interfaces(struct libusb_config_descriptor *cdesc, - struct thor_device_handle *th) + struct usb_device_handle *uh) { struct usb_descriptor_header *header; struct usb_interface_assoc_descriptor *assoc_desc = NULL; @@ -227,7 +282,7 @@ static int find_interfaces(struct libusb_config_descriptor *cdesc, break; assoc_desc = (struct usb_interface_assoc_descriptor *)header; - ret = check_assoc(cdesc, assoc_desc, th); + ret = check_assoc(cdesc, assoc_desc, uh); if (!ret) { assoc_valid = 1; break; @@ -241,31 +296,31 @@ static int find_interfaces(struct libusb_config_descriptor *cdesc, if (!assoc_valid) { int i; #define get_intf_desc(_intf) (&(cdesc->interface[_intf].altsetting[0])) - th->data_interface = -1; - th->control_interface = -1; + uh->data_interface = -1; + uh->control_interface = -1; for (i = 0; i < cdesc->bNumInterfaces; ++i) { if (!is_data_interface(get_intf_desc(i))) continue; - th->data_interface = i; - th->data_interface_id = + uh->data_interface = i; + uh->data_interface_id = get_intf_desc(i)->bInterfaceNumber; break; } - if (th->data_interface < 0) + if (uh->data_interface < 0) return -ENODEV; for (i = 0; i < cdesc->bNumInterfaces; ++i) { if (!is_control_interface(get_intf_desc(i))) continue; - th->control_interface = i; - th->control_interface_id = + uh->control_interface = i; + uh->control_interface_id = get_intf_desc(i)->bInterfaceNumber; } - if (th->control_interface < 0) + if (uh->control_interface < 0) return -ENODEV; #undef get_intf_desc } @@ -274,18 +329,18 @@ static int find_interfaces(struct libusb_config_descriptor *cdesc, } static int find_data_eps(struct libusb_config_descriptor *cdesc, - struct thor_device_handle *th) + struct usb_device_handle *uh) { const struct libusb_interface_descriptor *idesc; int i; - idesc = cdesc->interface[th->data_interface_id].altsetting + 0; + idesc = cdesc->interface[uh->data_interface_id].altsetting + 0; if (idesc->bNumEndpoints != 2) return -EINVAL; - th->data_ep_in = -1; - th->data_ep_out = -1; + uh->data_ep_in = -1; + uh->data_ep_out = -1; for (i = 0; i < idesc->bNumEndpoints; ++i) { if ((idesc->endpoint[i].bmAttributes & 0x03) != @@ -293,19 +348,19 @@ static int find_data_eps(struct libusb_config_descriptor *cdesc, return -1; if ((idesc->endpoint[i].bEndpointAddress & (1 << 7)) == LIBUSB_ENDPOINT_IN) - th->data_ep_in = idesc->endpoint[i].bEndpointAddress; + uh->data_ep_in = idesc->endpoint[i].bEndpointAddress; else - th->data_ep_out = idesc->endpoint[i].bEndpointAddress; + uh->data_ep_out = idesc->endpoint[i].bEndpointAddress; } - if (th->data_ep_in < 0 || th->data_ep_out < 0) + if (uh->data_ep_in < 0 || uh->data_ep_out < 0) return -EINVAL; return 0; } static int find_intf_and_eps(libusb_device *dev, - struct thor_device_handle *th) + struct usb_device_handle *uh) { struct libusb_config_descriptor *cdesc; int ret; @@ -314,13 +369,13 @@ static int find_intf_and_eps(libusb_device *dev, if (ret < 0) return ret; - ret = find_interfaces(cdesc, th); + ret = find_interfaces(cdesc, uh); if (ret) { ret = -ENODEV; goto cleanup_desc; } - ret = find_data_eps(cdesc, th); + ret = find_data_eps(cdesc, uh); if (ret) { ret = -ENODEV; goto cleanup_desc; @@ -332,7 +387,7 @@ cleanup_desc: return ret; } -static int claim_intf(struct thor_device_handle *th) +static int claim_intf(struct usb_device_handle *uh) { int ret; @@ -348,29 +403,30 @@ static int claim_intf(struct thor_device_handle *th) */ ret = libusb_has_capability(LIBUSB_CAP_SUPPORTS_DETACH_KERNEL_DRIVER); if (ret) { - ret = libusb_set_auto_detach_kernel_driver(th->devh, 1); + ret = libusb_set_auto_detach_kernel_driver(uh->devh, 1); if (ret < 0) goto out; } - ret = libusb_claim_interface(th->devh, th->data_interface_id); + ret = libusb_claim_interface(uh->devh, uh->data_interface_id); if (ret < 0) goto out; - ret = libusb_claim_interface(th->devh, th->control_interface_id); + ret = libusb_claim_interface(uh->devh, uh->control_interface_id); if (ret < 0) goto release_data; return 0; release_data: - libusb_release_interface(th->devh, th->data_interface); + libusb_release_interface(uh->devh, uh->data_interface); out: return ret; } -static int check_device_match(struct thor_device_id *dev_id, - libusb_device *dev, struct thor_device_handle *th) +static int check_device_match(struct usb_device_id *dev_id, + libusb_device *dev, + struct usb_device_handle *uh) { int ret; @@ -387,32 +443,32 @@ static int check_device_match(struct thor_device_id *dev_id, } if (dev_id->serial) { - ret = check_serial_match(dev_id->serial, dev, &th->devh); + ret = check_serial_match(dev_id->serial, dev, &uh->devh); if (ret <= 0) goto no_match; } else { - ret = libusb_open(dev, &th->devh); + ret = libusb_open(dev, &uh->devh); if (ret < 0) goto no_match; } - ret = find_intf_and_eps(dev, th); + ret = find_intf_and_eps(dev, uh); if (ret < 0) goto err; - ret = claim_intf(th); + ret = claim_intf(uh); if (ret < 0) goto err; return 1; err: - libusb_close(th->devh); + libusb_close(uh->devh); no_match: return 0; } -static int find_existing_device(struct thor_device_id *dev_id, - struct thor_device_handle *th) +static int find_existing_device(struct usb_device_id *dev_id, + struct usb_device_handle *uh) { libusb_device **dev_list; int i, ndevices; @@ -423,7 +479,7 @@ static int find_existing_device(struct thor_device_id *dev_id, return ndevices; for (i = 0; i < ndevices; ++i) { - ret = check_device_match(dev_id, dev_list[i], th); + ret = check_device_match(dev_id, dev_list[i], uh); if (ret > 0) /* device match and opened */ break; @@ -436,11 +492,11 @@ static int find_existing_device(struct thor_device_id *dev_id, } static int hotplug_device_arrived(libusb_context *ctx, libusb_device *device, - libusb_hotplug_event event, void *user_data) + libusb_hotplug_event event, void *user_data) { struct hotplug_helper *helper = user_data; - if (check_device_match(helper->dev_id, device, helper->th) > 0) { + if (check_device_match(helper->dev_id, device, helper->uh) > 0) { helper->completed = 1; return 1; } @@ -448,18 +504,17 @@ static int hotplug_device_arrived(libusb_context *ctx, libusb_device *device, return 0; } - -int t_usb_find_device(struct thor_device_id *dev_id, int wait, - struct thor_device_handle *th) +static int t_usb_find_device(struct usb_device_id *dev_id, int wait, + struct usb_device_handle *uh) { struct hotplug_helper helper = { - .th = th, + .uh = uh, .dev_id = dev_id, .completed = 0, }; int found; - found = find_existing_device(dev_id, th); + found = find_existing_device(dev_id, uh); if (found <= 0) { if (!wait) return found; @@ -483,96 +538,6 @@ int t_usb_find_device(struct thor_device_id *dev_id, int wait, return 1; } -void t_usb_close_device(struct thor_device_handle *th) -{ - if (th->devh) - libusb_close(th->devh); -} - -int t_usb_send(struct thor_device_handle *th, unsigned char *buf, - off_t count, int timeout) -{ - int ret; - int transferred = 0; - - ret = libusb_bulk_transfer(th->devh, - th->data_ep_out, - (unsigned char *)buf, - count, - &transferred, - timeout); - - if (ret < 0) - return ret; - if (transferred < count) - return -EIO; - - return 0; -} - -int t_usb_recv(struct thor_device_handle *th, unsigned char *buf, - off_t count, int timeout) -{ - int ret; - int transferred = 0; - - ret = libusb_bulk_transfer(th->devh, - th->data_ep_in, - (unsigned char *)buf, - count, - &transferred, - timeout); - - if (ret < 0) - return ret; - if (transferred < count) - return -EIO; - - return 0; -} - -int t_usb_send_req(struct thor_device_handle *th, request_type req_id, - int req_sub_id, int *idata, int icnt, char **sdata, int scnt) -{ - struct rqt_pkt req; - int i; - int ret; - - assert(icnt <= sizeof(req.int_data)/sizeof(req.int_data[0])); - assert(icnt >= 0); - assert(scnt <= sizeof(req.str_data)/sizeof(req.str_data[0])); - assert(scnt >= 0); - - memset(&req, 0, sizeof(req)); - - req.id = req_id; - req.sub_id = req_sub_id; - - if (idata) { - for (i = 0; i < icnt; i++) - req.int_data[i] = idata[i]; - } - - if (sdata) { - for (i = 0; i < scnt; i++) - strncpy(req.str_data[i], sdata[i], 32); - } - - ret = t_usb_send(th, (unsigned char *)&req, RQT_PKT_SIZE, DEFAULT_TIMEOUT); - - return ret; -} - -int t_usb_recv_req(struct thor_device_handle *th, struct res_pkt *resp) -{ - int ret; - - ret = t_usb_recv(th, (unsigned char *)resp, sizeof(*resp), - DEFAULT_TIMEOUT); - - return ret; -} - static void t_usb_transfer_finished(struct libusb_transfer *ltransfer) { struct t_usb_transfer *t = ltransfer->user_data; @@ -595,12 +560,12 @@ static void t_usb_transfer_finished(struct libusb_transfer *ltransfer) t->transfer_finished(t); } -int t_usb_init_transfer(struct t_usb_transfer *t, - libusb_device_handle *devh, - unsigned char ep, - unsigned char *buf, off_t size, - t_usb_transfer_cb transfer_finished, - unsigned int timeout) +static int t_usb_init_transfer(struct t_usb_transfer *t, + libusb_device_handle *devh, + unsigned char ep, + unsigned char *buf, off_t size, + t_usb_transfer_cb transfer_finished, + unsigned int timeout) { t->ltransfer = libusb_alloc_transfer(0); if (!t->ltransfer) @@ -615,7 +580,7 @@ int t_usb_init_transfer(struct t_usb_transfer *t, return 0; } -int t_usb_handle_events_completed(int *completed) +static int t_usb_handle_events_completed(int *completed) { struct timeval tv = {0, 0}; int ret = 0; @@ -636,3 +601,426 @@ int t_usb_handle_events_completed(int *completed) return ret; } +static inline void t_usb_cleanup_transfer(struct t_usb_transfer *t) +{ + libusb_free_transfer(t->ltransfer); +} + +static inline int t_usb_init_in_transfer(struct t_usb_transfer *t, + struct usb_device_handle *uh, + unsigned char *buf, off_t size, + t_usb_transfer_cb transfer_finished, + unsigned int timeout) +{ + return t_usb_init_transfer(t, uh->devh, uh->data_ep_in, buf, size, + transfer_finished, timeout); +} + +static inline int t_usb_init_out_transfer(struct t_usb_transfer *t, + struct usb_device_handle *uh, + unsigned char *buf, off_t size, + t_usb_transfer_cb transfer_finished, + unsigned int timeout) +{ + return t_usb_init_transfer(t, uh->devh, uh->data_ep_out, buf, size, + transfer_finished, timeout); +} + +static inline int t_usb_submit_transfer(struct t_usb_transfer *t) +{ + return libusb_submit_transfer(t->ltransfer); +} + +static inline int t_usb_cancel_transfer(struct t_usb_transfer *t) +{ + return libusb_cancel_transfer(t->ltransfer); +} + +static int t_thor_submit_chunk(struct t_thor_usb_chunk *chunk) +{ + int ret; + + chunk->data_finished = chunk->resp_finished = 0; + + ret = t_usb_submit_transfer(&chunk->data_transfer); + if (ret) + goto out; + + memset(&chunk->resp, 0, DATA_RES_PKT_SIZE); + ret = t_usb_submit_transfer(&chunk->resp_transfer); + if (ret) + goto cancel_data_transfer; + + return 0; +cancel_data_transfer: + t_usb_cancel_transfer(&chunk->data_transfer); +out: + return ret; +} + +static int t_thor_prep_next_chunk(struct t_thor_usb_chunk *chunk, + struct t_thor_usb_transfer *transfer_data) +{ + off_t to_read; + int ret; + + to_read = transfer_data->data_left - transfer_data->data_in_progress; + if (to_read <= 0) { + printf("to big data in progress\n"); + fflush(stdout); + return -EINVAL; + } + + chunk->useful_size = to_read > chunk->trans_unit_size ? + chunk->trans_unit_size : to_read; + + ret = transfer_data->data->get_block(transfer_data->data, + chunk->buf, chunk->useful_size); + if (ret < 0 || ret != chunk->useful_size) + return ret; + + memset(chunk->buf + chunk->useful_size, 0, + chunk->trans_unit_size - chunk->useful_size); + chunk->chunk_number = transfer_data->chunk_number++; + + ret = t_thor_submit_chunk(chunk); + if (!ret) + transfer_data->data_in_progress += chunk->useful_size; + + return ret; +} + +static void check_next_chunk(struct t_thor_usb_chunk *chunk, + struct t_thor_usb_transfer *transfer_data) +{ + /* If there is some more data to be queued */ + if (transfer_data->data_left - transfer_data->data_in_progress) { + int ret; + + ret = t_thor_prep_next_chunk(chunk, transfer_data); + if (ret) { + transfer_data->ret = ret; + transfer_data->completed = 1; + } + } else { + /* Last one turns the light off */ + if (transfer_data->data_in_progress == 0) + transfer_data->completed = 1; + } +} + +static void data_transfer_finished(struct t_usb_transfer *_data_transfer) +{ + struct t_thor_usb_chunk *chunk = container_of(_data_transfer, + struct t_thor_usb_chunk, + data_transfer); + struct t_thor_usb_transfer *transfer_data = chunk->user_data; + + chunk->data_finished = 1; + + if (_data_transfer->cancelled || transfer_data->ret) + return; + + if (_data_transfer->ret) { + transfer_data->ret = _data_transfer->ret; + transfer_data->completed = 1; + } + + if (chunk->resp_finished) + check_next_chunk(chunk, transfer_data); +} + +static void resp_transfer_finished(struct t_usb_transfer *_resp_transfer) +{ + struct t_thor_usb_chunk *chunk = container_of(_resp_transfer, + struct t_thor_usb_chunk, + resp_transfer); + struct t_thor_usb_transfer *transfer_data = chunk->user_data; + + chunk->resp_finished = 1; + transfer_data->data_in_progress -= chunk->useful_size; + + if (_resp_transfer->cancelled || transfer_data->ret) { + if (transfer_data->data_in_progress == 0) + transfer_data->completed = 1; + return; + } + + if (_resp_transfer->ret) { + transfer_data->ret = _resp_transfer->ret; + goto complete_all; + } + + if (chunk->resp.cnt != chunk->chunk_number) { + printf("chunk number mismatch: %d != %d\n", + chunk->resp.cnt, chunk->chunk_number); + fflush(stdout); + transfer_data->ret = -EINVAL; + goto complete_all; + } + + transfer_data->data_sent += chunk->useful_size; + transfer_data->data_left -= chunk->useful_size; + if (transfer_data->report_progress) + transfer_data->report_progress(transfer_data->th, + transfer_data->data, + transfer_data->data_sent, + transfer_data->data_left, + chunk->chunk_number, + transfer_data->user_data); + + if (chunk->data_finished) + check_next_chunk(chunk, transfer_data); + + return; +complete_all: + transfer_data->completed = 1; +} + +static int t_thor_init_chunk(struct t_thor_usb_chunk *chunk, + struct usb_device_handle *uh, + off_t trans_unit_size, + void *user_data) +{ + int ret; + + chunk->user_data = user_data; + chunk->useful_size = 0; + chunk->trans_unit_size = trans_unit_size; + + chunk->buf = malloc(trans_unit_size); + if (!chunk->buf) + return -ENOMEM; + + ret = t_usb_init_out_transfer(&chunk->data_transfer, uh, chunk->buf, + trans_unit_size, data_transfer_finished, + DEFAULT_TIMEOUT); + if (ret) + goto free_buf; + + ret = t_usb_init_in_transfer(&chunk->resp_transfer, uh, + (unsigned char *)&chunk->resp, + DATA_RES_PKT_SIZE, + resp_transfer_finished, + 2 * DEFAULT_TIMEOUT); + if (ret) + goto cleanup_data_transfer; + + return 0; +cleanup_data_transfer: + t_usb_cleanup_transfer(&chunk->data_transfer); +free_buf: + free(chunk->buf); + + return ret; +} + +static void t_thor_cleanup_chunk(struct t_thor_usb_chunk *chunk) +{ + t_usb_cleanup_transfer(&chunk->data_transfer); + t_usb_cleanup_transfer(&chunk->resp_transfer); + free(chunk->buf); +} + +static inline int +t_thor_handle_events(struct t_thor_usb_transfer *transfer_data) +{ + return t_usb_handle_events_completed(&transfer_data->completed); +} + +static inline void t_thor_cancel_chunk(struct t_thor_usb_chunk *chunk) +{ + t_usb_cancel_transfer(&chunk->data_transfer); + t_usb_cancel_transfer(&chunk->resp_transfer); +} + +static int thor_usb_send_raw_data_async(thor_device_handle *th, + struct thor_data_src *data, + off_t trans_unit_size, + thor_progress_cb report_progress, + void *user_data) +{ + struct usb_device_handle *uh = th->dev_priv; + struct t_thor_usb_chunk chunk[3]; + struct t_thor_usb_transfer transfer_data; + int i, j; + int ret; + + if (!uh) + return -ENODEV; + + for (i = 0; i < ARRAY_SIZE(chunk); ++i) { + ret = t_thor_init_chunk(chunk + i, uh, trans_unit_size, + &transfer_data); + if (ret) + goto cleanup_chunks; + } + + transfer_data.th = th; + transfer_data.data = data; + transfer_data.report_progress = report_progress; + transfer_data.user_data = user_data; + transfer_data.data_left = data->get_file_length(data); + transfer_data.data_sent = 0; + transfer_data.chunk_number = 1; + transfer_data.completed = 0; + transfer_data.data_in_progress = 0; + transfer_data.ret = 0; + + for (i = 0; + i < ARRAY_SIZE(chunk) + && (transfer_data.data_left - transfer_data.data_in_progress > 0); + ++i) { + ret = t_thor_prep_next_chunk(chunk + i, &transfer_data); + if (ret) + goto cancel_chunks; + } + + t_thor_handle_events(&transfer_data); + + if (transfer_data.data_in_progress) { + ret = transfer_data.ret; + goto cancel_chunks; + } + + for (i = 0; i < ARRAY_SIZE(chunk); ++i) + t_thor_cleanup_chunk(chunk + i); + + return transfer_data.ret; + +cancel_chunks: + for (j = 0; j < i; ++j) + t_thor_cancel_chunk(chunk + j); + if (i) { + transfer_data.completed = 0; + t_thor_handle_events(&transfer_data); + } + + i = ARRAY_SIZE(chunk); +cleanup_chunks: + for (j = 0; j < i; ++j) + t_thor_cleanup_chunk(chunk + j); + + return ret; +} + +static int thor_usb_open(thor_device_handle *th, + struct thor_device_id *user_dev_id, + int wait) +{ + struct usb_device_handle *uh; + struct usb_device_id *dev_id = thor_choose_id(user_dev_id); + int found, ret; + + uh = calloc(sizeof(*uh), 1); + if (!uh) + return -ENOMEM; + + found = t_usb_find_device(dev_id, wait, uh); + if (found <= 0) { + ret = -ENODEV; + goto close_dev; + } + + ret = t_acm_prepare_device(uh); + if (ret) + goto close_dev; + + th->dev_priv = uh; + + return 0; + +close_dev: + th->ops->close(th); + return ret; +} + +static void thor_usb_close(thor_device_handle *th) +{ + struct usb_device_handle *uh = th->dev_priv; + + if (!uh) + return; + + if (uh->devh) + libusb_close(uh->devh); + + free(uh); + th->dev_priv = NULL; +} + +static int thor_usb_send(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + struct usb_device_handle *uh = th->dev_priv; + int ret; + int transferred = 0; + + if (!uh) + return -ENODEV; + + ret = libusb_bulk_transfer(uh->devh, + uh->data_ep_out, + (unsigned char *)buf, + count, + &transferred, + timeout); + + if (ret < 0) + return ret; + if (transferred < (int)count) + return -EIO; + + return 0; +} + +static int thor_usb_recv(thor_device_handle *th, unsigned char *buf, + off_t count, int timeout) +{ + struct usb_device_handle *uh = th->dev_priv; + int ret; + int transferred = 0; + + if (!uh) + return -ENODEV; + + ret = libusb_bulk_transfer(uh->devh, + uh->data_ep_in, + (unsigned char *)buf, + count, + &transferred, + timeout); + + if (ret < 0) + return ret; + if (transferred < (int)count) + return -EIO; + + return 0; +} + +static struct thor_transport_ops thor_usb_ops = { + .open = thor_usb_open, + .close = thor_usb_close, + .send = thor_usb_send, + .recv = thor_usb_recv, + .send_data = thor_usb_send_raw_data_async, +}; + +int thor_usb_init(thor_device_handle *th) +{ + int ret; + + ret = libusb_init(NULL); + if (ret < 0) + return -EINVAL; + + th->ops = &thor_usb_ops; + + return 0; +} + +void thor_usb_cleanup(thor_device_handle *th) +{ + libusb_exit(NULL); +} |