1/* 2 * Copyright 2017, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(DATA61_BSD) 11 */ 12 13/** 14 * @brief USB HID subclass driver 15 * @see USB HID subclass specification 16 */ 17#include <stdio.h> 18#include <string.h> 19 20#include "../services.h" 21#include "hid.h" 22#include "usbkbd.h" 23 24static inline struct usbreq 25__set_protocol_req(enum hid_protocol p, int iface) { 26 struct usbreq r = { 27 .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE), 28 .bRequest = SET_PROTOCOL, 29 .wValue = p, 30 .wIndex = iface, 31 .wLength = 0 32 }; 33 return r; 34} 35 36static inline struct usbreq 37__get_protocol_req(int iface) { 38 struct usbreq r = { 39 .bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE), 40 .bRequest = GET_PROTOCOL, 41 .wValue = 0, 42 .wIndex = iface, 43 .wLength = 1 44 }; 45 return r; 46} 47 48static inline struct usbreq 49__set_idle_req(int idle_ms, int id, int iface) { 50 struct usbreq r = { 51 .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE), 52 .bRequest = SET_IDLE, 53 .wValue = idle_ms << 8 | id, 54 .wIndex = iface, 55 .wLength = 0 56 }; 57 return r; 58} 59 60 61static inline struct usbreq 62__get_report_req(enum hid_report_type type, int id, int iface, int len) { 63 struct usbreq r = { 64 .bmRequestType = (USB_DIR_IN | USB_TYPE_CLS | USB_RCPT_INTERFACE), 65 .bRequest = GET_REPORT, 66 .wValue = type << 8 | id, 67 .wIndex = iface, 68 .wLength = len 69 }; 70 return r; 71} 72 73static inline struct usbreq 74__set_report_req(enum hid_report_type type, int id, int iface, int len) { 75 struct usbreq r = { 76 .bmRequestType = (USB_DIR_OUT | USB_TYPE_CLS | USB_RCPT_INTERFACE), 77 .bRequest = SET_REPORT, 78 .wValue = type << 8 | id, 79 .wIndex = iface, 80 .wLength = len 81 }; 82 return r; 83} 84 85static int 86usb_hid_config_cb(void *token, int cfg, int iface, struct anon_desc *desc) 87{ 88 struct usb_hid_device *hid; 89 struct config_desc *cdesc; 90 struct iface_desc *idesc; 91 struct hid_desc *hdesc; 92 93 if (!desc) { 94 return 0; 95 } 96 97 hid = (struct usb_hid_device *)token; 98 99 switch (desc->bDescriptorType) { 100 case CONFIGURATION: 101 cdesc = (struct config_desc*)desc; 102 hid->config = cdesc->bConfigurationValue; 103 break; 104 case INTERFACE: 105 idesc = (struct iface_desc *)desc; 106 if (idesc->bInterfaceSubClass == 1) { 107 hid->subclass = idesc->bInterfaceSubClass; 108 hid->protocol = idesc->bInterfaceProtocol; 109 hid->iface = idesc->bInterfaceNumber; 110 } 111 break; 112 case HID: 113 hdesc = (struct hid_desc *)desc; 114 if (!hid->subclass) { 115 if (hdesc->bReportDescriptorType== HID_REPORT) { 116 hid->report_size = hdesc->wReportDescriptorLength; 117 } else { 118 ZF_LOGD("Descriptor %u not supported!\n", 119 hdesc->bReportDescriptorType); 120 } 121 } 122 break; 123 default: 124 break; 125 } 126 127 return 0; 128} 129 130struct usb_hid_device *usb_hid_alloc(struct usb_dev *udev) 131{ 132 int err; 133 struct usb_hid_device *hid; 134 struct xact xact; 135 struct usbreq *req; 136 int class; 137 138 if (!udev) { 139 ZF_LOGF("Invalid device\n"); 140 } 141 142 hid = usb_malloc(sizeof(struct usb_hid_device)); 143 if (!hid) { 144 ZF_LOGD("Not enough memory!\n"); 145 return NULL; 146 } 147 148 hid->udev = udev; 149 hid->subclass = 0xFF; 150 151 /* Parse the descriptors */ 152 err = usbdev_parse_config(udev, usb_hid_config_cb, hid); 153 if (err) { 154 ZF_LOGF("Invalid descriptors\n"); 155 } 156 157 class = usbdev_get_class(udev); 158 if (class != USB_CLASS_HID) { 159 ZF_LOGD("Not a HID device(%d)\n", class); 160 usb_free(hid); 161 return NULL; 162 } 163 164 /* Activate configuration */ 165 xact.len = sizeof(struct usbreq); 166 err = usb_alloc_xact(udev->dman, &xact, 1); 167 if (err) { 168 ZF_LOGF("Out of DMA memory\n"); 169 } 170 171 /* Fill in the request */ 172 xact.type = PID_SETUP; 173 req = xact_get_vaddr(&xact); 174 *req = __set_configuration_req(hid->config); 175 176 /* Send the request to the host */ 177 err = usbdev_schedule_xact(udev, udev->ep_ctrl, &xact, 1, NULL, NULL); 178 if (err) { 179 ZF_LOGF("Transaction error\n"); 180 } 181 182 usb_destroy_xact(udev->dman, &xact, 1); 183 184 return hid; 185} 186 187void usb_hid_free(struct usb_hid_device *hid) 188{ 189 usb_free(hid); 190} 191 192int usb_hid_set_idle(struct usb_hid_device *hid, int idle_ms) 193{ 194 int err; 195 struct usbreq *req; 196 struct xact xact; 197 198 xact.type = PID_SETUP; 199 xact.len = sizeof(struct usbreq); 200 201 err = usb_alloc_xact(hid->udev->dman, &xact, 1); 202 if (err) { 203 ZF_LOGF("Out of DMA memory\n"); 204 } 205 206 req = xact_get_vaddr(&xact); 207 *req = __set_idle_req(idle_ms, 0, hid->iface); 208 209 err = usbdev_schedule_xact(hid->udev, hid->udev->ep_ctrl, &xact, 1, NULL, NULL); 210 if (err) { 211 ZF_LOGF("Transaction error\n"); 212 } 213 214 usb_destroy_xact(hid->udev->dman, &xact, 1); 215 216 return err; 217} 218 219int usb_hid_get_idle(struct usb_hid_device *hid) 220{ 221 return 0; 222} 223 224int usb_hid_get_report(struct usb_hid_device *hid, enum hid_report_type type, void *buf) 225{ 226 return 0; 227} 228 229int usb_hid_set_report(struct usb_hid_device *hid, enum hid_report_type type, 230 void *buf, int size) 231{ 232 int err; 233 struct usbreq *req; 234 struct xact xact[2]; 235 236 xact[0].type = PID_SETUP; 237 xact[0].len = sizeof(struct usbreq); 238 xact[1].type = PID_OUT; 239 xact[1].len = size; 240 241 err = usb_alloc_xact(hid->udev->dman, xact, 2); 242 if (err) { 243 ZF_LOGF("Out of DMA memory\n"); 244 } 245 246 req = xact_get_vaddr(&xact[0]); 247 *req = __set_report_req(REPORT_OUTPUT, 0, hid->iface, size); 248 249 memcpy(xact_get_vaddr(&xact[1]), buf, size); 250 251 err = usbdev_schedule_xact(hid->udev, hid->udev->ep_ctrl, xact, 2, NULL, NULL); 252 if (err) { 253 ZF_LOGF("Transaction error\n"); 254 } 255 256 usb_destroy_xact(hid->udev->dman, xact, 2); 257 258 return err; 259} 260 261int usb_hid_get_protocol(struct usb_hid_device *hid) 262{ 263 return 0; 264} 265 266int usb_hid_set_protocol(struct usb_hid_device *hid) 267{ 268 return 0; 269} 270 271