Change API of jaylink_get_firmware_version()
[libjaylink.git] / libjaylink / device.c
blobb19e4515df1ef9d93c8ca8b131bc824c93515168
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2014-2015 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 <string.h>
23 #include <libusb.h>
25 #include "libjaylink.h"
26 #include "libjaylink-internal.h"
28 /**
29 * @file
31 * Device enumeration and handling.
34 /** @cond PRIVATE */
35 #define CMD_GET_VERSION 0x01
36 #define CMD_GET_HW_STATUS 0x07
37 #define CMD_REGISTER 0x09
38 #define CMD_GET_HW_INFO 0xc1
39 #define CMD_GET_FREE_MEMORY 0xd4
40 #define CMD_GET_CAPS 0xe8
41 #define CMD_GET_EXT_CAPS 0xed
42 #define CMD_GET_HW_VERSION 0xf0
43 #define CMD_READ_CONFIG 0xf2
44 #define CMD_WRITE_CONFIG 0xf3
46 #define REG_CMD_REGISTER 0x64
47 #define REG_CMD_UNREGISTER 0x65
49 /** Size of the registration header in bytes. */
50 #define REG_HEADER_SIZE 8
51 /** Minimum registration information size in bytes. */
52 #define REG_MIN_SIZE 0x4c
53 /** Maximum registration information size in bytes. */
54 #define REG_MAX_SIZE 0x200
55 /** Size of a connection entry in bytes. */
56 #define REG_CONN_INFO_SIZE 16
57 /** @endcond */
59 /** @private */
60 JAYLINK_PRIV struct jaylink_device *device_allocate(struct jaylink_context *ctx)
62 struct jaylink_device *dev;
63 struct list *list;
65 dev = malloc(sizeof(struct jaylink_device));
67 if (!dev)
68 return NULL;
70 list = list_prepend(ctx->devs, dev);
72 if (!list) {
73 free(dev);
74 return NULL;
77 ctx->devs = list;
79 dev->ctx = ctx;
80 dev->refcnt = 1;
81 dev->usb_dev = NULL;
83 return dev;
86 /** @private */
87 static struct jaylink_device_handle *allocate_device_handle(
88 struct jaylink_device *dev)
90 struct jaylink_device_handle *devh;
92 devh = malloc(sizeof(struct jaylink_device_handle));
94 if (!devh)
95 return NULL;
97 devh->dev = jaylink_ref_device(dev);
99 return devh;
102 /** @private */
103 static void free_device_handle(struct jaylink_device_handle *devh)
105 jaylink_unref_device(devh->dev);
106 free(devh);
110 * Get a list of available devices.
112 * @param[in,out] ctx libjaylink context.
113 * @param[out] devices Newly allocated array which contains instances of
114 * available devices on success, and undefined on failure.
115 * The array is NULL-terminated and must be free'd by the
116 * caller with jaylink_free_device_list().
118 * @return The length of the array excluding the trailing NULL-terminator, or a
119 * negative error code on failure.
121 JAYLINK_API ssize_t jaylink_get_device_list(struct jaylink_context *ctx,
122 struct jaylink_device ***devices)
124 if (!ctx || !devices)
125 return JAYLINK_ERR_ARG;
127 return discovery_get_device_list(ctx, devices);
131 * Free a device list.
133 * @param[in,out] devices Array of device instances. Must be NULL-terminated.
134 * @param[in] unref_devices Determines whether the device instances should be
135 * unreferenced.
137 JAYLINK_API void jaylink_free_device_list(struct jaylink_device **devices,
138 int unref_devices)
140 size_t i;
142 if (!devices)
143 return;
145 if (unref_devices) {
146 i = 0;
148 while (devices[i]) {
149 jaylink_unref_device(devices[i]);
150 i++;
154 free(devices);
158 * Get the serial number of a device.
160 * @note This serial number is for enumeration purpose only and might differ
161 * from the real serial number of the device.
163 * @param[in] dev Device instance.
164 * @param[out] serial_number Serial number of the device on success, and
165 * undefined on failure.
167 * @retval JAYLINK_OK Success.
168 * @retval JAYLINK_ERR_ARG Invalid arguments.
169 * @retval JAYLINK_ERR_NOT_AVAILABLE Serial number is not available.
171 JAYLINK_API int jaylink_device_get_serial_number(
172 const struct jaylink_device *dev, uint32_t *serial_number)
174 if (!dev || !serial_number)
175 return JAYLINK_ERR_ARG;
177 if (!dev->valid_serial_number)
178 return JAYLINK_ERR_NOT_AVAILABLE;
180 *serial_number = dev->serial_number;
182 return JAYLINK_OK;
186 * Get the USB address of a device.
188 * @note Identification of a device with the USB address is deprecated and the
189 * serial number should be used instead.
191 * @param[in] dev Device instance.
193 * @return The USB address of the device on success, or #JAYLINK_ERR_ARG for
194 * invalid device instance. See #jaylink_usb_address for valid USB
195 * addresses.
197 * @see jaylink_device_get_serial_number() to get the serial number of a device.
199 JAYLINK_API int jaylink_device_get_usb_address(const struct jaylink_device *dev)
201 if (!dev)
202 return JAYLINK_ERR_ARG;
204 return dev->usb_address;
208 * Increment the reference count of a device.
210 * @param[in,out] dev Device instance.
212 * @return The given device instance on success, or NULL for invalid device
213 * instance.
215 JAYLINK_API struct jaylink_device *jaylink_ref_device(
216 struct jaylink_device *dev)
218 if (!dev)
219 return NULL;
221 dev->refcnt++;
223 return dev;
227 * Decrement the reference count of a device.
229 * @param[in,out] dev Device instance.
231 JAYLINK_API void jaylink_unref_device(struct jaylink_device *dev)
233 if (!dev)
234 return;
236 dev->refcnt--;
238 if (dev->refcnt == 0) {
239 dev->ctx->devs = list_remove(dev->ctx->devs, dev);
241 if (dev->usb_dev)
242 libusb_unref_device(dev->usb_dev);
244 free(dev);
249 * Open a device.
251 * @param[in,out] dev Device instance.
252 * @param[out] devh Newly allocated handle for the opened device on success,
253 * and undefined on failure.
255 * @retval JAYLINK_OK Success.
256 * @retval JAYLINK_ERR_ARG Invalid arguments.
257 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
258 * @retval JAYLINK_ERR_MALLOC Memory allocation error.
259 * @retval JAYLINK_ERR Other error conditions.
261 JAYLINK_API int jaylink_open(struct jaylink_device *dev,
262 struct jaylink_device_handle **devh)
264 int ret;
265 struct jaylink_device_handle *handle;
267 if (!dev || !devh)
268 return JAYLINK_ERR_ARG;
270 handle = allocate_device_handle(dev);
272 if (!handle) {
273 log_err(dev->ctx, "Device handle malloc failed.");
274 return JAYLINK_ERR_MALLOC;
277 ret = transport_open(handle);
279 if (ret < 0) {
280 free_device_handle(handle);
281 return ret;
284 *devh = handle;
286 return JAYLINK_OK;
290 * Close a device.
292 * @param[in,out] devh Device instance.
294 JAYLINK_API void jaylink_close(struct jaylink_device_handle *devh)
296 if (!devh)
297 return;
299 transport_close(devh);
300 free_device_handle(devh);
304 * Retrieve the firmware version of a device.
306 * @param[in,out] devh Device handle.
307 * @param[out] version Newly allocated string which contains the firmware
308 * version on success, and undefined if @p length is zero
309 * or on failure. The string is null-terminated and must be
310 * free'd by the caller.
311 * @param[out] length Length of the firmware version string including trailing
312 * null-terminator on success, and undefined on failure.
313 * Zero if no firmware version string is available.
315 * @retval JAYLINK_OK Success.
316 * @retval JAYLINK_ERR_ARG Invalid arguments.
317 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
318 * @retval JAYLINK_ERR_MALLOC Memory allocation error.
319 * @retval JAYLINK_ERR Other error conditions.
321 JAYLINK_API int jaylink_get_firmware_version(struct jaylink_device_handle *devh,
322 char **version, size_t *length)
324 int ret;
325 struct jaylink_context *ctx;
326 uint8_t buf[2];
327 uint16_t dummy;
328 char *tmp;
330 if (!devh || !version || !length)
331 return JAYLINK_ERR_ARG;
333 ctx = devh->dev->ctx;
334 ret = transport_start_write_read(devh, 1, 2, 1);
336 if (ret != JAYLINK_OK) {
337 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
338 return ret;
341 buf[0] = CMD_GET_VERSION;
343 ret = transport_write(devh, buf, 1);
345 if (ret != JAYLINK_OK) {
346 log_err(ctx, "transport_write() failed: %i.", ret);
347 return ret;
350 ret = transport_read(devh, buf, 2);
352 if (ret != JAYLINK_OK) {
353 log_err(ctx, "transport_read() failed: %i.", ret);
354 return ret;
357 dummy = buffer_get_u16(buf, 0);
358 *length = dummy;
360 if (!dummy)
361 return JAYLINK_OK;
363 ret = transport_start_read(devh, dummy);
365 if (ret != JAYLINK_OK) {
366 log_err(ctx, "transport_start_read() failed: %i.", ret);
367 return ret;
370 tmp = malloc(dummy);
372 if (!tmp) {
373 log_err(ctx, "Firmware version string malloc failed.");
374 return JAYLINK_ERR_MALLOC;
377 ret = transport_read(devh, (uint8_t *)tmp, dummy);
379 if (ret != JAYLINK_OK) {
380 log_err(ctx, "transport_read() failed: %i.", ret);
381 free(tmp);
382 return ret;
385 /* Last byte is reserved for null-terminator. */
386 tmp[dummy - 1] = 0;
387 *version = tmp;
389 return JAYLINK_OK;
393 * Retrieve the hardware information of a device.
395 * @note This function must only be used if the device has the
396 * #JAYLINK_DEV_CAP_GET_HW_INFO capability.
398 * @param[in,out] devh Device handle.
399 * @param[in] mask A bit field where each set bit represents hardware
400 * information to request. See #jaylink_hardware_info for a
401 * description of the hardware information and their bit
402 * positions.
403 * @param[out] info Array to store the hardware information on success. Its
404 * content is undefined on failure. The array must be large
405 * enough to contain at least as many elements as bits set in
406 * @a mask.
408 * @retval JAYLINK_OK Success.
409 * @retval JAYLINK_ERR_ARG Invalid arguments.
410 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
411 * @retval JAYLINK_ERR Other error conditions.
413 JAYLINK_API int jaylink_get_hardware_info(struct jaylink_device_handle *devh,
414 uint32_t mask, uint32_t *info)
416 int ret;
417 struct jaylink_context *ctx;
418 uint8_t buf[5];
419 unsigned int i;
420 unsigned int num;
421 unsigned int length;
423 if (!devh || !mask || !info)
424 return JAYLINK_ERR_ARG;
426 ctx = devh->dev->ctx;
427 num = 0;
429 for (i = 0; i < 32; i++) {
430 if (mask & (1 << i))
431 num++;
434 length = num * sizeof(uint32_t);
436 ret = transport_start_write_read(devh, 5, length, 1);
438 if (ret != JAYLINK_OK) {
439 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
440 return ret;
443 buf[0] = CMD_GET_HW_INFO;
444 buffer_set_u32(buf, mask, 1);
446 ret = transport_write(devh, buf, 5);
448 if (ret != JAYLINK_OK) {
449 log_err(ctx, "transport_write() failed: %i.", ret);
450 return ret;
453 ret = transport_read(devh, (uint8_t *)info, length);
455 if (ret != JAYLINK_OK) {
456 log_err(ctx, "transport_read() failed: %i.", ret);
457 return ret;
460 for (i = 0; i < num; i++)
461 info[i] = buffer_get_u32((uint8_t *)info, i * sizeof(uint32_t));
463 return JAYLINK_OK;
467 * Retrieve the hardware version of a device.
469 * @note This function must only be used if the device has the
470 * #JAYLINK_DEV_CAP_GET_HW_VERSION capability.
472 * @param[in,out] devh Device handle.
473 * @param[out] version Hardware version on success, and undefined on failure.
475 * @retval JAYLINK_OK Success.
476 * @retval JAYLINK_ERR_ARG Invalid arguments.
477 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
478 * @retval JAYLINK_ERR Other error conditions.
480 * @see jaylink_get_caps() to retrieve device capabilities.
482 JAYLINK_API int jaylink_get_hardware_version(struct jaylink_device_handle *devh,
483 struct jaylink_hardware_version *version)
485 int ret;
486 struct jaylink_context *ctx;
487 uint8_t buf[4];
488 uint32_t tmp;
490 if (!devh || !version)
491 return JAYLINK_ERR_ARG;
493 ctx = devh->dev->ctx;
494 ret = transport_start_write_read(devh, 1, 4, 1);
496 if (ret != JAYLINK_OK) {
497 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
498 return ret;
501 buf[0] = CMD_GET_HW_VERSION;
503 ret = transport_write(devh, buf, 1);
505 if (ret != JAYLINK_OK) {
506 log_err(ctx, "transport_write() failed: %i.", ret);
507 return ret;
510 ret = transport_read(devh, buf, 4);
512 if (ret != JAYLINK_OK) {
513 log_err(ctx, "transport_read() failed: %i.", ret);
514 return ret;
517 tmp = buffer_get_u32(buf, 0);
519 version->type = (tmp / 1000000) % 100;
520 version->major = (tmp / 10000) % 100;
521 version->minor = (tmp / 100) % 100;
522 version->revision = tmp % 100;
524 return JAYLINK_OK;
528 * Retrieve the hardware status of a device.
530 * @param[in,out] devh Device handle.
531 * @param[out] status Hardware status on success, and undefined on failure.
533 * @retval JAYLINK_OK Success.
534 * @retval JAYLINK_ERR_ARG Invalid arguments.
535 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
536 * @retval JAYLINK_ERR Other error conditions.
538 JAYLINK_API int jaylink_get_hardware_status(struct jaylink_device_handle *devh,
539 struct jaylink_hardware_status *status)
541 int ret;
542 struct jaylink_context *ctx;
543 uint8_t buf[8];
545 if (!devh || !status)
546 return JAYLINK_ERR_ARG;
548 ctx = devh->dev->ctx;
549 ret = transport_start_write_read(devh, 1, 8, 1);
551 if (ret != JAYLINK_OK) {
552 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
553 return ret;
556 buf[0] = CMD_GET_HW_STATUS;
558 ret = transport_write(devh, buf, 1);
560 if (ret != JAYLINK_OK) {
561 log_err(ctx, "transport_write() failed: %i.", ret);
562 return ret;
565 ret = transport_read(devh, buf, 8);
567 if (ret != JAYLINK_OK) {
568 log_err(ctx, "transport_read() failed: %i.", ret);
569 return ret;
572 status->target_voltage = buffer_get_u16(buf, 0);
573 status->tck = buf[2];
574 status->tdi = buf[3];
575 status->tdo = buf[4];
576 status->tms = buf[5];
577 status->tres = buf[6];
578 status->trst = buf[7];
580 return JAYLINK_OK;
584 * Retrieve the capabilities of a device.
586 * The capabilities are stored in a 32-bit bit array consisting of
587 * #JAYLINK_DEV_CAPS_SIZE bytes where each individual bit represents a
588 * capability. The first bit of this array is the least significant bit of the
589 * first byte and the following bits are sequentially numbered in order of
590 * increasing bit significance and byte index. A set bit indicates a supported
591 * capability. See #jaylink_device_capability for a description of the
592 * capabilities and their bit positions.
594 * @param[in,out] devh Device handle.
595 * @param[out] caps Buffer to store capabilities on success. Its content is
596 * undefined on failure. The size of the buffer must be large
597 * enough to contain at least #JAYLINK_DEV_CAPS_SIZE bytes.
599 * @retval JAYLINK_OK Success.
600 * @retval JAYLINK_ERR_ARG Invalid arguments.
601 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
602 * @retval JAYLINK_ERR Other error conditions.
604 * @see jaylink_get_extended_caps() to retrieve extended device capabilities.
606 JAYLINK_API int jaylink_get_caps(struct jaylink_device_handle *devh,
607 uint8_t *caps)
609 int ret;
610 struct jaylink_context *ctx;
611 uint8_t buf[1];
613 if (!devh || !caps)
614 return JAYLINK_ERR_ARG;
616 ctx = devh->dev->ctx;
617 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CAPS_SIZE, 1);
619 if (ret != JAYLINK_OK) {
620 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
621 return ret;
624 buf[0] = CMD_GET_CAPS;
626 ret = transport_write(devh, buf, 1);
628 if (ret != JAYLINK_OK) {
629 log_err(ctx, "transport_write() failed: %i.", ret);
630 return ret;
633 ret = transport_read(devh, caps, JAYLINK_DEV_CAPS_SIZE);
635 if (ret != JAYLINK_OK) {
636 log_err(ctx, "transport_read() failed: %i.", ret);
637 return ret;
640 return JAYLINK_OK;
644 * Retrieve the extended capabilities of a device.
646 * The extended capabilities are stored in a 256-bit bit array consisting of
647 * #JAYLINK_DEV_EXT_CAPS_SIZE bytes. See jaylink_get_caps() for a further
648 * description of how the capabilities are represented in this bit array. For a
649 * description of the capabilities and their bit positions, see
650 * #jaylink_device_capability.
652 * @note This function must only be used if the device has the
653 * #JAYLINK_DEV_CAP_GET_EXT_CAPS capability.
655 * @param[in,out] devh Device handle.
656 * @param[out] caps Buffer to store capabilities on success. Its content is
657 * undefined on failure. The size of the buffer must be large
658 * enough to contain at least #JAYLINK_DEV_EXT_CAPS_SIZE bytes.
660 * @retval JAYLINK_OK Success.
661 * @retval JAYLINK_ERR_ARG Invalid arguments.
662 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
663 * @retval JAYLINK_ERR Other error conditions.
665 * @see jaylink_get_caps() to retrieve device capabilities.
667 JAYLINK_API int jaylink_get_extended_caps(struct jaylink_device_handle *devh,
668 uint8_t *caps)
670 int ret;
671 struct jaylink_context *ctx;
672 uint8_t buf[1];
674 if (!devh || !caps)
675 return JAYLINK_ERR_ARG;
677 ctx = devh->dev->ctx;
678 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_EXT_CAPS_SIZE, 1);
680 if (ret != JAYLINK_OK) {
681 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
682 return ret;
685 buf[0] = CMD_GET_EXT_CAPS;
687 ret = transport_write(devh, buf, 1);
689 if (ret != JAYLINK_OK) {
690 log_err(ctx, "transport_write() failed: %i.", ret);
691 return ret;
694 ret = transport_read(devh, caps, JAYLINK_DEV_EXT_CAPS_SIZE);
696 if (ret != JAYLINK_OK) {
697 log_err(ctx, "transport_read() failed: %i.", ret);
698 return ret;
701 return JAYLINK_OK;
705 * Retrieve the size of free memory of a device.
707 * @note This function must only be used if the device has the
708 * #JAYLINK_DEV_CAP_GET_FREE_MEMORY capability.
710 * @param[in,out] devh Device handle.
711 * @param[out] size Size of free memory in bytes on success, and undefined on
712 * failure.
714 * @retval JAYLINK_OK Success.
715 * @retval JAYLINK_ERR_ARG Invalid arguments.
716 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
717 * @retval JAYLINK_ERR Other error conditions.
719 * @see jaylink_get_caps() to retrieve device capabilities.
721 JAYLINK_API int jaylink_get_free_memory(struct jaylink_device_handle *devh,
722 uint32_t *size)
724 int ret;
725 struct jaylink_context *ctx;
726 uint8_t buf[4];
728 if (!devh || !size)
729 return JAYLINK_ERR_ARG;
731 ctx = devh->dev->ctx;
732 ret = transport_start_write_read(devh, 1, 4, 1);
734 if (ret != JAYLINK_OK) {
735 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
736 return ret;
739 buf[0] = CMD_GET_FREE_MEMORY;
741 ret = transport_write(devh, buf, 1);
743 if (ret != JAYLINK_OK) {
744 log_err(ctx, "transport_write() failed: %i.", ret);
745 return ret;
748 ret = transport_read(devh, buf, 4);
750 if (ret != JAYLINK_OK) {
751 log_err(ctx, "transport_read() failed: %i.", ret);
752 return ret;
755 *size = buffer_get_u32(buf, 0);
757 return JAYLINK_OK;
761 * Read the raw configuration data of a device.
763 * @note This function must only be used if the device has the
764 * #JAYLINK_DEV_CAP_READ_CONFIG capability.
766 * @param[in,out] devh Device handle.
767 * @param[out] config Buffer to store configuration data on success. Its
768 * content is undefined on failure. The size of the buffer
769 * must be large enough to contain at least
770 * #JAYLINK_DEV_CONFIG_SIZE bytes.
772 * @retval JAYLINK_OK Success.
773 * @retval JAYLINK_ERR_ARG Invalid arguments.
774 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
775 * @retval JAYLINK_ERR Other error conditions.
777 JAYLINK_API int jaylink_read_raw_config(struct jaylink_device_handle *devh,
778 uint8_t *config)
780 int ret;
781 struct jaylink_context *ctx;
782 uint8_t buf[1];
784 if (!devh || !config)
785 return JAYLINK_ERR_ARG;
787 ctx = devh->dev->ctx;
788 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CONFIG_SIZE, 1);
790 if (ret != JAYLINK_OK) {
791 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
792 return ret;
795 buf[0] = CMD_READ_CONFIG;
797 ret = transport_write(devh, buf, 1);
799 if (ret != JAYLINK_OK) {
800 log_err(ctx, "transport_write() failed: %i.", ret);
801 return ret;
804 ret = transport_read(devh, config, JAYLINK_DEV_CONFIG_SIZE);
806 if (ret != JAYLINK_OK) {
807 log_err(ctx, "transport_read() failed: %i.", ret);
808 return ret;
811 return JAYLINK_OK;
815 * Write the raw configuration data of a device.
817 * @note This function must only be used if the device has the
818 * #JAYLINK_DEV_CAP_WRITE_CONFIG capability.
820 * @param[in,out] devh Device handle.
821 * @param[in] config Buffer to write configuration data from. The size of the
822 * configuration data is expected to be
823 * #JAYLINK_DEV_CONFIG_SIZE bytes.
825 * @retval JAYLINK_OK Success.
826 * @retval JAYLINK_ERR_ARG Invalid arguments.
827 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
828 * @retval JAYLINK_ERR Other error conditions.
830 JAYLINK_API int jaylink_write_raw_config(struct jaylink_device_handle *devh,
831 const uint8_t *config)
833 int ret;
834 struct jaylink_context *ctx;
835 uint8_t buf[1];
837 if (!devh || !config)
838 return JAYLINK_ERR_ARG;
840 ctx = devh->dev->ctx;
841 ret = transport_start_write(devh, 1 + JAYLINK_DEV_CONFIG_SIZE, 1);
843 if (ret != JAYLINK_OK) {
844 log_err(ctx, "transport_start_write() failed: %i.", ret);
845 return ret;
848 buf[0] = CMD_WRITE_CONFIG;
850 ret = transport_write(devh, buf, 1);
852 if (ret != JAYLINK_OK) {
853 log_err(ctx, "transport_write() failed: %i.", ret);
854 return ret;
857 ret = transport_write(devh, config, JAYLINK_DEV_CONFIG_SIZE);
859 if (ret != JAYLINK_OK) {
860 log_err(ctx, "transport_write() failed: %i.", ret);
861 return ret;
864 return JAYLINK_OK;
867 static void parse_conntable(struct jaylink_connection *conns,
868 const uint8_t *buffer, uint16_t num, uint16_t entry_size)
870 unsigned int i;
871 size_t offset;
873 offset = 0;
875 for (i = 0; i < num; i++) {
876 conns[i].pid = buffer_get_u32(buffer, offset);
877 conns[i].hid = buffer_get_u32(buffer, offset + 4);
878 conns[i].iid = buffer[offset + 8];
879 conns[i].cid = buffer[offset + 9];
880 conns[i].handle = buffer_get_u16(buffer, offset + 10);
881 conns[i].timestamp = buffer_get_u32(buffer, offset + 12);
882 offset = offset + entry_size;
887 * Register a connection on a device.
889 * A connection can be registered by using 0 as handle. Additional information
890 * about the connection can be attached whereby the timestamp is a read-only
891 * value and therefore ignored for registration. On success, a new handle
892 * greater than 0 is obtained from the device.
894 * However, if an obtained handle does not appear in the list of device
895 * connections, the connection was not registered because the maximum number of
896 * connections on the device is reached.
898 * @note This function must only be used if the device has the
899 * #JAYLINK_DEV_CAP_REGISTER capability.
901 * @param[in,out] devh Device handle.
902 * @param[in,out] connection Connection to register on the device.
903 * @param[out] connections Array to store device connections on success.
904 * Its content is undefined on failure. The array must
905 * be large enough to contain at least
906 * #JAYLINK_MAX_CONNECTIONS elements.
907 * @param[out] info Buffer to store additional information on success, or NULL.
908 * The content of the buffer is undefined on failure.
909 * @param[out] info_size Size of the additional information in bytes on success,
910 * and undefined on failure. Can be NULL.
912 * @return The number of device connections on success, a negative error code on
913 * failure.
915 * @see jaylink_unregister() to unregister a connection from a device.
917 JAYLINK_API int jaylink_register(struct jaylink_device_handle *devh,
918 struct jaylink_connection *connection,
919 struct jaylink_connection *connections, uint8_t *info,
920 uint16_t *info_size)
922 int ret;
923 struct jaylink_context *ctx;
924 uint8_t buf[REG_MAX_SIZE];
925 uint16_t handle;
926 uint16_t num;
927 uint16_t entry_size;
928 uint32_t size;
929 uint32_t table_size;
930 uint16_t addinfo_size;
932 if (!devh || !connection || !connections)
933 return JAYLINK_ERR_ARG;
935 ctx = devh->dev->ctx;
936 ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, 1);
938 if (ret != JAYLINK_OK) {
939 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
940 return ret;
943 buf[0] = CMD_REGISTER;
944 buf[1] = REG_CMD_REGISTER;
945 buffer_set_u32(buf, connection->pid, 2);
946 buffer_set_u32(buf, connection->hid, 6);
947 buf[10] = connection->iid;
948 buf[11] = connection->cid;
949 buffer_set_u16(buf, connection->handle, 12);
951 ret = transport_write(devh, buf, 14);
953 if (ret != JAYLINK_OK) {
954 log_err(ctx, "transport_write() failed: %i.", ret);
955 return ret;
958 ret = transport_read(devh, buf, REG_MIN_SIZE);
960 if (ret != JAYLINK_OK) {
961 log_err(ctx, "transport_read() failed: %i.", ret);
962 return ret;
965 handle = buffer_get_u16(buf, 0);
966 num = buffer_get_u16(buf, 2);
967 entry_size = buffer_get_u16(buf, 4);
968 addinfo_size = buffer_get_u16(buf, 6);
970 if (num > JAYLINK_MAX_CONNECTIONS) {
971 log_err(ctx, "Maximum number of device connections exceeded: "
972 "%u.", num);
973 return JAYLINK_ERR_PROTO;
976 if (entry_size != REG_CONN_INFO_SIZE) {
977 log_err(ctx, "Invalid connection entry size: %u bytes.",
978 entry_size);
979 return JAYLINK_ERR_PROTO;
982 table_size = num * entry_size;
983 size = REG_HEADER_SIZE + table_size + addinfo_size;
985 if (size > REG_MAX_SIZE) {
986 log_err(ctx, "Maximum registration information size exceeded: "
987 "%u bytes.", size);
988 return JAYLINK_ERR_PROTO;
991 if (size > REG_MIN_SIZE) {
992 ret = transport_start_read(devh, size - REG_MIN_SIZE);
994 if (ret != JAYLINK_OK) {
995 log_err(ctx, "transport_start_read() failed: %i.", ret);
996 return JAYLINK_ERR;
999 ret = transport_read(devh, buf + REG_MIN_SIZE,
1000 size - REG_MIN_SIZE);
1002 if (ret != JAYLINK_OK) {
1003 log_err(ctx, "transport_read() failed: %i.", ret);
1004 return JAYLINK_ERR;
1008 if (!handle) {
1009 log_err(ctx, "Obtained invalid connection handle.");
1010 return JAYLINK_ERR_PROTO;
1013 connection->handle = handle;
1014 parse_conntable(connections, buf + REG_HEADER_SIZE, num, entry_size);
1016 if (info)
1017 memcpy(info, buf + REG_HEADER_SIZE + table_size, addinfo_size);
1019 if (info_size)
1020 *info_size = addinfo_size;
1022 return num;
1026 * Unregister a connection from a device.
1028 * @note This function must only be used if the device has the
1029 * #JAYLINK_DEV_CAP_REGISTER capability.
1031 * @param[in,out] devh Device handle.
1032 * @param[in,out] connection Connection to unregister from the device.
1033 * @param[out] connections Array to store device connections on success.
1034 * Its content is undefined on failure. The array must
1035 * be large enough to contain at least
1036 * #JAYLINK_MAX_CONNECTIONS elements.
1037 * @param[out] info Buffer to store additional information on success, or NULL.
1038 * The content of the buffer is undefined on failure.
1039 * @param[out] info_size Size of the additional information in bytes on success,
1040 * and undefined on failure. Can be NULL.
1042 * @return The number of device connections on success, a negative error code on
1043 * failure.
1045 JAYLINK_API int jaylink_unregister(struct jaylink_device_handle *devh,
1046 const struct jaylink_connection *connection,
1047 struct jaylink_connection *connections, uint8_t *info,
1048 uint16_t *info_size)
1050 int ret;
1051 struct jaylink_context *ctx;
1052 uint8_t buf[REG_MAX_SIZE];
1053 uint16_t num;
1054 uint16_t entry_size;
1055 uint32_t size;
1056 uint32_t table_size;
1057 uint16_t addinfo_size;
1059 if (!devh || !connection || !connections)
1060 return JAYLINK_ERR_ARG;
1062 ctx = devh->dev->ctx;
1063 ret = transport_start_write_read(devh, 14, REG_MIN_SIZE, 1);
1065 if (ret != JAYLINK_OK) {
1066 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
1067 return ret;
1070 buf[0] = CMD_REGISTER;
1071 buf[1] = REG_CMD_UNREGISTER;
1072 buffer_set_u32(buf, connection->pid, 2);
1073 buffer_set_u32(buf, connection->hid, 6);
1074 buf[10] = connection->iid;
1075 buf[11] = connection->cid;
1076 buffer_set_u16(buf, connection->handle, 12);
1078 ret = transport_write(devh, buf, 14);
1080 if (ret != JAYLINK_OK) {
1081 log_err(ctx, "transport_write() failed: %i.", ret);
1082 return ret;
1085 ret = transport_read(devh, buf, REG_MIN_SIZE);
1087 if (ret != JAYLINK_OK) {
1088 log_err(ctx, "transport_read() failed: %i.", ret);
1089 return ret;
1092 num = buffer_get_u16(buf, 2);
1093 entry_size = buffer_get_u16(buf, 4);
1094 addinfo_size = buffer_get_u16(buf, 6);
1096 if (num > JAYLINK_MAX_CONNECTIONS) {
1097 log_err(ctx, "Maximum number of device connections exceeded: "
1098 "%u.", num);
1099 return JAYLINK_ERR_PROTO;
1102 if (entry_size != REG_CONN_INFO_SIZE) {
1103 log_err(ctx, "Invalid connection entry size: %u bytes.",
1104 entry_size);
1105 return JAYLINK_ERR_PROTO;
1108 table_size = num * entry_size;
1109 size = REG_HEADER_SIZE + table_size + addinfo_size;
1111 if (size > REG_MAX_SIZE) {
1112 log_err(ctx, "Maximum registration information size exceeded: "
1113 "%u bytes.", size);
1114 return JAYLINK_ERR_PROTO;
1117 if (size > REG_MIN_SIZE) {
1118 ret = transport_start_read(devh, size - REG_MIN_SIZE);
1120 if (ret != JAYLINK_OK) {
1121 log_err(ctx, "transport_start_read() failed: %i.", ret);
1122 return JAYLINK_ERR;
1125 ret = transport_read(devh, buf + REG_MIN_SIZE,
1126 size - REG_MIN_SIZE);
1128 if (ret != JAYLINK_OK) {
1129 log_err(ctx, "transport_read() failed: %i.", ret);
1130 return JAYLINK_ERR;
1134 parse_conntable(connections, buf + REG_HEADER_SIZE, num, entry_size);
1136 if (info)
1137 memcpy(info, buf + REG_HEADER_SIZE + table_size, addinfo_size);
1139 if (info_size)
1140 *info_size = addinfo_size;
1142 return num;