1
0
Fork 0
mirror of https://github.com/linux-usb-gadgets/libusbgx.git synced 2025-07-23 00:45:05 +03:00
libusbgx/src/function/hid.c
Krzysztof Opasiak 5d0962ed41 libusbgx: Fix meaning of HAS_LIBCONFIG and HAS_GADGET_SCHEMES
We have two configure options related to libconfig:
1) --disable-gadget-schemes
2) --without-libconfig

Option #1 means that libusbgx itself should be compiled without gadget
schemes support. Option #2 means that everything what requires
libconfig should be turned off. So option #2 is wider than #1 as
libconfig us used also in our testing program.

To fix this meaning let's use HAS_GADGET_SCHEMES inside library source
code to determine if we should use libconfig or not and HAS_LIBCONFIG
inside our tests source code.

Signed-off-by: Krzysztof Opasiak <k.opasiak@samsung.com>
2017-03-03 17:48:44 +01:00

358 lines
7.8 KiB
C

/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
#include "usbg/usbg.h"
#include "usbg/usbg_internal.h"
#include "usbg/function/hid.h"
#include <malloc.h>
#include <assert.h>
#ifdef HAS_GADGET_SCHEMES
#include <libconfig.h>
#endif
struct usbg_f_hid {
struct usbg_function func;
};
#define HID_DEC_ATTR(_name) \
{ \
.name = #_name, \
.ro = false, \
.offset = offsetof(struct usbg_f_hid_attrs, _name), \
.get = usbg_get_dec, \
.set = usbg_set_dec, \
.import = usbg_get_config_node_int, \
.export = usbg_set_config_node_int, \
}
#define HID_DEV_ATTR_RO(_name) \
{ \
.name = #_name, \
.ro = true, \
.offset = offsetof(struct usbg_f_hid_attrs, _name), \
.get = usbg_get_dev, \
.export = usbg_set_config_node_dev, \
}
#ifdef HAS_GADGET_SCHEMES
static int hid_get_report(const char *path, const char *name, const char *attr,
void *val)
{
struct usbg_f_hid_report_desc *report_desc = val;
char buf[USBG_MAX_FILE_SIZE];
int ret;
ret = usbg_read_buf(path, name, attr, buf);
if (ret < 0)
return ret;
report_desc->len = ret;
if (ret == 0) {
report_desc->desc = NULL;
} else {
report_desc->desc = malloc(report_desc->len);
if (!report_desc->desc)
return USBG_ERROR_NO_MEM;
memcpy(report_desc->desc, buf, report_desc->len);
}
return 0;
}
static int hid_set_report(const char *path, const char *name, const char *attr,
void *val)
{
struct usbg_f_hid_report_desc *report_desc = val;
char *buf = report_desc->desc;
int len = report_desc->len;
int ret;
if (len == 0) {
buf = "";
len = 1;
}
ret = usbg_write_buf(path, name, attr, buf, len);
if (ret > 0)
ret = USBG_SUCCESS;
return ret;
}
static int hid_get_config_node_report(config_setting_t *root,
const char *node_name, void *val)
{
struct usbg_f_hid_report_desc *report_desc = val;
char *buf;
int tmp, i;
config_setting_t *list_node, *node;
int len;
int ret;
list_node = config_setting_get_member(root, node_name);
if (!list_node)
return 0;
if (!config_setting_is_list(list_node))
return USBG_ERROR_INVALID_TYPE;
len = config_setting_length(list_node);
buf = malloc(len * sizeof(char));
if (!buf)
return USBG_ERROR_NO_MEM;
for (i = 0; i < len; ++i) {
node = config_setting_get_elem(list_node, i);
assert(node);
if (!usbg_config_is_int(node)) {
ret = USBG_ERROR_INVALID_TYPE;
goto free_buf;
}
tmp = config_setting_get_int(node);
if (tmp < 0 || tmp > 255) {
ret = USBG_ERROR_INVALID_VALUE;
goto free_buf;
}
buf[i] = (char)tmp;
}
report_desc->desc = buf;
report_desc->len = len;
return 1;
free_buf:
free(buf);
return ret;
}
static int hid_set_config_node_report(config_setting_t *root,
const char *node_name, void *val)
{
struct usbg_f_hid_report_desc *report_desc = val;
config_setting_t *node;
int i;
int ret = 0;
node = config_setting_add(root, node_name, CONFIG_TYPE_LIST);
if (!node)
return USBG_ERROR_NO_MEM;
for (i = 0; i < report_desc->len; ++i) {
int tmp = report_desc->desc[i];
ret = usbg_set_config_node_int_hex(node, NULL, &tmp);
if (ret)
return ret;
}
return 0;
}
#else
#define hid_get_report NULL
#define hid_set_report NULL
#define hid_get_config_node_report NULL
#define hid_set_config_node_report NULL
#endif
#define HID_RD_ATTR(_name) \
{ \
.name = #_name, \
.ro = false, \
.offset = offsetof(struct usbg_f_hid_attrs, _name), \
.get = hid_get_report, \
.set = hid_set_report, \
.import = hid_get_config_node_report, \
.export = hid_set_config_node_report, \
}
struct {
const char *name;
bool ro;
size_t offset;
usbg_attr_get_func get;
usbg_attr_set_func set;
usbg_import_node_func import;
usbg_export_node_func export;
} hid_attr[USBG_F_HID_ATTR_MAX] = {
[USBG_F_HID_DEV] = HID_DEV_ATTR_RO(dev),
[USBG_F_HID_PROTOCOL] = HID_DEC_ATTR(protocol),
[USBG_F_HID_REPORT_DESC] = HID_RD_ATTR(report_desc),
[USBG_F_HID_REPORT_LENGTH] = HID_DEC_ATTR(report_length),
[USBG_F_HID_SUBCLASS] = HID_DEC_ATTR(subclass),
};
#undef HID_DEC_ATTR
#undef HID_DEV_ATTR_RO
#undef HID_RD_ATTR
GENERIC_ALLOC_INST(hid, struct usbg_f_hid, func);
GENERIC_FREE_INST(hid, struct usbg_f_hid, func);
static int hid_set_attrs(struct usbg_function *f, void *f_attrs)
{
return usbg_f_hid_set_attrs(usbg_to_hid_function(f), f_attrs);
}
static int hid_get_attrs(struct usbg_function *f, void *f_attrs)
{
return usbg_f_hid_get_attrs(usbg_to_hid_function(f), f_attrs);
}
static void hid_cleanup_attrs(struct usbg_function *f, void *f_attrs)
{
usbg_f_hid_cleanup_attrs(f_attrs);
}
#ifdef HAS_GADGET_SCHEMES
static int hid_libconfig_import(struct usbg_function *f,
config_setting_t *root)
{
struct usbg_f_hid *hf = usbg_to_hid_function(f);
union usbg_f_hid_attr_val val;
int i;
int ret = 0;
for (i = USBG_F_HID_ATTR_MIN; i < USBG_F_HID_ATTR_MAX; ++i) {
if (hid_attr[i].ro)
continue;
ret = hid_attr[i].import(root, hid_attr[i].name, &val);
/* node not found */
if (ret == 0)
continue;
/* error */
if (ret < 0)
break;
ret = usbg_f_hid_set_attr_val(hf, i, val);
if (ret)
break;
}
return ret;
}
static int hid_libconfig_export(struct usbg_function *f,
config_setting_t *root)
{
struct usbg_f_hid *hf = usbg_to_hid_function(f);
union usbg_f_hid_attr_val val;
int i;
int ret = 0;
for (i = USBG_F_HID_ATTR_MIN; i < USBG_F_HID_ATTR_MAX; ++i) {
ret = usbg_f_hid_get_attr_val(hf, i, &val);
if (ret)
break;
ret = hid_attr[i].export(root, hid_attr[i].name, &val);
if (ret)
break;
}
return ret;
}
#endif /* HAS_GADGET_SCHEMES */
struct usbg_function_type usbg_f_type_hid = {
.name = "hid",
.alloc_inst = hid_alloc_inst,
.free_inst = hid_free_inst,
.set_attrs = hid_set_attrs,
.get_attrs = hid_get_attrs,
.cleanup_attrs = hid_cleanup_attrs,
#ifdef HAS_GADGET_SCHEMES
.import = hid_libconfig_import,
.export = hid_libconfig_export,
#endif
};
/* API implementation */
usbg_f_hid *usbg_to_hid_function(usbg_function *f)
{
return f->ops == &usbg_f_type_hid ?
container_of(f, struct usbg_f_hid, func) : NULL;
}
usbg_function *usbg_from_hid_function(usbg_f_hid *hf)
{
return &hf->func;
}
int usbg_f_hid_get_attrs(usbg_f_hid *hf,
struct usbg_f_hid_attrs *attrs)
{
int i;
int ret = 0;
for (i = USBG_F_HID_ATTR_MIN; i < USBG_F_HID_ATTR_MAX; ++i) {
ret = usbg_f_hid_get_attr_val(hf, i,
(union usbg_f_hid_attr_val *)
((char *)attrs
+ hid_attr[i].offset));
if (ret)
break;
}
return ret;
}
int usbg_f_hid_set_attrs(usbg_f_hid *hf,
const struct usbg_f_hid_attrs *attrs)
{
int i;
int ret = 0;
for (i = USBG_F_HID_ATTR_MIN; i < USBG_F_HID_ATTR_MAX; ++i) {
if (hid_attr[i].ro)
continue;
ret = usbg_f_hid_set_attr_val(hf, i,
*(union usbg_f_hid_attr_val *)
((char *)attrs
+ hid_attr[i].offset));
if (ret)
break;
}
return ret;
}
int usbg_f_hid_get_attr_val(usbg_f_hid *hf, enum usbg_f_hid_attr attr,
union usbg_f_hid_attr_val *val)
{
return hid_attr[attr].get(hf->func.path, hf->func.name,
hid_attr[attr].name, val);
}
int usbg_f_hid_set_attr_val(usbg_f_hid *hf, enum usbg_f_hid_attr attr,
union usbg_f_hid_attr_val val)
{
return hid_attr[attr].ro ?
USBG_ERROR_INVALID_PARAM :
hid_attr[attr].set(hf->func.path, hf->func.name,
hid_attr[attr].name, &val);
}