summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmir Hammad <amir.hammad@hotmail.com>2016-09-09 18:37:22 +0200
committerAmir Hammad <amir.hammad@hotmail.com>2016-09-11 13:30:13 +0200
commit3d68ea280790351d0320fc4e712c51b820a5522a (patch)
tree5b5120d966e8d260d717773d4ea939e6295e5226
parented70a1efa3335b6bf64c8c6a6f5be4dc25bdd9b7 (diff)
downloadsecure-hid-3d68ea280790351d0320fc4e712c51b820a5522a.tar.gz
secure-hid-3d68ea280790351d0320fc4e712c51b820a5522a.tar.bz2
secure-hid-3d68ea280790351d0320fc4e712c51b820a5522a.zip
make hid_mouse driver generic HID driver
+ keyboard support + SET_REPORT commands - usually leds on keyboards (WIP) - missing parsing of HID report descriptor Signed-off-by: Amir Hammad <amir.hammad@hotmail.com>
-rw-r--r--README.md2
-rw-r--r--include/usbh_config.h8
-rw-r--r--include/usbh_driver_hid.h85
-rw-r--r--include/usbh_driver_hid_mouse.h53
-rw-r--r--src/CMakeLists.txt4
-rw-r--r--src/demo.c26
-rw-r--r--src/usbh_driver_hid.c537
-rw-r--r--src/usbh_driver_hid_mouse.c298
8 files changed, 648 insertions, 365 deletions
diff --git a/README.md b/README.md
index d23b425..a823eaf 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ This means no allocation and reallocation is affecting performance
- HUB
- Gamepad - XBox compatible Controller
-- mouse (draft: only displays raw data)
+- Generic Human Interface driver: mouse, keyboard (raw data)
- USB MIDI devices (raw data + note on/off)
## Steps to compile library and demo
diff --git a/include/usbh_config.h b/include/usbh_config.h
index 4fa38cb..8146ffb 100644
--- a/include/usbh_config.h
+++ b/include/usbh_config.h
@@ -38,10 +38,10 @@
// Set this wisely
#define BUFFER_ONE_BYTES (2048)
-// MOUSE
-#define USBH_HID_MOUSE_MAX_DEVICES (2)
-
-#define USBH_HID_MOUSE_BUFFER (32)
+// HID class devices
+#define USBH_HID_MAX_DEVICES (2)
+#define USBH_HID_BUFFER (256)
+#define USBH_HID_REPORT_BUFFER (4)
// MIDI
// Maximal number of midi devices connected to whatever hub
diff --git a/include/usbh_driver_hid.h b/include/usbh_driver_hid.h
new file mode 100644
index 0000000..8155d82
--- /dev/null
+++ b/include/usbh_driver_hid.h
@@ -0,0 +1,85 @@
+/*
+ * 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/>.
+ *
+ */
+
+#ifndef USBH_DRIVER_HID_
+#define USBH_DRIVER_HID_
+
+#include "usbh_core.h"
+
+#include <stdint.h>
+
+BEGIN_DECLS
+
+struct _hid_mouse_config {
+ /**
+ * @brief this is called when some data is read when polling the device
+ * @param device_id handle of HID device
+ * @param data pointer to the data
+ * @param length count of bytes in the data
+ *
+ * TODO: make better interface that provides data contained in the report descriptor
+ *
+ */
+ void (*hid_in_message_handler)(uint8_t device_id, const uint8_t *data, uint32_t length);
+};
+typedef struct _hid_mouse_config hid_config_t;
+
+/**
+ * @brief hid_mouse_driver_init initialization routine - this will initialize internal structures of this device driver
+ * @param config
+ * @see hid_mouse_config_t
+ */
+void hid_driver_init(const hid_config_t *config);
+
+/**
+ * @brief hid_set_report
+ * @param device_id handle of HID device
+ * @returns true on success, false otherwise
+ */
+bool hid_set_report(uint8_t device_id, uint8_t val);
+
+enum HID_TYPE {
+ HID_TYPE_NONE,
+ HID_TYPE_MOUSE,
+ HID_TYPE_KEYBOARD,
+};
+
+/**
+ * @brief hid_get_type
+ * @param device_id handle of HID device
+ * @return type of attached HID
+ * @see enum HID_TYPE
+ */
+enum HID_TYPE hid_get_type(uint8_t device_id);
+
+/**
+ * @brief hid_is_connected
+ * @param device_id handle of HID device
+ * @return true if the device with device_id is connected
+ */
+bool hid_is_connected(uint8_t device_id);
+
+extern const usbh_dev_driver_t usbh_hid_driver;
+
+END_DECLS
+
+#endif
diff --git a/include/usbh_driver_hid_mouse.h b/include/usbh_driver_hid_mouse.h
deleted file mode 100644
index 4a9f0d3..0000000
--- a/include/usbh_driver_hid_mouse.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * This file is part of the libusbhost library
- * hosted at http://github.com/libusbhost/libusbhost
- *
- * Copyright (C) 2015 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/>.
- *
- */
-
-#ifndef USBH_DRIVER_HID_MOUSE_
-#define USBH_DRIVER_HID_MOUSE_
-
-#include "usbh_core.h"
-
-#include <stdint.h>
-
-BEGIN_DECLS
-
-struct _hid_mouse_config {
- /**
- * @brief this is called when some data is read when polling the device
- * @param device_id
- * @param data pointer to the data (only 4 bytes are valid!)
- */
- void (*mouse_in_message_handler)(uint8_t device_id, const uint8_t *data);
-};
-typedef struct _hid_mouse_config hid_mouse_config_t;
-
-/**
- * @brief hid_mouse_driver_init initialization routine - this will initialize internal structures of this device driver
- * @param config
- * @see hid_mouse_config_t
- */
-void hid_mouse_driver_init(const hid_mouse_config_t *config);
-
-extern const usbh_dev_driver_t usbh_hid_mouse_driver;
-
-END_DECLS
-
-#endif
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 3165b51..f8478f6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -14,7 +14,7 @@ add_library (usbhost
${inc}/usbh_core.h
${inc}/usbh_driver_ac_midi.h
${inc}/usbh_driver_gp_xbox.h
- ${inc}/usbh_driver_hid_mouse.h
+ ${inc}/usbh_driver_hid.h
${inc}/usbh_driver_hub.h
${inc}/usbh_lld_stm32f4.h
${inc}/driver/usbh_device_driver.h
@@ -23,7 +23,7 @@ add_library (usbhost
usbh_driver_ac_midi.c
usbh_driver_ac_midi_private.h
usbh_driver_gp_xbox.c
- usbh_driver_hid_mouse.c
+ usbh_driver_hid.c
usbh_driver_hub.c
usbh_driver_hub_private.h
usbh_lld_stm32f4.c
diff --git a/src/demo.c b/src/demo.c
index 3fedbd9..995e68c 100644
--- a/src/demo.c
+++ b/src/demo.c
@@ -23,7 +23,7 @@
#include "usart_helpers.h" /// provides LOG_PRINTF macros used for debugging
#include "usbh_core.h" /// provides usbh_init() and usbh_poll()
#include "usbh_lld_stm32f4.h" /// provides low level usb host driver for stm32f4 platform
-#include "usbh_driver_hid_mouse.h" /// provides usb device driver Human Interface Device - type mouse
+#include "usbh_driver_hid.h" /// provides generic usb device driver for Human Interface Device (HID)
#include "usbh_driver_hub.h" /// provides usb full speed hub driver (Low speed devices on hub are not supported)
#include "usbh_driver_gp_xbox.h" /// provides usb device driver for Gamepad: Microsoft XBOX compatible Controller
#include "usbh_driver_ac_midi.h" /// provides usb device driver for midi class devices
@@ -116,7 +116,7 @@ static void gpio_setup(void)
static const usbh_dev_driver_t *device_drivers[] = {
&usbh_hub_driver,
- &usbh_hid_mouse_driver,
+ &usbh_hid_driver,
&usbh_gp_xbox_driver,
&usbh_midi_driver,
0
@@ -148,17 +148,29 @@ static const gp_xbox_config_t gp_xbox_config = {
.notify_disconnected = &gp_xbox_disconnected
};
-static void mouse_in_message_handler(uint8_t device_id, const uint8_t *data)
+static void hid_in_message_handler(uint8_t device_id, const uint8_t *data, uint32_t length)
{
(void)device_id;
(void)data;
+ if (length < 4) {
+ LOG_PRINTF("data too short, type=%d\n", hid_get_type(device_id));
+ return;
+ }
+
// print only first 4 bytes, since every mouse should have at least these four set.
// Report descriptors are not read by driver for now, so we do not know what each byte means
- LOG_PRINTF("MOUSE EVENT %02X %02X %02X %02X \n", data[0], data[1], data[2], data[3]);
+ LOG_PRINTF("HID EVENT %02X %02X %02X %02X \n", data[0], data[1], data[2], data[3]);
+ if (hid_get_type(device_id) == HID_TYPE_KEYBOARD) {
+ static int x = 0;
+ if (x != data[2]) {
+ x = data[2];
+ hid_set_report(device_id, x);
+ }
+ }
}
-static const hid_mouse_config_t mouse_config = {
- .mouse_in_message_handler = &mouse_in_message_handler
+static const hid_config_t hid_config = {
+ .hid_in_message_handler = &hid_in_message_handler
};
static void midi_in_message_handler(int device_id, uint8_t *data)
@@ -200,7 +212,7 @@ int main(void)
*
* Pass configuration struct where the callbacks are defined
*/
- hid_mouse_driver_init(&mouse_config);
+ hid_driver_init(&hid_config);
hub_driver_init();
gp_xbox_driver_init(&gp_xbox_config);
midi_driver_init(&midi_config);
diff --git a/src/usbh_driver_hid.c b/src/usbh_driver_hid.c
new file mode 100644
index 0000000..21fa262
--- /dev/null
+++ b/src/usbh_driver_hid.c
@@ -0,0 +1,537 @@
+/*
+ * 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>
+
+#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_SET_CONFIGURATION_REQUEST,
+ STATE_SET_CONFIGURATION_EMPTY_READ,
+ STATE_GET_REPORT_DESCRIPTOR_READ_SETUP,// configuration is complete at this point. We write request
+ STATE_GET_REPORT_DESCRIPTOR_READ,
+ 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_WRITE_PENDING,
+ REPORT_STATE_WRITE_PENDING_DATA,
+ REPORT_STATE_EMPTY_READ,
+};
+
+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(void *usbh_dev)
+{
+ if (!initialized) {
+ LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__);
+ return 0;
+ }
+
+ uint32_t i;
+ hid_device_t *drvdata = 0;
+
+ // 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_device_t *)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_SET_CONFIGURATION_REQUEST;
+ return true;
+ }
+
+ return false;
+}
+
+static void report_event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
+{
+ hid_device_t *hid = (hid_device_t *)dev->drvdata;
+ switch (hid->report_state) {
+ case REPORT_STATE_WRITE_PENDING:
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ hid->report_state = REPORT_STATE_WRITE_PENDING_DATA;
+
+ device_xfer_control_write_data(hid->report_data, hid->report_data_length, report_event, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ break;
+
+ case REPORT_STATE_WRITE_PENDING_DATA:
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ hid->report_state = REPORT_STATE_EMPTY_READ;
+ device_xfer_control_read(0, 0, report_event, dev);
+ LOG_PRINTF("reading empty\n");
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ break;
+
+
+ case REPORT_STATE_EMPTY_READ:
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ hid->report_state = REPORT_STATE_READY;
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+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;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_SET_CONFIGURATION_EMPTY_READ:
+ {
+ LOG_PRINTF("|empty packet read|");
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_SETUP;
+ device_xfer_control_read(0, 0, event, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_GET_REPORT_DESCRIPTOR_READ_SETUP:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ {
+ 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;
+ device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
+
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ hid->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_GET_REPORT_DESCRIPTOR_READ:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ hid->state_next = STATE_GET_REPORT_DESCRIPTOR_READ_COMPLETE;
+ device_xfer_control_read(hid->buffer, hid->report0_length, event, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ 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;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ 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_SET_CONFIGURATION_REQUEST:
+ {
+ struct usb_setup_data setup_data;
+
+ setup_data.bmRequestType = USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_DEVICE;
+ setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.wValue = hid->configuration_value;
+ setup_data.wIndex = 0;
+ setup_data.wLength = 0;
+
+ hid->state_next = STATE_SET_CONFIGURATION_EMPTY_READ;
+
+ device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
+ }
+ 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");
+ 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_WRITE_PENDING;
+ device_xfer_control_write_setup(&setup_data, sizeof(setup_data), report_event, hid->usbh_device);
+ return true;
+}
+
+bool hid_is_connected(uint8_t device_id)
+{
+ if (device_id >= USBH_HID_MAX_DEVICES) {
+ LOG_PRINTF("is connected: invalid device id");
+ 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
+};
+
+
+
diff --git a/src/usbh_driver_hid_mouse.c b/src/usbh_driver_hid_mouse.c
deleted file mode 100644
index b52392f..0000000
--- a/src/usbh_driver_hid_mouse.c
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * This file is part of the libusbhost library
- * hosted at http://github.com/libusbhost/libusbhost
- *
- * Copyright (C) 2015 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_mouse.h"
-#include "usart_helpers.h"
-
-#include <libopencm3/usb/usbstd.h>
-
-enum STATES {
- STATE_INACTIVE,
- STATE_READING_COMPLETE,
- STATE_READING_REQUEST,
- STATE_SET_CONFIGURATION_REQUEST,
- STATE_SET_CONFIGURATION_EMPTY_READ,
- STATE_SET_CONFIGURATION_COMPLETE
-};
-
-struct _hid_mouse_device {
- usbh_device_t *usbh_device;
- uint8_t buffer[USBH_HID_MOUSE_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;
-};
-typedef struct _hid_mouse_device hid_mouse_device_t;
-
-static hid_mouse_device_t mouse_device[USBH_HID_MOUSE_MAX_DEVICES];
-static const hid_mouse_config_t *mouse_config;
-
-
-
-
-#include <stdint.h>
-
-static bool initialized = false;
-
-void hid_mouse_driver_init(const hid_mouse_config_t *config)
-{
- uint32_t i;
-
- initialized = true;
-
- mouse_config = config;
- for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
- mouse_device[i].state_next = STATE_INACTIVE;
- }
-}
-
-/**
- *
- *
- */
-static void *init(void *usbh_dev)
-{
- if (!initialized) {
- LOG_PRINTF("\n%s/%d : driver not initialized\n", __FILE__, __LINE__);
- return 0;
- }
-
- uint32_t i;
- hid_mouse_device_t *drvdata = 0;
-
- // find free data space for mouse device
- for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
- if (mouse_device[i].state_next == STATE_INACTIVE) {
- drvdata = &mouse_device[i];
- drvdata->device_id = i;
- drvdata->endpoint_in_address = 0;
- drvdata->endpoint_in_toggle = 0;
- drvdata->usbh_device = (usbh_device_t *)usbh_dev;
- break;
- }
- }
-
- return drvdata;
-}
-
-/**
- * Returns true if all needed data are parsed
- */
-static bool analyze_descriptor(void *drvdata, void *descriptor)
-{
- hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
- uint8_t desc_type = ((uint8_t *)descriptor)[1];
- switch (desc_type) {
- case USB_DT_CONFIGURATION:
- {
- struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor;
- mouse->configuration_value = cfg->bConfigurationValue;
- }
- break;
- case USB_DT_DEVICE:
- break;
- case USB_DT_INTERFACE:
- break;
- case USB_DT_ENDPOINT:
- {
- struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor*)descriptor;
- if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) {
- uint8_t epaddr = ep->bEndpointAddress;
- if (epaddr & (1<<7)) {
- mouse->endpoint_in_address = epaddr&0x7f;
- if (ep->wMaxPacketSize < USBH_HID_MOUSE_BUFFER) {
- mouse->endpoint_in_maxpacketsize = ep->wMaxPacketSize;
- } else {
- mouse->endpoint_in_maxpacketsize = USBH_HID_MOUSE_BUFFER;
- }
- }
-
- if (mouse->endpoint_in_address) {
- mouse->state_next = STATE_SET_CONFIGURATION_REQUEST;
- return true;
- }
- }
- }
- break;
- // TODO Class Specific descriptors
- default:
- break;
- }
- return false;
-}
-
-static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
-{
- hid_mouse_device_t *mouse = (hid_mouse_device_t *)dev->drvdata;
- switch (mouse->state_next) {
- case STATE_READING_COMPLETE:
- {
- switch (cb_data.status) {
- case USBH_PACKET_CALLBACK_STATUS_OK:
- case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
- mouse->state_next = STATE_READING_REQUEST;
- break;
-
- case USBH_PACKET_CALLBACK_STATUS_EFATAL:
- case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
- ERROR(cb_data.status);
- mouse->state_next = STATE_INACTIVE;
- break;
- }
- }
- break;
-
- case STATE_SET_CONFIGURATION_EMPTY_READ:
- {
- LOG_PRINTF("|empty packet read|");
- switch (cb_data.status) {
- case USBH_PACKET_CALLBACK_STATUS_OK:
- mouse->state_next = STATE_SET_CONFIGURATION_COMPLETE;
- device_xfer_control_read(0, 0, event, dev);
- break;
-
- case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
- case USBH_PACKET_CALLBACK_STATUS_EFATAL:
- case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
- ERROR(cb_data.status);
- mouse->state_next = STATE_INACTIVE;
- break;
- }
- }
- break;
- case STATE_SET_CONFIGURATION_COMPLETE: // Configured
- {
- switch (cb_data.status) {
- case USBH_PACKET_CALLBACK_STATUS_OK:
- mouse->state_next = STATE_READING_REQUEST;
- mouse->endpoint_in_toggle = 0;
- LOG_PRINTF("\nMOUSE CONFIGURED\n");
- break;
-
- case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
- case USBH_PACKET_CALLBACK_STATUS_EFATAL:
- case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
- ERROR(cb_data.status);
- mouse->state_next = STATE_INACTIVE;
- break;
- }
- }
- break;
- default:
- break;
- }
-}
-
-
-static void read_mouse_in(void *drvdata)
-{
- hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
- usbh_packet_t packet;
-
- packet.address = mouse->usbh_device->address;
- packet.data.in = &mouse->buffer[0];
- packet.datalen = mouse->endpoint_in_maxpacketsize;
- packet.endpoint_address = mouse->endpoint_in_address;
- packet.endpoint_size_max = mouse->endpoint_in_maxpacketsize;
- packet.endpoint_type = USBH_ENDPOINT_TYPE_INTERRUPT;
- packet.speed = mouse->usbh_device->speed;
- packet.callback = event;
- packet.callback_arg = mouse->usbh_device;
- packet.toggle = &mouse->endpoint_in_toggle;
-
- mouse->state_next = STATE_READING_COMPLETE;
- usbh_read(mouse->usbh_device, &packet);
-
- // LOG_PRINTF("@MOUSE EP1 | \n");
-
-}
-
-/**
- * @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_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
- usbh_device_t *dev = mouse->usbh_device;
- switch (mouse->state_next) {
- case STATE_READING_REQUEST:
- {
- read_mouse_in(drvdata);
- }
- break;
-
- case STATE_SET_CONFIGURATION_REQUEST:
- {
- struct usb_setup_data setup_data;
-
- setup_data.bmRequestType = 0b00000000;
- setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
- setup_data.wValue = mouse->configuration_value;
- setup_data.wIndex = 0;
- setup_data.wLength = 0;
-
- mouse->state_next = STATE_SET_CONFIGURATION_EMPTY_READ;
-
- device_xfer_control_write_setup(&setup_data, sizeof(setup_data), event, dev);
- }
- break;
-
- default:
- // do nothing - probably transfer is in progress
- break;
- }
-}
-
-static void remove(void *drvdata)
-{
- hid_mouse_device_t *mouse = (hid_mouse_device_t *)drvdata;
- mouse->state_next = STATE_INACTIVE;
- mouse->endpoint_in_address = 0;
-}
-
-static const usbh_dev_driver_info_t driver_info = {
- .deviceClass = -1,
- .deviceSubClass = -1,
- .deviceProtocol = -1,
- .idVendor = -1,
- .idProduct = -1,
- .ifaceClass = 0x03,
- .ifaceSubClass = -1,
- .ifaceProtocol = 0x02
-};
-
-const usbh_dev_driver_t usbh_hid_mouse_driver = {
- .init = init,
- .analyze_descriptor = analyze_descriptor,
- .poll = poll,
- .remove = remove,
- .info = &driver_info
-};