3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2014 Intel Corporation. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library 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 GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include "src/shared/io.h"
35 #include "src/shared/util.h"
36 #include "src/shared/queue.h"
37 #include "src/shared/uhid.h"
39 #define UHID_DEVICE_FILE "/dev/uhid"
44 unsigned int notify_id;
45 struct queue *notify_list;
51 bt_uhid_callback_t func;
55 static void uhid_free(struct bt_uhid *uhid)
60 if (uhid->notify_list)
61 queue_destroy(uhid->notify_list, free);
66 static void notify_handler(void *data, void *user_data)
68 struct uhid_notify *notify = data;
69 struct uhid_event *ev = user_data;
71 if (notify->event != ev->type)
75 notify->func(ev, notify->user_data);
78 static bool uhid_read_handler(struct io *io, void *user_data)
80 struct bt_uhid *uhid = user_data;
89 memset(&ev, 0, sizeof(ev));
91 len = read(fd, &ev, sizeof(ev));
95 if ((size_t) len < sizeof(ev.type))
98 queue_foreach(uhid->notify_list, notify_handler, &ev);
103 struct bt_uhid *bt_uhid_new_default(void)
105 struct bt_uhid *uhid;
108 fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
112 uhid = bt_uhid_new(fd);
118 io_set_close_on_destroy(uhid->io, true);
123 struct bt_uhid *bt_uhid_new(int fd)
125 struct bt_uhid *uhid;
127 uhid = new0(struct bt_uhid, 1);
128 uhid->io = io_new(fd);
132 uhid->notify_list = queue_new();
134 if (!io_set_read_handler(uhid->io, uhid_read_handler, uhid, NULL))
137 return bt_uhid_ref(uhid);
144 struct bt_uhid *bt_uhid_ref(struct bt_uhid *uhid)
149 __sync_fetch_and_add(&uhid->ref_count, 1);
154 void bt_uhid_unref(struct bt_uhid *uhid)
159 if (__sync_sub_and_fetch(&uhid->ref_count, 1))
165 bool bt_uhid_set_close_on_unref(struct bt_uhid *uhid, bool do_close)
167 if (!uhid || !uhid->io)
170 io_set_close_on_destroy(uhid->io, do_close);
175 unsigned int bt_uhid_register(struct bt_uhid *uhid, uint32_t event,
176 bt_uhid_callback_t func, void *user_data)
178 struct uhid_notify *notify;
183 notify = new0(struct uhid_notify, 1);
184 notify->id = uhid->notify_id++;
185 notify->event = event;
187 notify->user_data = user_data;
189 if (!queue_push_tail(uhid->notify_list, notify)) {
197 static bool match_notify_id(const void *a, const void *b)
199 const struct uhid_notify *notify = a;
200 unsigned int id = PTR_TO_UINT(b);
202 return notify->id == id;
205 bool bt_uhid_unregister(struct bt_uhid *uhid, unsigned int id)
207 struct uhid_notify *notify;
212 notify = queue_remove_if(uhid->notify_list, match_notify_id,
221 int bt_uhid_send(struct bt_uhid *uhid, const struct uhid_event *ev)
229 iov.iov_base = (void *) ev;
230 iov.iov_len = sizeof(*ev);
232 len = io_send(uhid->io, &iov, 1);
236 /* uHID kernel driver does not handle partial writes */
237 return len != sizeof(*ev) ? -EIO : 0;