Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USB CDCの挙動の改善 #69

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
10 changes: 6 additions & 4 deletions kernel/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -626,11 +626,13 @@ void Terminal::ExecuteLine() {
}

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);
size_t received_len = 0;
while (received_len < send_len) {
int recv_len = usb::cdc::driver->ReceiveSerial(buf.data() + received_len,
send_len - received_len);
received_len += recv_len;
}
files_[1]->Write(buf.data(), recv_len);
files_[1]->Write(buf.data(), received_len);
PrintToFD(*files_[1], "\n");
}();
} else if (strcmp(command, "setbaud") == 0) {
Expand Down
50 changes: 40 additions & 10 deletions kernel/usb/classdriver/cdc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ namespace usb::cdc {
CDCDriver::CDCDriver(Device* dev, const InterfaceDescriptor* if_comm,
const InterfaceDescriptor* if_data)
: ClassDriver{dev},
if_data_index_{if_data->interface_number}
if_comm_index_{if_comm->interface_number}
{
}

Expand All @@ -25,6 +25,7 @@ namespace usb::cdc {
ep_interrupt_in_ = config.ep_id;
} else if (config.ep_type == EndpointType::kBulk && config.ep_id.IsIn()) {
ep_bulk_in_ = config.ep_id;
buf_in_.resize(config.max_packet_size);
} else if (config.ep_type == EndpointType::kBulk && !config.ep_id.IsIn()) {
ep_bulk_out_ = config.ep_id;
}
Expand All @@ -33,13 +34,43 @@ namespace usb::cdc {
}

Error CDCDriver::OnEndpointsConfigured() {
return MAKE_ERROR(Error::kSuccess);
// 現在の通信設定を取得する
line_coding_initialization_status_ = 1;
SetupData setup_data{};
setup_data.request_type.bits.direction = request_type::kIn;
setup_data.request_type.bits.type = request_type::kClass;
setup_data.request_type.bits.recipient = request_type::kInterface;
setup_data.request = request::kGetLineCoding;
setup_data.value = 0;
setup_data.index = if_comm_index_;
setup_data.length = sizeof(LineCoding);
return ParentDevice()->ControlIn(
kDefaultControlPipeID, setup_data,
&line_coding_, sizeof(LineCoding), this);
}

Error CDCDriver::OnControlCompleted(EndpointID ep_id, SetupData setup_data,
const void* buf, int len) {
Log(kDebug, "CDCDriver::OnControlCompleted: req_type=0x%02x req=0x%02x len=%u\n",
setup_data.request_type.data, setup_data.request, len);
if (line_coding_initialization_status_ == 1) {
if (setup_data.request == request::kGetLineCoding) {
if (line_coding_.dte_rate == 0) {
line_coding_ = LineCoding{9600, CharFormat::kStopBit1, ParityType::kNone, 8};
}
line_coding_initialization_status_ = 2;
return SetLineCoding(line_coding_);
}
} else if (line_coding_initialization_status_ == 2) {
if (setup_data.request == request::kSetLineCoding) {
line_coding_initialization_status_ = 0;
// 受信を開始する
if (auto err = ParentDevice()->NormalIn(ep_bulk_in_, buf_in_.data(), buf_in_.size())) {
Log(kError, "%s:%d: NormalIn failed: %s\n", err.File(), err.Line(), err.Name());
return err;
}
}
}
return MAKE_ERROR(Error::kSuccess);
}

Expand All @@ -48,11 +79,16 @@ namespace usb::cdc {
auto buf8 = reinterpret_cast<const uint8_t*>(buf);
if (ep_id == ep_bulk_in_) {
std::copy_n(buf8, len, std::back_inserter(receive_buf_));
// 次の受信を開始する
if (auto err = ParentDevice()->NormalIn(ep_bulk_in_, buf_in_.data(), buf_in_.size())) {
Log(kError, "%s:%d: NormalIn failed: %s\n", err.File(), err.Line(), err.Name());
return err;
}
} else if (ep_id == ep_bulk_out_) {
delete[] buf8;
} else {
return MAKE_ERROR(Error::kEndpointNotInCharge);
}
delete[] buf8;
return MAKE_ERROR(Error::kSuccess);
}

Expand All @@ -63,12 +99,6 @@ namespace usb::cdc {
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);
}

Expand All @@ -89,7 +119,7 @@ namespace usb::cdc {
setup_data.request_type.bits.recipient = request_type::kInterface;
setup_data.request = request::kSetLineCoding;
setup_data.value = 0;
setup_data.index = if_data_index_;
setup_data.index = if_comm_index_;
setup_data.length = sizeof(LineCoding);

line_coding_ = value;
Expand Down
5 changes: 4 additions & 1 deletion kernel/usb/classdriver/cdc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include <cstdint>
#include <deque>
#include <vector>

#include "usb/classdriver/base.hpp"
#include "usb/descriptor.hpp"
Expand Down Expand Up @@ -129,8 +130,10 @@ namespace usb::cdc {
private:
EndpointID ep_interrupt_in_, ep_bulk_in_, ep_bulk_out_;
std::deque<uint8_t> receive_buf_;
uint8_t if_data_index_;
uint8_t if_comm_index_;
LineCoding line_coding_;
int line_coding_initialization_status_{};
std::vector<uint8_t> buf_in_;
};

inline CDCDriver* driver = nullptr;
Expand Down
13 changes: 13 additions & 0 deletions kernel/usb/descriptor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,19 @@ namespace usb {
uint8_t max_power; // offset 8
} __attribute__((packed));

struct InterfaceAssociationDescriptor {
static const uint8_t kType = 11;

uint8_t length; // offset 0
uint8_t descriptor_type; // offset 1
uint8_t first_interface; // offset 2
uint8_t interface_count; // offset 3
uint8_t function_class; // offset 4
uint8_t function_sub_class; // offset 5
uint8_t function_protocol; // offset 6
uint8_t function; // offset 7
} __attribute__((packed));

struct InterfaceDescriptor {
static const uint8_t kType = 4;

Expand Down
122 changes: 82 additions & 40 deletions kernel/usb/device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ namespace {
return conf;
}

void Log(LogLevel level, const usb::InterfaceAssociationDescriptor& ia_desc) {
Log(level, "Interface Association Descriptor: num_if=%d class=%d sub=%d protocol=%d\n",
ia_desc.interface_count,
ia_desc.function_class,
ia_desc.function_sub_class,
ia_desc.function_protocol);
}

void Log(LogLevel level, const usb::InterfaceDescriptor& if_desc) {
Log(level, "Interface Descriptor %d: num_ep=%d class=%d sub=%d protocol=%d\n",
if_desc.interface_number,
Expand Down Expand Up @@ -81,6 +89,22 @@ namespace {
Log(level, "\n");
}

void GetEndPoints(
std::vector<usb::EndpointConfig>& ep_configs,
ConfigurationDescriptorReader& conf_reader,
int num_endpoints) {
for (int ep_index = 0; ep_index < num_endpoints;) {
auto desc = conf_reader.Next();
if (auto ep_desc = usb::DescriptorDynamicCast<usb::EndpointDescriptor>(desc)) {
ep_configs.push_back(MakeEPConfig(*ep_desc));
Log(kDebug, ep_configs.back());
++ep_index;
} else if (auto hid_desc = usb::DescriptorDynamicCast<usb::HIDDescriptor>(desc)) {
Log(kDebug, *hid_desc);
}
}
}

usb::ClassDriver* NewClassDriver(usb::Device* dev, const usb::InterfaceDescriptor& if_desc) {
if (if_desc.interface_class == 3 &&
if_desc.interface_sub_class == 1) { // HID boot interface
Expand All @@ -106,24 +130,26 @@ namespace {
usb::Device* dev,
ConfigurationDescriptorReader& conf_reader) {
using namespace usb::cdc;
Log(kWarn, "creating class driver for class=%d\n", dev->DeviceDesc().device_class);

if (dev->DeviceDesc().device_class == 2) {
auto cdc_driver = [&](int num_interface = -1) -> WithError<usb::ClassDriver*> {
const usb::InterfaceDescriptor* if_comm = nullptr;
const usb::InterfaceDescriptor* if_data = nullptr;
while (auto if_desc = conf_reader.Next<usb::InterfaceDescriptor>()) {
for (int i = 0; num_interface < 0 || i < num_interface; ++i) {
auto if_desc = conf_reader.Next<usb::InterfaceDescriptor>();
if (!if_desc) break;
Log(kWarn, *if_desc);
if (if_desc->interface_class == 2) {
if_comm = if_desc;
} else if (if_desc->interface_class == 10) {
if_data = if_desc;
}

for (int i = 0; i < if_desc->num_endpoints; ++i) {
for (int j = 0; j < if_desc->num_endpoints; ) {
auto desc = conf_reader.Next();
if (auto ep_desc = usb::DescriptorDynamicCast<usb::EndpointDescriptor>(desc)) {
ep_configs.push_back(MakeEPConfig(*ep_desc));
Log(kWarn, ep_configs.back());
++j;
} else if (auto cdc = FuncDescDynamicCast<HeaderDescriptor>(desc)) {
Log(kWarn, "kHeader: cdc=%04x\n", cdc->cdc);
} else if (auto call = FuncDescDynamicCast<CMDescriptor>(desc)) {
Expand All @@ -141,6 +167,50 @@ namespace {

usb::cdc::driver = new usb::cdc::CDCDriver{dev, if_comm, if_data};
return { usb::cdc::driver, MAKE_ERROR(Error::kSuccess) };
};

auto drop_iad = [&](int num_interface) {
for (int i = 0; num_interface < 0 || i < num_interface; ++i) {
auto if_desc = conf_reader.Next<usb::InterfaceDescriptor>();
if (!if_desc) break;
Log(kWarn, *if_desc);
for (int j = 0; j < if_desc->num_endpoints; ) {
auto desc = conf_reader.Next();
if (auto ep_desc = usb::DescriptorDynamicCast<usb::EndpointDescriptor>(desc)) {
Log(kWarn, MakeEPConfig(*ep_desc));
++j;
}
}
}
};

const auto& device_desc = dev->DeviceDesc();
if (device_desc.device_class == 0 ||
(device_desc.device_class == 0xef &&
device_desc.device_sub_class == 2 &&
device_desc.device_protocol == 1)) { // Interface Association Descriptor
while (auto desc = conf_reader.Next()) {
if (auto ia_desc = usb::DescriptorDynamicCast<usb::InterfaceAssociationDescriptor>(desc)) {
Log(kDebug, *ia_desc);
if (ia_desc->function_class == 2) {
return cdc_driver(ia_desc->interface_count);
}
drop_iad(ia_desc->interface_count);
} else if (auto if_desc = usb::DescriptorDynamicCast<usb::InterfaceDescriptor>(desc)) {
Log(kDebug, *if_desc);
auto class_driver = NewClassDriver(dev, *if_desc);
if (class_driver != nullptr) {
GetEndPoints(ep_configs, conf_reader, if_desc->num_endpoints);
return { class_driver, MAKE_ERROR(Error::kSuccess) };
}
}
}
return { nullptr, MAKE_ERROR(Error::kSuccess) };
}

Log(kWarn, "creating class driver for class=%d\n", device_desc.device_class);
if (device_desc.device_class == 2) {
return cdc_driver();
}
return { nullptr, MAKE_ERROR(Error::kNotImplemented) };
}
Expand Down Expand Up @@ -259,43 +329,15 @@ namespace usb {
}
ConfigurationDescriptorReader config_reader{buf, len};

if (device_desc_.device_class != 0) {
auto [ class_driver, err ] =
NewClassDriver(ep_configs_, this, config_reader);
if (err) {
return err;
}
class_drivers_.push_back(class_driver);
} else {
bool no_class_driver = true;
while (auto if_desc = config_reader.Next<InterfaceDescriptor>()) {
Log(kDebug, *if_desc);

auto class_driver = NewClassDriver(this, *if_desc);
if (class_driver == nullptr) {
// 非対応デバイス.次の interface を調べる.
continue;
}
no_class_driver = false;
class_drivers_.push_back(class_driver);

for (int ep_index = 0; ep_index < if_desc->num_endpoints;) {
auto desc = config_reader.Next();
if (auto ep_desc = DescriptorDynamicCast<EndpointDescriptor>(desc)) {
ep_configs_.push_back(MakeEPConfig(*ep_desc));
Log(kDebug, ep_configs_.back());
++ep_index;
} else if (auto hid_desc = DescriptorDynamicCast<HIDDescriptor>(desc)) {
Log(kDebug, *hid_desc);
}
}
break;
}

if (no_class_driver) {
return MAKE_ERROR(Error::kSuccess);
}
auto [ class_driver, err ] =
NewClassDriver(ep_configs_, this, config_reader);
if (err) {
return err;
}
if (class_driver == nullptr) {
return MAKE_ERROR(Error::kSuccess);
}
class_drivers_.push_back(class_driver);

initialize_phase_ = 3;
Log(kDebug, "issuing SetConfiguration: conf_val=%d\n",
Expand Down