1beacf11bSopenharmony_ci/* ---------------------------------------------------------------------------- 2beacf11bSopenharmony_ci * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019. All rights reserved. 3beacf11bSopenharmony_ci * Description: LiteOS USB Driver HID Data Stream 4beacf11bSopenharmony_ci * Author: wanghongxu 5beacf11bSopenharmony_ci * Create: 2019-10-24 6beacf11bSopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 7beacf11bSopenharmony_ci * are permitted provided that the following conditions are met: 8beacf11bSopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of 9beacf11bSopenharmony_ci * conditions and the following disclaimer. 10beacf11bSopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11beacf11bSopenharmony_ci * of conditions and the following disclaimer in the documentation and/or other materials 12beacf11bSopenharmony_ci * provided with the distribution. 13beacf11bSopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used 14beacf11bSopenharmony_ci * to endorse or promote products derived from this software without specific prior written 15beacf11bSopenharmony_ci * permission. 16beacf11bSopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17beacf11bSopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18beacf11bSopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19beacf11bSopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 20beacf11bSopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21beacf11bSopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22beacf11bSopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23beacf11bSopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24beacf11bSopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25beacf11bSopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 26beacf11bSopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27beacf11bSopenharmony_ci * --------------------------------------------------------------------------- */ 28beacf11bSopenharmony_ci/* ---------------------------------------------------------------------------- 29beacf11bSopenharmony_ci * Notice of Export Control Law 30beacf11bSopenharmony_ci * =============================================== 31beacf11bSopenharmony_ci * Huawei LiteOS may be subject to applicable export control laws and regulations, which might 32beacf11bSopenharmony_ci * include those applicable to Huawei LiteOS of U.S. and the country in which you are located. 33beacf11bSopenharmony_ci * Import, export and usage of Huawei LiteOS in any manner by you shall be in compliance with such 34beacf11bSopenharmony_ci * applicable export control laws and regulations. 35beacf11bSopenharmony_ci * --------------------------------------------------------------------------- */ 36beacf11bSopenharmony_ci 37beacf11bSopenharmony_ci#include <poll.h> 38beacf11bSopenharmony_ci#include "gadget/usbd_hid.h" 39beacf11bSopenharmony_ci#include "implementation/global_implementation.h" 40beacf11bSopenharmony_ci 41beacf11bSopenharmony_ci#ifdef __cplusplus 42beacf11bSopenharmony_ci#if __cplusplus 43beacf11bSopenharmony_ciextern "C" { 44beacf11bSopenharmony_ci#endif /* __cplusplus */ 45beacf11bSopenharmony_ci#endif /* __cplusplus */ 46beacf11bSopenharmony_ci 47beacf11bSopenharmony_cistatic int hid_open(FAR struct file *filep); 48beacf11bSopenharmony_cistatic int hid_close(FAR struct file *filep); 49beacf11bSopenharmony_cistatic ssize_t hid_read(FAR struct file *filep, FAR char *buffer, size_t buflen); 50beacf11bSopenharmony_cistatic ssize_t hid_write(FAR struct file *filep, FAR const char *buffer, size_t buflen); 51beacf11bSopenharmony_cistatic ssize_t hid_poll(FAR struct file *filep, poll_table *fds); 52beacf11bSopenharmony_ci 53beacf11bSopenharmony_cistatic const struct file_operations_vfs g_hid_fops = 54beacf11bSopenharmony_ci{ 55beacf11bSopenharmony_ci .open = hid_open, 56beacf11bSopenharmony_ci .close = hid_close, 57beacf11bSopenharmony_ci .read = hid_read, 58beacf11bSopenharmony_ci .write = hid_write, 59beacf11bSopenharmony_ci .seek = NULL, 60beacf11bSopenharmony_ci .ioctl = NULL, 61beacf11bSopenharmony_ci .mmap = NULL, 62beacf11bSopenharmony_ci#ifndef CONFIG_DISABLE_POLL 63beacf11bSopenharmony_ci .poll = hid_poll, 64beacf11bSopenharmony_ci#endif 65beacf11bSopenharmony_ci .unlink = NULL, 66beacf11bSopenharmony_ci}; 67beacf11bSopenharmony_ci 68beacf11bSopenharmony_cistatic int hid_open(FAR struct file *filep) 69beacf11bSopenharmony_ci{ 70beacf11bSopenharmony_ci struct hid_dev_s *hid = (struct hid_dev_s *)filep->f_inode->i_private; 71beacf11bSopenharmony_ci 72beacf11bSopenharmony_ci if (hid == NULL) 73beacf11bSopenharmony_ci { 74beacf11bSopenharmony_ci usb_err("Invalid private parameter!\n"); 75beacf11bSopenharmony_ci return -1; 76beacf11bSopenharmony_ci } 77beacf11bSopenharmony_ci 78beacf11bSopenharmony_ci atomic_set(&hid->open_flag, 1); 79beacf11bSopenharmony_ci 80beacf11bSopenharmony_ci return 0; 81beacf11bSopenharmony_ci} 82beacf11bSopenharmony_ci 83beacf11bSopenharmony_cistatic int hid_close(FAR struct file *filep) 84beacf11bSopenharmony_ci{ 85beacf11bSopenharmony_ci struct hid_dev_s *hid = (struct hid_dev_s *)filep->f_inode->i_private; 86beacf11bSopenharmony_ci 87beacf11bSopenharmony_ci if (hid == NULL) 88beacf11bSopenharmony_ci { 89beacf11bSopenharmony_ci usb_err("Invalid private parameter!\n"); 90beacf11bSopenharmony_ci return -1; 91beacf11bSopenharmony_ci } 92beacf11bSopenharmony_ci 93beacf11bSopenharmony_ci atomic_set(&hid->open_flag, 0); 94beacf11bSopenharmony_ci 95beacf11bSopenharmony_ci return 0; 96beacf11bSopenharmony_ci} 97beacf11bSopenharmony_ci 98beacf11bSopenharmony_ciint hid_fops_init(struct hid_dev_s *hid) 99beacf11bSopenharmony_ci{ 100beacf11bSopenharmony_ci int ret; 101beacf11bSopenharmony_ci 102beacf11bSopenharmony_ci hid->open_flag = 0; 103beacf11bSopenharmony_ci ret = register_driver(USB_HID_DEV, &g_hid_fops, O_RDWR, hid); 104beacf11bSopenharmony_ci if (ret != OK) 105beacf11bSopenharmony_ci { 106beacf11bSopenharmony_ci usb_err("hid_dev register failed!\n"); 107beacf11bSopenharmony_ci } 108beacf11bSopenharmony_ci 109beacf11bSopenharmony_ci return ret; 110beacf11bSopenharmony_ci} 111beacf11bSopenharmony_ci 112beacf11bSopenharmony_ciint hid_fops_deinit(const struct hid_dev_s *hid) 113beacf11bSopenharmony_ci{ 114beacf11bSopenharmony_ci int ret; 115beacf11bSopenharmony_ci 116beacf11bSopenharmony_ci if (hid == NULL) 117beacf11bSopenharmony_ci { 118beacf11bSopenharmony_ci return -1; 119beacf11bSopenharmony_ci } 120beacf11bSopenharmony_ci 121beacf11bSopenharmony_ci ret = unregister_driver(USB_HID_DEV); 122beacf11bSopenharmony_ci if (ret != OK) 123beacf11bSopenharmony_ci { 124beacf11bSopenharmony_ci usb_err("hid_dev unregister failed!\n"); 125beacf11bSopenharmony_ci } 126beacf11bSopenharmony_ci 127beacf11bSopenharmony_ci return ret; 128beacf11bSopenharmony_ci} 129beacf11bSopenharmony_ci 130beacf11bSopenharmony_cistruct hid_queue_node *hid_queue_node_alloc(size_t len) 131beacf11bSopenharmony_ci{ 132beacf11bSopenharmony_ci struct hid_queue_node *queue_node; 133beacf11bSopenharmony_ci 134beacf11bSopenharmony_ci queue_node = zalloc(sizeof(struct hid_queue_node)); 135beacf11bSopenharmony_ci if (queue_node == NULL) 136beacf11bSopenharmony_ci { 137beacf11bSopenharmony_ci usb_err("Malloc hid queue node failed\n"); 138beacf11bSopenharmony_ci return queue_node; 139beacf11bSopenharmony_ci } 140beacf11bSopenharmony_ci 141beacf11bSopenharmony_ci queue_node->buf_len = len; 142beacf11bSopenharmony_ci queue_node->buf_used = 0; 143beacf11bSopenharmony_ci queue_node->buf = malloc(len); 144beacf11bSopenharmony_ci if (queue_node->buf == NULL) 145beacf11bSopenharmony_ci { 146beacf11bSopenharmony_ci free(queue_node); 147beacf11bSopenharmony_ci usb_err("Malloc hid queue node buf failed\n"); 148beacf11bSopenharmony_ci return NULL; 149beacf11bSopenharmony_ci } 150beacf11bSopenharmony_ci 151beacf11bSopenharmony_ci return queue_node; 152beacf11bSopenharmony_ci} 153beacf11bSopenharmony_ci 154beacf11bSopenharmony_civoid hid_queue_node_free(struct hid_queue_node *node) 155beacf11bSopenharmony_ci{ 156beacf11bSopenharmony_ci free(node->buf); 157beacf11bSopenharmony_ci node->buf = NULL; 158beacf11bSopenharmony_ci free(node); 159beacf11bSopenharmony_ci} 160beacf11bSopenharmony_ci 161beacf11bSopenharmony_civoid hid_queue_free(struct hid_dev_s *sc) 162beacf11bSopenharmony_ci{ 163beacf11bSopenharmony_ci struct hid_queue_node *node; 164beacf11bSopenharmony_ci struct hid_dev_s *fhid_sc = sc; 165beacf11bSopenharmony_ci 166beacf11bSopenharmony_ci if (fhid_sc->cur_node != NULL) 167beacf11bSopenharmony_ci { 168beacf11bSopenharmony_ci hid_queue_node_free(fhid_sc->cur_node); 169beacf11bSopenharmony_ci fhid_sc->cur_node = NULL; 170beacf11bSopenharmony_ci } 171beacf11bSopenharmony_ci 172beacf11bSopenharmony_ci while (!list_empty(&fhid_sc->hid_queue)) 173beacf11bSopenharmony_ci { 174beacf11bSopenharmony_ci node = list_first_entry(&fhid_sc->hid_queue, struct hid_queue_node, irqqueue); 175beacf11bSopenharmony_ci list_del_init(&node->irqqueue); 176beacf11bSopenharmony_ci hid_queue_node_free(node); 177beacf11bSopenharmony_ci } 178beacf11bSopenharmony_ci INIT_LIST_HEAD(&fhid_sc->hid_queue); 179beacf11bSopenharmony_ci 180beacf11bSopenharmony_ci fhid_sc->hid_queue_len = 0; 181beacf11bSopenharmony_ci} 182beacf11bSopenharmony_ci 183beacf11bSopenharmony_civoid hid_send_data_sub(struct hid_dev_s *sc) 184beacf11bSopenharmony_ci{ 185beacf11bSopenharmony_ci struct hid_dev_s *fhid = sc; 186beacf11bSopenharmony_ci struct hid_queue_node *node; 187beacf11bSopenharmony_ci struct usbdev_req_s *req; 188beacf11bSopenharmony_ci 189beacf11bSopenharmony_ci node = fhid->cur_node; 190beacf11bSopenharmony_ci req = &fhid->inputreq; 191beacf11bSopenharmony_ci 192beacf11bSopenharmony_ci atomic_set(&fhid->busy_flag, 1); 193beacf11bSopenharmony_ci 194beacf11bSopenharmony_ci if (node->buf_len > HID_IN_DATA_SIZE) 195beacf11bSopenharmony_ci { 196beacf11bSopenharmony_ci req->len = HID_IN_DATA_SIZE; 197beacf11bSopenharmony_ci } 198beacf11bSopenharmony_ci else 199beacf11bSopenharmony_ci { 200beacf11bSopenharmony_ci req->len = node->buf_len; 201beacf11bSopenharmony_ci } 202beacf11bSopenharmony_ci req->buf = node->buf + node->buf_used; 203beacf11bSopenharmony_ci 204beacf11bSopenharmony_ci node->buf_len -= req->len; 205beacf11bSopenharmony_ci node->buf_used += req->len; 206beacf11bSopenharmony_ci (void)EP_SUBMIT(fhid->in_ep, req); 207beacf11bSopenharmony_ci} 208beacf11bSopenharmony_ci 209beacf11bSopenharmony_cistatic ssize_t hid_poll(FAR struct file *filep, poll_table *fds) 210beacf11bSopenharmony_ci{ 211beacf11bSopenharmony_ci struct hid_dev_s *hid = (struct hid_dev_s *)filep->f_inode->i_private; 212beacf11bSopenharmony_ci uint32_t revents = 0; 213beacf11bSopenharmony_ci uint32_t ret; 214beacf11bSopenharmony_ci uint32_t value = fds->key & (POLLIN | POLLRDNORM); 215beacf11bSopenharmony_ci 216beacf11bSopenharmony_ci if (hid == NULL) 217beacf11bSopenharmony_ci { 218beacf11bSopenharmony_ci usb_err("Invalid private parameter!\n"); 219beacf11bSopenharmony_ci return (POLLERR); 220beacf11bSopenharmony_ci } 221beacf11bSopenharmony_ci 222beacf11bSopenharmony_ci if (value) 223beacf11bSopenharmony_ci { 224beacf11bSopenharmony_ci ret = LOS_EventPoll(&hid->read_event.uwEventID, USB_HID_READ_EVENT, LOS_WAITMODE_OR); 225beacf11bSopenharmony_ci if (ret == USB_HID_READ_EVENT) 226beacf11bSopenharmony_ci { 227beacf11bSopenharmony_ci revents |= value; 228beacf11bSopenharmony_ci } 229beacf11bSopenharmony_ci } 230beacf11bSopenharmony_ci 231beacf11bSopenharmony_ci return (ssize_t)revents; 232beacf11bSopenharmony_ci} 233beacf11bSopenharmony_ci 234beacf11bSopenharmony_cistatic ssize_t hid_read(FAR struct file *filep, FAR char *buffer, size_t buflen) 235beacf11bSopenharmony_ci{ 236beacf11bSopenharmony_ci struct hid_dev_s *hid = (struct hid_dev_s *)filep->f_inode->i_private; 237beacf11bSopenharmony_ci uint32_t flags; 238beacf11bSopenharmony_ci errno_t ret; 239beacf11bSopenharmony_ci 240beacf11bSopenharmony_ci if (buflen == 0) 241beacf11bSopenharmony_ci { 242beacf11bSopenharmony_ci usb_err("buflen is 0!\n"); 243beacf11bSopenharmony_ci return -1; 244beacf11bSopenharmony_ci } 245beacf11bSopenharmony_ci 246beacf11bSopenharmony_ci if (buflen > HID_OUT_DATA_SIZE) 247beacf11bSopenharmony_ci { 248beacf11bSopenharmony_ci usb_err("buflen exceeds buffer size: %u\n", HID_OUT_DATA_SIZE); 249beacf11bSopenharmony_ci return -1; 250beacf11bSopenharmony_ci } 251beacf11bSopenharmony_ci 252beacf11bSopenharmony_ci if (hid == NULL) 253beacf11bSopenharmony_ci { 254beacf11bSopenharmony_ci usb_err("Invalid private parameter!\n"); 255beacf11bSopenharmony_ci return -1; 256beacf11bSopenharmony_ci } 257beacf11bSopenharmony_ci 258beacf11bSopenharmony_ci (VOID)LOS_EventRead(&hid->read_event, USB_HID_READ_EVENT, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); 259beacf11bSopenharmony_ci 260beacf11bSopenharmony_ci spin_lock_irqsave(&hid->hid_lock, flags); 261beacf11bSopenharmony_ci ret = usbd_copy_to_user(buffer, buflen, (const void *)hid->read_buf, hid->read_len); 262beacf11bSopenharmony_ci spin_unlock_irqrestore(&hid->hid_lock, flags); 263beacf11bSopenharmony_ci if (ret != EOK) 264beacf11bSopenharmony_ci { 265beacf11bSopenharmony_ci usb_err("memcpy failed!\n"); 266beacf11bSopenharmony_ci return -1; 267beacf11bSopenharmony_ci } 268beacf11bSopenharmony_ci 269beacf11bSopenharmony_ci return 0; 270beacf11bSopenharmony_ci} 271beacf11bSopenharmony_ci 272beacf11bSopenharmony_cistatic ssize_t hid_write(FAR struct file *filep, FAR const char *buffer, size_t buflen) 273beacf11bSopenharmony_ci{ 274beacf11bSopenharmony_ci struct hid_queue_node *node; 275beacf11bSopenharmony_ci struct hid_queue_node *node_temp; 276beacf11bSopenharmony_ci struct hid_dev_s *hid = (struct hid_dev_s *)filep->f_inode->i_private; 277beacf11bSopenharmony_ci uint32_t flags; 278beacf11bSopenharmony_ci int ret; 279beacf11bSopenharmony_ci 280beacf11bSopenharmony_ci if (buflen == 0) 281beacf11bSopenharmony_ci { 282beacf11bSopenharmony_ci usb_err("buflen is 0!\n"); 283beacf11bSopenharmony_ci return -1; 284beacf11bSopenharmony_ci } 285beacf11bSopenharmony_ci 286beacf11bSopenharmony_ci if (hid == NULL) 287beacf11bSopenharmony_ci { 288beacf11bSopenharmony_ci usb_err("Invalid private parameter!\n"); 289beacf11bSopenharmony_ci return -1; 290beacf11bSopenharmony_ci } 291beacf11bSopenharmony_ci 292beacf11bSopenharmony_ci node = hid_queue_node_alloc(buflen); 293beacf11bSopenharmony_ci if (node == NULL) 294beacf11bSopenharmony_ci { 295beacf11bSopenharmony_ci return -1; 296beacf11bSopenharmony_ci } 297beacf11bSopenharmony_ci 298beacf11bSopenharmony_ci /* buflen represents the size of the write data */ 299beacf11bSopenharmony_ci 300beacf11bSopenharmony_ci ret = usbd_copy_from_user(node->buf, buflen, buffer, buflen); 301beacf11bSopenharmony_ci if (ret != 0) 302beacf11bSopenharmony_ci { 303beacf11bSopenharmony_ci hid_queue_node_free(node); 304beacf11bSopenharmony_ci return -1; 305beacf11bSopenharmony_ci } 306beacf11bSopenharmony_ci spin_lock_irqsave(&hid->hid_lock, flags); 307beacf11bSopenharmony_ci if (hid->hid_queue_len > 8) 308beacf11bSopenharmony_ci { 309beacf11bSopenharmony_ci hid_queue_free(hid); 310beacf11bSopenharmony_ci } 311beacf11bSopenharmony_ci 312beacf11bSopenharmony_ci list_add_tail(&node->irqqueue, &hid->hid_queue); 313beacf11bSopenharmony_ci hid->hid_queue_len++; 314beacf11bSopenharmony_ci 315beacf11bSopenharmony_ci if (atomic_read(&hid->busy_flag)) 316beacf11bSopenharmony_ci { 317beacf11bSopenharmony_ci spin_unlock_irqrestore(&hid->hid_lock, flags); 318beacf11bSopenharmony_ci return 0; 319beacf11bSopenharmony_ci } 320beacf11bSopenharmony_ci 321beacf11bSopenharmony_ci if (!list_empty(&hid->hid_queue)) 322beacf11bSopenharmony_ci { 323beacf11bSopenharmony_ci node_temp = list_first_entry(&hid->hid_queue, struct hid_queue_node, irqqueue); 324beacf11bSopenharmony_ci list_del_init(&node_temp->irqqueue); 325beacf11bSopenharmony_ci hid->hid_queue_len--; 326beacf11bSopenharmony_ci hid->cur_node = node_temp; 327beacf11bSopenharmony_ci hid_send_data_sub(hid); 328beacf11bSopenharmony_ci } 329beacf11bSopenharmony_ci spin_unlock_irqrestore(&hid->hid_lock, flags); 330beacf11bSopenharmony_ci 331beacf11bSopenharmony_ci return 0; 332beacf11bSopenharmony_ci} 333beacf11bSopenharmony_ci 334beacf11bSopenharmony_ci#ifdef __cplusplus 335beacf11bSopenharmony_ci#if __cplusplus 336beacf11bSopenharmony_ci} 337beacf11bSopenharmony_ci#endif /* __cplusplus */ 338beacf11bSopenharmony_ci#endif /* __cplusplus */ 339