3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <sys/socket.h>
38 #include "src/shared/uhid.h"
39 #include "src/shared/util.h"
41 #include "src/shared/tester.h"
51 struct test_pdu *pdu_list;
59 unsigned int pdu_offset;
60 const struct test_data *data;
63 #define event(args...) \
66 .data = (void *) args, \
67 .size = sizeof(*args), \
70 #define define_test(name, function, args...) \
72 const struct test_pdu pdus[] = { \
75 static struct test_data data; \
76 data.test_name = g_strdup(name); \
77 data.pdu_list = g_memdup(pdus, sizeof(pdus)); \
78 tester_add(name, &data, NULL, function, NULL); \
81 static void test_debug(const char *str, void *user_data)
83 const char *prefix = user_data;
85 tester_debug("%s%s\n", prefix, str);
88 static void test_free(gconstpointer user_data)
90 const struct test_data *data = user_data;
92 g_free(data->test_name);
93 g_free(data->pdu_list);
96 static void destroy_context(struct context *context)
98 if (context->source > 0)
99 g_source_remove(context->source);
101 bt_uhid_unref(context->uhid);
103 test_free(context->data);
107 static gboolean context_quit(gpointer user_data)
109 struct context *context = user_data;
114 if (context->process > 0)
115 g_source_remove(context->process);
117 destroy_context(context);
118 tester_test_passed();
123 static gboolean send_pdu(gpointer user_data)
125 struct context *context = user_data;
126 const struct test_pdu *pdu;
129 pdu = &context->data->pdu_list[context->pdu_offset++];
131 len = write(context->fd, pdu->data, pdu->size);
134 util_hexdump('<', pdu->data, len, test_debug, "uHID: ");
136 g_assert_cmpint(len, ==, pdu->size);
138 context->process = 0;
142 static void context_process(struct context *context)
144 if (!context->data->pdu_list[context->pdu_offset].valid) {
145 context_quit(context);
149 context->process = g_idle_add(send_pdu, context);
152 static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
155 struct context *context = user_data;
156 const struct test_pdu *pdu;
157 unsigned char buf[sizeof(struct uhid_event)];
161 pdu = &context->data->pdu_list[context->pdu_offset++];
163 if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
165 g_print("%s: cond %x\n", __func__, cond);
169 fd = g_io_channel_unix_get_fd(channel);
171 len = read(fd, buf, sizeof(buf));
175 util_hexdump('>', buf, len, test_debug, "uHID: ");
177 g_assert_cmpint(len, ==, pdu->size);
179 g_assert(memcmp(buf, pdu->data, pdu->size) == 0);
181 context_process(context);
186 static struct context *create_context(gconstpointer data)
188 struct context *context = g_new0(struct context, 1);
192 err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
195 context->uhid = bt_uhid_new(sv[0]);
196 g_assert(context->uhid != NULL);
198 channel = g_io_channel_unix_new(sv[1]);
200 g_io_channel_set_close_on_unref(channel, TRUE);
201 g_io_channel_set_encoding(channel, NULL, NULL);
202 g_io_channel_set_buffered(channel, FALSE);
204 context->source = g_io_add_watch(channel,
205 G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
206 test_handler, context);
207 g_assert(context->source > 0);
209 g_io_channel_unref(channel);
212 context->data = data;
217 static const struct uhid_event ev_create = {
221 static const struct uhid_event ev_destroy = {
222 .type = UHID_DESTROY,
225 static const struct uhid_event ev_feature_answer = {
226 .type = UHID_FEATURE_ANSWER,
229 static const struct uhid_event ev_input = {
233 static const struct uhid_event ev_output = {
237 static const struct uhid_event ev_feature = {
238 .type = UHID_FEATURE,
241 static void test_client(gconstpointer data)
243 struct context *context = create_context(data);
245 if (g_str_equal(context->data->test_name, "/uhid/command/create"))
246 bt_uhid_send(context->uhid, &ev_create);
248 if (g_str_equal(context->data->test_name, "/uhid/command/destroy"))
249 bt_uhid_send(context->uhid, &ev_destroy);
251 if (g_str_equal(context->data->test_name,
252 "/uhid/command/feature_answer"))
253 bt_uhid_send(context->uhid, &ev_feature_answer);
255 if (g_str_equal(context->data->test_name, "/uhid/command/input"))
256 bt_uhid_send(context->uhid, &ev_input);
258 context_quit(context);
261 static void handle_output(struct uhid_event *ev, void *user_data)
263 g_assert_cmpint(ev->type, ==, UHID_OUTPUT);
265 context_quit(user_data);
268 static void handle_feature(struct uhid_event *ev, void *user_data)
270 g_assert_cmpint(ev->type, ==, UHID_FEATURE);
272 context_quit(user_data);
275 static void test_server(gconstpointer data)
277 struct context *context = create_context(data);
279 bt_uhid_register(context->uhid, UHID_OUTPUT, handle_output, context);
280 bt_uhid_register(context->uhid, UHID_FEATURE, handle_feature, context);
282 g_idle_add(send_pdu, context);
285 int main(int argc, char *argv[])
287 tester_init(&argc, &argv);
289 define_test("/uhid/command/create", test_client, event(&ev_create));
290 define_test("/uhid/command/destroy", test_client, event(&ev_destroy));
291 define_test("/uhid/command/feature_answer", test_client,
292 event(&ev_feature_answer));
293 define_test("/uhid/command/input", test_client, event(&ev_input));
295 define_test("/uhid/event/output", test_server, event(&ev_output));
296 define_test("/uhid/event/feature", test_server, event(&ev_feature));