summaryrefslogtreecommitdiff
path: root/src/usbh_driver_hid.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/usbh_driver_hid.c')
-rw-r--r--src/usbh_driver_hid.c412
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
-};
-
-
-