Comparar commits

...

1 Commits

Autor SHA1 Mensagem Data
Mike Voydanoff 939e6a30c0 start on virtual USB
Change-Id: Id8bd23580a56ac0b54f168370e17a96bf7c63aae
2017-07-19 09:40:08 -07:00
15 arquivos alterados com 1037 adições e 0 exclusões
+206
Ver Arquivo
@@ -0,0 +1,206 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ddk/binding.h>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/protocol/usb-client.h>
static const usb_device_descriptor_t device_desc = {
.bLength = sizeof(usb_device_descriptor_t),
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = htole16(0x0200),
.bDeviceClass = 0,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
.bMaxPacketSize0 = 64,
.idVendor = htole16(0x18D1),
.idProduct = htole16(0x1234),
.bcdDevice = htole16(0x0100),
.iManufacturer = 0,
.iProduct = 0,
.iSerialNumber = 0,
.bNumConfigurations = 1,
};
static const struct {
usb_configuration_descriptor_t config;
usb_interface_descriptor_t intf;
usb_endpoint_descriptor_t endp1;
usb_endpoint_descriptor_t endp2;
} config_desc = {
.config = {
.bLength = sizeof(usb_configuration_descriptor_t),
.bDescriptorType = USB_DT_CONFIG,
.wTotalLength = htole16(sizeof(config_desc)),
.bNumInterfaces = 1,
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0xE0, // self powered
.bMaxPower = 0,
},
.intf = {
.bLength = sizeof(usb_interface_descriptor_t),
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
.bAlternateSetting = 0,
.bNumEndpoints = 1,
.bInterfaceClass = 255,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.iInterface = 0,
},
.endp1 = {
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_IN | 1,
.bmAttributes = USB_ENDPOINT_BULK,
.wMaxPacketSize = htole16(512),
.bInterval = 0,
},
.endp2 = {
.bLength = sizeof(usb_endpoint_descriptor_t),
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_ENDPOINT_OUT | 1,
.bmAttributes = USB_ENDPOINT_BULK,
.wMaxPacketSize = htole16(512),
.bInterval = 0,
},
};
typedef struct {
mx_device_t* mxdev;
usb_client_protocol_t usb_client;
} usb_client_test_t;
static mx_status_t usb_client_get_descriptor(uint8_t request_type, uint16_t value, uint16_t index,
void* buffer, uint length) {
uint8_t type = request_type & USB_TYPE_MASK;
uint8_t recipient = request_type & USB_RECIP_MASK;
if (type == USB_TYPE_STANDARD && recipient == USB_RECIP_DEVICE) {
uint8_t desc_type = value >> 8;
if (desc_type == USB_DT_DEVICE && index == 0) {
if (length > sizeof(device_desc)) length = sizeof(device_desc);
memcpy(buffer, &device_desc, length);
return length;
} else if (desc_type == USB_DT_CONFIG && index == 0) {
if (length > sizeof(config_desc)) length = sizeof(config_desc);
memcpy(buffer, &config_desc, length);
return length;
}
/* else if (value >> 8 == USB_DT_STRING) {
uint8_t string_index = value & 0xFF;
if (string_index < countof(xhci_rh_string_table)) {
const uint8_t* string = xhci_rh_string_table[string_index];
if (length > string[0]) length = string[0];
txn->ops->copyto(txn, string, length, 0);
txn->ops->complete(txn, MX_OK, length);
return MX_OK;
}
}*/
}
printf("usb_client_get_descriptor unsupported value: %d index: %d\n", value, index);
return MX_ERR_NOT_SUPPORTED;
}
static mx_status_t client_test_control(void* ctx, const usb_setup_t* setup, void* buffer,
int buffer_length) {
uint8_t request_type = setup->bmRequestType;
uint8_t request = setup->bRequest;
uint16_t value = le16toh(setup->wValue);
uint16_t index = le16toh(setup->wIndex);
uint16_t length = le16toh(setup->wLength);
if (length > buffer_length) length = buffer_length;
printf("client_test_control type: 0x%02X req: %d value: %d index: %d length: %d\n",
request_type, request, value, index, length);
if ((request_type & USB_DIR_MASK) == USB_DIR_IN && request == USB_REQ_GET_DESCRIPTOR) {
return usb_client_get_descriptor(request_type, value, index, buffer, length);
} else if (request_type == (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE) &&
request == USB_REQ_SET_CONFIGURATION && length == 0) {
return MX_OK;
}
return MX_ERR_NOT_SUPPORTED;
}
usb_client_interface_ops_t client_ops = {
.control = client_test_control,
};
static void usb_client_test_unbind(void* ctx) {
printf("usb_client_test_unbind\n");
usb_client_test_t* test = ctx;
device_remove(test->mxdev);
}
static void usb_client_test_release(void* ctx) {
printf("usb_client_test_release\n");
usb_client_test_t* test = ctx;
free(test);
}
static mx_protocol_device_t usb_client_test_proto = {
.version = DEVICE_OPS_VERSION,
.unbind = usb_client_test_unbind,
.release = usb_client_test_release,
};
mx_status_t usb_client_test_bind(void* ctx, mx_device_t* parent, void** cookie) {
printf("usb_client_test_bind\n");
usb_client_test_t* test = calloc(1, sizeof(usb_client_test_t));
if (!test) {
return MX_ERR_NO_MEMORY;
}
if (device_get_protocol(parent, MX_PROTOCOL_USB_CLIENT, &test->usb_client)) {
free(test);
return MX_ERR_NOT_SUPPORTED;
}
device_add_args_t args = {
.version = DEVICE_ADD_ARGS_VERSION,
.name = "usb-client-test",
.ctx = test,
.ops = &usb_client_test_proto,
// .proto_id = MX_PROTOCOL_USB_CLIENT,
// .proto_ops = &client_ops,
};
mx_status_t status = device_add(parent, &args, &test->mxdev);
if (status != MX_OK) {
printf("usb_client_bind add_device failed %d\n", status);
free(test);
return status;
}
usb_client_interface_t intf = {
.ops = &client_ops,
.ctx = test,
};
usb_client_set_interface(&test->usb_client, &intf);
return MX_OK;
}
static mx_driver_ops_t usb_client_test_ops = {
.version = DRIVER_OPS_VERSION,
.bind = usb_client_test_bind,
};
// clang-format off
MAGENTA_DRIVER_BEGIN(usb_client_test, usb_client_test_ops, "magenta", "0.1", 1)
BI_MATCH_IF(EQ, BIND_PROTOCOL, MX_PROTOCOL_USB_CLIENT),
MAGENTA_DRIVER_END(usb_client_test)
+21
Ver Arquivo
@@ -0,0 +1,21 @@
#Copyright 2017 The Fuchsia Authors.All rights reserved.
#Use of this source code is governed by a BSD - style license that can be
#found in the LICENSE file.
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_TYPE := driver
MODULE_SRCS += \
$(LOCAL_DIR)/client-test.c \
MODULE_STATIC_LIBS := system/ulib/ddk
MODULE_LIBS := \
system/ulib/driver \
system/ulib/magenta \
system/ulib/c
include make/module.mk
+26
Ver Arquivo
@@ -0,0 +1,26 @@
# Copyright 2017 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_TYPE := driver
MODULE_SRCS += \
$(LOCAL_DIR)/usb-virtual-bus.c \
$(LOCAL_DIR)/usb-virtual-client.c \
$(LOCAL_DIR)/usb-virtual-hci.c \
$(LOCAL_DIR)/util.c \
MODULE_STATIC_LIBS := \
system/ulib/ddk \
system/ulib/sync
MODULE_LIBS := \
system/ulib/driver \
system/ulib/magenta \
system/ulib/c
include make/module.mk
@@ -0,0 +1,79 @@
// Copyright 2017 The Fuchsia Authors. All riusghts reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/binding.h>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/protocol/usb-hci.h>
#include <magenta/syscalls.h>
#include <stdlib.h>
#include <stdio.h>
#include <threads.h>
#include "usb-virtual-bus.h"
typedef struct {
mx_device_t* mxdev;
mx_device_t* hci_dev;
mx_device_t* client_dev;
} usb_virtual_bus_t;
static void usb_bus_unbind(void* ctx) {
usb_virtual_bus_t* bus = ctx;
device_remove(bus->hci_dev);
device_remove(bus->client_dev);
device_remove(bus->mxdev);
}
static void usb_bus_release(void* ctx) {
usb_virtual_bus_t* bus = ctx;
free(bus);
}
static mx_protocol_device_t usb_virtual_bus_proto = {
.version = DEVICE_OPS_VERSION,
.unbind = usb_bus_unbind,
.release = usb_bus_release,
};
static mx_status_t usb_virtual_bus_bind(void* ctx, mx_device_t* parent, void** cookie) {
printf("usb_virtual_bus_bind\n");
usb_virtual_bus_t* bus = calloc(1, sizeof(usb_virtual_bus_t));
if (!bus) {
return MX_ERR_NO_MEMORY;
}
device_add_args_t args = {
.version = DEVICE_ADD_ARGS_VERSION,
.name = "usb-virtual-bus",
.ctx = bus,
.ops = &usb_virtual_bus_proto,
.flags = DEVICE_ADD_NON_BINDABLE,
};
mx_status_t status = device_add(parent, &args, &bus->mxdev);
if (status != MX_OK) {
free(bus);
return status;
}
mx_handle_t channel_handles[2];
mx_channel_create(0, &channel_handles[0], &channel_handles[1]);
bus->hci_dev = usb_virtual_hci_add(bus->mxdev, channel_handles[0]);
bus->client_dev = usb_virtual_client_add(bus->mxdev, channel_handles[1]);
return MX_OK;
}
static mx_driver_ops_t bus_driver_ops = {
.version = DRIVER_OPS_VERSION,
.bind = usb_virtual_bus_bind,
};
// clang-format off
MAGENTA_DRIVER_BEGIN(usb_virtual_bus, bus_driver_ops, "magenta", "0.1", 1)
BI_MATCH_IF(EQ, BIND_PROTOCOL, MX_PROTOCOL_MISC_PARENT),
MAGENTA_DRIVER_END(usb_virtual_bus)
@@ -0,0 +1,35 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <magenta/types.h>
typedef enum {
// Sent from client to host to simulate device connect/disconnect
USB_VIRT_CONNECT,
USB_VIRT_DISCONNECT,
// Sent from either side to simulate packet send
USB_VIRT_PACKET,
USB_VIRT_PACKET_RESP,
} usb_virt_channel_cmd_t;
#define USB_VIRT_MAX_PACKET (65536)
#define USB_VIRT_BUFFER_SIZE (USB_VIRT_MAX_PACKET + sizeof(usb_virt_channel_cmd_t))
typedef struct {
usb_virt_channel_cmd_t cmd;
// endpoint address for USB_VIRT_PACKET
size_t data_length;
mx_status_t status;
uintptr_t cookie;
uint8_t ep_addr;
uint8_t padding[3]; // align data to 4 byte boundary
uint8_t data[0]; // variable length packet data
} usb_virt_header_t;
mx_device_t* usb_virtual_hci_add(mx_device_t* parent, mx_handle_t channel_handle);
mx_device_t* usb_virtual_client_add(mx_device_t* parent, mx_handle_t channel_handle);
@@ -0,0 +1,204 @@
// Copyright 2017 The Fuchsia Authors. All riusghts reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/binding.h>
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/protocol/usb-client.h>
#include <ddk/protocol/usb.h>
#include <magenta/types.h>
#include <magenta/device/usb-client.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include "usb-virtual-bus.h"
typedef struct {
// the device we implement
mx_device_t* mxdev;
mx_handle_t channel_handle;
usb_client_interface_t interface;
} usb_virtual_client_t;
static void handle_packet(usb_virtual_client_t* client, usb_virt_header_t* header) {
printf("handle_packet length %zu\n", header->data_length);
char response_buffer[USB_VIRT_BUFFER_SIZE];
usb_virt_header_t* response = (usb_virt_header_t *)response_buffer;
if (header->ep_addr == 0 && header->data_length >= sizeof(usb_setup_t)) {
mx_status_t status;
if (client->interface.ops) {
usb_setup_t* setup = (usb_setup_t *)header->data;
printf("handle_packet type: 0x%02X req: %d value: %d index: %d length: %d\n",
setup->bmRequestType, setup->bRequest, le16toh(setup->wValue), le16toh(setup->wIndex), le16toh(setup->wLength));
void* buffer;
size_t length;
if ((setup->bmRequestType & USB_DIR_MASK) == USB_DIR_IN) {
buffer = response->data;
length = sizeof(response_buffer) - sizeof(usb_virt_header_t);
} else {
buffer = setup + 1;
length = header->data_length - sizeof(*setup);
}
status = usb_client_intf_control(&client->interface, setup, buffer, length);
printf("control returned %d\n", status);
} else {
status = MX_ERR_UNAVAILABLE;
}
// send response
printf("status %d write response\n", status);
response->cmd = USB_VIRT_PACKET_RESP;
response->cookie = header->cookie;
response->status = (status > 0 ? MX_OK : status);
response->data_length = (status < 0 ? 0 : status);
size_t packet_length = sizeof(usb_virt_header_t);
if (status > 0) packet_length += status;
mx_channel_write(client->channel_handle, 0, response, packet_length, NULL, 0);
} else {
printf("non ep0 not supported yet\n");
}
}
static mx_status_t usb_virtual_client_set_interface(void* ctx, usb_client_interface_t* interface) {
printf("usb_virtual_client_set_callbacks\n");
usb_virtual_client_t* client = ctx;
memcpy(&client->interface, interface, sizeof(client->interface));
return MX_OK;
}
static mx_status_t usb_virtual_client_config_ep(void* ctx,
const usb_endpoint_descriptor_t* ep_desc) {
return MX_OK;
}
static void usb_virtual_client_set_connected(usb_virtual_client_t* client, bool connected) {
usb_virt_header_t connect;
connect.cmd = (connected ? USB_VIRT_CONNECT : USB_VIRT_DISCONNECT);
mx_channel_write(client->channel_handle, 0, &connect, sizeof(connect), NULL, 0);
}
usb_client_protocol_ops_t virtual_client_protocol = {
.set_interface = usb_virtual_client_set_interface,
.config_ep = usb_virtual_client_config_ep,
};
static mx_status_t usb_virtual_client_open(void* ctx, mx_device_t** dev_out, uint32_t flags) {
printf("usb_virtual_client_open\n");
return MX_OK;
}
static mx_status_t usb_virtual_client_ioctl(void* ctx, uint32_t op, const void* in_buf,
size_t in_len, void* out_buf, size_t out_len,
size_t* out_actual) {
usb_virtual_client_t* client = ctx;
switch (op) {
case IOCTL_USB_CLIENT_SET_CONNNECTED: {
if (!in_buf || in_len != sizeof(int)) {
return MX_ERR_INVALID_ARGS;
}
int connected = *((int *)in_buf);
printf("IOCTL_USB_CLIENT_SET_CONNNECTED %d\n", connected);
usb_virtual_client_set_connected(client, !!connected);
return MX_OK;
}
}
return MX_ERR_NOT_SUPPORTED;
}
static void usb_virtual_client_iotxn_queue(void* ctx, iotxn_t* txn) {
}
static void usb_virtual_client_unbind(void* ctx) {
printf("usb_virtual_client_unbind\n");
// usb_virtual_client_t* client = dev_to_usb_virtual_client(dev);
}
static void usb_virtual_client_release(void* ctx) {
// FIXME - do something here
}
static mx_protocol_device_t usb_virtual_client_device_proto = {
.version = DEVICE_OPS_VERSION,
.open = usb_virtual_client_open,
.ioctl = usb_virtual_client_ioctl,
.iotxn_queue = usb_virtual_client_iotxn_queue,
.unbind = usb_virtual_client_unbind,
.release = usb_virtual_client_release,
};
static int usb_virtual_client_thread(void* arg) {
usb_virtual_client_t* client = (usb_virtual_client_t*)arg;
printf("usb_virtual_client_thread\n");
while (1) {
char buffer[USB_VIRT_BUFFER_SIZE];
uint32_t actual;
mx_status_t status = mx_object_wait_one(client->channel_handle, MX_CHANNEL_READABLE, MX_TIME_INFINITE, NULL);
printf("mx_object_wait_one returned %d\n", status);
status = mx_channel_read(client->channel_handle, 0, buffer, NULL, sizeof(buffer), 0,
&actual, NULL);
if (status != MX_OK) {
printf("usb_virtual_client_thread mx_channel_read failed %d\n", status);
return status;
}
usb_virt_header_t* header = (usb_virt_header_t *)buffer;
switch (header->cmd) {
case USB_VIRT_PACKET:
printf("client got packet\n");
handle_packet(client, header);
break;
default:
printf("usb_virtual_client_thread bad command %d\n", header->cmd);
break;
}
}
return 0;
}
mx_device_t* usb_virtual_client_add(mx_device_t* parent, mx_handle_t channel_handle) {
printf("usb_virtual_client_add\n");
usb_virtual_client_t* client = calloc(1, sizeof(usb_virtual_client_t));
if (!client) {
mx_handle_close(channel_handle);
return NULL;
}
client->channel_handle = channel_handle;
device_add_args_t args = {
.version = DEVICE_ADD_ARGS_VERSION,
.name = "usb-virtual-client",
.ctx = client,
.ops = &usb_virtual_client_device_proto,
.proto_id = MX_PROTOCOL_USB_CLIENT,
.proto_ops = &virtual_client_protocol,
};
mx_status_t status = device_add(parent, &args, &client->mxdev);
if (status != MX_OK) {
printf("usb_virtual_client_add device_add failed %d\n", status);
mx_handle_close(channel_handle);
free(client);
return NULL;
}
thrd_t thread;
thrd_create_with_name(&thread, usb_virtual_client_thread, client, "usb_virtual_client_thread");
thrd_detach(thread);
return client->mxdev;
}
@@ -0,0 +1,290 @@
// Copyright 2017 The Fuchsia Authors. All riusghts reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <ddk/device.h>
#include <ddk/driver.h>
#include <ddk/protocol/usb-bus.h>
#include <ddk/protocol/usb-hci.h>
#include <ddk/protocol/usb.h>
#include <sync/completion.h>
#include <magenta/listnode.h>
#include <magenta/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <threads.h>
#include "usb-virtual-bus.h"
#include "util.h"
#define CLIENT_SLOT_ID 0
#define CLIENT_HUB_ID 0
#define CLIENT_SPEED USB_SPEED_HIGH
typedef struct {
mx_device_t* mxdev;
usb_bus_interface_t bus;
mx_handle_t channel_handle;
mtx_t lock;
completion_t completion;
bool connected;
bool was_connected;
list_node_t ep_txns[USB_MAX_EPS];
} usb_virtual_hci_t;
static void usb_virtual_hci_set_bus_interface(void* ctx, usb_bus_interface_t* bus) {
usb_virtual_hci_t* hci = ctx;
if (bus) {
memcpy(&hci->bus, bus, sizeof(hci->bus));
mtx_lock(&hci->lock);
bool connected = hci->connected;
hci->was_connected = connected;
mtx_unlock(&hci->lock);
if (connected) {
usb_bus_add_device(&hci->bus, CLIENT_SLOT_ID, CLIENT_HUB_ID, CLIENT_SPEED);
}
} else {
memset(&hci->bus, 0, sizeof(hci->bus));
}
}
static size_t usb_virtual_hci_get_max_device_count(void* ctx) {
return 1;
}
static mx_status_t usb_virtual_hci_enable_ep(void* ctx, uint32_t device_id,
usb_endpoint_descriptor_t* ep_desc,
usb_ss_ep_comp_descriptor_t* ss_comp_desc, bool enable) {
return MX_OK;
}
static uint64_t usb_virtual_hci_get_frame(void* ctx) {
return 0;
}
mx_status_t usb_virtual_hci_config_hub(void* ctx, uint32_t device_id, usb_speed_t speed,
usb_hub_descriptor_t* descriptor) {
return MX_OK;
}
mx_status_t usb_virtual_hci_hub_device_added(void* ctx, uint32_t hub_address, int port,
usb_speed_t speed) {
return MX_OK;
}
mx_status_t usb_virtual_hci_hub_device_removed(void* ctx, uint32_t hub_address, int port) {
return MX_OK;
}
mx_status_t usb_virtual_hci_reset_endpoint(void* ctx, uint32_t device_id, uint8_t ep_address) {
return MX_ERR_NOT_SUPPORTED;
}
size_t usb_virtual_hci_get_max_transfer_size(void* ctx, uint32_t device_id, uint8_t ep_address) {
return 65536;
}
static usb_hci_protocol_ops_t virtual_hci_protocol = {
.set_bus_interface = usb_virtual_hci_set_bus_interface,
.get_max_device_count = usb_virtual_hci_get_max_device_count,
.enable_endpoint = usb_virtual_hci_enable_ep,
.get_current_frame = usb_virtual_hci_get_frame,
.configure_hub = usb_virtual_hci_config_hub,
.hub_device_added = usb_virtual_hci_hub_device_added,
.hub_device_removed = usb_virtual_hci_hub_device_removed,
.reset_endpoint = usb_virtual_hci_reset_endpoint,
.get_max_transfer_size = usb_virtual_hci_get_max_transfer_size,
};
static void usb_virtual_hci_iotxn_queue(void* ctx, iotxn_t* txn) {
printf("usb_virtual_hci_iotxn_queue\n");
usb_virtual_hci_t* hci = ctx;
usb_protocol_data_t* data = iotxn_pdata(txn, usb_protocol_data_t);
if (data->device_id != CLIENT_SLOT_ID) {
iotxn_complete(txn, MX_ERR_INVALID_ARGS, 0);
return;
}
uint8_t ep_index = ep_addr_to_index(data->ep_address);
if (ep_index >= USB_MAX_EPS) {
iotxn_complete(txn, MX_ERR_INVALID_ARGS, 0);
return;
}
if (txn->length > USB_VIRT_MAX_PACKET) {
iotxn_complete(txn, MX_ERR_OUT_OF_RANGE, 0);
return;
}
// queue the transaction for the specified endpoint
list_add_tail(&hci->ep_txns[ep_index], &txn->node);
bool out = ((data->ep_address & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT);
if (out) {
char buffer[USB_VIRT_BUFFER_SIZE];
usb_virt_header_t* header = (usb_virt_header_t *)buffer;
header->cmd = USB_VIRT_PACKET;
header->cookie = (uintptr_t)txn;
header->ep_addr = data->ep_address;
if (data->ep_address == 0) {
usb_setup_t* setup = (usb_setup_t *)header->data;
memcpy(setup, &data->setup, sizeof(usb_setup_t));
printf("sending type: 0x%02X req: %d value: %d index: %d length: %d\n",
setup->bmRequestType, setup->bRequest, le16toh(setup->wValue), le16toh(setup->wIndex), le16toh(setup->wLength));
header->data_length = sizeof(usb_setup_t);
if (txn->length > 0 && (setup->bmRequestType & USB_DIR_MASK) == USB_DIR_OUT) {
header->data_length += txn->length;
iotxn_copyfrom(txn, &header->data[sizeof(usb_setup_t)], txn->length, 0);
}
} else {
// FIXME only for out direction
header->data_length = txn->length;
iotxn_copyfrom(txn, header->data, txn->length, 0);
}
mx_channel_write(hci->channel_handle, 0, buffer, sizeof(usb_virt_header_t) + header->data_length,
NULL, 0);
}
}
static void usb_virtual_hci_unbind(void* ctx) {
printf("usb_virtual_hci_unbind\n");
usb_virtual_hci_t* hci = ctx;
device_remove(hci->mxdev);
}
static void usb_virtual_hci_release(void* ctx) {
printf("usb_virtual_hci_release\n");
usb_virtual_hci_t* hci = ctx;
mx_handle_close(hci->channel_handle);
free(hci);
}
static mx_protocol_device_t usb_virtual_hci_device_proto = {
.version = DEVICE_OPS_VERSION,
.iotxn_queue = usb_virtual_hci_iotxn_queue,
.unbind = usb_virtual_hci_unbind,
.release = usb_virtual_hci_release,
};
static int connection_thread(void* arg) {
usb_virtual_hci_t* hci = (usb_virtual_hci_t*)arg;
while (1) {
completion_wait(&hci->completion, MX_TIME_INFINITE);
mtx_lock(&hci->lock);
bool connect = hci->connected && !hci->was_connected;
bool disconnect = !hci->connected && hci->was_connected;
hci->was_connected = hci->connected;
mtx_unlock(&hci->lock);
if (hci->bus.ops) {
if (connect) {
usb_bus_add_device(&hci->bus, CLIENT_SLOT_ID, CLIENT_HUB_ID, CLIENT_SPEED);
} else if (disconnect) {
usb_bus_remove_device(&hci->bus, CLIENT_SLOT_ID);
}
}
}
return 0;
}
static int channel_thread(void* arg) {
usb_virtual_hci_t* hci = (usb_virtual_hci_t*)arg;
printf("channel_thread\n");
while (1) {
char buffer[USB_VIRT_BUFFER_SIZE];
uint32_t actual;
mx_status_t status = mx_object_wait_one(hci->channel_handle, MX_CHANNEL_READABLE,
MX_TIME_INFINITE, NULL);
status = mx_channel_read(hci->channel_handle, 0, buffer, NULL, sizeof(buffer), 0,
&actual, NULL);
if (status != MX_OK) {
printf("channel_thread mx_channel_read failed %d\n", status);
return status;
}
usb_virt_header_t* header = (usb_virt_header_t *)buffer;
switch (header->cmd) {
case USB_VIRT_CONNECT:
case USB_VIRT_DISCONNECT:
mtx_lock(&hci->lock);
hci->connected = (header->cmd == USB_VIRT_CONNECT);
mtx_unlock(&hci->lock);
completion_signal(&hci->completion);
break;
case USB_VIRT_PACKET:
printf("HCI: USB_VIRT_PACKET\n");
break;
case USB_VIRT_PACKET_RESP: {
printf("HCI: USB_VIRT_PACKET_RESP status %d length %zu\n", header->status, header->data_length);
iotxn_t* txn = (iotxn_t *)header->cookie;
if (header->data_length > 0) {
printf("copyto header %p data %p length %zu\n", header, header->data, header->data_length);
iotxn_copyto(txn, header->data, header->data_length, 0);
}
iotxn_complete(txn, header->status, header->data_length);
break;
}
default:
printf("channel_thread bad command %d\n", header->cmd);
break;
}
}
return 0;
}
mx_device_t* usb_virtual_hci_add(mx_device_t* parent, mx_handle_t channel_handle) {
printf("usb_virtual_hci_add\n");
usb_virtual_hci_t* hci = calloc(1, sizeof(usb_virtual_hci_t));
if (!hci) {
mx_handle_close(channel_handle);
return NULL;
}
for (uint i = 0; i < countof(hci->ep_txns); i++) {
list_initialize(&hci->ep_txns[i]);
}
mtx_init(&hci->lock, mtx_plain);
completion_reset(&hci->completion);
hci->channel_handle = channel_handle;
device_add_args_t args = {
.version = DEVICE_ADD_ARGS_VERSION,
.name = "usb-virtual-hci",
.ctx = hci,
.ops = &usb_virtual_hci_device_proto,
.proto_id = MX_PROTOCOL_USB_HCI,
.proto_ops = &virtual_hci_protocol,
};
mx_status_t status = device_add(parent, &args, &hci->mxdev);
if (status != MX_OK) {
printf("usb_virtual_hci_add device_add failed %d\n", status);
mx_handle_close(channel_handle);
free(hci);
return NULL;
}
thrd_t thread;
thrd_create_with_name(&thread, channel_thread, hci, "channel_thread");
thrd_detach(thread);
thrd_create_with_name(&thread, connection_thread, hci, "connection_thread");
thrd_detach(thread);
return hci->mxdev;
}
+14
Ver Arquivo
@@ -0,0 +1,14 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <magenta/hw/usb.h>
#include "util.h"
uint8_t ep_addr_to_index(uint8_t ep_address) {
if (ep_address == 0) return 0;
uint32_t index = 2 * (ep_address & ~USB_ENDPOINT_DIR_MASK);
if ((ep_address & USB_ENDPOINT_DIR_MASK) == USB_ENDPOINT_OUT)
index--;
return index;
}
+8
Ver Arquivo
@@ -0,0 +1,8 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
// converts a USB endpoint adddress to an index from 0 to 31
uint8_t ep_addr_to_index(uint8_t ep_address);
+1
Ver Arquivo
@@ -57,6 +57,7 @@
#define IOCTL_FAMILY_WLAN 0x24
#define IOCTL_FAMILY_PTY 0x25
#define IOCTL_FAMILY_NETCONFIG 0x26
#define IOCTL_FAMILY_USB_CLIENT 0x27
// IOCTL constructor
// --K-FFNN
+21
Ver Arquivo
@@ -0,0 +1,21 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
// clang-format off
#include <stdint.h>
#include <magenta/device/ioctl.h>
#include <magenta/device/ioctl-wrapper.h>
__BEGIN_CDECLS
// sets the client controller's connected state
// call with in_len = sizeof(int)
#define IOCTL_USB_CLIENT_SET_CONNNECTED IOCTL(IOCTL_KIND_DEFAULT, IOCTL_FAMILY_USB_CLIENT, 1)
IOCTL_WRAPPER_IN(ioctl_usb_client_set_connected, IOCTL_USB_CLIENT_SET_CONNNECTED, int);
__END_CDECLS
+62
Ver Arquivo
@@ -0,0 +1,62 @@
// Copyright 2016 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <magenta/device/usb-client.h>
#include <magenta/types.h>
#define DEV_VIRTUAL_USB "/dev/class/usb-client/000"
#define xprintf(fmt...) do { if (verbose) printf(fmt); } while (0)
static void usage(void) {
printf("usage: virtual-usb <command> [<args>]\n\n");
printf(" commands:\n");
printf(" connect\n");
printf(" disconnect\n");
}
int main(int argc, const char** argv) {
/*
if (argc < 2) {
usage();
return 0;
}
argc--;
argv++;
if (!strcmp("read", argv[0])) {
if (argc > 1) {
return read_reports(argc, argv);
} else {
return readall_reports(argc, argv);
}
}
if (!strcmp("get", argv[0])) return get_report(argc, argv);
if (!strcmp("set", argv[0])) return set_report(argc, argv);
usage();
*/
int fd = open(DEV_VIRTUAL_USB, O_RDWR);
if (fd < 0) {
fprintf(stderr, "could not open %s\n", DEV_VIRTUAL_USB);
return fd;
}
int connected = 1;
mx_status_t status = ioctl_usb_client_set_connected(fd, &connected);
printf("ioctl_usb_client_set_connected returned %d\n", status);
close(fd);
return 0;
}
+19
Ver Arquivo
@@ -0,0 +1,19 @@
# Copyright 2016 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
LOCAL_DIR := $(GET_LOCAL_DIR)
MODULE := $(LOCAL_DIR)
MODULE_TYPE := userapp
MODULE_SRCS += \
$(LOCAL_DIR)/main.c
MODULE_LIBS := \
system/ulib/magenta \
system/ulib/mxio \
system/ulib/c
include make/module.mk
@@ -0,0 +1,50 @@
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <magenta/compiler.h>
#include <magenta/types.h>
#include <magenta/hw/usb.h>
__BEGIN_CDECLS;
// callbacks installed by function driver
typedef struct {
// callback for handling ep0 control requests
mx_status_t (*control)(void* ctx, const usb_setup_t* setup, void* buffer, int length);
} usb_client_interface_ops_t;
typedef struct {
usb_client_interface_ops_t* ops;
void* ctx;
} usb_client_interface_t;
static inline mx_status_t usb_client_intf_control(usb_client_interface_t* intf,
const usb_setup_t* setup,
void* buffer, int length) {
return intf->ops->control(intf->ctx, setup, buffer, length);
}
typedef struct {
mx_status_t (*set_interface)(void* ctx, usb_client_interface_t* interface);
mx_status_t (*config_ep)(void* ctx, const usb_endpoint_descriptor_t* ep_desc);
} usb_client_protocol_ops_t;
typedef struct {
usb_client_protocol_ops_t* ops;
void* ctx;
} usb_client_protocol_t;
static inline void usb_client_set_interface(usb_client_protocol_t* client,
usb_client_interface_t* intf) {
client->ops->set_interface(client->ctx, intf);
}
static inline void usb_client_config_ep(usb_client_protocol_t* client,
const usb_endpoint_descriptor_t* ep_desc) {
client->ops->config_ep(client->ctx, ep_desc);
}
__END_CDECLS;
+1
Ver Arquivo
@@ -28,6 +28,7 @@ DDK_PROTOCOL_DEF(MISC_PARENT, 'pMSP', "misc-parent", PF_NOPUB)
DDK_PROTOCOL_DEF(PCI, 'pPCI', "pci", 0)
DDK_PROTOCOL_DEF(TPM, 'pTPM', "tpm", 0)
DDK_PROTOCOL_DEF(USB, 'pUSB', "usb", 0)
DDK_PROTOCOL_DEF(USB_CLIENT, 'pUSC', "usb-client", 0)
DDK_PROTOCOL_DEF(USB_HCI, 'pUHI', "usb-hci", 0)
DDK_PROTOCOL_DEF(USB_BUS, 'pUBS', "usb-bus", 0)
DDK_PROTOCOL_DEF(BLUETOOTH_HCI, 'pBHC', "bt-hci", 0)