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