mirror of
https://github.com/trezor/trezor-firmware.git
synced 2025-01-03 12:00:59 +00:00
148 lines
3.4 KiB
C++
148 lines
3.4 KiB
C++
// Copyright Google Inc. All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file or at
|
|
// https://developers.google.com/open-source/licenses/bsd
|
|
|
|
// Thin shim to allow abstracting away from hid_* calls to
|
|
// a set or read/write pipes w/ a particular interface.
|
|
#include <assert.h>
|
|
#include <endian.h>
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
|
|
#include <string>
|
|
|
|
#include "u2f_util.h"
|
|
|
|
bool DEV_opened(struct U2Fob* device) {
|
|
return device->dev != NULL || (device->fd_in != -1 && device->fd_out != -1);
|
|
}
|
|
|
|
void DEV_close(struct U2Fob* device) {
|
|
if (device->dev) {
|
|
hid_close(device->dev);
|
|
device->dev = NULL;
|
|
}
|
|
if (device->fd_in != -1) {
|
|
close(device->fd_in);
|
|
device->fd_in = -1;
|
|
}
|
|
if (device->fd_out != -1) {
|
|
close(device->fd_out);
|
|
device->fd_out = -1;
|
|
}
|
|
}
|
|
|
|
void DEV_open_path(struct U2Fob* device) {
|
|
std::string path(device->path);
|
|
if (path[path.size() - 1] == '-') {
|
|
device->fd_in = open((path + "out").c_str(), O_RDONLY);
|
|
device->fd_out = open((path + "in").c_str(), O_RDWR);
|
|
} else {
|
|
device->dev = hid_open_path(device->path);
|
|
}
|
|
}
|
|
|
|
void DEV_quit(struct U2Fob* device) {
|
|
if (device->dev) return;
|
|
|
|
struct {
|
|
uint32_t cmd;
|
|
uint32_t len;
|
|
uint32_t mode;
|
|
} data;
|
|
|
|
data.cmd = htole32(2); // kReset
|
|
data.len = htole32(4);
|
|
data.mode = htole32(3); // kResetQuit
|
|
assert(write(device->fd_out, (const void*)&data, sizeof(data)) == sizeof(data));
|
|
}
|
|
|
|
int DEV_write(struct U2Fob* device, const uint8_t* src, size_t n) {
|
|
assert(n == 65);
|
|
|
|
if (device->dev != NULL) return hid_write(device->dev, src, n);
|
|
|
|
struct {
|
|
uint32_t cmd;
|
|
uint32_t len;
|
|
uint8_t data[64];
|
|
} data;
|
|
|
|
static_assert(sizeof(data) == 64 + 8);
|
|
|
|
data.cmd = htole32(4); // k64ByteWrite
|
|
data.len = htole32(64);
|
|
memcpy(data.data, src + 1, 64);
|
|
|
|
int nwritten = write(device->fd_out, (const void*)&data, sizeof(data));
|
|
assert(nwritten == sizeof(data));
|
|
usleep(1500); // delay a bit to mimic HID transport.
|
|
return 65;
|
|
}
|
|
|
|
int DEV_read_timeout(struct U2Fob* device, uint8_t* dst, size_t n,
|
|
int timeout) {
|
|
assert(n == 64);
|
|
|
|
if (device->dev != NULL)
|
|
return hid_read_timeout(device->dev, dst, n, timeout);
|
|
|
|
struct {
|
|
uint32_t cmd;
|
|
uint32_t len;
|
|
} data;
|
|
|
|
static_assert(sizeof(data) == 8);
|
|
|
|
data.cmd = htole32(5); // k64ByteRead
|
|
data.len = htole32(0);
|
|
|
|
uint64_t t0, t1;
|
|
float dt;
|
|
U2Fob_deltaTime(&t0);
|
|
|
|
// Poll until timeout
|
|
do {
|
|
assert(write(device->fd_out, (uint8_t*)&data, sizeof(data)) ==
|
|
sizeof(data));
|
|
assert(read(device->fd_in, (uint8_t*)&data, sizeof(data)) == sizeof(data));
|
|
|
|
assert(data.cmd == htole32(5));
|
|
if (data.len == htole32(64)) break;
|
|
|
|
assert(data.len == 0);
|
|
|
|
usleep(100);
|
|
|
|
t1 = t0;
|
|
dt = U2Fob_deltaTime(&t1);
|
|
} while (dt < timeout / 1000.0);
|
|
|
|
if (data.len == 0) return 0;
|
|
|
|
assert(data.len == htole32(64));
|
|
assert(read(device->fd_in, dst, 64) == 64);
|
|
return 64;
|
|
}
|
|
|
|
int DEV_touch(struct U2Fob* device) {
|
|
if (device->dev != NULL) return 0;
|
|
|
|
struct {
|
|
uint32_t cmd;
|
|
uint32_t len;
|
|
uint32_t number;
|
|
} data;
|
|
|
|
static_assert(sizeof(data) == 12);
|
|
|
|
data.cmd = htole32(6); // kRaiseInterrupt
|
|
data.len = htole32(sizeof(uint32_t));
|
|
data.number = htole32(199); // touch toggle handler
|
|
|
|
assert(write(device->fd_out, (uint8_t*)&data, sizeof(data)) == sizeof(data));
|
|
return 1;
|
|
}
|