diff options
Diffstat (limited to 'lib/chibios-contrib/os/hal/src/hal_usb_hid.c')
-rw-r--r-- | lib/chibios-contrib/os/hal/src/hal_usb_hid.c | 589 |
1 files changed, 589 insertions, 0 deletions
diff --git a/lib/chibios-contrib/os/hal/src/hal_usb_hid.c b/lib/chibios-contrib/os/hal/src/hal_usb_hid.c new file mode 100644 index 000000000..8b0ac3292 --- /dev/null +++ b/lib/chibios-contrib/os/hal/src/hal_usb_hid.c | |||
@@ -0,0 +1,589 @@ | |||
1 | /* | ||
2 | ChibiOS - Copyright (C) 2016 Jonathan Struebel | ||
3 | |||
4 | Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | you may not use this file except in compliance with the License. | ||
6 | You may obtain a copy of the License at | ||
7 | |||
8 | http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | |||
10 | Unless required by applicable law or agreed to in writing, software | ||
11 | distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | See the License for the specific language governing permissions and | ||
14 | limitations under the License. | ||
15 | */ | ||
16 | |||
17 | /** | ||
18 | * @file hal_usb_hid.c | ||
19 | * @brief USB HID Driver code. | ||
20 | * | ||
21 | * @addtogroup USB_HID | ||
22 | * @{ | ||
23 | */ | ||
24 | |||
25 | #include "hal.h" | ||
26 | |||
27 | #if (HAL_USE_USB_HID == TRUE) || defined(__DOXYGEN__) | ||
28 | |||
29 | /*===========================================================================*/ | ||
30 | /* Driver local definitions. */ | ||
31 | /*===========================================================================*/ | ||
32 | |||
33 | /*===========================================================================*/ | ||
34 | /* Driver exported variables. */ | ||
35 | /*===========================================================================*/ | ||
36 | |||
37 | /*===========================================================================*/ | ||
38 | /* Driver local variables and types. */ | ||
39 | /*===========================================================================*/ | ||
40 | |||
41 | /*===========================================================================*/ | ||
42 | /* Driver local functions. */ | ||
43 | /*===========================================================================*/ | ||
44 | |||
45 | static uint16_t get_hword(uint8_t *p) { | ||
46 | uint16_t hw; | ||
47 | |||
48 | hw = (uint16_t)*p++; | ||
49 | hw |= (uint16_t)*p << 8U; | ||
50 | return hw; | ||
51 | } | ||
52 | |||
53 | /* | ||
54 | * Interface implementation. | ||
55 | */ | ||
56 | |||
57 | static size_t write(void *ip, const uint8_t *bp, size_t n) { | ||
58 | |||
59 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
60 | return 0; | ||
61 | } | ||
62 | |||
63 | return obqWriteTimeout(&((USBHIDDriver *)ip)->obqueue, bp, | ||
64 | n, TIME_INFINITE); | ||
65 | } | ||
66 | |||
67 | static size_t read(void *ip, uint8_t *bp, size_t n) { | ||
68 | |||
69 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
70 | return 0; | ||
71 | } | ||
72 | |||
73 | return ibqReadTimeout(&((USBHIDDriver *)ip)->ibqueue, bp, | ||
74 | n, TIME_INFINITE); | ||
75 | } | ||
76 | |||
77 | static msg_t put(void *ip, uint8_t b) { | ||
78 | |||
79 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
80 | return MSG_RESET; | ||
81 | } | ||
82 | |||
83 | return obqPutTimeout(&((USBHIDDriver *)ip)->obqueue, b, TIME_INFINITE); | ||
84 | } | ||
85 | |||
86 | static msg_t get(void *ip) { | ||
87 | |||
88 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
89 | return MSG_RESET; | ||
90 | } | ||
91 | |||
92 | return ibqGetTimeout(&((USBHIDDriver *)ip)->ibqueue, TIME_INFINITE); | ||
93 | } | ||
94 | |||
95 | static msg_t putt(void *ip, uint8_t b, systime_t timeout) { | ||
96 | |||
97 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
98 | return MSG_RESET; | ||
99 | } | ||
100 | |||
101 | return obqPutTimeout(&((USBHIDDriver *)ip)->obqueue, b, timeout); | ||
102 | } | ||
103 | |||
104 | static msg_t gett(void *ip, systime_t timeout) { | ||
105 | |||
106 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
107 | return MSG_RESET; | ||
108 | } | ||
109 | |||
110 | return ibqGetTimeout(&((USBHIDDriver *)ip)->ibqueue, timeout); | ||
111 | } | ||
112 | |||
113 | static size_t writet(void *ip, const uint8_t *bp, size_t n, systime_t timeout) { | ||
114 | |||
115 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | return obqWriteTimeout(&((USBHIDDriver *)ip)->obqueue, bp, n, timeout); | ||
120 | } | ||
121 | |||
122 | static size_t readt(void *ip, uint8_t *bp, size_t n, systime_t timeout) { | ||
123 | |||
124 | if (usbGetDriverStateI(((USBHIDDriver *)ip)->config->usbp) != USB_ACTIVE) { | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | return ibqReadTimeout(&((USBHIDDriver *)ip)->ibqueue, bp, n, timeout); | ||
129 | } | ||
130 | |||
131 | static msg_t ctl(void *ip, unsigned int operation, void *arg) { | ||
132 | (void)ip; | ||
133 | (void)operation; | ||
134 | (void)arg; | ||
135 | return MSG_OK; | ||
136 | } | ||
137 | |||
138 | static void flush(void *ip) { | ||
139 | |||
140 | obqFlush(&((USBHIDDriver *)ip)->obqueue); | ||
141 | } | ||
142 | |||
143 | static const struct USBHIDDriverVMT vmt = { | ||
144 | (size_t)0, | ||
145 | write, read, put, get, | ||
146 | putt, gett, writet, readt, | ||
147 | ctl, flush | ||
148 | }; | ||
149 | |||
150 | /** | ||
151 | * @brief Notification of empty buffer released into the input buffers queue. | ||
152 | * | ||
153 | * @param[in] bqp the buffers queue pointer. | ||
154 | */ | ||
155 | static void ibnotify(io_buffers_queue_t *bqp) { | ||
156 | USBHIDDriver *uhdp = bqGetLinkX(bqp); | ||
157 | |||
158 | /* If the USB driver is not in the appropriate state then transactions | ||
159 | must not be started.*/ | ||
160 | if ((usbGetDriverStateI(uhdp->config->usbp) != USB_ACTIVE) || | ||
161 | (uhdp->state != HID_READY)) { | ||
162 | return; | ||
163 | } | ||
164 | |||
165 | /* Checking if there is already a transaction ongoing on the endpoint.*/ | ||
166 | if (!usbGetReceiveStatusI(uhdp->config->usbp, uhdp->config->int_out)) { | ||
167 | /* Trying to get a free buffer.*/ | ||
168 | uint8_t *buf = ibqGetEmptyBufferI(&uhdp->ibqueue); | ||
169 | if (buf != NULL) { | ||
170 | /* Buffer found, starting a new transaction.*/ | ||
171 | usbStartReceiveI(uhdp->config->usbp, uhdp->config->int_out, | ||
172 | buf, SERIAL_USB_BUFFERS_SIZE); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | /** | ||
178 | * @brief Notification of filled buffer inserted into the output buffers queue. | ||
179 | * | ||
180 | * @param[in] bqp the buffers queue pointer. | ||
181 | */ | ||
182 | static void obnotify(io_buffers_queue_t *bqp) { | ||
183 | size_t n; | ||
184 | USBHIDDriver *uhdp = bqGetLinkX(bqp); | ||
185 | |||
186 | /* If the USB driver is not in the appropriate state then transactions | ||
187 | must not be started.*/ | ||
188 | if ((usbGetDriverStateI(uhdp->config->usbp) != USB_ACTIVE) || | ||
189 | (uhdp->state != HID_READY)) { | ||
190 | return; | ||
191 | } | ||
192 | |||
193 | /* Checking if there is already a transaction ongoing on the endpoint.*/ | ||
194 | if (!usbGetTransmitStatusI(uhdp->config->usbp, uhdp->config->int_in)) { | ||
195 | /* Trying to get a full buffer.*/ | ||
196 | uint8_t *buf = obqGetFullBufferI(&uhdp->obqueue, &n); | ||
197 | if (buf != NULL) { | ||
198 | /* Buffer found, starting a new transaction.*/ | ||
199 | usbStartTransmitI(uhdp->config->usbp, uhdp->config->int_in, buf, n); | ||
200 | } | ||
201 | } | ||
202 | } | ||
203 | |||
204 | /*===========================================================================*/ | ||
205 | /* Driver exported functions. */ | ||
206 | /*===========================================================================*/ | ||
207 | |||
208 | /** | ||
209 | * @brief USB HID Driver initialization. | ||
210 | * @note This function is implicitly invoked by @p halInit(), there is | ||
211 | * no need to explicitly initialize the driver. | ||
212 | * | ||
213 | * @init | ||
214 | */ | ||
215 | void hidInit(void) { | ||
216 | } | ||
217 | |||
218 | /** | ||
219 | * @brief Initializes a generic full duplex USB HID driver object. | ||
220 | * @details The HW dependent part of the initialization has to be performed | ||
221 | * outside, usually in the hardware initialization code. | ||
222 | * | ||
223 | * @param[out] uhdp pointer to a @p USBHIDDriver structure | ||
224 | * | ||
225 | * @init | ||
226 | */ | ||
227 | void hidObjectInit(USBHIDDriver *uhdp) { | ||
228 | |||
229 | uhdp->vmt = &vmt; | ||
230 | osalEventObjectInit(&uhdp->event); | ||
231 | uhdp->state = HID_STOP; | ||
232 | ibqObjectInit(&uhdp->ibqueue, true, uhdp->ib, | ||
233 | USB_HID_BUFFERS_SIZE, USB_HID_BUFFERS_NUMBER, | ||
234 | ibnotify, uhdp); | ||
235 | obqObjectInit(&uhdp->obqueue, true, uhdp->ob, | ||
236 | USB_HID_BUFFERS_SIZE, USB_HID_BUFFERS_NUMBER, | ||
237 | obnotify, uhdp); | ||
238 | } | ||
239 | |||
240 | /** | ||
241 | * @brief Configures and starts the driver. | ||
242 | * | ||
243 | * @param[in] uhdp pointer to a @p USBHIDDriver object | ||
244 | * @param[in] config the USB HID driver configuration | ||
245 | * | ||
246 | * @api | ||
247 | */ | ||
248 | void hidStart(USBHIDDriver *uhdp, const USBHIDConfig *config) { | ||
249 | USBDriver *usbp = config->usbp; | ||
250 | |||
251 | osalDbgCheck(uhdp != NULL); | ||
252 | |||
253 | osalSysLock(); | ||
254 | osalDbgAssert((uhdp->state == HID_STOP) || (uhdp->state == HID_READY), | ||
255 | "invalid state"); | ||
256 | usbp->in_params[config->int_in - 1U] = uhdp; | ||
257 | usbp->out_params[config->int_out - 1U] = uhdp; | ||
258 | uhdp->config = config; | ||
259 | uhdp->state = HID_READY; | ||
260 | osalSysUnlock(); | ||
261 | } | ||
262 | |||
263 | /** | ||
264 | * @brief Stops the driver. | ||
265 | * @details Any thread waiting on the driver's queues will be awakened with | ||
266 | * the message @p MSG_RESET. | ||
267 | * | ||
268 | * @param[in] uhdp pointer to a @p USBHIDDriver object | ||
269 | * | ||
270 | * @api | ||
271 | */ | ||
272 | void hidStop(USBHIDDriver *uhdp) { | ||
273 | USBDriver *usbp = uhdp->config->usbp; | ||
274 | |||
275 | osalDbgCheck(uhdp != NULL); | ||
276 | |||
277 | osalSysLock(); | ||
278 | osalDbgAssert((uhdp->state == HID_STOP) || (uhdp->state == HID_READY), | ||
279 | "invalid state"); | ||
280 | |||
281 | /* Driver in stopped state.*/ | ||
282 | usbp->in_params[uhdp->config->int_in - 1U] = NULL; | ||
283 | usbp->out_params[uhdp->config->int_out - 1U] = NULL; | ||
284 | uhdp->state = HID_STOP; | ||
285 | |||
286 | /* Enforces a disconnection.*/ | ||
287 | hidDisconnectI(uhdp); | ||
288 | osalOsRescheduleS(); | ||
289 | osalSysUnlock(); | ||
290 | } | ||
291 | |||
292 | /** | ||
293 | * @brief USB device disconnection handler. | ||
294 | * @note If this function is not called from an ISR then an explicit call | ||
295 | * to @p osalOsRescheduleS() in necessary afterward. | ||
296 | * | ||
297 | * @param[in] uhdp pointer to a @p USBHIDDriver object | ||
298 | * | ||
299 | * @iclass | ||
300 | */ | ||
301 | void hidDisconnectI(USBHIDDriver *uhdp) { | ||
302 | |||
303 | /* Queues reset in order to signal the driver stop to the application.*/ | ||
304 | chnAddFlagsI(uhdp, CHN_DISCONNECTED); | ||
305 | ibqResetI(&uhdp->ibqueue); | ||
306 | obqResetI(&uhdp->obqueue); | ||
307 | } | ||
308 | |||
309 | /** | ||
310 | * @brief USB device configured handler. | ||
311 | * | ||
312 | * @param[in] uhdp pointer to a @p USBHIDDriver object | ||
313 | * | ||
314 | * @iclass | ||
315 | */ | ||
316 | void hidConfigureHookI(USBHIDDriver *uhdp) { | ||
317 | uint8_t *buf; | ||
318 | |||
319 | ibqResetI(&uhdp->ibqueue); | ||
320 | obqResetI(&uhdp->obqueue); | ||
321 | chnAddFlagsI(uhdp, CHN_CONNECTED); | ||
322 | |||
323 | /* Starts the first OUT transaction immediately.*/ | ||
324 | buf = ibqGetEmptyBufferI(&uhdp->ibqueue); | ||
325 | |||
326 | osalDbgAssert(buf != NULL, "no free buffer"); | ||
327 | |||
328 | usbStartReceiveI(uhdp->config->usbp, uhdp->config->int_out, | ||
329 | buf, USB_HID_BUFFERS_SIZE); | ||
330 | } | ||
331 | |||
332 | /** | ||
333 | * @brief Default requests hook. | ||
334 | * @details Applications wanting to use the USB HID driver can use | ||
335 | * this function at the end of the application specific | ||
336 | * requests hook. The HID_* requests handled here do not | ||
337 | * transfer any data to the application. | ||
338 | * The following requests are handled: | ||
339 | * - HID_GET_IDLE. | ||
340 | * - HID_GET_PROTOCOL. | ||
341 | * - HID_SET_REPORT. | ||
342 | * - HID_SET_IDLE. | ||
343 | * - HID_SET_PROTOCOL. | ||
344 | * - USB_REQ_GET_DESCRIPTOR. | ||
345 | * . | ||
346 | * | ||
347 | * @param[in] usbp pointer to the @p USBDriver object | ||
348 | * @return The hook status. | ||
349 | * @retval true Message handled internally. | ||
350 | * @retval false Message not handled. | ||
351 | */ | ||
352 | bool hidRequestsHook(USBDriver *usbp) { | ||
353 | const USBDescriptor *dp; | ||
354 | |||
355 | if ((usbp->setup[0] & USB_RTYPE_TYPE_MASK) == USB_RTYPE_TYPE_CLASS) { | ||
356 | switch (usbp->setup[1]) { | ||
357 | case HID_GET_IDLE: | ||
358 | usbSetupTransfer(usbp, NULL, 0, NULL); | ||
359 | return true; | ||
360 | case HID_GET_PROTOCOL: | ||
361 | return true; | ||
362 | case HID_SET_REPORT: | ||
363 | usbSetupTransfer(usbp, NULL, 0, NULL); | ||
364 | return true; | ||
365 | case HID_SET_IDLE: | ||
366 | usbSetupTransfer(usbp, NULL, 0, NULL); | ||
367 | return true; | ||
368 | case HID_SET_PROTOCOL: | ||
369 | return true; | ||
370 | default: | ||
371 | return false; | ||
372 | } | ||
373 | } | ||
374 | |||
375 | /* GET_DESCRIPTOR from interface not handled by default so handle it here */ | ||
376 | if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) == USB_RTYPE_DIR_DEV2HOST) && | ||
377 | ((usbp->setup[0] & USB_RTYPE_RECIPIENT_MASK) == USB_RTYPE_RECIPIENT_INTERFACE)) { | ||
378 | switch (usbp->setup[1]) { | ||
379 | case USB_REQ_GET_DESCRIPTOR: | ||
380 | dp = usbp->config->get_descriptor_cb(usbp, usbp->setup[3], usbp->setup[2], | ||
381 | get_hword(&usbp->setup[4])); | ||
382 | if (dp == NULL) | ||
383 | return false; | ||
384 | |||
385 | usbSetupTransfer(usbp, (uint8_t *)dp->ud_string, dp->ud_size, NULL); | ||
386 | return true; | ||
387 | default: | ||
388 | return false; | ||
389 | } | ||
390 | } | ||
391 | return false; | ||
392 | } | ||
393 | |||
394 | /** | ||
395 | * @brief Default data transmitted callback. | ||
396 | * @details The application must use this function as callback for the IN | ||
397 | * data endpoint. | ||
398 | * | ||
399 | * @param[in] usbp pointer to the @p USBDriver object | ||
400 | * @param[in] ep IN endpoint number | ||
401 | */ | ||
402 | void hidDataTransmitted(USBDriver *usbp, usbep_t ep) { | ||
403 | uint8_t *buf; | ||
404 | size_t n; | ||
405 | USBHIDDriver *uhdp = usbp->in_params[ep - 1U]; | ||
406 | |||
407 | if (uhdp == NULL) { | ||
408 | return; | ||
409 | } | ||
410 | |||
411 | osalSysLockFromISR(); | ||
412 | |||
413 | /* Signaling that space is available in the output queue.*/ | ||
414 | chnAddFlagsI(uhdp, CHN_OUTPUT_EMPTY); | ||
415 | |||
416 | /* Freeing the buffer just transmitted, if it was not a zero size packet.*/ | ||
417 | if (usbp->epc[ep]->in_state->txsize > 0U) { | ||
418 | obqReleaseEmptyBufferI(&uhdp->obqueue); | ||
419 | } | ||
420 | |||
421 | /* Checking if there is a buffer ready for transmission.*/ | ||
422 | buf = obqGetFullBufferI(&uhdp->obqueue, &n); | ||
423 | |||
424 | if (buf != NULL) { | ||
425 | /* The endpoint cannot be busy, we are in the context of the callback, | ||
426 | so it is safe to transmit without a check.*/ | ||
427 | usbStartTransmitI(usbp, ep, buf, n); | ||
428 | } | ||
429 | else if ((usbp->epc[ep]->in_state->txsize > 0U) && | ||
430 | ((usbp->epc[ep]->in_state->txsize & | ||
431 | ((size_t)usbp->epc[ep]->in_maxsize - 1U)) == 0U)) { | ||
432 | /* Transmit zero sized packet in case the last one has maximum allowed | ||
433 | size. Otherwise the recipient may expect more data coming soon and | ||
434 | not return buffered data to app. See section 5.8.3 Bulk Transfer | ||
435 | Packet Size Constraints of the USB Specification document.*/ | ||
436 | usbStartTransmitI(usbp, ep, usbp->setup, 0); | ||
437 | |||
438 | } | ||
439 | else { | ||
440 | /* Nothing to transmit.*/ | ||
441 | } | ||
442 | |||
443 | osalSysUnlockFromISR(); | ||
444 | } | ||
445 | |||
446 | /** | ||
447 | * @brief Default data received callback. | ||
448 | * @details The application must use this function as callback for the OUT | ||
449 | * data endpoint. | ||
450 | * | ||
451 | * @param[in] usbp pointer to the @p USBDriver object | ||
452 | * @param[in] ep OUT endpoint number | ||
453 | */ | ||
454 | void hidDataReceived(USBDriver *usbp, usbep_t ep) { | ||
455 | uint8_t *buf; | ||
456 | USBHIDDriver *uhdp = usbp->out_params[ep - 1U]; | ||
457 | |||
458 | if (uhdp == NULL) { | ||
459 | return; | ||
460 | } | ||
461 | |||
462 | osalSysLockFromISR(); | ||
463 | |||
464 | /* Signaling that data is available in the input queue.*/ | ||
465 | chnAddFlagsI(uhdp, CHN_INPUT_AVAILABLE); | ||
466 | |||
467 | /* Posting the filled buffer in the queue.*/ | ||
468 | ibqPostFullBufferI(&uhdp->ibqueue, | ||
469 | usbGetReceiveTransactionSizeX(uhdp->config->usbp, ep)); | ||
470 | |||
471 | /* The endpoint cannot be busy, we are in the context of the callback, | ||
472 | so a packet is in the buffer for sure. Trying to get a free buffer | ||
473 | for the next transaction.*/ | ||
474 | buf = ibqGetEmptyBufferI(&uhdp->ibqueue); | ||
475 | if (buf != NULL) { | ||
476 | /* Buffer found, starting a new transaction.*/ | ||
477 | usbStartReceiveI(uhdp->config->usbp, ep, buf, USB_HID_BUFFERS_SIZE); | ||
478 | } | ||
479 | |||
480 | osalSysUnlockFromISR(); | ||
481 | } | ||
482 | |||
483 | /** | ||
484 | * @brief Write HID Report | ||
485 | * @details The function writes data from a buffer to an output queue. The | ||
486 | * operation completes when the specified amount of data has been | ||
487 | * transferred or if the queue has been reset. | ||
488 | * | ||
489 | * @param[in] uhdp pointer to the @p USBHIDDriver object | ||
490 | * @param[in] bp pointer to the report data buffer | ||
491 | * @param[in] n the maximum amount of data to be transferred, the | ||
492 | * value 0 is reserved | ||
493 | * @return The number of bytes effectively transferred. | ||
494 | * @retval 0 if a timeout occurred. | ||
495 | * | ||
496 | * @api | ||
497 | */ | ||
498 | size_t hidWriteReport(USBHIDDriver *uhdp, uint8_t *bp, size_t n) { | ||
499 | size_t val; | ||
500 | |||
501 | val = uhdp->vmt->write(uhdp, bp, n); | ||
502 | |||
503 | if (val > 0) | ||
504 | uhdp->vmt->flush(uhdp); | ||
505 | |||
506 | return val; | ||
507 | } | ||
508 | |||
509 | /** | ||
510 | * @brief Write HID report with timeout | ||
511 | * @details The function writes data from a buffer to an output queue. The | ||
512 | * operation completes when the specified amount of data has been | ||
513 | * transferred or after the specified timeout or if the queue has | ||
514 | * been reset. | ||
515 | * | ||
516 | * @param[in] uhdp pointer to the @p USBHIDDriver object | ||
517 | * @param[in] bp pointer to the report data buffer | ||
518 | * @param[in] n the maximum amount of data to be transferred, the | ||
519 | * value 0 is reserved | ||
520 | * @param[in] timeout the number of ticks before the operation timeouts, | ||
521 | * the following special values are allowed: | ||
522 | * - @a TIME_IMMEDIATE immediate timeout. | ||
523 | * - @a TIME_INFINITE no timeout. | ||
524 | * . | ||
525 | * @return The number of bytes effectively transferred. | ||
526 | * @retval 0 if a timeout occurred. | ||
527 | * | ||
528 | * @api | ||
529 | */ | ||
530 | size_t hidWriteReportt(USBHIDDriver *uhdp, uint8_t *bp, size_t n, systime_t timeout) { | ||
531 | size_t val; | ||
532 | |||
533 | val = uhdp->vmt->writet(uhdp, bp, n, timeout); | ||
534 | |||
535 | if (val > 0) | ||
536 | uhdp->vmt->flush(uhdp); | ||
537 | |||
538 | return val; | ||
539 | } | ||
540 | |||
541 | /** | ||
542 | * @brief Read HID report | ||
543 | * @details The function reads data from an input queue into a buffer. | ||
544 | * The operation completes when the specified amount of data has been | ||
545 | * transferred or if the queue has been reset. | ||
546 | * | ||
547 | * @param[in] uhdp pointer to the @p input_buffers_queue_t object | ||
548 | * @param[out] bp pointer to the data buffer | ||
549 | * @param[in] n the maximum amount of data to be transferred, the | ||
550 | * value 0 is reserved | ||
551 | * @return The number of bytes effectively transferred. | ||
552 | * @retval 0 if a timeout occurred. | ||
553 | * | ||
554 | * @api | ||
555 | */ | ||
556 | size_t hidReadReport(USBHIDDriver *uhdp, uint8_t *bp, size_t n) { | ||
557 | |||
558 | return uhdp->vmt->read(uhdp, bp, n); | ||
559 | } | ||
560 | |||
561 | /** | ||
562 | * @brief Read HID report with timeout | ||
563 | * @details The function reads data from an input queue into a buffer. | ||
564 | * The operation completes when the specified amount of data has been | ||
565 | * transferred or after the specified timeout or if the queue has | ||
566 | * been reset. | ||
567 | * | ||
568 | * @param[in] uhdp pointer to the @p input_buffers_queue_t object | ||
569 | * @param[out] bp pointer to the data buffer | ||
570 | * @param[in] n the maximum amount of data to be transferred, the | ||
571 | * value 0 is reserved | ||
572 | * @param[in] timeout the number of ticks before the operation timeouts, | ||
573 | * the following special values are allowed: | ||
574 | * - @a TIME_IMMEDIATE immediate timeout. | ||
575 | * - @a TIME_INFINITE no timeout. | ||
576 | * . | ||
577 | * @return The number of bytes effectively transferred. | ||
578 | * @retval 0 if a timeout occurred. | ||
579 | * | ||
580 | * @api | ||
581 | */ | ||
582 | size_t hidReadReportt(USBHIDDriver *uhdp, uint8_t *bp, size_t n, systime_t timeout) { | ||
583 | |||
584 | return uhdp->vmt->readt(uhdp, bp, n, timeout); | ||
585 | } | ||
586 | |||
587 | #endif /* HAL_USE_USB_HID == TRUE */ | ||
588 | |||
589 | /** @} */ | ||