/* * Tiny USB stack * HID device driver * * Copyright (C) 2014 Michael Buesch * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * * This program 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 General Public License for more details. */ #include "usb_hid.h" #include "usb.h" #include "util.h" #include #include /** struct hid_3bmouse_data - 3 button mouse wire protocol */ struct hid_3bmouse_data { uint8_t buttons; int8_t wheel; int16_t x; int16_t y; } __attribute__((packed)); #define bSize0 0x00 #define bSize1 0x01 #define bSize2 0x02 #define bSize4 0x03 #define bTypeMain (0x00 << 2) #define bTypeGlobal (0x01 << 2) #define bTypeLocal (0x02 << 2) #define bTypeReserved (0x03 << 2) #define bTagShift 4 #define bTag(tag) ((tag) << bTagShift) #define bit(bitNumber) (1 << (bitNumber)) #define le16(number) lo8(number), hi8(number) static const uint8_t USB_PROGMEM hid_3buttonmouse_descriptor[] = { /* Usage Page (Generic Desktop) */ bSize1 | bTypeGlobal | bTag(0x0), 0x01, /* Usage (Mouse) */ bSize1 | bTypeLocal | bTag(0x0), 0x02, /* Collection (Application) */ bSize1 | bTypeMain | bTag(0xA), 0x01, /* Usage (Pointer) */ bSize1 | bTypeLocal | bTag(0x0), 0x01, /* Collection (Physical) */ bSize1 | bTypeMain | bTag(0xA), 0x00, /*** Buttons ***/ /* Usage Page (Buttons) */ bSize1 | bTypeGlobal | bTag(0x0), 0x09, /* Usage Minimum */ bSize1 | bTypeLocal | bTag(0x1), 0x01, /* Usage Maximum */ bSize1 | bTypeLocal | bTag(0x2), 0x03, /* Logical Minimum */ bSize1 | bTypeGlobal | bTag(0x1), 0x00, /* Logical Maximum */ bSize1 | bTypeGlobal | bTag(0x2), 0x01, /* Report Count */ bSize1 | bTypeGlobal | bTag(0x9), 3, /* Report Size */ bSize1 | bTypeGlobal | bTag(0x7), 1, /* Input (Data, Variable, Absolute) */ bSize1 | bTypeMain | bTag(0x8), bit(1), /*** Padding ***/ /* Report Count */ bSize1 | bTypeGlobal | bTag(0x9), 1, /* Report Size */ bSize1 | bTypeGlobal | bTag(0x7), 5, /* Input (Constant) */ bSize1 | bTypeMain | bTag(0x8), bit(0), /*** Wheel ***/ /* Usage Page (Generic Desktop) */ bSize1 | bTypeGlobal | bTag(0x0), 0x01, /* Usage (Wheel) */ bSize1 | bTypeLocal | bTag(0x0), 0x38, /* Logical Minimum */ bSize1 | bTypeGlobal | bTag(0x1), -128, /* Logical Maximum */ bSize1 | bTypeGlobal | bTag(0x2), 127, /* Report Size */ bSize1 | bTypeGlobal | bTag(0x7), 8, /* Report Count */ bSize1 | bTypeGlobal | bTag(0x9), 1, /* Input (Data, Variable, Relative) */ bSize1 | bTypeMain | bTag(0x8), bit(1)|bit(2), /*** X/Y Axis ***/ /* Usage Page (Generic Desktop) */ bSize1 | bTypeGlobal | bTag(0x0), 0x01, /* Usage (X) */ bSize1 | bTypeLocal | bTag(0x0), 0x30, /* Usage (Y) */ bSize1 | bTypeLocal | bTag(0x0), 0x31, /* Logical Minimum */ bSize2 | bTypeGlobal | bTag(0x1), le16(-32768), /* Logical Maximum */ bSize2 | bTypeGlobal | bTag(0x2), le16(32767), /* Report Size */ bSize1 | bTypeGlobal | bTag(0x7), 16, /* Report Count */ bSize1 | bTypeGlobal | bTag(0x9), 2, /* Input (Data, Variable, Relative) */ bSize1 | bTypeMain | bTag(0x8), bit(1)|bit(2), /* End Collection */ bSize0 | bTypeMain | bTag(0xC), /* End Collection */ bSize0 | bTypeMain | bTag(0xC), }; #define hid_descriptor hid_3buttonmouse_descriptor uint16_t usb_hid_get_descriptor_length(void) { return sizeof(hid_descriptor); } void usb_hid_reset(void) { // usb_hid_ep2_txbuffer_empty(); } uint8_t usb_hid_control_rx(struct usb_ctrl *ctl, uint8_t *reply_buf) { usb_print1num("HID: Received control frame", ctl->bRequest); switch (ctl->bRequest) { case USB_REQ_GET_INTERFACE: /* Reply with a null frame */ return 0; case USB_REQ_GET_DESCRIPTOR: BUILD_BUG_ON(sizeof(hid_descriptor) > USBCFG_EP0_MAXSIZE); usb_copy_from_pgm(reply_buf, hid_descriptor, sizeof(hid_descriptor)); return sizeof(hid_descriptor); } return USB_HID_UNHANDLED; } uint8_t usb_hid_ep1_rx(uint8_t *data, uint8_t size, uint8_t *reply_buf) { usb_printstr("HID: Received EP1 frame\n"); return USB_HID_UNHANDLED; } uint8_t usb_hid_ep1_tx_poll(uint8_t *buf) { return 0; } uint8_t usb_hid_ep2_rx(uint8_t *data, uint8_t size, uint8_t *reply_buf) { usb_printstr("HID: Received EP2 frame\n"); return USB_HID_UNHANDLED; } /* The interrupt endpoint buffer is empty. * Refill it, so the next interrupt poll can fetch new data. */ uint8_t usb_hid_ep2_tx_poll(uint8_t *buf) { struct hid_3bmouse_data *d = (struct hid_3bmouse_data *)buf; memset(d, 0, sizeof(*d)); /* TODO: Test. Move the cursor towards the upper left. */ d->x = -1; d->y = -1; return sizeof(*d); }