blob: 0ac04e2cf80139ca29a953a937989d6d5e3d04a3 [file] [log] [blame]
/*
* Copyright 2016 Google Inc. All Rights Reserved.
* Author: gkalsi@google.com (Gurjant Kalsi)
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files
* (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <lib/ndebug/ndebug.h>
#include <lib/ndebug/shared_structs.h>
#include <lib/ndebug/user.h>
#include <assert.h>
#include <err.h>
#include <kernel/mutex.h>
#include <stdlib.h>
#include <string.h>
#include <trace.h>
#define LOCAL_TRACE 0
#define HOST_MSG_TIMEOUT (1000) // 1 Second
static volatile bool connected = false;
static mutex_t usr_mutex = MUTEX_INITIAL_VALUE(usr_mutex);
static uint8_t scratch_buffer[NDEBUG_MAX_PACKET_SIZE];
status_t ndebug_await_connection_usr(lk_time_t timeout)
{
LTRACEF("timeout: %u\n", timeout);
status_t result = ndebug_await_connection(NDEBUG_CHANNEL_USR, timeout);
if (result == NO_ERROR) {
connected = true;
} else {
connected = false;
}
return result;
}
ssize_t ndebug_read_usr(uint8_t *buf, const lk_time_t timeout)
{
LTRACEF("buf: 0x%p, timeout: %u\n", buf, timeout);
if (!connected) {
// User must call ndebugusr_await_host and establish a connection
// before continuing.
return ERR_CHANNEL_CLOSED;
}
mutex_acquire(&usr_mutex);
// Retry Loop
while (true) {
ssize_t result = ndebug_usb_read(NDEBUG_CHANNEL_USR,
NDEBUG_MAX_PACKET_SIZE,
timeout, scratch_buffer);
if (result < (ssize_t)sizeof(ndebug_ctrl_packet_t)) {
dprintf(INFO, "Short Packet. Len = %ld\n", result);
continue;
}
ndebug_ctrl_packet_t *ctrl = (ndebug_ctrl_packet_t *)scratch_buffer;
if (ctrl->magic != NDEBUG_CTRL_PACKET_MAGIC) {
dprintf(INFO, "Bad Packet Magic = %u\n", ctrl->magic);
continue;
}
if (ctrl->type == NDEBUG_CTRL_CMD_RESET) {
msg_host(NDEBUG_CHANNEL_USR, NDEBUG_CTRL_CMD_RESET, timeout,
scratch_buffer);
connected = false;
mutex_release(&usr_mutex);
return ERR_CHANNEL_CLOSED;
} else if (ctrl->type == NDEBUG_CTRL_CMD_DATA) {
const ssize_t n_data_bytes = result - sizeof(ndebug_ctrl_packet_t);
memcpy(buf, scratch_buffer + sizeof(ndebug_ctrl_packet_t),
n_data_bytes);
mutex_release(&usr_mutex);
return n_data_bytes;
} else {
dprintf(INFO, "Unexpected packet type = %u\n", ctrl->type);
}
}
}
ssize_t ndebug_write_usr(uint8_t *buf, const size_t n, const lk_time_t timeout)
{
LTRACEF("buf = 0x%p, n = %u, timeout = %u\n", buf, n, timeout);
if (!connected) {
// User must call ndebugusr_await_host and establish a connection
// before continuing.
return ERR_CHANNEL_CLOSED;
}
mutex_acquire(&usr_mutex);
uint8_t *cursor = scratch_buffer;
ndebug_ctrl_packet_t *pkt = (ndebug_ctrl_packet_t *)cursor;
pkt->magic = NDEBUG_CTRL_PACKET_MAGIC;
pkt->type = NDEBUG_CTRL_CMD_DATA;
cursor += sizeof(ndebug_ctrl_packet_t);
ssize_t res;
size_t bytes_remaining = n;
do {
size_t bytes_to_copy = MIN(NDEBUG_USR_MAX_PACKET_SIZE, bytes_remaining);
memcpy(cursor, buf, bytes_to_copy);
buf += bytes_to_copy;
bytes_remaining -= bytes_to_copy;
res = ndebug_usb_write(
NDEBUG_CHANNEL_USR,
bytes_to_copy + sizeof(ndebug_ctrl_packet_t),
timeout,
scratch_buffer
);
if (res < 0) {
break;
}
} while (bytes_remaining > 0);
mutex_release(&usr_mutex);
if (res < 0) {
return res;
} else {
return (ssize_t)n;
}
}