libthor/thor.c
libthor/thor_raw_file.c
libthor/thor_tar.c
+ libthor/thor_transport.c
libthor/thor_usb.c
)
* 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;
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;
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)
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];
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;
}
{
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,
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);
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;
}
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,
if (data->release)
data->release(data);
}
-
#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;
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);
#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);
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),
};
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);
}
-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;
}
#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__ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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__ */
-#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
#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 */
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;
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;
}
}
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;
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;
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
}
}
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) !=
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;
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;
return ret;
}
-static int claim_intf(struct thor_device_handle *th)
+static int claim_intf(struct usb_device_handle *uh)
{
int ret;
*/
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;
}
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;
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;
}
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;
}
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;
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;
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)
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;
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);
+}
return ret;
}
-/* Check if LHOR protocol is in working state */
-static int check_proto(struct thor_device_id *dev_id)
+/* Check if THOR protocol is in working state */
+static int check_proto(thor_device_handle *th, struct thor_device_id *dev_id)
{
- thor_device_handle *handle;
int ret;
- ret = thor_open(dev_id, 0, &handle);
+ ret = thor_open(th, dev_id, 0);
if (ret)
fprintf(stderr, "Unable to open device: %d\n", ret);
- else
- thor_close(handle);
return ret;
}
return ret;
}
-static int process_download(struct thor_device_id *dev_id, const char *pitfile,
- char **tarfilelist)
+static int process_download(thor_device_handle *th,
+ struct thor_device_id *dev_id,
+ const char *pitfile,
+ char **tarfilelist)
{
- thor_device_handle *th;
off_t total_size = 0;
struct helper *data_parts;
int nfiles;
int i;
int ret;
- ret = thor_open(dev_id, 1, &th);
+ ret = thor_open(th, dev_id, 1);
if (ret) {
fprintf(stderr, "Unable to open device: %d\n", ret);
return ret;
int main(int argc, char **argv)
{
+ thor_device_handle *th;
const char *exename = NULL, *pitfile = NULL;
+ enum thor_transport_type type = THOR_TRANSPORT_USB; /* default is USB */
int opt;
int opt_test = 0;
int opt_check = 0;
int optindex;
int ret;
struct thor_device_id dev_id = {
- .busid = NULL,
- .vid = -1,
- .pid = -1,
- .serial = NULL,
+ .usb_dev.busid = NULL,
+ .usb_dev.vid = -1,
+ .usb_dev.pid = -1,
+ .usb_dev.serial = NULL,
};
struct option opts[] = {
exename = argv[0];
- ret = thor_init();
- if (ret) {
- fprintf(stderr, "Unable to init io backend: %d\n", ret);
- exit(-1);
- }
-
while (1) {
opt = getopt_long(argc, argv, "tvcd:p:b:", opts, &optindex);
if (opt == -1)
pitfile = optarg;
break;
case 'b':
- dev_id.busid = optarg;
+ dev_id.usb_dev.busid = optarg;
break;
case 1:
{
exit(-1);
}
- dev_id.vid = (int)val;
+ dev_id.usb_dev.vid = (int)val;
break;
}
case 2:
exit(-1);
}
- dev_id.pid = (int)val;
+ dev_id.usb_dev.pid = (int)val;
break;
}
case 3:
- dev_id.serial = optarg;
+ dev_id.usb_dev.serial = optarg;
break;
case 0:
default:
}
}
- ret = 0;
+ th = thor_init(type);
+ if (!th) {
+ fprintf(stderr, "Unable to init transport backend\n");
+ exit(-1);
+ }
+
if (opt_test)
ret = test_tar_file_list(&(argv[optind]));
else if (opt_check)
- ret = check_proto(&dev_id);
+ ret = check_proto(th, &dev_id);
else if (pitfile || argv[optind])
- ret = process_download(&dev_id, pitfile, &(argv[optind]));
+ ret = process_download(th, &dev_id, pitfile, &(argv[optind]));
else
usage(exename);
- thor_cleanup();
+ thor_cleanup(th);
return ret;
}