device: Add function to retrieve hardware version.
[libjaylink.git] / libjaylink / device.c
blob98bebc43e461ecdb9e36ab1189976c81a58c71de
1 /*
2 * This file is part of the libjaylink project.
4 * Copyright (C) 2014 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 3 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 <libusb.h>
23 #include "libjaylink.h"
24 #include "libjaylink-internal.h"
26 #define CMD_GET_VERSION 0x01
27 #define CMD_SET_SPEED 0x05
28 #define CMD_GET_HW_STATUS 0x07
29 #define CMD_GET_FREE_MEMORY 0xd4
30 #define CMD_GET_CAPS 0xe8
31 #define CMD_GET_EXT_CAPS 0xed
32 #define CMD_GET_HW_VERSION 0xf0
34 struct jaylink_device *device_allocate(struct jaylink_context *ctx)
36 struct jaylink_device *dev;
37 struct list *list;
39 dev = malloc(sizeof(struct jaylink_device));
41 if (!dev)
42 return NULL;
44 list = list_prepend(ctx->devs, dev);
46 if (!list) {
47 free(dev);
48 return NULL;
51 ctx->devs = list;
53 dev->ctx = ctx;
54 dev->refcnt = 1;
55 dev->usb_dev = NULL;
57 return dev;
60 static struct jaylink_device_handle *allocate_device_handle(
61 struct jaylink_device *dev)
63 struct jaylink_device_handle *devh;
65 devh = malloc(sizeof(struct jaylink_device_handle));
67 if (!devh)
68 return NULL;
70 devh->dev = jaylink_ref_device(dev);
72 return devh;
75 static void free_device_handle(struct jaylink_device_handle *devh)
77 jaylink_unref_device(devh->dev);
78 free(devh);
81 ssize_t jaylink_get_device_list(struct jaylink_context *ctx,
82 struct jaylink_device ***list)
84 if (!ctx || !list)
85 return JAYLINK_ERR_ARG;
87 return discovery_get_device_list(ctx, list);
90 void jaylink_free_device_list(struct jaylink_device **list, int unref_devices)
92 size_t i;
94 if (!list)
95 return;
97 if (unref_devices) {
98 i = 0;
100 while (list[i]) {
101 jaylink_unref_device(list[i]);
102 i++;
106 free(list);
109 int jaylink_device_get_serial_number(const struct jaylink_device *dev,
110 uint32_t *serial_number)
112 if (!dev || !serial_number)
113 return JAYLINK_ERR_ARG;
115 *serial_number = dev->serial_number;
117 return JAYLINK_OK;
120 int jaylink_device_get_usb_address(const struct jaylink_device *dev)
122 if (!dev)
123 return JAYLINK_ERR_ARG;
125 return dev->usb_address;
128 struct jaylink_device *jaylink_ref_device(struct jaylink_device *dev)
130 if (!dev)
131 return NULL;
133 dev->refcnt++;
135 return dev;
138 void jaylink_unref_device(struct jaylink_device *dev)
140 if (!dev)
141 return;
143 dev->refcnt--;
145 if (dev->refcnt == 0) {
146 dev->ctx->devs = list_remove(dev->ctx->devs, dev);
148 if (dev->usb_dev)
149 libusb_unref_device(dev->usb_dev);
151 free(dev);
155 int jaylink_open(struct jaylink_device *dev,
156 struct jaylink_device_handle **devh)
158 int ret;
159 struct jaylink_device_handle *handle;
161 if (!dev || !devh)
162 return JAYLINK_ERR_ARG;
164 handle = allocate_device_handle(dev);
166 if (!handle) {
167 log_err(dev->ctx, "Device handle malloc failed.");
168 return JAYLINK_ERR_MALLOC;
171 ret = transport_open(handle);
173 if (ret < 0) {
174 free_device_handle(handle);
175 return ret;
178 *devh = handle;
180 return JAYLINK_OK;
183 void jaylink_close(struct jaylink_device_handle *devh)
185 if (!devh)
186 return;
188 transport_close(devh);
189 free_device_handle(devh);
193 * Retrieve the firmware version of a device.
195 * @param[in,out] devh Device handle.
196 * @param[out] version Newly allocated string which contains the firmware
197 * version, and undefined if the device returns no
198 * firmware version or on failure. The string is
199 * null-terminated and must be free'd by the caller.
201 * @return The length of the newly allocated firmware version string including
202 * trailing null-terminator or 0 if the device returns no firmware
203 * version or any #jaylink_error error code on failure.
205 int jaylink_get_firmware_version(struct jaylink_device_handle *devh,
206 char **version)
208 int ret;
209 struct jaylink_context *ctx;
210 uint8_t buf[2];
211 uint16_t length;
212 char *tmp;
214 if (!devh || !version)
215 return JAYLINK_ERR_ARG;
217 ctx = devh->dev->ctx;
218 ret = transport_start_write_read(devh, 1, 2, 1);
220 if (ret != JAYLINK_OK) {
221 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
222 return ret;
225 buf[0] = CMD_GET_VERSION;
227 ret = transport_write(devh, buf, 1);
229 if (ret != JAYLINK_OK) {
230 log_err(ctx, "transport_write() failed: %i.", ret);
231 return ret;
234 ret = transport_read(devh, buf, 2);
236 if (ret != JAYLINK_OK) {
237 log_err(ctx, "transport_read() failed: %i.", ret);
238 return ret;
241 length = buffer_get_u16(buf, 0);
243 if (!length)
244 return 0;
246 ret = transport_start_read(devh, length);
248 if (ret != JAYLINK_OK) {
249 log_err(ctx, "transport_start_read() failed: %i.", ret);
250 return ret;
253 tmp = malloc(length);
255 if (!tmp) {
256 log_err(ctx, "Firmware version string malloc failed.");
257 return JAYLINK_ERR_MALLOC;
260 ret = transport_read(devh, (uint8_t *)tmp, length);
262 if (ret != JAYLINK_OK) {
263 log_err(ctx, "transport_read() failed: %i.", ret);
264 free(tmp);
265 return ret;
268 /* Last byte is reserved for null-terminator. */
269 tmp[length - 1] = 0;
270 *version = tmp;
272 return length;
276 * Retrieve the hardware version of a device.
278 * @note This function must only be used if the device has the
279 * #JAYLINK_DEV_CAP_GET_HW_VERSION capability.
281 * @param[in,out] devh Device handle.
282 * @param[out] version Hardware version on success, and undefined on failure.
284 * @retval JAYLINK_OK Success.
285 * @retval JAYLINK_ERR_ARG Invalid arguments.
286 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
287 * @retval JAYLINK_ERR Other error conditions.
289 * @see jaylink_get_caps() to retrieve device capabilities.
291 int jaylink_get_hardware_version(struct jaylink_device_handle *devh,
292 struct jaylink_hardware_version *version)
294 int ret;
295 struct jaylink_context *ctx;
296 uint8_t buf[4];
297 uint32_t tmp;
299 if (!devh || !version)
300 return JAYLINK_ERR_ARG;
302 ctx = devh->dev->ctx;
303 ret = transport_start_write_read(devh, 1, 4, 1);
305 if (ret != JAYLINK_OK) {
306 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
307 return ret;
310 buf[0] = CMD_GET_HW_VERSION;
312 ret = transport_write(devh, buf, 1);
314 if (ret != JAYLINK_OK) {
315 log_err(ctx, "transport_write() failed: %i.", ret);
316 return ret;
319 ret = transport_read(devh, buf, 4);
321 if (ret != JAYLINK_OK) {
322 log_err(ctx, "transport_read() failed: %i.", ret);
323 return ret;
326 tmp = buffer_get_u32(buf, 0);
328 version->type = (tmp / 1000000) % 100;
329 version->major = (tmp / 10000) % 100;
330 version->minor = (tmp / 100) % 100;
331 version->revision = tmp % 100;
333 return JAYLINK_OK;
337 * Retrieve the hardware status of a device.
339 * @param[in,out] devh Device handle.
340 * @param[out] status Hardware status on success, and undefined on failure.
342 * @retval JAYLINK_OK Success.
343 * @retval JAYLINK_ERR_ARG Invalid arguments.
344 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
345 * @retval JAYLINK_ERR Other error conditions.
347 int jaylink_get_hardware_status(struct jaylink_device_handle *devh,
348 struct jaylink_hardware_status *status)
350 int ret;
351 struct jaylink_context *ctx;
352 uint8_t buf[8];
354 if (!devh || !status)
355 return JAYLINK_ERR_ARG;
357 ctx = devh->dev->ctx;
358 ret = transport_start_write_read(devh, 1, 8, 1);
360 if (ret != JAYLINK_OK) {
361 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
362 return ret;
365 buf[0] = CMD_GET_HW_STATUS;
367 ret = transport_write(devh, buf, 1);
369 if (ret != JAYLINK_OK) {
370 log_err(ctx, "transport_write() failed: %i.", ret);
371 return ret;
374 ret = transport_read(devh, buf, 8);
376 if (ret != JAYLINK_OK) {
377 log_err(ctx, "transport_read() failed: %i.", ret);
378 return ret;
381 status->target_voltage = buffer_get_u16(buf, 0);
382 status->tck = buf[2];
383 status->tdi = buf[3];
384 status->tdo = buf[4];
385 status->tms = buf[5];
386 status->tres = buf[6];
387 status->trst = buf[7];
389 return JAYLINK_OK;
393 * Retrieve the capabilities of a device.
395 * The capabilities are stored in a 32-bit bit array consisting of
396 * #JAYLINK_DEV_CAPS_SIZE bytes where each individual bit represents a
397 * capability. The first bit of this array is the least significant bit of the
398 * first byte and the following bits are sequentially numbered in order of
399 * increasing bit significance and byte index. A set bit indicates a supported
400 * capability. See #jaylink_device_capability for a description of the
401 * capabilities and their bit positions.
403 * @param[in,out] devh Device handle.
404 * @param[out] caps Buffer to store capabilities on success. Its value is
405 * undefined on failure. The size of the buffer must be large
406 * enough to contain at least #JAYLINK_DEV_CAPS_SIZE bytes.
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 * @see jaylink_get_extended_caps() to retrieve extended device capabilities.
415 int jaylink_get_caps(struct jaylink_device_handle *devh, uint8_t *caps)
417 int ret;
418 struct jaylink_context *ctx;
419 uint8_t buf[1];
421 if (!devh || !caps)
422 return JAYLINK_ERR_ARG;
424 ctx = devh->dev->ctx;
425 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_CAPS_SIZE, 1);
427 if (ret != JAYLINK_OK) {
428 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
429 return ret;
432 buf[0] = CMD_GET_CAPS;
434 ret = transport_write(devh, buf, 1);
436 if (ret != JAYLINK_OK) {
437 log_err(ctx, "transport_write() failed: %i.", ret);
438 return ret;
441 ret = transport_read(devh, caps, JAYLINK_DEV_CAPS_SIZE);
443 if (ret != JAYLINK_OK) {
444 log_err(ctx, "transport_read() failed: %i.", ret);
445 return ret;
448 return JAYLINK_OK;
452 * Retrieve the extended capabilities of a device.
454 * The extended capabilities are stored in a 256-bit bit array consisting of
455 * #JAYLINK_DEV_EXT_CAPS_SIZE bytes. See jaylink_get_caps() for a further
456 * description of how the capabilities are represented in this bit array. For a
457 * description of the capabilities and their bit positions, see
458 * #jaylink_device_capability.
460 * @note This function must only be used if the device has the
461 * #JAYLINK_DEV_CAP_GET_EXT_CAPS capability.
463 * @param[in,out] devh Device handle.
464 * @param[out] caps Buffer to store capabilities on success. Its value is
465 * undefined on failure. The size of the buffer must be large
466 * enough to contain at least #JAYLINK_DEV_EXT_CAPS_SIZE bytes.
468 * @retval JAYLINK_OK Success.
469 * @retval JAYLINK_ERR_ARG Invalid arguments.
470 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
471 * @retval JAYLINK_ERR Other error conditions.
473 * @see jaylink_get_caps() to retrieve device capabilities.
475 int jaylink_get_extended_caps(struct jaylink_device_handle *devh, uint8_t *caps)
477 int ret;
478 struct jaylink_context *ctx;
479 uint8_t buf[1];
481 if (!devh || !caps)
482 return JAYLINK_ERR_ARG;
484 ctx = devh->dev->ctx;
485 ret = transport_start_write_read(devh, 1, JAYLINK_DEV_EXT_CAPS_SIZE, 1);
487 if (ret != JAYLINK_OK) {
488 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
489 return ret;
492 buf[0] = CMD_GET_EXT_CAPS;
494 ret = transport_write(devh, buf, 1);
496 if (ret != JAYLINK_OK) {
497 log_err(ctx, "transport_write() failed: %i.", ret);
498 return ret;
501 ret = transport_read(devh, caps, JAYLINK_DEV_EXT_CAPS_SIZE);
503 if (ret != JAYLINK_OK) {
504 log_err(ctx, "transport_read() failed: %i.", ret);
505 return ret;
508 return JAYLINK_OK;
512 * Retrieve the size of free memory of a device.
514 * @note This function must only be used if the device has the
515 * #JAYLINK_DEV_CAP_GET_FREE_MEMORY capability.
517 * @param[in,out] devh Device handle.
518 * @param[out] size Size of free memory in bytes on success, and undefined on
519 * failure.
521 * @retval JAYLINK_OK Success.
522 * @retval JAYLINK_ERR_ARG Invalid arguments.
523 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
524 * @retval JAYLINK_ERR Other error conditions.
526 * @see jaylink_get_caps() to retrieve device capabilities.
528 int jaylink_get_free_memory(struct jaylink_device_handle *devh, uint32_t *size)
530 int ret;
531 struct jaylink_context *ctx;
532 uint8_t buf[4];
534 if (!devh || !size)
535 return JAYLINK_ERR_ARG;
537 ctx = devh->dev->ctx;
538 ret = transport_start_write_read(devh, 1, 4, 1);
540 if (ret != JAYLINK_OK) {
541 log_err(ctx, "transport_start_write_read() failed: %i.", ret);
542 return ret;
545 buf[0] = CMD_GET_FREE_MEMORY;
547 ret = transport_write(devh, buf, 1);
549 if (ret != JAYLINK_OK) {
550 log_err(ctx, "transport_write() failed: %i.", ret);
551 return ret;
554 ret = transport_read(devh, buf, 4);
556 if (ret != JAYLINK_OK) {
557 log_err(ctx, "transport_read() failed: %i.", ret);
558 return ret;
561 *size = buffer_get_u32(buf, 0);
563 return JAYLINK_OK;
567 * Set the target interface speed of a device.
569 * @param[in,out] devh Device handle.
570 * @param[in] speed Speed in kHz or #JAYLINK_SPEED_ADAPTIVE_CLOCKING for
571 * adaptive clocking. Speed of 0 kHz is not allowed and
572 * adaptive clocking must only be used if the device has the
573 * #JAYLINK_DEV_CAP_ADAPTIVE_CLOCKING capability.
575 * @retval JAYLINK_OK Success.
576 * @retval JAYLINK_ERR_ARG Invalid arguments.
577 * @retval JAYLINK_ERR_TIMEOUT A timeout occurred.
578 * @retval JAYLINK_ERR Other error conditions.
580 int jaylink_set_speed(struct jaylink_device_handle *devh, uint16_t speed)
582 int ret;
583 struct jaylink_context *ctx;
584 uint8_t buf[3];
586 if (!devh || !speed)
587 return JAYLINK_ERR_ARG;
589 ctx = devh->dev->ctx;
590 ret = transport_start_write(devh, 3, 1);
592 if (ret != JAYLINK_OK) {
593 log_err(ctx, "transport_start_write() failed: %i.", ret);
594 return ret;
597 buf[0] = CMD_SET_SPEED;
598 buffer_set_u16(buf, speed, 1);
600 ret = transport_write(devh, buf, 3);
602 if (ret != JAYLINK_OK) {
603 log_err(ctx, "transport_write() failed: %i.", ret);
604 return ret;
607 return JAYLINK_OK;