1 /* 2 * Copyright (c) 2006-2018, RT-Thread Development Team 3 * 4 * SPDX-License-Identifier: Apache-2.0 5 * 6 * Change Logs: 7 * Date Author Notes 8 * 2011-12-12 Yi Qiu first version 9 */ 10 11 #include <rtthread.h> 12 #include <drivers/usb_host.h> 13 #include "hid.h" 14 15 #ifdef RT_USBH_HID 16 17 static struct uclass_driver hid_driver; 18 static rt_list_t _protocal_list; 19 20 /** 21 * This function will do USB_REQ_SET_IDLE request to set idle period to the usb hid device 22 * 23 * @param intf the interface instance. 24 * @duration the idle period of requesting data. 25 * @report_id the report id 26 * 27 * @return the error code, RT_EOK on successfully. 28 */ 29 rt_err_t rt_usbh_hid_set_idle(struct uintf* intf, int duration, int report_id) 30 { 31 struct urequest setup; 32 struct uinstance* device; 33 int timeout = USB_TIMEOUT_BASIC; 34 35 /* parameter check */ 36 RT_ASSERT(intf != RT_NULL); 37 RT_ASSERT(intf->device != RT_NULL); 38 39 device = intf->device; 40 41 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | 42 USB_REQ_TYPE_INTERFACE; 43 setup.request = USB_REQ_SET_IDLE; 44 setup.index = 0; 45 setup.length = 0; 46 setup.value = (duration << 8 )| report_id; 47 48 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, 49 timeout) == 0) return RT_EOK; 50 else return -RT_FALSE; 51 } 52 53 /** 54 * This function will do USB_REQ_GET_REPORT request to get report from the usb hid device 55 * 56 * @param intf the interface instance. 57 * @buffer the data buffer to save usb report descriptor. 58 * @param nbytes the size of buffer 59 * 60 * @return the error code, RT_EOK on successfully. 61 */ 62 rt_err_t rt_usbh_hid_get_report(struct uintf* intf, rt_uint8_t type, 63 rt_uint8_t id, rt_uint8_t *buffer, rt_size_t size) 64 { 65 struct urequest setup; 66 struct uinstance* device; 67 int timeout = USB_TIMEOUT_BASIC; 68 69 /* parameter check */ 70 RT_ASSERT(intf != RT_NULL); 71 RT_ASSERT(intf->device != RT_NULL); 72 73 device = intf->device; 74 75 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | 76 USB_REQ_TYPE_INTERFACE; 77 setup.request = USB_REQ_GET_REPORT; 78 setup.index = intf->intf_desc->bInterfaceNumber; 79 setup.length = size; 80 setup.value = (type << 8 ) + id; 81 82 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, size, 83 timeout) == size) return RT_EOK; 84 else return -RT_FALSE; 85 } 86 87 /** 88 * This function will do USB_REQ_SET_REPORT request to set report to the usb hid device 89 * 90 * @param intf the interface instance. 91 * @buffer the data buffer to save usb report descriptor. 92 * @param nbytes the size of buffer 93 * 94 * @return the error code, RT_EOK on successfully. 95 */ 96 rt_err_t rt_usbh_hid_set_report(struct uintf* intf, rt_uint8_t *buffer, rt_size_t size) 97 { 98 struct urequest setup; 99 struct uinstance* device; 100 int timeout = USB_TIMEOUT_BASIC; 101 102 /* parameter check */ 103 RT_ASSERT(intf != RT_NULL); 104 RT_ASSERT(intf->device != RT_NULL); 105 106 device = intf->device; 107 108 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | 109 USB_REQ_TYPE_INTERFACE; 110 setup.request = USB_REQ_SET_REPORT; 111 setup.index = intf->intf_desc->bInterfaceNumber; 112 setup.length = size; 113 setup.value = 0x02 << 8; 114 115 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, size, 116 timeout) == size) return RT_EOK; 117 else return -RT_FALSE; 118 } 119 120 /** 121 * This function will do USB_REQ_SET_PROTOCOL request to set protocal to the usb hid device. 122 * 123 * @param intf the interface instance. 124 * @param protocol the protocol id. 125 * 126 * @return the error code, RT_EOK on successfully. 127 */ 128 rt_err_t rt_usbh_hid_set_protocal(struct uintf* intf, int protocol) 129 { 130 struct urequest setup; 131 struct uinstance* device; 132 int timeout = USB_TIMEOUT_BASIC; 133 134 /* parameter check */ 135 RT_ASSERT(intf != RT_NULL); 136 RT_ASSERT(intf->device != RT_NULL); 137 138 device = intf->device; 139 140 setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | 141 USB_REQ_TYPE_INTERFACE; 142 setup.request = USB_REQ_SET_PROTOCOL; 143 setup.index = 0; 144 setup.length = 0; 145 setup.value = protocol; 146 147 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0, 148 timeout) == 0) return RT_EOK; 149 else return -RT_FALSE; 150 } 151 152 /** 153 * This function will do USB_REQ_GET_DESCRIPTOR request for the device instance 154 * to set feature of the hub port. 155 * 156 * @param intf the interface instance. 157 * @buffer the data buffer to save usb report descriptor. 158 * @param nbytes the size of buffer 159 * 160 * @return the error code, RT_EOK on successfully. 161 */ 162 rt_err_t rt_usbh_hid_get_report_descriptor(struct uintf* intf, 163 rt_uint8_t *buffer, rt_size_t size) 164 { 165 struct urequest setup; 166 struct uinstance* device; 167 int timeout = USB_TIMEOUT_BASIC; 168 169 /* parameter check */ 170 RT_ASSERT(intf != RT_NULL); 171 RT_ASSERT(intf->device != RT_NULL); 172 173 device = intf->device; 174 175 setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_STANDARD| 176 USB_REQ_TYPE_INTERFACE; 177 setup.request = USB_REQ_GET_DESCRIPTOR; 178 setup.index = 0; 179 setup.length = size; 180 setup.value = USB_DESC_TYPE_REPORT << 8; 181 182 if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, buffer, size, 183 timeout) == size) return RT_EOK; 184 else return -RT_FALSE; 185 } 186 187 /** 188 * This function will register specified hid protocal to protocal list 189 * 190 * @param protocal the specified protocal. 191 * 192 * @return the error code, RT_EOK on successfully. 193 */ 194 rt_err_t rt_usbh_hid_protocal_register(uprotocal_t protocal) 195 { 196 RT_ASSERT(protocal != RT_NULL); 197 198 if (protocal == RT_NULL) return -RT_ERROR; 199 200 /* insert class driver into driver list */ 201 rt_list_insert_after(&_protocal_list, &(protocal->list)); 202 203 return RT_EOK; 204 } 205 206 /** 207 * This function is the callback function of hid's int endpoint, it is invoked when data comes. 208 * 209 * @param context the context of the callback function. 210 * 211 * @return none. 212 */ 213 static void rt_usbh_hid_callback(void* context) 214 { 215 upipe_t pipe; 216 struct uhid* hid; 217 int timeout = USB_TIMEOUT_LONG; 218 219 /* parameter check */ 220 RT_ASSERT(context != RT_NULL); 221 222 pipe = (upipe_t)context; 223 hid = (struct uhid*)pipe->intf->user_data; 224 225 /* invoke protocal callback function */ 226 hid->protocal->callback((void*)hid); 227 228 /* parameter check */ 229 RT_ASSERT(pipe->intf->device->hcd != RT_NULL); 230 231 rt_usb_hcd_int_xfer(pipe->intf->device->hcd, pipe, hid->buffer, 232 pipe->ep.wMaxPacketSize, timeout); 233 } 234 235 /** 236 * This function will find specified hid protocal from protocal list 237 * 238 * @param pro_id the protocal id. 239 * 240 * @return the found protocal or RT_NULL if there is no this protocal. 241 */ 242 static uprotocal_t rt_usbh_hid_protocal_find(int pro_id) 243 { 244 struct rt_list_node *node; 245 246 /* try to find protocal object */ 247 for (node = _protocal_list.next; node != &_protocal_list; node = node->next) 248 { 249 uprotocal_t protocal = 250 (uprotocal_t)rt_list_entry(node, struct uprotocal, list); 251 if (protocal->pro_id == pro_id) return protocal; 252 } 253 254 /* not found */ 255 return RT_NULL; 256 } 257 258 /** 259 * This function will run hid class driver when usb device is detected and identified 260 * as a hid class device, it will continue the enumulate process. 261 * 262 * @param arg the argument. 263 * 264 * @return the error code, RT_EOK on successfully. 265 */ 266 static rt_err_t rt_usbh_hid_enable(void* arg) 267 { 268 int i = 0, pro_id; 269 uprotocal_t protocal; 270 struct uhid* hid; 271 struct uintf* intf = (struct uintf*)arg; 272 int timeout = USB_TIMEOUT_BASIC; 273 upipe_t pipe; 274 275 /* parameter check */ 276 if(intf == RT_NULL) 277 { 278 rt_kprintf("the interface is not available\n"); 279 return -RT_EIO; 280 } 281 282 pro_id = intf->intf_desc->bInterfaceProtocol; 283 284 RT_DEBUG_LOG(RT_DEBUG_USB, 285 ("HID device enable, protocal id %d\n", pro_id)); 286 287 protocal = rt_usbh_hid_protocal_find(pro_id); 288 if(protocal == RT_NULL) 289 { 290 rt_kprintf("can't find hid protocal %d\n", pro_id); 291 intf->user_data = RT_NULL; 292 return -RT_ERROR; 293 } 294 295 hid = rt_malloc(sizeof(struct uhid)); 296 RT_ASSERT(hid != RT_NULL); 297 298 /* initilize the data structure */ 299 rt_memset(hid, 0, sizeof(struct uhid)); 300 intf->user_data = (void*)hid; 301 hid->protocal = protocal; 302 303 for(i=0; i<intf->intf_desc->bNumEndpoints; i++) 304 { 305 rt_err_t ret; 306 uep_desc_t ep_desc; 307 308 /* get endpoint descriptor */ 309 rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc); 310 if(ep_desc == RT_NULL) 311 { 312 rt_kprintf("rt_usbh_get_endpoint_descriptor error\n"); 313 return -RT_ERROR; 314 } 315 316 if(USB_EP_ATTR(ep_desc->bmAttributes) != USB_EP_ATTR_INT) 317 continue; 318 319 if(!(ep_desc->bEndpointAddress & USB_DIR_IN)) continue; 320 321 ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &hid->pipe_in, 322 intf, ep_desc, rt_usbh_hid_callback); 323 if(ret != RT_EOK) return ret; 324 } 325 326 /* initialize hid protocal */ 327 hid->protocal->init((void*)intf); 328 pipe = hid->pipe_in; 329 330 /* parameter check */ 331 RT_ASSERT(pipe->intf->device->hcd != RT_NULL); 332 333 rt_usb_hcd_int_xfer(pipe->intf->device->hcd, hid->pipe_in, 334 hid->buffer, hid->pipe_in->ep.wMaxPacketSize, timeout); 335 return RT_EOK; 336 } 337 338 /** 339 * This function will be invoked when usb device plug out is detected and it would clean 340 * and release all hub class related resources. 341 * 342 * @param arg the argument. 343 * 344 * @return the error code, RT_EOK on successfully. 345 */ 346 static rt_err_t rt_usbh_hid_disable(void* arg) 347 { 348 struct uhid* hid; 349 struct uintf* intf = (struct uintf*)arg; 350 351 RT_ASSERT(intf != RT_NULL); 352 353 RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_hid_disable\n")); 354 355 hid = (struct uhid*)intf->user_data; 356 if(hid != RT_NULL) 357 { 358 if(hid->pipe_in != RT_NULL) 359 { 360 /* free the HID in pipe */ 361 rt_usb_hcd_free_pipe(intf->device->hcd, hid->pipe_in); 362 } 363 364 /* free the hid instance */ 365 rt_free(hid); 366 } 367 368 /* free the instance */ 369 rt_free(intf); 370 371 return RT_EOK; 372 } 373 374 /** 375 * This function will register hid class driver to the usb class driver manager. 376 * and it should be invoked in the usb system initialization. 377 * 378 * @return the error code, RT_EOK on successfully. 379 */ 380 ucd_t rt_usbh_class_driver_hid(void) 381 { 382 rt_list_init(&_protocal_list); 383 384 hid_driver.class_code = USB_CLASS_HID; 385 386 hid_driver.enable = rt_usbh_hid_enable; 387 hid_driver.disable = rt_usbh_hid_disable; 388 389 return &hid_driver; 390 } 391 392 #endif 393 394