/* * 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 drvusbmouse * @{ */ /** * @file * Initialization routines for USB mouse driver. */ #include "mouse.h" #include #include #include #include #include /** Mouse polling endpoint description for boot protocol subclass. */ static usb_endpoint_description_t poll_endpoint_description = { .transfer_type = USB_TRANSFER_INTERRUPT, .direction = USB_DIRECTION_IN, .interface_class = USB_CLASS_HID, .interface_subclass = USB_HID_SUBCLASS_BOOT, .interface_protocol = USB_HID_PROTOCOL_MOUSE, .flags = 0 }; /** Initialize poll pipe. * * Expects that session is already started on control pipe zero. * * @param mouse Mouse device. * @param my_interface Interface number. * @return Error code. */ static int intialize_poll_pipe(usb_mouse_t *mouse, int my_interface) { assert(usb_endpoint_pipe_is_session_started(&mouse->ctrl_pipe)); int rc; void *config_descriptor; size_t config_descriptor_size; rc = usb_request_get_full_configuration_descriptor_alloc( &mouse->ctrl_pipe, 0, &config_descriptor, &config_descriptor_size); if (rc != EOK) { return rc; } usb_endpoint_mapping_t endpoint_mapping[1] = { { .pipe = &mouse->poll_pipe, .description = &poll_endpoint_description, .interface_no = my_interface } }; rc = usb_endpoint_pipe_initialize_from_configuration(endpoint_mapping, 1, config_descriptor, config_descriptor_size, &mouse->wire); if (rc != EOK) { return rc; } if (!endpoint_mapping[0].present) { return ENOENT; } mouse->poll_interval_us = 1000 * endpoint_mapping[0].descriptor->poll_interval; usb_log_debug("prepared polling endpoint %d (interval %zu).\n", mouse->poll_pipe.endpoint_no, mouse->poll_interval_us); return EOK; } static void default_connection_handler(ddf_fun_t *, ipc_callid_t, ipc_call_t *); static ddf_dev_ops_t mouse_ops = { .default_handler = default_connection_handler }; /** Default handler for IPC methods not handled by DDF. * * @param dev Device handling the call. * @param icallid Call id. * @param icall Call data. */ void default_connection_handler(ddf_fun_t *fun, ipc_callid_t icallid, ipc_call_t *icall) { sysarg_t method = IPC_GET_IMETHOD(*icall); usb_mouse_t *mouse = (usb_mouse_t *) fun->driver_data; assert(mouse != NULL); if (method == IPC_M_CONNECT_TO_ME) { int callback = IPC_GET_ARG5(*icall); if (mouse->console_phone != -1) { async_answer_0(icallid, ELIMIT); return; } mouse->console_phone = callback; async_answer_0(icallid, EOK); return; } async_answer_0(icallid, EINVAL); } int usb_mouse_create(ddf_dev_t *dev) { usb_mouse_t *mouse = malloc(sizeof(usb_mouse_t)); if (mouse == NULL) { return ENOMEM; } mouse->device = dev; mouse->console_phone = -1; int rc; /* Initialize the backing connection. */ rc = usb_device_connection_initialize_from_device(&mouse->wire, dev); if (rc != EOK) { goto leave; } /* Initialize the default control pipe. */ rc = usb_endpoint_pipe_initialize_default_control(&mouse->ctrl_pipe, &mouse->wire); if (rc != EOK) { goto leave; } rc = usb_endpoint_pipe_start_session(&mouse->ctrl_pipe); if (rc != EOK) { goto leave; } rc = intialize_poll_pipe(mouse, usb_device_get_assigned_interface(dev)); /* We can ignore error here. */ usb_endpoint_pipe_end_session(&mouse->ctrl_pipe); if (rc != EOK) { goto leave; } /* Create DDF function. */ mouse->mouse_fun = ddf_fun_create(dev, fun_exposed, "mouse"); if (mouse->mouse_fun == NULL) { rc = ENOMEM; goto leave; } mouse->mouse_fun->ops = &mouse_ops; rc = ddf_fun_bind(mouse->mouse_fun); if (rc != EOK) { goto leave; } /* Add the function to mouse class. */ rc = ddf_fun_add_to_class(mouse->mouse_fun, "mouse"); if (rc != EOK) { goto leave; } /* Everything allright. */ dev->driver_data = mouse; mouse->mouse_fun->driver_data = mouse; return EOK; leave: free(mouse); return rc; } /** * @} */