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