Rework device discovery API
[libjaylink.git] / libjaylink / device.c
blob9ec00a7d373c1459b4ea4a45f86c99d79d668be9
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2014-2016 Marc Schink <jaylink-dev@marcschink.de>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <stdlib.h>
21 #include <stdint.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include <libusb.h>
26 #include "libjaylink.h"
27 #include "libjaylink-internal.h"
29 /**
30 * @file
32 * Device enumeration and handling.
35 /** @cond PRIVATE */
36 #define CMD_GET_VERSION 0x01
37 #define CMD_GET_HW_STATUS 0x07
38 #define CMD_REGISTER 0x09
39 #define CMD_GET_HW_INFO 0xc1
40 #define CMD_GET_FREE_MEMORY 0xd4
41 #define CMD_GET_CAPS 0xe8
42 #define CMD_GET_EXT_CAPS 0xed
43 #define CMD_GET_HW_VERSION 0xf0
44 #define CMD_READ_CONFIG 0xf2
45 #define CMD_WRITE_CONFIG 0xf3
47 #define REG_CMD_REGISTER 0x64
48 #define REG_CMD_UNREGISTER 0x65
50 /** Size of the registration header in bytes. */
51 #define REG_HEADER_SIZE 8
52 /** Minimum registration information size in bytes. */
53 #define REG_MIN_SIZE 0x4c
54 /** Maximum registration information size in bytes. */
55 #define REG_MAX_SIZE 0x200
56 /** Size of a connection entry in bytes. */
57 #define REG_CONN_INFO_SIZE 16
58 /** @endcond */
60 /** @private */
61 JAYLINK_PRIV struct jaylink_device *device_allocate(struct jaylink_context *ctx)
63 struct jaylink_device *dev;
64 struct list *list;
66 dev = malloc(sizeof(struct jaylink_device));
68 if (!dev)
69 return NULL;
71 list = list_prepend(ctx->devs, dev);
73 if (!list) {
74 free(dev);
75 return NULL;
78 ctx->devs = list;
80 dev->ctx = ctx;
81 dev->refcnt = 1;
82 dev->usb_dev = NULL;
84 return dev;
87 /** @private */
88 static struct jaylink_device_handle *allocate_device_handle(
89 struct jaylink_device *dev)
91 struct jaylink_device_handle *devh;
93 devh = malloc(sizeof(struct jaylink_device_handle));
95 if (!devh)
96 return NULL;
98 devh->dev = jaylink_ref_device(dev);
100 return devh;
103 /** @private */
104 static void free_device_handle(struct jaylink_device_handle *devh)
106 jaylink_unref_device(devh->dev);
107 free(devh);
110 /** @private */
111 static struct jaylink_device **allocate_device_list(size_t length)
113 struct jaylink_device **list;
115 list = malloc(sizeof(struct jaylink_device *) * (length + 1));
117 if (!list)
118 return NULL;
120 list[length] = NULL;
122 return list;
126 * Get available devices.
128 * @param[in,out] ctx libjaylink context.
129 * @param[out] devices Newly allocated array which contains instances of
130 * available devices on success, and undefined on failure.
131 * The array is NULL-terminated and must be free'd by the
132 * caller with jaylink_free_devices().
133 * @param[out] count Number of available devices on success, and undefined on
134 * failure. Can be NULL.
136 * @retval JAYLINK_OK Success.
137 * @retval JAYLINK_ERR_ARG Invalid arguments.
138 * @retval JAYLINK_ERR_MALLOC Memory allocation error.
139 * @retval JAYLINK_ERR Other error conditions.
141 * @see jaylink_discovery_scan()
143 JAYLINK_API int jaylink_get_devices(struct jaylink_context *ctx,
144 struct jaylink_device ***devices, size_t *count)
146 size_t num;
147 struct list *item;
148 struct jaylink_device **devs;
149 struct jaylink_device *dev;
150 size_t i;
152 if (!ctx || !devices)
153 return JAYLINK_ERR_ARG;
155 num = list_length(ctx->discovered_devs);
156 devs = allocate_device_list(num);
158 if (!devs) {
159 log_err(ctx, "Failed to allocate device list.");
160 return JAYLINK_ERR_MALLOC;
163 item = ctx->discovered_devs;
165 for (i = 0; i < num; i++) {
166 dev = (struct jaylink_device *)item->data;
167 devs[i] = jaylink_ref_device(dev);
168 item = item->next;
171 if (count)
172 *count = num;
174 *devices = devs;
176 return JAYLINK_OK;
180 * Free devices.
182 * @param[in,out] devices Array of device instances. Must be NULL-terminated.
183 * @param[in] unref Determines whether the device instances should be
184 * unreferenced.
186 * @see jaylink_get_devices()
188 JAYLINK_API void jaylink_free_devices(struct jaylink_device **devices,
189 bool unref)
191 size_t i;
193 if (!devices)
194 return;
196 if (unref) {
197 i = 0;
199 while (devices[i]) {
200 jaylink_unref_device(devices[i]);
201 i++;
205 free(devices);
209 * Get the host interface of a device.
211 * @param[in] dev Device instance.
212 * @param[out] interface Host interface of the device on success, and undefined
213 * on failure.
215 * @retval JAYLINK_OK Success.
216 * @retval JAYLINK_ERR_ARG Invalid arguments.
218 JAYLINK_API int jaylink_device_get_host_interface(
219 const struct jaylink_device *dev,
220 enum jaylink_host_interface *interface)
222 if (!dev || !interface)
223 return JAYLINK_ERR_ARG;
225 *interface = dev->interface;
227 return JAYLINK_OK;
231 * Get the serial number of a device.
233 * @note This serial number is for enumeration purpose only and might differ
234 * from the real serial number of the device.
236 * @param[in] dev Device instance.
237 * @param[out] serial_number Serial number of the device on success, and
238 * undefined on failure.
240 * @retval JAYLINK_OK Success.
241 * @retval JAYLINK_ERR_ARG Invalid arguments.
242 * @retval JAYLINK_ERR_NOT_AVAILABLE Serial number is not available.
244 JAYLINK_API int jaylink_device_get_serial_number(
245 const struct jaylink_device *dev, uint32_t *serial_number)
247 if (!dev || !serial_number)
248 return JAYLINK_ERR_ARG;
250 if (!dev->valid_serial_number)
251 return JAYLINK_ERR_NOT_AVAILABLE;
253 *serial_number = dev->serial_number;
255 return JAYLINK_OK;
259 * Get the USB address of a device.
261 * @note Identification of a device with the USB address is deprecated and the
262 * serial number should be used instead.
264 * @param[in] dev Device instance.
265 * @param[out] address USB address of the device on success, and undefined on
266 * failure.
268 * @retval JAYLINK_OK Success.
269 * @retval JAYLINK_ERR_ARG Invalid arguments.
270 * @retval JAYLINK_ERR_NOT_SUPPORTED Operation not supported.
272 * @see jaylink_device_get_serial_number() to get the serial number of a device.
274 JAYLINK_API int jaylink_device_get_usb_address(const struct jaylink_device *dev,
275 enum jaylink_usb_address *address)
277 if (!dev || !address)
278 return JAYLINK_ERR_ARG;
280 if (dev->interface != JAYLINK_HIF_USB)
281 return JAYLINK_ERR_NOT_SUPPORTED;
283 *address = dev->usb_address;
285 return JAYLINK_OK;
289 * Increment the reference count of a device.
291 * @param[in,out] dev Device instance.
293 * @return The given device instance on success, or NULL for invalid device
294 * instance.
296 JAYLINK_API struct jaylink_device *jaylink_ref_device(
297 struct jaylink_device *dev)
299 if (!dev)
300 return NULL;
302 dev->refcnt++;
304 return dev;
308 * Decrement the reference count of a device.
310 * @param[in,out] dev Device instance.
312 JAYLINK_API void jaylink_unref_device(struct jaylink_device *dev)
314 struct jaylink_context *ctx;
316 if (!dev)
317 return;
319 dev->refcnt--;
321 if (dev->refcnt == 0) {
322 ctx = dev->ctx;
324 log_dbg(ctx, "Device destroyed (bus:address = %03u:%03u).",
325 libusb_get_bus_number(dev->usb_dev),
326 libusb_get_device_address(dev->usb_dev));
328 ctx->devs = list_remove(dev->ctx->devs, dev);
330 if (dev->usb_dev)
331 libusb_unref_device(dev->usb_dev);
333 free(dev);
338 * Open a device.
340 * @param[in,out] dev Device instance.
341 * @param[out] devh Newly allocated handle for the opened device on success,
342 * and undefined on failure.
344 * @retval JAYLINK_OK Success.
345 * @retval JAYLINK_ERR_ARG Invalid arguments.
346 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
347 * @retval JAYLINK_ERR_MALLOC Memory allocation error.
348 * @retval JAYLINK_ERR Other error conditions.
350 JAYLINK_API int jaylink_open(struct jaylink_device *dev,
351 struct jaylink_device_handle **devh)
353 int ret;
354 struct jaylink_device_handle *handle;
356 if (!dev || !devh)
357 return JAYLINK_ERR_ARG;
359 handle = allocate_device_handle(dev);
361 if (!handle) {
362 log_err(dev->ctx, "Device handle malloc failed.");
363 return JAYLINK_ERR_MALLOC;
366 ret = transport_open(handle);
368 if (ret < 0) {
369 free_device_handle(handle);
370 return ret;
373 *devh = handle;
375 return JAYLINK_OK;
379 * Close a device.
381 * @param[in,out] devh Device instance.
383 JAYLINK_API void jaylink_close(struct jaylink_device_handle *devh)
385 if (!devh)
386 return;
388 transport_close(devh);
389 free_device_handle(devh);
393 * Get the device instance from a device handle.
395 * @note The reference count of the device instance is not increased.
397 * @param[in] devh Device handle.
399 * @return The device instance on success, or NULL on invalid argument.
401 JAYLINK_API struct jaylink_device *jaylink_get_device(
402 struct jaylink_device_handle *devh)
404 if (!devh)
405 return NULL;
407 return devh->dev;
411 * Retrieve the firmware version of a device.
413 * @param[in,out] devh Device handle.
414 * @param[out] version Newly allocated string which contains the firmware
415 * version on success, and undefined if @p length is zero
416 * or on failure. The string is null-terminated and must be
417 * free'd by the caller.
418 * @param[out] length Length of the firmware version string including trailing
419 * null-terminator on success, and undefined on failure.
420 * Zero if no firmware version string is available.
422 * @retval JAYLINK_OK Success.
423 * @retval JAYLINK_ERR_ARG Invalid arguments.
424 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
425 * @retval JAYLINK_ERR_MALLOC Memory allocation error.
426 * @retval JAYLINK_ERR Other error conditions.
428 JAYLINK_API int jaylink_get_firmware_version(struct jaylink_device_handle *devh,
429 char **version, size_t *length)
431 int ret;
432 struct jaylink_context *ctx;
433 uint8_t buf[2];
434 uint16_t dummy;
435 char *tmp;
437 if (!devh || !version || !length)
438 return JAYLINK_ERR_ARG;
440 ctx = devh->dev->ctx;
441 ret = transport_start_write_read(devh, 1, 2, true);
443 if (ret != JAYLINK_OK) {
444 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
445 return ret;
448 buf[0] = CMD_GET_VERSION;
450 ret = transport_write(devh, buf, 1);
452 if (ret != JAYLINK_OK) {
453 log_err(ctx, "transport_write() failed: %i.", ret);
454 return ret;
457 ret = transport_read(devh, buf, 2);
459 if (ret != JAYLINK_OK) {
460 log_err(ctx, "transport_read() failed: %i.", ret);
461 return ret;
464 dummy = buffer_get_u16(buf, 0);
465 *length = dummy;
467 if (!dummy)
468 return JAYLINK_OK;
470 ret = transport_start_read(devh, dummy);
472 if (ret != JAYLINK_OK) {
473 log_err(ctx, "transport_start_read() failed: %i.", ret);
474 return ret;
477 tmp = malloc(dummy);
479 if (!tmp) {
480 log_err(ctx, "Firmware version string malloc failed.");
481 return JAYLINK_ERR_MALLOC;
484 ret = transport_read(devh, (uint8_t *)tmp, dummy);
486 if (ret != JAYLINK_OK) {
487 log_err(ctx, "transport_read() failed: %i.", ret);
488 free(tmp);
489 return ret;
492 /* Last byte is reserved for null-terminator. */
493 tmp[dummy - 1] = 0;
494 *version = tmp;
496 return JAYLINK_OK;
500 * Retrieve the hardware information of a device.
502 * @note This function must only be used if the device has the
503 * #JAYLINK_DEV_CAP_GET_HW_INFO capability.
505 * @param[in,out] devh Device handle.
506 * @param[in] mask A bit field where each set bit represents hardware
507 * information to request. See #jaylink_hardware_info for a
508 * description of the hardware information and their bit
509 * positions.
510 * @param[out] info Array to store the hardware information on success. Its
511 * content is undefined on failure. The array must be large
512 * enough to contain at least as many elements as bits set in
513 * @a mask.
515 * @retval JAYLINK_OK Success.
516 * @retval JAYLINK_ERR_ARG Invalid arguments.
517 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
518 * @retval JAYLINK_ERR Other error conditions.
520 JAYLINK_API int jaylink_get_hardware_info(struct jaylink_device_handle *devh,
521 uint32_t mask, uint32_t *info)
523 int ret;
524 struct jaylink_context *ctx;
525 uint8_t buf[5];
526 unsigned int i;
527 unsigned int num;
528 unsigned int length;
530 if (!devh || !mask || !info)
531 return JAYLINK_ERR_ARG;
533 ctx = devh->dev->ctx;
534 num = 0;
536 for (i = 0; i < 32; i++) {
537 if (mask & (1 << i))
538 num++;
541 length = num * sizeof(uint32_t);
543 ret = transport_start_write_read(devh, 5, length, true);
545 if (ret != JAYLINK_OK) {
546 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
547 return ret;
550 buf[0] = CMD_GET_HW_INFO;
551 buffer_set_u32(buf, mask, 1);
553 ret = transport_write(devh, buf, 5);
555 if (ret != JAYLINK_OK) {
556 log_err(ctx, "transport_write() failed: %i.", ret);
557 return ret;
560 ret = transport_read(devh, (uint8_t *)info, length);
562 if (ret != JAYLINK_OK) {
563 log_err(ctx, "transport_read() failed: %i.", ret);
564 return ret;
567 for (i = 0; i < num; i++)
568 info[i] = buffer_get_u32((uint8_t *)info, i * sizeof(uint32_t));
570 return JAYLINK_OK;
574 * Retrieve the hardware version of a device.
576 * @note This function must only be used if the device has the
577 * #JAYLINK_DEV_CAP_GET_HW_VERSION capability.
579 * @param[in,out] devh Device handle.
580 * @param[out] version Hardware version on success, and undefined on failure.
582 * @retval JAYLINK_OK Success.
583 * @retval JAYLINK_ERR_ARG Invalid arguments.
584 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
585 * @retval JAYLINK_ERR Other error conditions.
587 * @see jaylink_get_caps() to retrieve device capabilities.
589 JAYLINK_API int jaylink_get_hardware_version(struct jaylink_device_handle *devh,
590 struct jaylink_hardware_version *version)
592 int ret;
593 struct jaylink_context *ctx;
594 uint8_t buf[4];
595 uint32_t tmp;
597 if (!devh || !version)
598 return JAYLINK_ERR_ARG;
600 ctx = devh->dev->ctx;
601 ret = transport_start_write_read(devh, 1, 4, true);
603 if (ret != JAYLINK_OK) {
604 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
605 return ret;
608 buf[0] = CMD_GET_HW_VERSION;
610 ret = transport_write(devh, buf, 1);
612 if (ret != JAYLINK_OK) {
613 log_err(ctx, "transport_write() failed: %i.", ret);
614 return ret;
617 ret = transport_read(devh, buf, 4);
619 if (ret != JAYLINK_OK) {
620 log_err(ctx, "transport_read() failed: %i.", ret);
621 return ret;
624 tmp = buffer_get_u32(buf, 0);
626 version->type = (tmp / 1000000) % 100;
627 version->major = (tmp / 10000) % 100;
628 version->minor = (tmp / 100) % 100;
629 version->revision = tmp % 100;
631 return JAYLINK_OK;
635 * Retrieve the hardware status of a device.
637 * @param[in,out] devh Device handle.
638 * @param[out] status Hardware status on success, and undefined on failure.
640 * @retval JAYLINK_OK Success.
641 * @retval JAYLINK_ERR_ARG Invalid arguments.
642 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
643 * @retval JAYLINK_ERR Other error conditions.
645 JAYLINK_API int jaylink_get_hardware_status(struct jaylink_device_handle *devh,
646 struct jaylink_hardware_status *status)
648 int ret;
649 struct jaylink_context *ctx;
650 uint8_t buf[8];
652 if (!devh || !status)
653 return JAYLINK_ERR_ARG;
655 ctx = devh->dev->ctx;
656 ret = transport_start_write_read(devh, 1, 8, true);
658 if (ret != JAYLINK_OK) {
659 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
660 return ret;
663 buf[0] = CMD_GET_HW_STATUS;
665 ret = transport_write(devh, buf, 1);
667 if (ret != JAYLINK_OK) {
668 log_err(ctx, "transport_write() failed: %i.", ret);
669 return ret;
672 ret = transport_read(devh, buf, 8);
674 if (ret != JAYLINK_OK) {
675 log_err(ctx, "transport_read() failed: %i.", ret);
676 return ret;
679 status->target_voltage = buffer_get_u16(buf, 0);
680 status->tck = buf[2];
681 status->tdi = buf[3];
682 status->tdo = buf[4];
683 status->tms = buf[5];
684 status->tres = buf[6];
685 status->trst = buf[7];
687 return JAYLINK_OK;
691 * Retrieve the capabilities of a device.
693 * The capabilities are stored in a 32-bit bit array consisting of
694 * #JAYLINK_DEV_CAPS_SIZE bytes where each individual bit represents a
695 * capability. The first bit of this array is the least significant bit of the
696 * first byte and the following bits are sequentially numbered in order of
697 * increasing bit significance and byte index. A set bit indicates a supported
698 * capability. See #jaylink_device_capability for a description of the
699 * capabilities and their bit positions.
701 * @param[in,out] devh Device handle.
702 * @param[out] caps Buffer to store capabilities on success. Its content is
703 * undefined on failure. The size of the buffer must be large
704 * enough to contain at least #JAYLINK_DEV_CAPS_SIZE bytes.
706 * @retval JAYLINK_OK Success.
707 * @retval JAYLINK_ERR_ARG Invalid arguments.
708 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
709 * @retval JAYLINK_ERR Other error conditions.
711 * @see jaylink_get_extended_caps() to retrieve extended device capabilities.
713 JAYLINK_API int jaylink_get_caps(struct jaylink_device_handle *devh,
714 uint8_t *caps)
716 int ret;
717 struct jaylink_context *ctx;
718 uint8_t buf[1];
720 if (!devh || !caps)
721 return JAYLINK_ERR_ARG;
723 ctx = devh->dev->ctx;
724 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CAPS_SIZE, true);
726 if (ret != JAYLINK_OK) {
727 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
728 return ret;
731 buf[0] = CMD_GET_CAPS;
733 ret = transport_write(devh, buf, 1);
735 if (ret != JAYLINK_OK) {
736 log_err(ctx, "transport_write() failed: %i.", ret);
737 return ret;
740 ret = transport_read(devh, caps, JAYLINK_DEV_CAPS_SIZE);
742 if (ret != JAYLINK_OK) {
743 log_err(ctx, "transport_read() failed: %i.", ret);
744 return ret;
747 return JAYLINK_OK;
751 * Retrieve the extended capabilities of a device.
753 * The extended capabilities are stored in a 256-bit bit array consisting of
754 * #JAYLINK_DEV_EXT_CAPS_SIZE bytes. See jaylink_get_caps() for a further
755 * description of how the capabilities are represented in this bit array. For a
756 * description of the capabilities and their bit positions, see
757 * #jaylink_device_capability.
759 * @note This function must only be used if the device has the
760 * #JAYLINK_DEV_CAP_GET_EXT_CAPS capability.
762 * @param[in,out] devh Device handle.
763 * @param[out] caps Buffer to store capabilities on success. Its content is
764 * undefined on failure. The size of the buffer must be large
765 * enough to contain at least #JAYLINK_DEV_EXT_CAPS_SIZE bytes.
767 * @retval JAYLINK_OK Success.
768 * @retval JAYLINK_ERR_ARG Invalid arguments.
769 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
770 * @retval JAYLINK_ERR Other error conditions.
772 * @see jaylink_get_caps() to retrieve device capabilities.
774 JAYLINK_API int jaylink_get_extended_caps(struct jaylink_device_handle *devh,
775 uint8_t *caps)
777 int ret;
778 struct jaylink_context *ctx;
779 uint8_t buf[1];
781 if (!devh || !caps)
782 return JAYLINK_ERR_ARG;
784 ctx = devh->dev->ctx;
785 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_EXT_CAPS_SIZE,
786 true);
788 if (ret != JAYLINK_OK) {
789 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
790 return ret;
793 buf[0] = CMD_GET_EXT_CAPS;
795 ret = transport_write(devh, buf, 1);
797 if (ret != JAYLINK_OK) {
798 log_err(ctx, "transport_write() failed: %i.", ret);
799 return ret;
802 ret = transport_read(devh, caps, JAYLINK_DEV_EXT_CAPS_SIZE);
804 if (ret != JAYLINK_OK) {
805 log_err(ctx, "transport_read() failed: %i.", ret);
806 return ret;
809 return JAYLINK_OK;
813 * Retrieve the size of free memory of a device.
815 * @note This function must only be used if the device has the
816 * #JAYLINK_DEV_CAP_GET_FREE_MEMORY capability.
818 * @param[in,out] devh Device handle.
819 * @param[out] size Size of free memory in bytes on success, and undefined on
820 * failure.
822 * @retval JAYLINK_OK Success.
823 * @retval JAYLINK_ERR_ARG Invalid arguments.
824 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
825 * @retval JAYLINK_ERR Other error conditions.
827 * @see jaylink_get_caps() to retrieve device capabilities.
829 JAYLINK_API int jaylink_get_free_memory(struct jaylink_device_handle *devh,
830 uint32_t *size)
832 int ret;
833 struct jaylink_context *ctx;
834 uint8_t buf[4];
836 if (!devh || !size)
837 return JAYLINK_ERR_ARG;
839 ctx = devh->dev->ctx;
840 ret = transport_start_write_read(devh, 1, 4, true);
842 if (ret != JAYLINK_OK) {
843 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
844 return ret;
847 buf[0] = CMD_GET_FREE_MEMORY;
849 ret = transport_write(devh, buf, 1);
851 if (ret != JAYLINK_OK) {
852 log_err(ctx, "transport_write() failed: %i.", ret);
853 return ret;
856 ret = transport_read(devh, buf, 4);
858 if (ret != JAYLINK_OK) {
859 log_err(ctx, "transport_read() failed: %i.", ret);
860 return ret;
863 *size = buffer_get_u32(buf, 0);
865 return JAYLINK_OK;
869 * Read the raw configuration data of a device.
871 * @note This function must only be used if the device has the
872 * #JAYLINK_DEV_CAP_READ_CONFIG capability.
874 * @param[in,out] devh Device handle.
875 * @param[out] config Buffer to store configuration data on success. Its
876 * content is undefined on failure. The size of the buffer
877 * must be large enough to contain at least
878 * #JAYLINK_DEV_CONFIG_SIZE bytes.
880 * @retval JAYLINK_OK Success.
881 * @retval JAYLINK_ERR_ARG Invalid arguments.
882 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
883 * @retval JAYLINK_ERR Other error conditions.
885 JAYLINK_API int jaylink_read_raw_config(struct jaylink_device_handle *devh,
886 uint8_t *config)
888 int ret;
889 struct jaylink_context *ctx;
890 uint8_t buf[1];
892 if (!devh || !config)
893 return JAYLINK_ERR_ARG;
895 ctx = devh->dev->ctx;
896 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CONFIG_SIZE,
897 true);
899 if (ret != JAYLINK_OK) {
900 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
901 return ret;
904 buf[0] = CMD_READ_CONFIG;
906 ret = transport_write(devh, buf, 1);
908 if (ret != JAYLINK_OK) {
909 log_err(ctx, "transport_write() failed: %i.", ret);
910 return ret;
913 ret = transport_read(devh, config, JAYLINK_DEV_CONFIG_SIZE);
915 if (ret != JAYLINK_OK) {
916 log_err(ctx, "transport_read() failed: %i.", ret);
917 return ret;
920 return JAYLINK_OK;
924 * Write the raw configuration data of a device.
926 * @note This function must only be used if the device has the
927 * #JAYLINK_DEV_CAP_WRITE_CONFIG capability.
929 * @param[in,out] devh Device handle.
930 * @param[in] config Buffer to write configuration data from. The size of the
931 * configuration data is expected to be
932 * #JAYLINK_DEV_CONFIG_SIZE bytes.
934 * @retval JAYLINK_OK Success.
935 * @retval JAYLINK_ERR_ARG Invalid arguments.
936 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
937 * @retval JAYLINK_ERR Other error conditions.
939 JAYLINK_API int jaylink_write_raw_config(struct jaylink_device_handle *devh,
940 const uint8_t *config)
942 int ret;
943 struct jaylink_context *ctx;
944 uint8_t buf[1];
946 if (!devh || !config)
947 return JAYLINK_ERR_ARG;
949 ctx = devh->dev->ctx;
950 ret = transport_start_write(devh, 1 + JAYLINK_DEV_CONFIG_SIZE, true);
952 if (ret != JAYLINK_OK) {
953 log_err(ctx, "transport_start_write() failed: %i.", ret);
954 return ret;
957 buf[0] = CMD_WRITE_CONFIG;
959 ret = transport_write(devh, buf, 1);
961 if (ret != JAYLINK_OK) {
962 log_err(ctx, "transport_write() failed: %i.", ret);
963 return ret;
966 ret = transport_write(devh, config, JAYLINK_DEV_CONFIG_SIZE);
968 if (ret != JAYLINK_OK) {
969 log_err(ctx, "transport_write() failed: %i.", ret);
970 return ret;
973 return JAYLINK_OK;
976 static void parse_conntable(struct jaylink_connection *conns,
977 const uint8_t *buffer, uint16_t num, uint16_t entry_size)
979 unsigned int i;
980 size_t offset;
982 offset = 0;
984 for (i = 0; i < num; i++) {
985 conns[i].pid = buffer_get_u32(buffer, offset);
986 conns[i].hid = buffer_get_u32(buffer, offset + 4);
987 conns[i].iid = buffer[offset + 8];
988 conns[i].cid = buffer[offset + 9];
989 conns[i].handle = buffer_get_u16(buffer, offset + 10);
990 conns[i].timestamp = buffer_get_u32(buffer, offset + 12);
991 offset = offset + entry_size;
996 * Register a connection on a device.
998 * A connection can be registered by using 0 as handle. Additional information
999 * about the connection can be attached whereby the timestamp is a read-only
1000 * value and therefore ignored for registration. On success, a new handle
1001 * greater than 0 is obtained from the device.
1003 * However, if an obtained handle does not appear in the list of device
1004 * connections, the connection was not registered because the maximum number of
1005 * connections on the device is reached.
1007 * @note This function must only be used if the device has the
1008 * #JAYLINK_DEV_CAP_REGISTER capability.
1010 * @param[in,out] devh Device handle.
1011 * @param[in,out] connection Connection to register on the device.
1012 * @param[out] connections Array to store device connections on success.
1013 * Its content is undefined on failure. The array must
1014 * be large enough to contain at least
1015 * #JAYLINK_MAX_CONNECTIONS elements.
1016 * @param[out] count Number of device connections on success, and undefined on
1017 * failure.
1018 * @param[out] info Buffer to store additional information on success, or NULL.
1019 * The content of the buffer is undefined on failure.
1020 * @param[out] info_size Size of the additional information in bytes on success,
1021 * and undefined on failure. Can be NULL.
1023 * @retval JAYLINK_OK Success.
1024 * @retval JAYLINK_ERR_ARG Invalid arguments.
1025 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
1026 * @retval JAYLINK_ERR_PROTO Protocol violation.
1027 * @retval JAYLINK_ERR Other error conditions.
1029 * @see jaylink_unregister() to unregister a connection from a device.
1031 JAYLINK_API int jaylink_register(struct jaylink_device_handle *devh,
1032 struct jaylink_connection *connection,
1033 struct jaylink_connection *connections, size_t *count,
1034 uint8_t *info, uint16_t *info_size)
1036 int ret;
1037 struct jaylink_context *ctx;
1038 uint8_t buf[REG_MAX_SIZE];
1039 uint16_t handle;
1040 uint16_t num;
1041 uint16_t entry_size;
1042 uint32_t size;
1043 uint32_t table_size;
1044 uint16_t addinfo_size;
1046 if (!devh || !connection || !connections || !count)
1047 return JAYLINK_ERR_ARG;
1049 ctx = devh->dev->ctx;
1050 ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, true);
1052 if (ret != JAYLINK_OK) {
1053 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
1054 return ret;
1057 buf[0] = CMD_REGISTER;
1058 buf[1] = REG_CMD_REGISTER;
1059 buffer_set_u32(buf, connection->pid, 2);
1060 buffer_set_u32(buf, connection->hid, 6);
1061 buf[10] = connection->iid;
1062 buf[11] = connection->cid;
1063 buffer_set_u16(buf, connection->handle, 12);
1065 ret = transport_write(devh, buf, 14);
1067 if (ret != JAYLINK_OK) {
1068 log_err(ctx, "transport_write() failed: %i.", ret);
1069 return ret;
1072 ret = transport_read(devh, buf, REG_MIN_SIZE);
1074 if (ret != JAYLINK_OK) {
1075 log_err(ctx, "transport_read() failed: %i.", ret);
1076 return ret;
1079 handle = buffer_get_u16(buf, 0);
1080 num = buffer_get_u16(buf, 2);
1081 entry_size = buffer_get_u16(buf, 4);
1082 addinfo_size = buffer_get_u16(buf, 6);
1084 if (num > JAYLINK_MAX_CONNECTIONS) {
1085 log_err(ctx, "Maximum number of device connections exceeded: "
1086 "%u.", num);
1087 return JAYLINK_ERR_PROTO;
1090 if (entry_size != REG_CONN_INFO_SIZE) {
1091 log_err(ctx, "Invalid connection entry size: %u bytes.",
1092 entry_size);
1093 return JAYLINK_ERR_PROTO;
1096 table_size = num * entry_size;
1097 size = REG_HEADER_SIZE + table_size + addinfo_size;
1099 if (size > REG_MAX_SIZE) {
1100 log_err(ctx, "Maximum registration information size exceeded: "
1101 "%u bytes.", size);
1102 return JAYLINK_ERR_PROTO;
1105 if (size > REG_MIN_SIZE) {
1106 ret = transport_start_read(devh, size - REG_MIN_SIZE);
1108 if (ret != JAYLINK_OK) {
1109 log_err(ctx, "transport_start_read() failed: %i.", ret);
1110 return JAYLINK_ERR;
1113 ret = transport_read(devh, buf + REG_MIN_SIZE,
1114 size - REG_MIN_SIZE);
1116 if (ret != JAYLINK_OK) {
1117 log_err(ctx, "transport_read() failed: %i.", ret);
1118 return JAYLINK_ERR;
1122 if (!handle) {
1123 log_err(ctx, "Obtained invalid connection handle.");
1124 return JAYLINK_ERR_PROTO;
1127 connection->handle = handle;
1128 parse_conntable(connections, buf + REG_HEADER_SIZE, num, entry_size);
1130 if (info)
1131 memcpy(info, buf + REG_HEADER_SIZE + table_size, addinfo_size);
1133 if (info_size)
1134 *info_size = addinfo_size;
1136 *count = num;
1138 return JAYLINK_OK;
1142 * Unregister a connection from a device.
1144 * @note This function must only be used if the device has the
1145 * #JAYLINK_DEV_CAP_REGISTER capability.
1147 * @param[in,out] devh Device handle.
1148 * @param[in,out] connection Connection to unregister from the device.
1149 * @param[out] connections Array to store device connections on success.
1150 * Its content is undefined on failure. The array must
1151 * be large enough to contain at least
1152 * #JAYLINK_MAX_CONNECTIONS elements.
1153 * @param[out] count Number of device connections on success, and undefined on
1154 * failure.
1155 * @param[out] info Buffer to store additional information on success, or NULL.
1156 * The content of the buffer is undefined on failure.
1157 * @param[out] info_size Size of the additional information in bytes on success,
1158 * and undefined on failure. Can be NULL.
1160 * @retval JAYLINK_OK Success.
1161 * @retval JAYLINK_ERR_ARG Invalid arguments.
1162 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
1163 * @retval JAYLINK_ERR_PROTO Protocol violation.
1164 * @retval JAYLINK_ERR Other error conditions.
1166 JAYLINK_API int jaylink_unregister(struct jaylink_device_handle *devh,
1167 const struct jaylink_connection *connection,
1168 struct jaylink_connection *connections, size_t *count,
1169 uint8_t *info, uint16_t *info_size)
1171 int ret;
1172 struct jaylink_context *ctx;
1173 uint8_t buf[REG_MAX_SIZE];
1174 uint16_t num;
1175 uint16_t entry_size;
1176 uint32_t size;
1177 uint32_t table_size;
1178 uint16_t addinfo_size;
1180 if (!devh || !connection || !connections || !count)
1181 return JAYLINK_ERR_ARG;
1183 ctx = devh->dev->ctx;
1184 ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, true);
1186 if (ret != JAYLINK_OK) {
1187 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
1188 return ret;
1191 buf[0] = CMD_REGISTER;
1192 buf[1] = REG_CMD_UNREGISTER;
1193 buffer_set_u32(buf, connection->pid, 2);
1194 buffer_set_u32(buf, connection->hid, 6);
1195 buf[10] = connection->iid;
1196 buf[11] = connection->cid;
1197 buffer_set_u16(buf, connection->handle, 12);
1199 ret = transport_write(devh, buf, 14);
1201 if (ret != JAYLINK_OK) {
1202 log_err(ctx, "transport_write() failed: %i.", ret);
1203 return ret;
1206 ret = transport_read(devh, buf, REG_MIN_SIZE);
1208 if (ret != JAYLINK_OK) {
1209 log_err(ctx, "transport_read() failed: %i.", ret);
1210 return ret;
1213 num = buffer_get_u16(buf, 2);
1214 entry_size = buffer_get_u16(buf, 4);
1215 addinfo_size = buffer_get_u16(buf, 6);
1217 if (num > JAYLINK_MAX_CONNECTIONS) {
1218 log_err(ctx, "Maximum number of device connections exceeded: "
1219 "%u.", num);
1220 return JAYLINK_ERR_PROTO;
1223 if (entry_size != REG_CONN_INFO_SIZE) {
1224 log_err(ctx, "Invalid connection entry size: %u bytes.",
1225 entry_size);
1226 return JAYLINK_ERR_PROTO;
1229 table_size = num * entry_size;
1230 size = REG_HEADER_SIZE + table_size + addinfo_size;
1232 if (size > REG_MAX_SIZE) {
1233 log_err(ctx, "Maximum registration information size exceeded: "
1234 "%u bytes.", size);
1235 return JAYLINK_ERR_PROTO;
1238 if (size > REG_MIN_SIZE) {
1239 ret = transport_start_read(devh, size - REG_MIN_SIZE);
1241 if (ret != JAYLINK_OK) {
1242 log_err(ctx, "transport_start_read() failed: %i.", ret);
1243 return JAYLINK_ERR;
1246 ret = transport_read(devh, buf + REG_MIN_SIZE,
1247 size - REG_MIN_SIZE);
1249 if (ret != JAYLINK_OK) {
1250 log_err(ctx, "transport_read() failed: %i.", ret);
1251 return JAYLINK_ERR;
1255 parse_conntable(connections, buf + REG_HEADER_SIZE, num, entry_size);
1257 if (info)
1258 memcpy(info, buf + REG_HEADER_SIZE + table_size, addinfo_size);
1260 if (info_size)
1261 *info_size = addinfo_size;
1263 *count = num;
1265 return JAYLINK_OK;