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