diff options
Diffstat (limited to 'src/usbh_driver_hid.c')
-rw-r--r-- | src/usbh_driver_hid.c | 412 |
1 files changed, 0 insertions, 412 deletions
diff --git a/src/usbh_driver_hid.c b/src/usbh_driver_hid.c deleted file mode 100644 index 4893354..0000000 --- a/src/usbh_driver_hid.c +++ /dev/null @@ -1,412 +0,0 @@ -/* - * This file is part of the libusbhost library - * hosted at http://github.com/libusbhost/libusbhost - * - * Copyright (C) 2016 Amir Hammad <amir.hammad@hotmail.com> - * - * - * libusbhost is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "usbh_core.h" -#include "driver/usbh_device_driver.h" -#include "usbh_driver_hid.h" -#include "usart_helpers.h" - -#include <libopencm3/usb/usbstd.h> -#include <libopencm3/usb/hid.h> -#include <stdint.h> -#include <stddef.h> - -#define USB_HID_SET_REPORT 0x09 -#define USB_HID_SET_IDLE 0x0A - -enum STATES { - STATE_INACTIVE, - STATE_READING_REQUEST, - STATE_READING_COMPLETE_AND_CHECK_REPORT, - STATE_SET_REPORT_EMPTY_READ, - STATE_GET_REPORT_DESCRIPTOR_READ_SETUP,// configuration is complete at this point. We write request - STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE,// after the read finishes, we parse that descriptor - STATE_SET_IDLE, - STATE_SET_IDLE_COMPLETE, -}; - -enum REPORT_STATE { - REPORT_STATE_NULL, - REPORT_STATE_READY, - REPORT_STATE_PENDING, -}; - -struct _hid_device { - usbh_device_t *usbh_device; - uint8_t buffer[USBH_HID_BUFFER]; - uint16_t endpoint_in_maxpacketsize; - uint8_t endpoint_in_address; - enum STATES state_next; - uint8_t endpoint_in_toggle; - uint8_t device_id; - uint8_t configuration_value; - uint16_t report0_length; - enum REPORT_STATE report_state; - uint8_t report_data[USBH_HID_REPORT_BUFFER]; - uint8_t report_data_length; - enum HID_TYPE hid_type; - uint8_t interface_number; -}; -typedef struct _hid_device hid_device_t; - -struct hid_report_decriptor { - struct usb_hid_descriptor header; - struct _report_descriptor_info { - uint8_t bDescriptorType; - uint16_t wDescriptorLength; - } __attribute__((packed)) report_descriptors_info[]; -} __attribute__((packed)); - -static hid_device_t hid_device[USBH_HID_MAX_DEVICES]; -static hid_config_t hid_config; - -static bool initialized = false; - -void hid_driver_init(const hid_config_t *config) -{ - uint32_t i; - - initialized = true; - - hid_config = *config; - for (i = 0; i < USBH_HID_MAX_DEVICES; i++) { - hid_device[i].state_next = STATE_INACTIVE; - } -} - -static void *init(usbh_device_t *usbh_dev) -{ - if (!initialized) { - LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__); - return 0; - } - - uint32_t i; - hid_device_t *drvdata = NULL; - - // find free data space for HID device - for (i = 0; i < USBH_HID_MAX_DEVICES; i++) { - if (hid_device[i].state_next == STATE_INACTIVE) { - drvdata = &hid_device[i]; - drvdata->device_id = i; - drvdata->endpoint_in_address = 0; - drvdata->endpoint_in_toggle = 0; - drvdata->report0_length = 0; - drvdata->usbh_device = usbh_dev; - drvdata->report_state = REPORT_STATE_NULL; - drvdata->hid_type = HID_TYPE_NONE; - break; - } - } - - return drvdata; -} - -static void parse_report_descriptor(hid_device_t *hid, const uint8_t *buffer, uint32_t length) -{ - // TODO - // Do some parsing! - // add some checks - hid->report_state = REPORT_STATE_READY; - - // TODO: parse this from buffer! - hid->report_data_length = 1; - (void)buffer; - (void)length; -} - -/** - * Returns true if all needed data are parsed - */ -static bool analyze_descriptor(void *drvdata, void *descriptor) -{ - hid_device_t *hid = (hid_device_t *)drvdata; - uint8_t desc_type = ((uint8_t *)descriptor)[1]; - switch (desc_type) { - case USB_DT_CONFIGURATION: - { - const struct usb_config_descriptor * cfg = (const struct usb_config_descriptor*)descriptor; - hid->configuration_value = cfg->bConfigurationValue; - } - break; - - case USB_DT_DEVICE: - { - const struct usb_device_descriptor *devDesc = (const struct usb_device_descriptor *)descriptor; - (void)devDesc; - } - break; - - case USB_DT_INTERFACE: - { - const struct usb_interface_descriptor *ifDesc = (const struct usb_interface_descriptor *)descriptor; - if (ifDesc->bInterfaceProtocol == 0x01) { - hid->hid_type = HID_TYPE_KEYBOARD; - hid->interface_number = ifDesc->bInterfaceNumber; - } else if (ifDesc->bInterfaceProtocol == 0x02) { - hid->hid_type = HID_TYPE_MOUSE; - hid->interface_number = ifDesc->bInterfaceNumber; - } - } - break; - - case USB_DT_ENDPOINT: - { - const struct usb_endpoint_descriptor *ep = (const struct usb_endpoint_descriptor *)descriptor; - if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) { - uint8_t epaddr = ep->bEndpointAddress; - if (epaddr & (1<<7)) { - hid->endpoint_in_address = epaddr&0x7f; - if (ep->wMaxPacketSize < USBH_HID_BUFFER) { - hid->endpoint_in_maxpacketsize = ep->wMaxPacketSize; - } else { - hid->endpoint_in_maxpacketsize = USBH_HID_BUFFER; - } - } - } - } - break; - - case USB_DT_HID: - { - const struct hid_report_decriptor *desc = (const struct hid_report_decriptor *)descriptor; - if (desc->header.bNumDescriptors > 0 && desc->report_descriptors_info[0].bDescriptorType == USB_DT_REPORT) { - hid->report0_length = desc->report_descriptors_info[0].wDescriptorLength; - } - } - break; - - default: - break; - } - - if (hid->endpoint_in_address && hid->report0_length) { - hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_SETUP; - return true; - } - - return false; -} - -static void report_event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) -{ - (void)cb_data;// UNUSED - - hid_device_t *hid = (hid_device_t *)dev->drvdata; - hid->report_state = REPORT_STATE_READY; -} - -static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data) -{ - hid_device_t *hid = (hid_device_t *)dev->drvdata; - - switch (hid->state_next) { - case STATE_READING_COMPLETE_AND_CHECK_REPORT: - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - case USBH_PACKET_CALLBACK_STATUS_ERRSIZ: - if (hid_config.hid_in_message_handler) { - hid_config.hid_in_message_handler(hid->device_id, hid->buffer, cb_data.transferred_length); - } - hid->state_next = STATE_READING_REQUEST; - break; - - default: - ERROR(cb_data.status); - hid->state_next = STATE_INACTIVE; - break; - } - } - break; - - case STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE: // read complete, SET_IDLE to 0 - { - switch (cb_data.status) { - case USBH_PACKET_CALLBACK_STATUS_OK: - LOG_PRINTF("READ REPORT COMPLETE \n"); - hid->state_next = STATE_READING_REQUEST; - hid->endpoint_in_toggle = 0; - - parse_report_descriptor(hid, hid->buffer, cb_data.transferred_length); - break; - - default: - ERROR(cb_data.status); - hid->state_next = STATE_INACTIVE; - break; - } - } - break; - - default: - break; - } -} - - -static void read_hid_in_endpoint(void *drvdata) -{ - hid_device_t *hid = (hid_device_t *)drvdata; - usbh_packet_t packet; - - packet.address = hid->usbh_device->address; - packet.data.in = &hid->buffer[0]; - packet.datalen = hid->endpoint_in_maxpacketsize; - packet.endpoint_address = hid->endpoint_in_address; - packet.endpoint_size_max = hid->endpoint_in_maxpacketsize; - packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT; - packet.speed = hid->usbh_device->speed; - packet.callback = event; - packet.callback_arg = hid->usbh_device; - packet.toggle = &hid->endpoint_in_toggle; - - hid->state_next = STATE_READING_COMPLETE_AND_CHECK_REPORT; - usbh_read(hid->usbh_device, &packet); -} - -/** - * @param time_curr_us - monotically rising time - * unit is microseconds - * @see usbh_poll() - */ -static void poll(void *drvdata, uint32_t time_curr_us) -{ - (void)time_curr_us; - - hid_device_t *hid = (hid_device_t *)drvdata; - usbh_device_t *dev = hid->usbh_device; - switch (hid->state_next) { - case STATE_READING_REQUEST: - { - read_hid_in_endpoint(drvdata); - } - break; - - case STATE_GET_REPORT_DESCRIPTOR_READ_SETUP: - { - hid->endpoint_in_toggle = 0; - // We support only the first report descriptor with index 0 - - // limit the size of the report descriptor! - if (hid->report0_length > USBH_HID_BUFFER) { - hid->report0_length = USBH_HID_BUFFER; - } - - struct usb_setup_data setup_data; - - setup_data.bmRequestType = USB_REQ_TYPE_IN | USB_REQ_TYPE_INTERFACE; - setup_data.bRequest = USB_REQ_GET_DESCRIPTOR; - setup_data.wValue = USB_DT_REPORT << 8; - setup_data.wIndex = 0; - setup_data.wLength = hid->report0_length; - - hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE; - device_control(dev, event, &setup_data, hid->buffer); - } - break; - - default: - // do nothing - probably transfer is in progress - break; - } -} - -static void remove(void *drvdata) -{ - hid_device_t *hid = (hid_device_t *)drvdata; - hid->state_next = STATE_INACTIVE; - hid->endpoint_in_address = 0; -} - -bool hid_set_report(uint8_t device_id, uint8_t val) -{ - if (device_id >= USBH_HID_MAX_DEVICES) { - LOG_PRINTF("invalid device id\n"); - return false; - } - - hid_device_t *hid = &hid_device[device_id]; - if (hid->report_state != REPORT_STATE_READY) { - LOG_PRINTF("reporting is not ready\n"); - // store and update afterwards - return false; - } - - if (hid->report_data_length == 0) { - LOG_PRINTF("reporting is not available (report len=0)\n"); - return false; - } - - struct usb_setup_data setup_data; - setup_data.bmRequestType = USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; - setup_data.bRequest = USB_HID_SET_REPORT; - setup_data.wValue = 0x02 << 8; - setup_data.wIndex = hid->interface_number; - setup_data.wLength = hid->report_data_length; - - hid->report_data[0] = val; - - hid->report_state = REPORT_STATE_PENDING; - device_control(hid->usbh_device, report_event, &setup_data, &hid->report_data); - return true; -} - -bool hid_is_connected(uint8_t device_id) -{ - if (device_id >= USBH_HID_MAX_DEVICES) { - LOG_PRINTF("is connected: invalid device id\n"); - return false; - } - return hid_device[device_id].state_next == STATE_INACTIVE; -} - - -enum HID_TYPE hid_get_type(uint8_t device_id) -{ - if (hid_is_connected(device_id)) { - return HID_TYPE_NONE; - } - return hid_device[device_id].hid_type; -} - -static const usbh_dev_driver_info_t driver_info = { - .deviceClass = -1, - .deviceSubClass = -1, - .deviceProtocol = -1, - .idVendor = -1, - .idProduct = -1, - .ifaceClass = 0x03, // HID class - .ifaceSubClass = -1, - .ifaceProtocol = -1, // Do not care -}; - -const usbh_dev_driver_t usbh_hid_driver = { - .init = init, - .analyze_descriptor = analyze_descriptor, - .poll = poll, - .remove = remove, - .info = &driver_info -}; - - - |