int source_connect(struct btd_service *service) { struct source *source = btd_service_get_user_data(service); if (!source->session) source->session = a2dp_avdtp_get(btd_service_get_device(service)); if (!source->session) { DBG("Unable to get a session"); return -EIO; } if (source->connect_id > 0 || source->disconnect_id > 0) return -EBUSY; if (source->state == SOURCE_STATE_CONNECTING) return -EBUSY; if (source->stream_state >= AVDTP_STATE_OPEN) return -EALREADY; if (!source_setup_stream(service, NULL)) { DBG("Failed to create a stream"); return -EIO; } DBG("stream creation in progress"); return 0; }
int source_disconnect(struct btd_service *service) { struct source *source = btd_service_get_user_data(service); if (!source->session) return -ENOTCONN; /* cancel pending connect */ if (source->connect_id > 0) { a2dp_cancel(source->connect_id); source->connect_id = 0; btd_service_connecting_complete(source->service, -ECANCELED); avdtp_unref(source->session); source->session = NULL; return 0; } /* disconnect already ongoing */ if (source->disconnect_id > 0) return -EBUSY; if (!source->stream) return -ENOTCONN; return avdtp_close(source->session, source->stream, FALSE); }
static int gap_accept(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct gatt_db *db = btd_device_get_gatt_db(device); struct bt_gatt_client *client = btd_device_get_gatt_client(device); struct gas *gas = btd_service_get_user_data(service); char addr[18]; bt_uuid_t gap_uuid; ba2str(device_get_address(device), addr); DBG("GAP profile accept (%s)", addr); if (!gas) { error("GAP service not handled by profile"); return -1; } gas->db = gatt_db_ref(db); gas->client = bt_gatt_client_ref(client); /* Handle the GAP services */ bt_uuid16_create(&gap_uuid, GAP_UUID16); gatt_db_foreach_service(db, &gap_uuid, foreach_gap_service, gas); if (!gas->attr) { error("GAP attribute not found"); gas_reset(gas); return -1; } btd_service_connecting_complete(service, 0); return 0; }
static void source_free(struct btd_service *service) { struct source *source = btd_service_get_user_data(service); if (source->cb_id) avdtp_stream_remove_cb(source->session, source->stream, source->cb_id); if (source->session) avdtp_unref(source->session); if (source->connect_id > 0) { btd_service_connecting_complete(source->service, -ECANCELED); a2dp_cancel(source->connect_id); source->connect_id = 0; } if (source->disconnect_id > 0) { btd_service_disconnecting_complete(source->service, -ECANCELED); a2dp_cancel(source->disconnect_id); source->disconnect_id = 0; } avdtp_remove_state_cb(source->avdtp_callback_id); btd_service_unref(source->service); g_free(source); }
/* Connect and initiate BNEP session */ int connection_connect(struct btd_service *service) { struct network_conn *nc = btd_service_get_user_data(service); struct network_peer *peer = nc->peer; uint16_t id = get_service_id(service); GError *err = NULL; const bdaddr_t *src; const bdaddr_t *dst; DBG("id %u", id); if (nc->state != DISCONNECTED) return -EALREADY; src = btd_adapter_get_address(device_get_adapter(peer->device)); dst = device_get_address(peer->device); nc->io = bt_io_connect(connect_cb, nc, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_DEST_BDADDR, dst, BT_IO_OPT_PSM, BNEP_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_OMTU, BNEP_MTU, BT_IO_OPT_IMTU, BNEP_MTU, BT_IO_OPT_INVALID); if (!nc->io) return -EIO; nc->state = CONNECTING; return 0; }
gboolean control_is_active(struct btd_service *service) { struct control *control = btd_service_get_user_data(service); if (control && control->session) return TRUE; return FALSE; }
gboolean sink_is_active(struct btd_service *service) { struct sink *sink = btd_service_get_user_data(service); if (sink->session) return TRUE; return FALSE; }
static int gap_disconnect(struct btd_service *service) { struct gas *gas = btd_service_get_user_data(service); gas_reset(gas); btd_service_disconnecting_complete(service, 0); return 0; }
static void hog_remove(struct btd_service *service) { struct hog_device *dev = btd_service_get_user_data(service); struct btd_device *device = btd_service_get_device(service); const char *path = device_get_path(device); DBG("path %s", path); hog_device_free(dev); }
int control_disconnect(struct btd_service *service) { struct control *control = btd_service_get_user_data(service); if (!control->session) return -ENOTCONN; avctp_disconnect(control->session); return 0; }
int connection_disconnect(struct btd_service *service) { struct network_conn *nc = btd_service_get_user_data(service); if (nc->state == DISCONNECTED) return 0; connection_destroy(NULL, nc); return 0; }
static void scan_param_remove(struct btd_service *service) { struct scan *scan = btd_service_get_user_data(service); if (scan->attrib != NULL && scan->refresh_cb_id > 0) g_attrib_unregister(scan->attrib, scan->refresh_cb_id); btd_device_remove_attio_callback(scan->device, scan->attioid); btd_device_unref(scan->device); g_attrib_unref(scan->attrib); g_free(scan); }
int control_connect(struct btd_service *service) { struct control *control = btd_service_get_user_data(service); if (control->session) return -EALREADY; control->session = avctp_connect(control->dev); if (!control->session) return -EIO; return 0; }
void input_device_unregister(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); const char *path = device_get_path(device); struct input_device *idev = btd_service_get_user_data(service); DBG("%s", path); g_dbus_unregister_interface(btd_get_dbus_connection(), idev->path, INPUT_INTERFACE); input_device_free(idev); }
int input_device_connect(struct btd_service *service) { struct input_device *idev; idev = btd_service_get_user_data(service); if (idev->ctrl_io) return -EBUSY; if (is_connected(idev)) return -EALREADY; return dev_connect(idev); }
int input_device_disconnect(struct btd_service *service) { struct input_device *idev; int err; DBG(""); idev = btd_service_get_user_data(service); err = connection_disconnect(idev, 0); if (err < 0) return err; return 0; }
static struct input_device *find_device(const bdaddr_t *src, const bdaddr_t *dst) { struct btd_device *device; struct btd_service *service; device = btd_adapter_find_device(adapter_find(src), dst); if (device == NULL) return NULL; service = btd_device_get_service(device, HID_UUID); if (service == NULL) return NULL; return btd_service_get_user_data(service); }
static void deviceinfo_driver_remove(struct btd_service *service) { struct deviceinfo *d = btd_service_get_user_data(service); if (d->attioid > 0) btd_device_remove_attio_callback(d->dev, d->attioid); if (d->attrib != NULL) g_attrib_unref(d->attrib); g_slist_free_full(d->chars, g_free); btd_device_unref(d->dev); g_free(d->svc_range); g_free(d); }
static void gap_remove(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct gas *gas; char addr[18]; ba2str(device_get_address(device), addr); DBG("GAP profile remove (%s)", addr); gas = btd_service_get_user_data(service); if (!gas) { error("GAP service not handled by profile"); return; } gas_free(gas); }
gboolean source_new_stream(struct btd_service *service, struct avdtp *session, struct avdtp_stream *stream) { struct source *source = btd_service_get_user_data(service); if (source->stream) return FALSE; if (!source->session) source->session = avdtp_ref(session); source->stream = stream; source->cb_id = avdtp_stream_add_cb(session, stream, stream_state_changed, service); return TRUE; }
gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session) { struct sink *sink = btd_service_get_user_data(service); if (sink->connect_id > 0 || sink->disconnect_id > 0) return FALSE; if (session && !sink->session) sink->session = avdtp_ref(session); if (!sink->session) return FALSE; if (avdtp_discover(sink->session, discovery_complete, sink) < 0) return FALSE; return TRUE; }
int input_device_disconnect(struct btd_service *service) { struct input_device *idev; int err, flags; DBG(""); idev = btd_service_get_user_data(service); flags = device_is_temporary(idev->device) ? (1 << HIDP_VIRTUAL_CABLE_UNPLUG) : 0; err = connection_disconnect(idev, flags); if (err < 0) return err; return 0; }
static void stream_state_changed(struct avdtp_stream *stream, avdtp_state_t old_state, avdtp_state_t new_state, struct avdtp_error *err, void *user_data) { struct btd_service *service = user_data; struct source *source = btd_service_get_user_data(service); if (err) return; switch (new_state) { case AVDTP_STATE_IDLE: btd_service_disconnecting_complete(source->service, 0); if (source->disconnect_id > 0) { a2dp_cancel(source->disconnect_id); source->disconnect_id = 0; } if (source->session) { avdtp_unref(source->session); source->session = NULL; } source->stream = NULL; source->cb_id = 0; break; case AVDTP_STATE_OPEN: btd_service_connecting_complete(source->service, 0); source_set_state(source, SOURCE_STATE_CONNECTED); break; case AVDTP_STATE_STREAMING: source_set_state(source, SOURCE_STATE_PLAYING); break; case AVDTP_STATE_CONFIGURED: case AVDTP_STATE_CLOSING: case AVDTP_STATE_ABORTING: default: break; } source->stream_state = new_state; }
void connection_unregister(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct network_conn *conn = btd_service_get_user_data(service); struct network_peer *peer = conn->peer; uint16_t id = get_service_id(service); DBG("%s id %u", device_get_path(device), id); peer->connections = g_slist_remove(peer->connections, conn); connection_free(conn); if (peer->connections != NULL) return; g_dbus_unregister_interface(btd_get_dbus_connection(), device_get_path(device), NETWORK_PEER_INTERFACE); }
static DBusMessage *local_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_peer *peer = data; struct btd_service *service; struct network_conn *nc; const char *svc; const char *uuid; uint16_t id; int err; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc, DBUS_TYPE_INVALID) == FALSE) return btd_error_invalid_args(msg); id = bnep_service_id(svc); uuid = bnep_uuid(id); if (uuid == NULL) return btd_error_invalid_args(msg); service = btd_device_get_service(peer->device, uuid); if (service == NULL) return btd_error_not_supported(msg); nc = btd_service_get_user_data(service); if (nc->connect != NULL) return btd_error_busy(msg); err = connection_connect(nc->service); if (err < 0) return btd_error_failed(msg, strerror(-err)); nc->connect = dbus_message_ref(msg); return NULL; }
static int gap_probe(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct gas *gas = btd_service_get_user_data(service); char addr[18]; ba2str(device_get_address(device), addr); DBG("GAP profile probe (%s)", addr); /* Ignore, if we were probed for this device already */ if (gas) { error("Profile probed twice for the same device!"); return -1; } gas = g_new0(struct gas, 1); if (!gas) return -1; gas->device = btd_device_ref(device); btd_service_set_user_data(service, gas); return 0; }