Skip to content

Commit

Permalink
Merge branch 'usb-cdc'
Browse files Browse the repository at this point in the history
  • Loading branch information
uchan-nos committed May 6, 2021
2 parents a68d282 + c1a734f commit d4048a3
Show file tree
Hide file tree
Showing 14 changed files with 452 additions and 133 deletions.
2 changes: 1 addition & 1 deletion kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ OBJS = main.o graphics.o mouse.o font.o hankaku.o newlib_support.o console.o \
usb/memory.o usb/device.o usb/xhci/ring.o usb/xhci/trb.o usb/xhci/xhci.o \
usb/xhci/port.o usb/xhci/device.o usb/xhci/devmgr.o usb/xhci/registers.o \
usb/classdriver/base.o usb/classdriver/hid.o usb/classdriver/keyboard.o \
usb/classdriver/mouse.o
usb/classdriver/mouse.o usb/classdriver/cdc.o
DEPENDS = $(join $(dir $(OBJS)),$(addprefix .,$(notdir $(OBJS:.o=.d))))

CPPFLAGS += -I.
Expand Down
2 changes: 2 additions & 0 deletions kernel/error.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class Error {
kIsDirectory,
kNoSuchEntry,
kFreeTypeError,
kEndpointNotInCharge,
kLastOfCode, // この列挙子は常に最後に配置する
};

Expand Down Expand Up @@ -68,6 +69,7 @@ class Error {
"kInvalidFile",
"kIsDirectory",
"kNoSuchEntry",
"kEndpointNotInCharge",
"kFreeTypeError",
};
static_assert(Error::Code::kLastOfCode == code_names_.size());
Expand Down
42 changes: 42 additions & 0 deletions kernel/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <cstring>
#include <limits>
#include <vector>

#include "font.hpp"
#include "layer.hpp"
Expand All @@ -14,6 +15,8 @@
#include "keyboard.hpp"
#include "logger.hpp"
#include "uefi.hpp"
#include "usb/classdriver/cdc.hpp"
#include "usb/xhci/xhci.hpp"

namespace {

Expand Down Expand Up @@ -527,6 +530,45 @@ void Terminal::ExecuteLine() {
uefi_rt->ResetSystem(EfiResetWarm, EFI_SUCCESS, 0, nullptr);
} else if (strcmp(command, "poweroff") == 0) {
uefi_rt->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, nullptr);
} else if (strcmp(command, "lsusb") == 0) {
auto devmgr = usb::xhci::controller->DeviceManager();
for (int slot = 1; slot < 256; ++slot) {
auto dev = devmgr->FindBySlot(slot);
if (!dev) {
continue;
}
PrintToFD(*files_[1], "Slot %d: ID %04x:%04x Class %d.%d.%d\n",
slot,
dev->DeviceDesc().vendor_id,
dev->DeviceDesc().product_id,
dev->DeviceDesc().device_class,
dev->DeviceDesc().device_sub_class,
dev->DeviceDesc().device_protocol);
}
} else if (strcmp(command, "usbtest") == 0) {
[&]{
if (!usb::cdc::driver) {
PrintToFD(*files_[2], "CDC device not exist\n");
exit_code = 1;
return;
}

size_t send_len;
if (first_arg && first_arg[0]) {
send_len = strlen(first_arg);
usb::cdc::driver->SendSerial(first_arg, send_len);
} else {
send_len = 1;
usb::cdc::driver->SendSerial("a", 1);
}

std::vector<uint8_t> buf(send_len);
int recv_len = usb::cdc::driver->ReceiveSerial(buf.data(), send_len);
while (recv_len == 0) {
recv_len = usb::cdc::driver->ReceiveSerial(buf.data(), send_len);
}
PrintToFD(*files_[1], "%.*s\n", recv_len, buf.data());
}();
} else if (command[0] != 0) {
auto file_entry = FindCommand(command);
if (!file_entry) {
Expand Down
6 changes: 4 additions & 2 deletions kernel/usb/classdriver/base.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#pragma once

#include <vector>

#include "error.hpp"
#include "usb/endpoint.hpp"
#include "usb/setupdata.hpp"
Expand All @@ -19,11 +21,11 @@ namespace usb {
virtual ~ClassDriver();

virtual Error Initialize() = 0;
virtual Error SetEndpoint(const EndpointConfig& config) = 0;
virtual Error SetEndpoint(const std::vector<EndpointConfig>& configs) = 0;
virtual Error OnEndpointsConfigured() = 0;
virtual Error OnControlCompleted(EndpointID ep_id, SetupData setup_data,
const void* buf, int len) = 0;
virtual Error OnInterruptCompleted(EndpointID ep_id, const void* buf, int len) = 0;
virtual Error OnNormalCompleted(EndpointID ep_id, const void* buf, int len) = 0;

/** このクラスドライバを保持する USB デバイスを返す. */
Device* ParentDevice() const { return dev_; }
Expand Down
79 changes: 79 additions & 0 deletions kernel/usb/classdriver/cdc.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "usb/classdriver/cdc.hpp"

#include <algorithm>
#include <cstdlib>
#include <iterator>

#include "logger.hpp"
#include "usb/device.hpp"

namespace usb::cdc {
CDCDriver::CDCDriver(Device* dev, const InterfaceDescriptor* if_comm,
const InterfaceDescriptor* if_data) : ClassDriver{dev} {
}

Error CDCDriver::Initialize() {
return MAKE_ERROR(Error::kNotImplemented);
}

Error CDCDriver::SetEndpoint(const std::vector<EndpointConfig>& configs) {
for (const auto& config : configs) {
if (config.ep_type == EndpointType::kInterrupt && config.ep_id.IsIn()) {
ep_interrupt_in_ = config.ep_id;
} else if (config.ep_type == EndpointType::kBulk && config.ep_id.IsIn()) {
ep_bulk_in_ = config.ep_id;
} else if (config.ep_type == EndpointType::kBulk && !config.ep_id.IsIn()) {
ep_bulk_out_ = config.ep_id;
}
}
return MAKE_ERROR(Error::kSuccess);
}

Error CDCDriver::OnEndpointsConfigured() {
return MAKE_ERROR(Error::kSuccess);
}

Error CDCDriver::OnControlCompleted(EndpointID ep_id, SetupData setup_data,
const void* buf, int len) {
return MAKE_ERROR(Error::kNotImplemented);
}

Error CDCDriver::OnNormalCompleted(EndpointID ep_id, const void* buf, int len) {
Log(kDebug, "CDCDriver::OnNormalCompleted: buf='%.*s'\n", len, buf);
auto buf8 = reinterpret_cast<const uint8_t*>(buf);
if (ep_id == ep_bulk_in_) {
std::copy_n(buf8, len, std::back_inserter(receive_buf_));
} else if (ep_id == ep_bulk_out_) {
} else {
return MAKE_ERROR(Error::kEndpointNotInCharge);
}
delete[] buf8;
return MAKE_ERROR(Error::kSuccess);
}

Error CDCDriver::SendSerial(const void* buf, int len) {
uint8_t* buf_out = new uint8_t[len];
memcpy(buf_out, buf, len);
if (auto err = ParentDevice()->NormalOut(ep_bulk_out_, buf_out, len)) {
Log(kError, "%s:%d: NormalOut failed: %s\n", err.File(), err.Line(), err.Name());
return err;
}

uint8_t* buf_in = new uint8_t[8];
if (auto err = ParentDevice()->NormalIn(ep_bulk_in_, buf_in, 8)) {
Log(kError, "%s:%d: NormalIn failed: %s\n", err.File(), err.Line(), err.Name());
return err;
}
return MAKE_ERROR(Error::kSuccess);
}

int CDCDriver::ReceiveSerial(void* buf, int len) {
const auto recv_len = std::min(len, static_cast<int>(receive_buf_.size()));
auto buf8 = reinterpret_cast<uint8_t*>(buf);
for (int i = 0; i < recv_len; ++i) {
buf8[i] = receive_buf_.front();
receive_buf_.pop_front();
}
return recv_len;
}
}
113 changes: 113 additions & 0 deletions kernel/usb/classdriver/cdc.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* @file usb/classdriver/cdc.hpp
*
* CDC class drivers.
*/

#pragma once

#include <cstdint>
#include <deque>

#include "usb/classdriver/base.hpp"
#include "usb/descriptor.hpp"

namespace usb::cdc {
enum class DescriptorSubType : uint8_t {
kHeader = 0,
kCM = 1, // Call Management
kACM = 2, // Abstract Control Management
kUnion = 6,
};

struct FunctionalDescriptor {
static const uint8_t kType = 36; // CS_INTERFACE

uint8_t length; // offset 0
uint8_t descriptor_type; // offset 1
DescriptorSubType descriptor_subtype; // offset 2
} __attribute__((packed));

struct HeaderDescriptor : public FunctionalDescriptor {
static const auto kSubType = DescriptorSubType::kHeader;

uint16_t cdc;
} __attribute__((packed));

struct CMDescriptor : public FunctionalDescriptor {
static const auto kSubType = DescriptorSubType::kCM;

union {
uint8_t data;
struct {
uint8_t handle_call_management : 1;
uint8_t data_interface_usable : 1;
uint8_t : 6;
} __attribute__((packed)) bits;
} capabilities;
uint8_t data_interface;
} __attribute__((packed));

struct ACMDescriptor : public FunctionalDescriptor {
static const auto kSubType = DescriptorSubType::kACM;

union {
uint8_t data;
struct {
uint8_t comm_feature : 1;
uint8_t hw_handshake : 1;
uint8_t send_break : 1;
uint8_t conn_notification : 1;
uint8_t : 4;
} __attribute__((packed)) bits;
} capabilities;
} __attribute__((packed));

struct UnionDescriptor : public FunctionalDescriptor {
static const auto kSubType = DescriptorSubType::kUnion;

uint8_t control_interface;
uint8_t SubordinateInterface(size_t index) const {
return reinterpret_cast<const uint8_t*>(this)[index + 4];
}
} __attribute__((packed));

template <class T>
const T* FuncDescDynamicCast(const uint8_t* desc_data) {
if (desc_data[1] == T::kType &&
desc_data[2] == static_cast<uint8_t>(T::kSubType)) {
return reinterpret_cast<const T*>(desc_data);
}
return nullptr;
}

template <class T>
T* FuncDescDynamicCast(uint8_t* desc_data) {
if (FuncDescDynamicCast<const T>(desc_data)) {
return reinterpret_cast<T*>(desc_data);
}
return nullptr;
}

class CDCDriver : public ClassDriver {
public:
CDCDriver(Device* dev, const InterfaceDescriptor* if_comm,
const InterfaceDescriptor* if_data);

Error Initialize() override;
Error SetEndpoint(const std::vector<EndpointConfig>& configs) override;
Error OnEndpointsConfigured() override;
Error OnControlCompleted(EndpointID ep_id, SetupData setup_data,
const void* buf, int len) override;
Error OnNormalCompleted(EndpointID ep_id, const void* buf, int len) override;

Error SendSerial(const void* buf, int len);
int ReceiveSerial(void* buf, int len);

private:
EndpointID ep_interrupt_in_, ep_bulk_in_, ep_bulk_out_;
std::deque<uint8_t> receive_buf_;
};

inline CDCDriver* driver = nullptr;
}
20 changes: 11 additions & 9 deletions kernel/usb/classdriver/hid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ namespace usb {
return MAKE_ERROR(Error::kNotImplemented);
}

Error HIDBaseDriver::SetEndpoint(const EndpointConfig& config) {
if (config.ep_type == EndpointType::kInterrupt && config.ep_id.IsIn()) {
ep_interrupt_in_ = config.ep_id;
} else if (config.ep_type == EndpointType::kInterrupt && !config.ep_id.IsIn()) {
ep_interrupt_out_ = config.ep_id;
Error HIDBaseDriver::SetEndpoint(const std::vector<EndpointConfig>& configs) {
for (const auto& config : configs) {
if (config.ep_type == EndpointType::kInterrupt && config.ep_id.IsIn()) {
ep_interrupt_in_ = config.ep_id;
} else if (config.ep_type == EndpointType::kInterrupt && !config.ep_id.IsIn()) {
ep_interrupt_out_ = config.ep_id;
}
}
return MAKE_ERROR(Error::kSuccess);
}
Expand All @@ -44,20 +46,20 @@ namespace usb {
this, initialize_phase_, len);
if (initialize_phase_ == 1) {
initialize_phase_ = 2;
return ParentDevice()->InterruptIn(ep_interrupt_in_, buf_.data(), in_packet_size_);
return ParentDevice()->NormalIn(ep_interrupt_in_, buf_.data(), in_packet_size_);
}

return MAKE_ERROR(Error::kNotImplemented);
}

Error HIDBaseDriver::OnInterruptCompleted(EndpointID ep_id, const void* buf, int len) {
Error HIDBaseDriver::OnNormalCompleted(EndpointID ep_id, const void* buf, int len) {
if (ep_id.IsIn()) {
OnDataReceived();
std::copy_n(buf_.begin(), len, previous_buf_.begin());
return ParentDevice()->InterruptIn(ep_interrupt_in_, buf_.data(), in_packet_size_);
return ParentDevice()->NormalIn(ep_interrupt_in_, buf_.data(), in_packet_size_);
}

return MAKE_ERROR(Error::kNotImplemented);
return MAKE_ERROR(Error::kEndpointNotInCharge);
}
}

4 changes: 2 additions & 2 deletions kernel/usb/classdriver/hid.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ namespace usb {
public:
HIDBaseDriver(Device* dev, int interface_index, int in_packet_size);
Error Initialize() override;
Error SetEndpoint(const EndpointConfig& config) override;
Error SetEndpoint(const std::vector<EndpointConfig>& configs) override;
Error OnEndpointsConfigured() override;
Error OnControlCompleted(EndpointID ep_id, SetupData setup_data,
const void* buf, int len) override;
Error OnInterruptCompleted(EndpointID ep_id, const void* buf, int len) override;
Error OnNormalCompleted(EndpointID ep_id, const void* buf, int len) override;

virtual Error OnDataReceived() = 0;
const static size_t kBufferSize = 1024;
Expand Down
Loading

0 comments on commit d4048a3

Please sign in to comment.