/* * Copyright (c) 2011 Vojtech Horky * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** @addtogroup usbvirthid * @{ */ /** * @file * Virtual USB HID device. */ #include #include #include #include #include #include #include #include #include #include #include #include "virthid.h" #include "ifaces.h" #include "stdreq.h" static usbvirt_control_request_handler_t endpoint_zero_handlers[] = { { .req_direction = USB_DIRECTION_IN, .req_type = USB_REQUEST_TYPE_STANDARD, .req_recipient = USB_REQUEST_RECIPIENT_INTERFACE, .request = USB_DEVREQ_GET_DESCRIPTOR, .name = "Get_Descriptor", .callback = req_get_descriptor }, { .req_direction = USB_DIRECTION_OUT, .req_recipient = USB_REQUEST_RECIPIENT_INTERFACE, .req_type = USB_REQUEST_TYPE_CLASS, .request = USB_HIDREQ_SET_PROTOCOL, .name = "Set_Protocol", .callback = req_set_protocol }, { .req_direction = USB_DIRECTION_OUT, .req_recipient = USB_REQUEST_RECIPIENT_INTERFACE, .req_type = USB_REQUEST_TYPE_CLASS, .request = USB_HIDREQ_SET_REPORT, .name = "Set_Report", .callback = req_set_report }, { .callback = NULL } }; /** Keyboard callbacks. * We abuse the fact that static variables are zero-filled. */ static usbvirt_device_ops_t hid_ops = { .control = endpoint_zero_handlers, }; /** Standard configuration descriptor. */ static usb_standard_configuration_descriptor_t std_configuration_descriptor = { .length = sizeof(usb_standard_configuration_descriptor_t), .descriptor_type = USB_DESCTYPE_CONFIGURATION, /* Will be patched at runtime. */ .total_length = sizeof(usb_standard_configuration_descriptor_t), .interface_count = 0, .configuration_number = 1, .str_configuration = 0, .attributes = 128, /* denotes bus-powered device */ .max_power = 50 }; /** Standard device descriptor. */ static usb_standard_device_descriptor_t std_device_descriptor = { .length = sizeof(usb_standard_device_descriptor_t), .descriptor_type = USB_DESCTYPE_DEVICE, .usb_spec_version = 0x110, .device_class = USB_CLASS_USE_INTERFACE, .device_subclass = 0, .device_protocol = 0, .max_packet_size = 64, .configuration_count = 1 }; /** HID configuration. */ usbvirt_device_configuration_t configuration = { .descriptor = &std_configuration_descriptor, .extra = NULL, .extra_count = 0 }; /** HID standard descriptors. */ usbvirt_descriptors_t descriptors = { .device = &std_device_descriptor, .configuration = &configuration, .configuration_count = 1, }; static vuhid_data_t vuhid_data = { .in_endpoints_mapping = { NULL }, .in_endpoint_first_free = 1, .out_endpoints_mapping = { NULL }, .out_endpoint_first_free = 1, .iface_count = 0, .iface_died_count = 0 // mutex and CV must be initialized elsewhere }; /** Keyboard device. * Rest of the items will be initialized later. */ static usbvirt_device_t hid_dev = { .ops = &hid_ops, .descriptors = &descriptors, .name = "HID", .device_data = &vuhid_data }; int main(int argc, char * argv[]) { int rc; usb_log_enable(USB_LOG_LEVEL_DEBUG2, "vusbhid"); fibril_mutex_initialize(&vuhid_data.iface_count_mutex); fibril_condvar_initialize(&vuhid_data.iface_count_cv); /* Determine which interfaces to initialize. */ int i; for (i = 1; i < argc; i++) { rc = add_interface_by_id(available_hid_interfaces, argv[i], &hid_dev); if (rc != EOK) { fprintf(stderr, "Failed to add device `%s': %s.\n", argv[i], str_error(rc)); } else { printf("Added device `%s'.\n", argv[i]); } } for (i = 0; i < (int) hid_dev.descriptors->configuration->extra_count; i++) { usb_log_debug("Found extra descriptor: %s.\n", usb_debug_str_buffer( hid_dev.descriptors->configuration->extra[i].data, hid_dev.descriptors->configuration->extra[i].length, 0)); } rc = usbvirt_device_plug(&hid_dev, "/virt/usbhc/hc"); if (rc != EOK) { printf("Unable to start communication with VHCD: %s.\n", str_error(rc)); return rc; } printf("Connected to VHCD...\n"); wait_for_interfaces_death(&hid_dev); printf("Terminating...\n"); usbvirt_device_unplug(&hid_dev); return 0; } /** @} */