3 * neard - Near Field Communication manager
5 * Copyright (C) 2011 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
38 /* We check for the tag being present every 2 seconds */
39 #define CHECK_PRESENCE_PERIOD 2
41 static DBusConnection *connection = NULL;
43 static GHashTable *adapter_hash;
45 #define NEAR_ADAPTER_MODE_INITIATOR 0x1
46 #define NEAR_ADAPTER_MODE_TARGET 0x2
47 #define NEAR_ADAPTER_MODE_DUAL 0x3
60 near_bool_t constant_poll;
64 struct near_tag *tag_link;
68 struct near_device *device_link;
75 guint presence_timeout;
78 struct near_adapter_ioreq {
81 unsigned char buf[1024];
91 static void free_adapter(gpointer data)
93 struct near_adapter *adapter = data;
95 if (adapter->presence_timeout > 0)
96 g_source_remove(adapter->presence_timeout);
98 g_free(adapter->name);
99 g_free(adapter->path);
103 static void free_tag(gpointer data)
105 struct near_tag *tag = data;
107 __near_tag_remove(tag);
110 static void free_device(gpointer data)
112 struct near_device *device = data;
114 __near_device_remove(device);
117 static void polling_changed(struct near_adapter *adapter)
120 near_dbus_property_changed_basic(adapter->path,
121 NFC_ADAPTER_INTERFACE, "Polling",
122 DBUS_TYPE_BOOLEAN, &adapter->polling);
125 static int adapter_start_poll(struct near_adapter *adapter)
128 uint32_t im_protos, tm_protos;
130 if (g_hash_table_size(adapter->tags) > 0) {
131 DBG("Clearing tags");
133 g_hash_table_remove_all(adapter->tags);
134 __near_adapter_tags_changed(adapter->idx);
137 if (g_hash_table_size(adapter->devices) > 0) {
138 DBG("Clearing devices");
140 g_hash_table_remove_all(adapter->devices);
141 __near_adapter_devices_changed(adapter->idx);
144 DBG("Poll mode 0x%x", adapter->poll_mode);
146 im_protos = tm_protos = 0;
148 if (adapter->poll_mode & NEAR_ADAPTER_MODE_INITIATOR)
149 im_protos = adapter->protocols;
151 if (adapter->poll_mode & NEAR_ADAPTER_MODE_TARGET)
152 tm_protos = adapter->protocols;
154 err = __near_netlink_start_poll(adapter->idx, im_protos, tm_protos);
158 adapter->polling = TRUE;
160 polling_changed(adapter);
165 static void append_path(gpointer key, gpointer value, gpointer user_data)
167 struct near_adapter *adapter = value;
168 DBusMessageIter *iter = user_data;
170 DBG("%s", adapter->path);
172 if (adapter->path == NULL)
175 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
179 void __near_adapter_list(DBusMessageIter *iter, void *user_data)
181 g_hash_table_foreach(adapter_hash, append_path, iter);
184 static void append_protocols(DBusMessageIter *iter, void *user_data)
186 struct near_adapter *adapter = user_data;
189 DBG("protocols 0x%x", adapter->protocols);
191 if (adapter->protocols & NFC_PROTO_FELICA_MASK) {
194 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
197 if (adapter->protocols & NFC_PROTO_MIFARE_MASK) {
200 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
203 if (adapter->protocols & NFC_PROTO_JEWEL_MASK) {
206 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
209 if (adapter->protocols & NFC_PROTO_ISO14443_MASK) {
212 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
215 if (adapter->protocols & NFC_PROTO_NFC_DEP_MASK) {
218 dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
222 static void append_tag_path(gpointer key, gpointer value, gpointer user_data)
224 struct near_tag *tag = value;
225 DBusMessageIter *iter = user_data;
226 const char *tag_path;
228 tag_path = __near_tag_get_path(tag);
229 if (tag_path == NULL)
234 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &tag_path);
237 static void append_tags(DBusMessageIter *iter, void *user_data)
239 struct near_adapter *adapter = user_data;
243 g_hash_table_foreach(adapter->tags, append_tag_path, iter);
246 static void append_device_path(gpointer key, gpointer value, gpointer user_data)
248 struct near_device *device = value;
249 DBusMessageIter *iter = user_data;
250 const char *device_path;
252 device_path = __near_device_get_path(device);
253 if (device_path == NULL)
256 DBG("%s", device_path);
258 dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
262 static void append_devices(DBusMessageIter *iter, void *user_data)
264 struct near_adapter *adapter = user_data;
268 g_hash_table_foreach(adapter->devices, append_device_path, iter);
271 void __near_adapter_tags_changed(uint32_t adapter_idx)
273 struct near_adapter *adapter;
277 adapter = g_hash_table_lookup(adapter_hash,
278 GINT_TO_POINTER(adapter_idx));
282 near_dbus_property_changed_array(adapter->path,
283 NFC_ADAPTER_INTERFACE, "Tags",
284 DBUS_TYPE_OBJECT_PATH, append_tags,
288 void __near_adapter_devices_changed(uint32_t adapter_idx)
290 struct near_adapter *adapter;
294 adapter = g_hash_table_lookup(adapter_hash,
295 GINT_TO_POINTER(adapter_idx));
299 near_dbus_property_changed_array(adapter->path,
300 NFC_ADAPTER_INTERFACE, "Devices",
301 DBUS_TYPE_OBJECT_PATH, append_devices,
305 static DBusMessage *get_properties(DBusConnection *conn,
306 DBusMessage *msg, void *data)
308 struct near_adapter *adapter = data;
310 DBusMessageIter array, dict;
312 DBG("conn %p", conn);
314 reply = dbus_message_new_method_return(msg);
318 dbus_message_iter_init_append(reply, &array);
320 near_dbus_dict_open(&array, &dict);
322 near_dbus_dict_append_basic(&dict, "Powered",
323 DBUS_TYPE_BOOLEAN, &adapter->powered);
325 near_dbus_dict_append_basic(&dict, "Polling",
326 DBUS_TYPE_BOOLEAN, &adapter->polling);
328 near_dbus_dict_append_array(&dict, "Protocols",
329 DBUS_TYPE_STRING, append_protocols, adapter);
331 near_dbus_dict_append_array(&dict, "Tags",
332 DBUS_TYPE_OBJECT_PATH, append_tags, adapter);
334 near_dbus_dict_append_array(&dict, "Devices",
335 DBUS_TYPE_OBJECT_PATH, append_devices, adapter);
337 near_dbus_dict_close(&array, &dict);
342 static DBusMessage *set_property(DBusConnection *conn,
343 DBusMessage *msg, void *data)
345 struct near_adapter *adapter = data;
346 DBusMessageIter iter, value;
350 DBG("conn %p", conn);
352 if (dbus_message_iter_init(msg, &iter) == FALSE)
353 return __near_error_invalid_arguments(msg);
355 dbus_message_iter_get_basic(&iter, &name);
356 dbus_message_iter_next(&iter);
357 dbus_message_iter_recurse(&iter, &value);
359 type = dbus_message_iter_get_arg_type(&value);
361 if (g_str_equal(name, "Powered") == TRUE) {
364 if (type != DBUS_TYPE_BOOLEAN)
365 return __near_error_invalid_arguments(msg);
367 dbus_message_iter_get_basic(&value, &powered);
369 err = __near_netlink_adapter_enable(adapter->idx, powered);
371 if (err == -EALREADY)
372 return __near_error_already_enabled(msg);
374 return __near_error_failed(msg, -err);
377 adapter->powered = powered;
379 return __near_error_invalid_property(msg);
382 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
385 static DBusMessage *start_poll_loop(DBusConnection *conn,
386 DBusMessage *msg, void *data)
388 struct near_adapter *adapter = data;
389 const char *dbus_mode;
392 DBG("conn %p", conn);
394 dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &dbus_mode,
397 DBG("Mode %s", dbus_mode);
399 if (g_strcmp0(dbus_mode, "Initiator") == 0)
400 adapter->poll_mode = NEAR_ADAPTER_MODE_INITIATOR;
401 else if (g_strcmp0(dbus_mode, "Target") == 0)
402 adapter->poll_mode = NEAR_ADAPTER_MODE_TARGET;
403 else if (g_strcmp0(dbus_mode, "Dual") == 0)
404 adapter->poll_mode = NEAR_ADAPTER_MODE_DUAL;
406 adapter->poll_mode = NEAR_ADAPTER_MODE_INITIATOR;
408 err = adapter_start_poll(adapter);
410 return __near_error_failed(msg, -err);
412 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
415 static DBusMessage *stop_poll_loop(DBusConnection *conn,
416 DBusMessage *msg, void *data)
418 struct near_adapter *adapter = data;
421 DBG("conn %p", conn);
423 err = __near_netlink_stop_poll(adapter->idx);
425 return __near_error_failed(msg, -err);
427 adapter->polling = FALSE;
429 polling_changed(adapter);
431 return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
434 static void tag_present_cb(uint32_t adapter_idx, uint32_t target_idx,
437 static gboolean check_presence(gpointer user_data)
439 struct near_adapter *adapter = user_data;
440 struct near_tag *tag;
448 tag = adapter->tag_link;
452 err = __near_tag_check_presence(tag, tag_present_cb);
454 DBG("Could not check target presence");
461 near_adapter_disconnect(adapter->idx);
462 if (adapter->constant_poll == TRUE)
463 adapter_start_poll(adapter);
468 static void tag_present_cb(uint32_t adapter_idx, uint32_t target_idx,
471 struct near_adapter *adapter;
475 adapter = g_hash_table_lookup(adapter_hash,
476 GINT_TO_POINTER(adapter_idx));
483 near_adapter_disconnect(adapter->idx);
484 if (adapter->constant_poll == TRUE)
485 adapter_start_poll(adapter);
490 adapter->presence_timeout =
491 g_timeout_add_seconds(CHECK_PRESENCE_PERIOD,
492 check_presence, adapter);
495 static const GDBusMethodTable adapter_methods[] = {
496 { GDBUS_METHOD("GetProperties",
497 NULL, GDBUS_ARGS({"properties", "a{sv}"}),
499 { GDBUS_METHOD("SetProperty",
500 GDBUS_ARGS({"name", "s"}, {"value", "v"}),
501 NULL, set_property) },
502 { GDBUS_METHOD("StartPollLoop", GDBUS_ARGS({"name", "s"}), NULL,
504 { GDBUS_METHOD("StopPollLoop", NULL, NULL, stop_poll_loop) },
508 static const GDBusSignalTable adapter_signals[] = {
509 { GDBUS_SIGNAL("PropertyChanged",
510 GDBUS_ARGS({"name", "s"}, {"value", "v"})) },
511 { GDBUS_SIGNAL("TagFound", GDBUS_ARGS({"address", "o"})) },
512 { GDBUS_SIGNAL("TagLost", GDBUS_ARGS({"address", "o"})) },
516 struct near_adapter * __near_adapter_create(uint32_t idx,
517 const char *name, uint32_t protocols, near_bool_t powered)
519 struct near_adapter *adapter;
521 adapter = g_try_malloc0(sizeof(struct near_adapter));
525 adapter->name = g_strdup(name);
526 if (adapter->name == NULL) {
531 adapter->protocols = protocols;
532 adapter->powered = powered;
533 adapter->constant_poll = near_setting_get_bool("ConstantPoll");
534 adapter->dep_up = FALSE;
535 adapter->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
537 adapter->tag_sock = -1;
539 adapter->devices = g_hash_table_new_full(g_direct_hash, g_direct_equal,
541 adapter->device_sock = -1;
543 adapter->path = g_strdup_printf("%s/nfc%d", NFC_PATH, idx);
548 void __near_adapter_destroy(struct near_adapter *adapter)
552 free_adapter(adapter);
555 const char *__near_adapter_get_path(struct near_adapter *adapter)
557 return adapter->path;
560 struct near_adapter *__near_adapter_get(uint32_t idx)
562 return g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
565 int __near_adapter_set_dep_state(uint32_t idx, near_bool_t dep)
567 struct near_adapter *adapter;
571 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
575 adapter->dep_up = dep;
577 if (dep == FALSE && adapter->constant_poll == TRUE)
578 adapter_start_poll(adapter);
583 near_bool_t __near_adapter_get_dep_state(uint32_t idx)
585 struct near_adapter *adapter;
589 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
593 return adapter->dep_up;
596 int __near_adapter_add(struct near_adapter *adapter)
598 uint32_t idx = adapter->idx;
600 DBG("%s", adapter->path);
602 if (g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx)) != NULL)
605 g_hash_table_insert(adapter_hash, GINT_TO_POINTER(idx), adapter);
607 DBG("connection %p", connection);
609 g_dbus_register_interface(connection, adapter->path,
610 NFC_ADAPTER_INTERFACE,
611 adapter_methods, adapter_signals,
612 NULL, adapter, NULL);
617 void __near_adapter_remove(struct near_adapter *adapter)
619 DBG("%s", adapter->path);
621 g_dbus_unregister_interface(connection, adapter->path,
622 NFC_ADAPTER_INTERFACE);
624 g_hash_table_remove(adapter_hash, GINT_TO_POINTER(adapter->idx));
627 static void tag_read_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
629 struct near_adapter *adapter;
631 DBG("status %d", status);
633 adapter = g_hash_table_lookup(adapter_hash,
634 GINT_TO_POINTER(adapter_idx));
639 near_adapter_disconnect(adapter->idx);
640 if (adapter->constant_poll == TRUE)
641 adapter_start_poll(adapter);
646 __near_adapter_tags_changed(adapter_idx);
648 adapter->presence_timeout =
649 g_timeout_add_seconds(CHECK_PRESENCE_PERIOD,
650 check_presence, adapter);
653 static void device_read_cb(uint32_t adapter_idx, uint32_t target_idx,
656 struct near_adapter *adapter;
658 DBG("status %d", status);
660 adapter = g_hash_table_lookup(adapter_hash,
661 GINT_TO_POINTER(adapter_idx));
666 if (adapter->device_link != NULL) {
667 __near_netlink_dep_link_down(adapter->idx);
668 adapter->device_link = NULL;
671 if (adapter->constant_poll == TRUE)
672 adapter_start_poll(adapter);
677 __near_adapter_devices_changed(adapter_idx);
680 static int adapter_add_tag(struct near_adapter *adapter, uint32_t target_idx,
682 uint16_t sens_res, uint8_t sel_res,
683 uint8_t *nfcid, uint8_t nfcid_len)
685 struct near_tag *tag;
689 tag = __near_tag_add(adapter->idx, target_idx, protocols,
695 g_hash_table_insert(adapter->tags, GINT_TO_POINTER(target_idx), tag);
697 tag_type = __near_tag_get_type(tag);
699 err = near_adapter_connect(adapter->idx, target_idx, tag_type);
701 near_error("Could not connect");
705 return __near_tag_read(tag, tag_read_cb);
708 static int adapter_add_device(struct near_adapter *adapter,
710 uint8_t *nfcid, uint8_t nfcid_len)
712 struct near_device *device;
715 device = __near_device_add(adapter->idx, target_idx, nfcid, nfcid_len);
719 g_hash_table_insert(adapter->devices, GINT_TO_POINTER(target_idx),
722 /* For p2p, reading is listening for an incoming connection */
723 err = __near_device_listen(device, device_read_cb);
725 near_error("Could not read device");
729 adapter->device_link = device;
731 if (adapter->dep_up == TRUE)
734 err = __near_netlink_dep_link_up(adapter->idx, target_idx,
735 NFC_COMM_ACTIVE, NFC_RF_INITIATOR);
738 adapter->device_link = NULL;
743 int __near_adapter_add_target(uint32_t idx, uint32_t target_idx,
744 uint32_t protocols, uint16_t sens_res, uint8_t sel_res,
745 uint8_t *nfcid, uint8_t nfcid_len)
747 struct near_adapter *adapter;
751 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
755 adapter->polling = FALSE;
756 polling_changed(adapter);
758 if (protocols & NFC_PROTO_NFC_DEP_MASK)
759 return adapter_add_device(adapter, target_idx,
762 return adapter_add_tag(adapter, target_idx, protocols,
763 sens_res, sel_res, nfcid, nfcid_len);
766 int __near_adapter_remove_target(uint32_t idx, uint32_t target_idx)
768 struct near_adapter *adapter;
772 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
776 if (g_hash_table_remove(adapter->tags,
777 GINT_TO_POINTER(target_idx)) == TRUE) {
778 __near_adapter_tags_changed(idx);
783 if (g_hash_table_remove(adapter->devices,
784 GINT_TO_POINTER(target_idx)) == TRUE) {
785 __near_adapter_devices_changed(idx);
793 int __near_adapter_add_device(uint32_t idx, uint8_t *nfcid, uint8_t nfcid_len)
795 struct near_adapter *adapter;
799 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
803 adapter->polling = FALSE;
804 adapter->dep_up = TRUE;
805 polling_changed(adapter);
807 return adapter_add_device(adapter, 0, nfcid, nfcid_len);
810 int __near_adapter_remove_device(uint32_t idx)
812 struct near_adapter *adapter;
813 uint32_t device_idx = 0;
817 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
821 if (g_hash_table_remove(adapter->devices,
822 GINT_TO_POINTER(device_idx)) == FALSE)
825 __near_adapter_devices_changed(idx);
827 adapter->dep_up = FALSE;
829 if (adapter->constant_poll == TRUE)
830 adapter_start_poll(adapter);
835 static void adapter_flush_rx(struct near_adapter *adapter, int error)
839 for (list = adapter->ioreq_list; list; list = list->next) {
840 struct near_adapter_ioreq *req = list->data;
845 req->cb(NULL, error, req->data);
849 g_list_free(adapter->ioreq_list);
850 adapter->ioreq_list = NULL;
853 static gboolean execute_recv_cb(gpointer user_data)
855 struct near_adapter_ioreq *req = user_data;
857 DBG("data %p", req->data);
859 req->cb(req->buf, req->len, req->data);
866 static gboolean adapter_recv_event(GIOChannel *channel, GIOCondition condition,
869 struct near_adapter *adapter = user_data;
870 struct near_adapter_ioreq *req;
874 DBG("condition 0x%x", condition);
876 if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
877 near_error("Error while reading NFC bytes");
879 adapter_flush_rx(adapter, -EIO);
881 near_adapter_disconnect(adapter->idx);
883 adapter->presence_timeout =
884 g_timeout_add_seconds(2 * CHECK_PRESENCE_PERIOD,
885 check_presence, adapter);
889 sk = g_io_channel_unix_get_fd(channel);
890 first = g_list_first(adapter->ioreq_list);
895 req->len = recv(sk, req->buf, sizeof(req->buf), 0);
897 adapter->ioreq_list = g_list_remove(adapter->ioreq_list, req);
899 g_idle_add(execute_recv_cb, req);
904 int near_adapter_connect(uint32_t idx, uint32_t target_idx, uint8_t protocol)
906 struct near_adapter *adapter;
907 struct near_tag *tag;
908 struct sockaddr_nfc addr;
913 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
917 if (adapter->tag_sock != -1)
920 tag = g_hash_table_lookup(adapter->tags,
921 GINT_TO_POINTER(target_idx));
925 sock = socket(AF_NFC, SOCK_SEQPACKET, NFC_SOCKPROTO_RAW);
929 addr.sa_family = AF_NFC;
931 addr.target_idx = target_idx;
932 addr.nfc_protocol = protocol;
934 err = connect(sock, (struct sockaddr *) &addr, sizeof(addr));
940 adapter->tag_sock = sock;
941 adapter->tag_link = tag;
943 if (adapter->channel == NULL)
944 adapter->channel = g_io_channel_unix_new(adapter->tag_sock);
946 g_io_channel_set_flags(adapter->channel, G_IO_FLAG_NONBLOCK, NULL);
947 g_io_channel_set_close_on_unref(adapter->channel, TRUE);
949 if (adapter->watch == 0)
950 adapter->watch = g_io_add_watch(adapter->channel,
951 G_IO_IN | G_IO_NVAL | G_IO_ERR | G_IO_HUP,
952 adapter_recv_event, adapter);
957 int near_adapter_disconnect(uint32_t idx)
959 struct near_adapter *adapter;
965 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
969 DBG("link %p", adapter->tag_link);
971 if (adapter->tag_link == NULL)
974 tag_type = __near_tag_get_type(adapter->tag_link);
975 target_idx = __near_tag_get_idx(adapter->tag_link);
977 DBG("tag type %d", tag_type);
979 __near_adapter_remove_target(adapter->idx, target_idx);
981 if (adapter->tag_sock == -1)
984 if (adapter->watch > 0) {
985 g_source_remove(adapter->watch);
989 g_io_channel_unref(adapter->channel);
990 adapter->channel = NULL;
991 adapter->tag_sock = -1;
992 adapter->tag_link = NULL;
997 int near_adapter_send(uint32_t idx, uint8_t *buf, size_t length,
998 near_recv cb, void *data)
1000 struct near_adapter *adapter;
1001 struct near_adapter_ioreq *req = NULL;
1006 adapter = g_hash_table_lookup(adapter_hash, GINT_TO_POINTER(idx));
1007 if (adapter == NULL)
1010 if (adapter->tag_sock == -1 || adapter->tag_link == NULL)
1013 if (cb != NULL && adapter->watch != 0) {
1014 req = g_try_malloc0(sizeof(*req));
1018 DBG("req %p cb %p data %p", req, cb, data);
1020 req->target_idx = __near_tag_get_idx(adapter->tag_link);
1024 adapter->ioreq_list =
1025 g_list_append(adapter->ioreq_list, req);
1028 err = send(adapter->tag_sock, buf, length, 0);
1036 GList *last = g_list_last(adapter->ioreq_list);
1039 adapter->ioreq_list =
1040 g_list_delete_link(adapter->ioreq_list, last);
1046 static void adapter_listen(gpointer key, gpointer value, gpointer user_data)
1048 struct near_adapter *adapter = value;
1049 struct near_device_driver *driver = user_data;
1051 DBG("%s", adapter->path);
1053 if (adapter->path == NULL)
1056 driver->listen(adapter->idx, device_read_cb);
1059 void __near_adapter_listen(struct near_device_driver *driver)
1061 g_hash_table_foreach(adapter_hash, adapter_listen, driver);
1064 int __near_adapter_init(void)
1068 connection = near_dbus_get_connection();
1070 adapter_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
1071 NULL, free_adapter);
1076 void __near_adapter_cleanup(void)
1080 g_hash_table_destroy(adapter_hash);
1081 adapter_hash = NULL;